make-4.2.1/ 0000755 0001750 0001750 00000000000 12726643534 007450 5 0000000 0000000 make-4.2.1/vmsfunctions.c 0000644 0001750 0001750 00000013452 12667724516 012303 0000000 0000000 /* VMS functions
Copyright (C) 1996-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include "debug.h"
#include "job.h"
#include
#include
#ifdef __DECC
#include
#endif
#include
#include "vmsdir.h"
#ifdef HAVE_VMSDIR_H
DIR *
opendir (char *dspec)
{
struct DIR *dir = xcalloc (sizeof (struct DIR));
struct NAM *dnam = xmalloc (sizeof (struct NAM));
struct FAB *dfab = &dir->fab;
char *searchspec = xmalloc (MAXNAMLEN + 1);
*dfab = cc$rms_fab;
*dnam = cc$rms_nam;
sprintf (searchspec, "%s*.*;", dspec);
dfab->fab$l_fna = searchspec;
dfab->fab$b_fns = strlen (searchspec);
dfab->fab$l_nam = dnam;
*dnam = cc$rms_nam;
dnam->nam$l_esa = searchspec;
dnam->nam$b_ess = MAXNAMLEN;
if (! (sys$parse (dfab) & 1))
{
free (dir);
free (dnam);
free (searchspec);
return (NULL);
}
return dir;
}
#define uppercasify(str) \
do \
{ \
char *tmp; \
for (tmp = (str); *tmp != '\0'; tmp++) \
if (islower ((unsigned char)*tmp)) \
*tmp = toupper ((unsigned char)*tmp); \
} \
while (0)
struct direct *
readdir (DIR *dir)
{
struct FAB *dfab = &dir->fab;
struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam);
struct direct *dentry = &dir->dir;
int i;
memset (dentry, 0, sizeof *dentry);
dnam->nam$l_rsa = dir->d_result;
dnam->nam$b_rss = MAXNAMLEN;
DB (DB_VERBOSE, ("."));
if (!((i = sys$search (dfab)) & 1))
{
DB (DB_VERBOSE, (_("sys$search() failed with %d\n"), i));
return (NULL);
}
dentry->d_off = 0;
if (dnam->nam$w_fid == 0)
dentry->d_fileno = 1;
else
dentry->d_fileno = dnam->nam$w_fid[0] + (dnam->nam$w_fid[1] << 16);
dentry->d_reclen = sizeof (struct direct);
dentry->d_namlen = dnam->nam$b_name + dnam->nam$b_type;
strncpy (dentry->d_name, dnam->nam$l_name, dentry->d_namlen);
dentry->d_name[dentry->d_namlen] = '\0';
#ifdef HAVE_CASE_INSENSITIVE_FS
uppercasify (dentry->d_name);
#endif
return (dentry);
}
int
closedir (DIR *dir)
{
if (dir != NULL)
{
struct FAB *dfab = &dir->fab;
struct NAM *dnam = (struct NAM *)(dfab->fab$l_nam);
if (dnam != NULL)
free (dnam->nam$l_esa);
free (dnam);
free (dir);
}
return 0;
}
#endif /* compiled for OpenVMS prior to V7.x */
/* Argv0 will be a full vms file specification, like
node$dka100:[utils.gnumake]make.exe;47
prefix it with "mcr " to make it a vms command, executable for DCL. */
const char *
vms_command(const char* argv0)
{
size_t l = strlen(argv0) + 1;
char* s = xmalloc(l + 4);
memcpy(s, "mcr ", 4);
memcpy(s+4, argv0, l);
return s;
}
/* Argv0 aka argv[0] will be a full vms file specification, like
node$dka100:[utils.gnumake]make.exe;47, set up by the CRTL.
The vms progname should be ^^^^, the file name without
file type .exe and ;version.
Use sys$parse to get the name part of the file specification. That is
in the above example, pick up "make" and return a copy of that string.
If something goes wrong in sys$parse (unlikely, this is a VMS/CRTL supplied
file specification) or if there is an empty name part (not easy to produce,
but it is possible) just return "make".
Somes notes ...
NAM[L]$M_SYNCHK requests a syntax check, only.
NAM is for ODS2 names (shorter parts, output usually converted to UPPERCASE).
NAML is for ODS2/ODS5 names (longer parts, output unchanged).
NAM$M_NO_SHORT_UPCASE may not be available for older versions of VMS.
NAML is not available on older versions of VMS (NAML$C_BID not defined).
argv[0] on older versions of VMS (no extended parse style and no
CRTL feature DECC$ARGV_PARSE_STYLE) is always in lowercase. */
const char *
vms_progname(const char* argv0)
{
int status;
static struct FAB fab;
char *progname;
const char *fallback = "make";
#ifdef NAML$C_BID
static char esa[NAML$C_MAXRSS];
static struct NAML naml;
#else
static char esa[NAM$C_MAXRSS];
static struct NAM nam;
#endif
fab = cc$rms_fab;
fab.fab$l_fna = (char*)argv0;
fab.fab$b_fns = strlen(argv0);
#ifdef NAML$C_BID
fab.fab$l_naml = &naml;
naml = cc$rms_naml;
naml.naml$l_long_expand = esa;
naml.naml$l_long_expand_alloc = NAML$C_MAXRSS;
naml.naml$b_nop = NAML$M_SYNCHK;
naml.naml$l_input_flags = NAML$M_NO_SHORT_OUTPUT;
#else
fab.fab$l_nam = &nam;
nam = cc$rms_nam;
nam.nam$l_esa = esa;
nam.nam$b_ess = NAM$C_MAXRSS;
# ifdef NAM$M_NO_SHORT_UPCASE
nam.nam$b_nop = NAM$M_SYNCHK | NAM$M_NO_SHORT_UPCASE;
# else
nam.nam$b_nop = NAM$M_SYNCHK;
# endif
#endif
status = sys$parse(&fab);
if (!(status & 1))
return fallback;
#ifdef NAML$C_BID
if (naml.naml$l_long_name_size == 0)
return fallback;
progname = xmalloc(naml.naml$l_long_name_size + 1);
memcpy(progname, naml.naml$l_long_name, naml.naml$l_long_name_size);
progname[naml.naml$l_long_name_size] = '\0';
#else
if (nam.nam$b_name == 0)
return fallback;
progname = xmalloc(nam.nam$b_name + 1);
# ifdef NAM$M_NO_SHORT_UPCASE
memcpy(progname, nam.nam$l_name, nam.nam$b_name);
# else
{
int i;
for (i = 0; i < nam.nam$b_name; i++)
progname[i] = tolower(nam.nam$l_name[i]);
}
# endif
progname[nam.nam$b_name] = '\0';
#endif
return progname;
}
make-4.2.1/getopt.h 0000644 0001750 0001750 00000010570 12664631374 011046 0000000 0000000 /* Declarations for getopt.
Copyright (C) 1989-2016 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
#ifdef __GNU_LIBRARY__
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in stdlib.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
extern int getopt ();
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* getopt.h */
make-4.2.1/make.1 0000644 0001750 0001750 00000025370 12664631604 010372 0000000 0000000 .TH MAKE 1 "28 February 2016" "GNU" "User Commands"
.SH NAME
make \- GNU make utility to maintain groups of programs
.SH SYNOPSIS
.B make
[\fIOPTION\fR]... [\fITARGET\fR]...
.SH DESCRIPTION
.LP
The
.I make
utility will determine automatically which pieces of a large program need to
be recompiled, and issue the commands to recompile them. The manual describes
the GNU implementation of
.BR make ,
which was written by Richard Stallman and Roland McGrath, and is currently
maintained by Paul Smith. Our examples show C programs, since they are very
common, but you can use
.B make
with any programming language whose compiler can be run with a shell command.
In fact,
.B make
is not limited to programs. You can use it to describe any task where some
files must be updated automatically from others whenever the others change.
.LP
To prepare to use
.BR make ,
you must write a file called the
.I makefile
that describes the relationships among files in your program, and the states
the commands for updating each file. In a program, typically the executable
file is updated from object files, which are in turn made by compiling source
files.
.LP
Once a suitable makefile exists, each time you change some source files,
this simple shell command:
.sp 1
.RS
.B make
.RE
.sp 1
suffices to perform all necessary recompilations.
The
.B make
program uses the makefile description and the last-modification times of the
files to decide which of the files need to be updated. For each of those
files, it issues the commands recorded in the makefile.
.LP
.B make
executes commands in the
.I makefile
to update one or more target
.IR names ,
where
.I name
is typically a program.
If no
.B \-f
option is present,
.B make
will look for the makefiles
.IR GNUmakefile ,
.IR makefile ,
and
.IR Makefile ,
in that order.
.LP
Normally you should call your makefile either
.I makefile
or
.IR Makefile .
(We recommend
.I Makefile
because it appears prominently near the beginning of a directory
listing, right near other important files such as
.IR README .)
The first name checked,
.IR GNUmakefile ,
is not recommended for most makefiles. You should use this name if you have a
makefile that is specific to GNU
.BR make ,
and will not be understood by other versions of
.BR make .
If
.I makefile
is '\-', the standard input is read.
.LP
.B make
updates a target if it depends on prerequisite files
that have been modified since the target was last modified,
or if the target does not exist.
.SH OPTIONS
.sp 1
.TP 0.5i
\fB\-b\fR, \fB\-m\fR
These options are ignored for compatibility with other versions of
.BR make .
.TP 0.5i
\fB\-B\fR, \fB\-\-always\-make\fR
Unconditionally make all targets.
.TP 0.5i
\fB\-C\fR \fIdir\fR, \fB\-\-directory\fR=\fIdir\fR
Change to directory
.I dir
before reading the makefiles or doing anything else.
If multiple
.B \-C
options are specified, each is interpreted relative to the
previous one:
.BR "\-C " /
.BR "\-C " etc
is equivalent to
.BR "\-C " /etc.
This is typically used with recursive invocations of
.BR make .
.TP 0.5i
.B \-d
Print debugging information in addition to normal processing.
The debugging information says which files are being considered for
remaking, which file-times are being compared and with what results,
which files actually need to be remade, which implicit rules are
considered and which are applied---everything interesting about how
.B make
decides what to do.
.TP 0.5i
.BI \-\-debug "[=FLAGS]"
Print debugging information in addition to normal processing.
If the
.I FLAGS
are omitted, then the behavior is the same as if
.B \-d
was specified.
.I FLAGS
may be
.I a
for all debugging output (same as using
.BR \-d ),
.I b
for basic debugging,
.I v
for more verbose basic debugging,
.I i
for showing implicit rules,
.I j
for details on invocation of commands, and
.I m
for debugging while remaking makefiles. Use
.I n
to disable all previous debugging flags.
.TP 0.5i
\fB\-e\fR, \fB\-\-environment\-overrides\fR
Give variables taken from the environment precedence
over variables from makefiles.
.TP 0.5i
\fB\-f\fR \fIfile\fR, \fB\-\-file\fR=\fIfile\fR, \fB\-\-makefile\fR=\fIFILE\fR
Use
.I file
as a makefile.
.TP 0.5i
\fB\-i\fR, \fB\-\-ignore\-errors\fR
Ignore all errors in commands executed to remake files.
.TP 0.5i
\fB\-I\fR \fIdir\fR, \fB\-\-include\-dir\fR=\fIdir\fR
Specifies a directory
.I dir
to search for included makefiles.
If several
.B \-I
options are used to specify several directories, the directories are
searched in the order specified.
Unlike the arguments to other flags of
.BR make ,
directories given with
.B \-I
flags may come directly after the flag:
.BI \-I dir
is allowed, as well as
.B \-I
.IR dir .
This syntax is allowed for compatibility with the C
preprocessor's
.B \-I
flag.
.TP 0.5i
\fB\-j\fR [\fIjobs\fR], \fB\-\-jobs\fR[=\fIjobs\fR]
Specifies the number of
.I jobs
(commands) to run simultaneously.
If there is more than one
.B \-j
option, the last one is effective.
If the
.B \-j
option is given without an argument,
.BR make
will not limit the number of jobs that can run simultaneously.
.TP 0.5i
\fB\-k\fR, \fB\-\-keep\-going\fR
Continue as much as possible after an error.
While the target that failed, and those that depend on it, cannot
be remade, the other dependencies of these targets can be processed
all the same.
.TP 0.5i
\fB\-l\fR [\fIload\fR], \fB\-\-load\-average\fR[=\fIload\fR]
Specifies that no new jobs (commands) should be started if there are
others jobs running and the load average is at least
.I load
(a floating-point number).
With no argument, removes a previous load limit.
.TP 0.5i
\fB\-L\fR, \fB\-\-check\-symlink\-times\fR
Use the latest mtime between symlinks and target.
.TP 0.5i
\fB\-n\fR, \fB\-\-just\-print\fR, \fB\-\-dry\-run\fR, \fB\-\-recon\fR
Print the commands that would be executed, but do not execute them (except in
certain circumstances).
.TP 0.5i
\fB\-o\fR \fIfile\fR, \fB\-\-old\-file\fR=\fIfile\fR, \fB\-\-assume\-old\fR=\fIfile\fR
Do not remake the file
.I file
even if it is older than its dependencies, and do not remake anything
on account of changes in
.IR file .
Essentially the file is treated as very old and its rules are ignored.
.TP 0.5i
\fB\-O\fR[\fItype\fR], \fB\-\-output\-sync\fR[=\fItype\fR]
When running multiple jobs in parallel with \fB-j\fR, ensure the output of
each job is collected together rather than interspersed with output from
other jobs. If
.I type
is not specified or is
.B target
the output from the entire recipe for each target is grouped together. If
.I type
is
.B line
the output from each command line within a recipe is grouped together.
If
.I type
is
.B recurse
output from an entire recursive make is grouped together. If
.I type
is
.B none
output synchronization is disabled.
.TP 0.5i
\fB\-p\fR, \fB\-\-print\-data\-base\fR
Print the data base (rules and variable values) that results from
reading the makefiles; then execute as usual or as otherwise
specified.
This also prints the version information given by the
.B \-v
switch (see below).
To print the data base without trying to remake any files, use
.IR "make \-p \-f/dev/null" .
.TP 0.5i
\fB\-q\fR, \fB\-\-question\fR
``Question mode''.
Do not run any commands, or print anything; just return an exit status
that is zero if the specified targets are already up to date, nonzero
otherwise.
.TP 0.5i
\fB\-r\fR, \fB\-\-no\-builtin\-rules\fR
Eliminate use of the built\-in implicit rules.
Also clear out the default list of suffixes for suffix rules.
.TP 0.5i
\fB\-R\fR, \fB\-\-no\-builtin\-variables\fR
Don't define any built\-in variables.
.TP 0.5i
\fB\-s\fR, \fB\-\-silent\fR, \fB\-\-quiet\fR
Silent operation; do not print the commands as they are executed.
.TP 0.5i
\fB\-S\fR, \fB\-\-no\-keep\-going\fR, \fB\-\-stop\fR
Cancel the effect of the
.B \-k
option.
This is never necessary except in a recursive
.B make
where
.B \-k
might be inherited from the top-level
.B make
via MAKEFLAGS or if you set
.B \-k
in MAKEFLAGS in your environment.
.TP 0.5i
\fB\-t\fR, \fB\-\-touch\fR
Touch files (mark them up to date without really changing them)
instead of running their commands.
This is used to pretend that the commands were done, in order to fool
future invocations of
.BR make .
.TP 0.5i
.B \-\-trace
Information about the disposition of each target is printed (why the target is
being rebuilt and what commands are run to rebuild it).
.TP 0.5i
\fB\-v\fR, \fB\-\-version\fR
Print the version of the
.B make
program plus a copyright, a list of authors and a notice that there
is no warranty.
.TP 0.5i
\fB\-w\fR, \fB\-\-print\-directory\fR
Print a message containing the working directory
before and after other processing.
This may be useful for tracking down errors from complicated nests of
recursive
.B make
commands.
.TP 0.5i
.B \-\-no\-print\-directory
Turn off
.BR \-w ,
even if it was turned on implicitly.
.TP 0.5i
\fB\-W\fR \fIfile\fR, \fB\-\-what\-if\fR=\fIfile\fR, \fB\-\-new\-file\fR=\fIfile\fR, \fB\-\-assume\-new\fR=\fIfile\fR
Pretend that the target
.I file
has just been modified.
When used with the
.B \-n
flag, this shows you what would happen if you were to modify that file.
Without
.BR \-n ,
it is almost the same as running a
.I touch
command on the given file before running
.BR make ,
except that the modification time is changed only in the imagination of
.BR make .
.TP 0.5i
.B \-\-warn\-undefined\-variables
Warn when an undefined variable is referenced.
.SH "EXIT STATUS"
GNU
.B make
exits with a status of zero if all makefiles were successfully parsed
and no targets that were built failed. A status of one will be returned
if the
.B \-q
flag was used and
.B make
determines that a target needs to be rebuilt. A status of two will be
returned if any errors were encountered.
.SH "SEE ALSO"
The full documentation for
.B make
is maintained as a Texinfo manual. If the
.B info
and
.B make
programs are properly installed at your site, the command
.IP
.B info make
.PP
should give you access to the complete manual.
.SH BUGS
See the chapter ``Problems and Bugs'' in
.IR "The GNU Make Manual" .
.SH AUTHOR
This manual page contributed by Dennis Morse of Stanford University.
Further updates contributed by Mike Frysinger. It has been reworked by Roland
McGrath. Maintained by Paul Smith.
.SH "COPYRIGHT"
Copyright \(co 1992-1993, 1996-2016 Free Software Foundation, Inc.
This file is part of
.IR "GNU make" .
.LP
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
.LP
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
.LP
You should have received a copy of the GNU General Public License along with
this program. If not, see
.IR http://www.gnu.org/licenses/ .
make-4.2.1/job.c 0000644 0001750 0001750 00000317722 12720141610 010300 0000000 0000000 /* Job execution and handling for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include
#include "job.h"
#include "debug.h"
#include "filedef.h"
#include "commands.h"
#include "variable.h"
#include "os.h"
#include
/* Default shell to use. */
#ifdef WINDOWS32
#include
const char *default_shell = "sh.exe";
int no_default_sh_exe = 1;
int batch_mode_shell = 1;
HANDLE main_thread;
#elif defined (_AMIGA)
const char *default_shell = "";
extern int MyExecute (char **);
int batch_mode_shell = 0;
#elif defined (__MSDOS__)
/* The default shell is a pointer so we can change it if Makefile
says so. It is without an explicit path so we get a chance
to search the $PATH for it (since MSDOS doesn't have standard
directories we could trust). */
const char *default_shell = "command.com";
int batch_mode_shell = 0;
#elif defined (__EMX__)
const char *default_shell = "/bin/sh";
int batch_mode_shell = 0;
#elif defined (VMS)
# include
# include
const char *default_shell = "";
int batch_mode_shell = 0;
#define strsignal vms_strsignal
char * vms_strsignal (int status);
#ifndef C_FACILITY_NO
# define C_FACILITY_NO 0x350000
#endif
#ifndef VMS_POSIX_EXIT_MASK
# define VMS_POSIX_EXIT_MASK (C_FACILITY_NO | 0xA000)
#endif
#else
const char *default_shell = "/bin/sh";
int batch_mode_shell = 0;
#endif
#ifdef __MSDOS__
# include
static int execute_by_shell;
static int dos_pid = 123;
int dos_status;
int dos_command_running;
#endif /* __MSDOS__ */
#ifdef _AMIGA
# include
static int amiga_pid = 123;
static int amiga_status;
static char amiga_bname[32];
static int amiga_batch_file;
#endif /* Amiga. */
#ifdef VMS
# ifndef __GNUC__
# include
# endif
# include
# include
static void vmsWaitForChildren (int *);
#endif
#ifdef WINDOWS32
# include
# include
# include
# include "sub_proc.h"
# include "w32err.h"
# include "pathstuff.h"
# define WAIT_NOHANG 1
#endif /* WINDOWS32 */
#ifdef __EMX__
# include
#endif
#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT)
# include
#endif
#ifdef HAVE_WAITPID
# define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG)
#else /* Don't have waitpid. */
# ifdef HAVE_WAIT3
# ifndef wait3
extern int wait3 ();
# endif
# define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0)
# endif /* Have wait3. */
#endif /* Have waitpid. */
#if !defined (wait) && !defined (POSIX)
int wait ();
#endif
#ifndef HAVE_UNION_WAIT
# define WAIT_T int
# ifndef WTERMSIG
# define WTERMSIG(x) ((x) & 0x7f)
# endif
# ifndef WCOREDUMP
# define WCOREDUMP(x) ((x) & 0x80)
# endif
# ifndef WEXITSTATUS
# define WEXITSTATUS(x) (((x) >> 8) & 0xff)
# endif
# ifndef WIFSIGNALED
# define WIFSIGNALED(x) (WTERMSIG (x) != 0)
# endif
# ifndef WIFEXITED
# define WIFEXITED(x) (WTERMSIG (x) == 0)
# endif
#else /* Have 'union wait'. */
# define WAIT_T union wait
# ifndef WTERMSIG
# define WTERMSIG(x) ((x).w_termsig)
# endif
# ifndef WCOREDUMP
# define WCOREDUMP(x) ((x).w_coredump)
# endif
# ifndef WEXITSTATUS
# define WEXITSTATUS(x) ((x).w_retcode)
# endif
# ifndef WIFSIGNALED
# define WIFSIGNALED(x) (WTERMSIG(x) != 0)
# endif
# ifndef WIFEXITED
# define WIFEXITED(x) (WTERMSIG(x) == 0)
# endif
#endif /* Don't have 'union wait'. */
#if !defined(HAVE_UNISTD_H) && !defined(WINDOWS32)
int dup2 ();
int execve ();
void _exit ();
# ifndef VMS
int geteuid ();
int getegid ();
int setgid ();
int getgid ();
# endif
#endif
/* Different systems have different requirements for pid_t.
Plus we have to support gettext string translation... Argh. */
static const char *
pid2str (pid_t pid)
{
static char pidstring[100];
#if defined(WINDOWS32) && (__GNUC__ > 3 || _MSC_VER > 1300)
/* %Id is only needed for 64-builds, which were not supported by
older versions of Windows compilers. */
sprintf (pidstring, "%Id", pid);
#else
sprintf (pidstring, "%lu", (unsigned long) pid);
#endif
return pidstring;
}
#ifndef HAVE_GETLOADAVG
int getloadavg (double loadavg[], int nelem);
#endif
static void free_child (struct child *);
static void start_job_command (struct child *child);
static int load_too_high (void);
static int job_next_command (struct child *);
static int start_waiting_job (struct child *);
/* Chain of all live (or recently deceased) children. */
struct child *children = 0;
/* Number of children currently running. */
unsigned int job_slots_used = 0;
/* Nonzero if the 'good' standard input is in use. */
static int good_stdin_used = 0;
/* Chain of children waiting to run until the load average goes down. */
static struct child *waiting_jobs = 0;
/* Non-zero if we use a *real* shell (always so on Unix). */
int unixy_shell = 1;
/* Number of jobs started in the current second. */
unsigned long job_counter = 0;
/* Number of jobserver tokens this instance is currently using. */
unsigned int jobserver_tokens = 0;
#ifdef WINDOWS32
/*
* The macro which references this function is defined in makeint.h.
*/
int
w32_kill (pid_t pid, int sig)
{
return ((process_kill ((HANDLE)pid, sig) == TRUE) ? 0 : -1);
}
/* This function creates a temporary file name with an extension specified
* by the unixy arg.
* Return an xmalloc'ed string of a newly created temp file and its
* file descriptor, or die. */
static char *
create_batch_file (char const *base, int unixy, int *fd)
{
const char *const ext = unixy ? "sh" : "bat";
const char *error_string = NULL;
char temp_path[MAXPATHLEN]; /* need to know its length */
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
int path_is_dot = 0;
/* The following variable is static so we won't try to reuse a name
that was generated a little while ago, because that file might
not be on disk yet, since we use FILE_ATTRIBUTE_TEMPORARY below,
which tells the OS it doesn't need to flush the cache to disk.
If the file is not yet on disk, we might think the name is
available, while it really isn't. This happens in parallel
builds, where Make doesn't wait for one job to finish before it
launches the next one. */
static unsigned uniq = 0;
static int second_loop = 0;
const unsigned sizemax = strlen (base) + strlen (ext) + 10;
if (path_size == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
++uniq;
if (uniq >= 0x10000 && !second_loop)
{
/* If we already had 64K batch files in this
process, make a second loop through the numbers,
looking for free slots, i.e. files that were
deleted in the meantime. */
second_loop = 1;
uniq = 1;
}
while (path_size > 0 &&
path_size + sizemax < sizeof temp_path &&
!(uniq >= 0x10000 && second_loop))
{
unsigned size = sprintf (temp_path + path_size,
"%s%s-%x.%s",
temp_path[path_size - 1] == '\\' ? "" : "\\",
base, uniq, ext);
HANDLE h = CreateFile (temp_path, /* file name */
GENERIC_READ | GENERIC_WRITE, /* desired access */
0, /* no share mode */
NULL, /* default security attributes */
CREATE_NEW, /* creation disposition */
FILE_ATTRIBUTE_NORMAL | /* flags and attributes */
FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */
NULL); /* no template file */
if (h == INVALID_HANDLE_VALUE)
{
const DWORD er = GetLastError ();
if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS)
{
++uniq;
if (uniq == 0x10000 && !second_loop)
{
second_loop = 1;
uniq = 1;
}
}
/* the temporary path is not guaranteed to exist */
else if (path_is_dot == 0)
{
path_size = GetCurrentDirectory (sizeof temp_path, temp_path);
path_is_dot = 1;
}
else
{
error_string = map_windows32_error_to_string (er);
break;
}
}
else
{
const unsigned final_size = path_size + size + 1;
char *const path = xmalloc (final_size);
memcpy (path, temp_path, final_size);
*fd = _open_osfhandle ((intptr_t)h, 0);
if (unixy)
{
char *p;
int ch;
for (p = path; (ch = *p) != 0; ++p)
if (ch == '\\')
*p = '/';
}
return path; /* good return */
}
}
*fd = -1;
if (error_string == NULL)
error_string = _("Cannot create a temporary file\n");
O (fatal, NILF, error_string);
/* not reached */
return NULL;
}
#endif /* WINDOWS32 */
#ifdef __EMX__
/* returns whether path is assumed to be a unix like shell. */
int
_is_unixy_shell (const char *path)
{
/* list of non unix shells */
const char *known_os2shells[] = {
"cmd.exe",
"cmd",
"4os2.exe",
"4os2",
"4dos.exe",
"4dos",
"command.com",
"command",
NULL
};
/* find the rightmost '/' or '\\' */
const char *name = strrchr (path, '/');
const char *p = strrchr (path, '\\');
unsigned i;
if (name && p) /* take the max */
name = (name > p) ? name : p;
else if (p) /* name must be 0 */
name = p;
else if (!name) /* name and p must be 0 */
name = path;
if (*name == '/' || *name == '\\') name++;
i = 0;
while (known_os2shells[i] != NULL)
{
if (strcasecmp (name, known_os2shells[i]) == 0)
return 0; /* not a unix shell */
i++;
}
/* in doubt assume a unix like shell */
return 1;
}
#endif /* __EMX__ */
/* determines whether path looks to be a Bourne-like shell. */
int
is_bourne_compatible_shell (const char *path)
{
/* List of known POSIX (or POSIX-ish) shells. */
static const char *unix_shells[] = {
"sh",
"bash",
"ksh",
"rksh",
"zsh",
"ash",
"dash",
NULL
};
const char **s;
/* find the rightmost '/' or '\\' */
const char *name = strrchr (path, '/');
char *p = strrchr (path, '\\');
if (name && p) /* take the max */
name = (name > p) ? name : p;
else if (p) /* name must be 0 */
name = p;
else if (!name) /* name and p must be 0 */
name = path;
if (*name == '/' || *name == '\\')
++name;
/* this should be able to deal with extensions on Windows-like systems */
for (s = unix_shells; *s != NULL; ++s)
{
#if defined(WINDOWS32) || defined(__MSDOS__)
unsigned int len = strlen (*s);
if ((strlen (name) >= len && STOP_SET (name[len], MAP_DOT|MAP_NUL))
&& strncasecmp (name, *s, len) == 0)
#else
if (strcmp (name, *s) == 0)
#endif
return 1; /* a known unix-style shell */
}
/* if not on the list, assume it's not a Bourne-like shell */
return 0;
}
/* Write an error message describing the exit status given in
EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
Append "(ignored)" if IGNORED is nonzero. */
static void
child_error (struct child *child,
int exit_code, int exit_sig, int coredump, int ignored)
{
const char *pre = "*** ";
const char *post = "";
const char *dump = "";
const struct file *f = child->file;
const floc *flocp = &f->cmds->fileinfo;
const char *nm;
size_t l;
if (ignored && silent_flag)
return;
if (exit_sig && coredump)
dump = _(" (core dumped)");
if (ignored)
{
pre = "";
post = _(" (ignored)");
}
if (! flocp->filenm)
nm = _("");
else
{
char *a = alloca (strlen (flocp->filenm) + 1 + 11 + 1);
sprintf (a, "%s:%lu", flocp->filenm, flocp->lineno + flocp->offset);
nm = a;
}
l = strlen (pre) + strlen (nm) + strlen (f->name) + strlen (post);
OUTPUT_SET (&child->output);
show_goal_error ();
if (exit_sig == 0)
error (NILF, l + INTSTR_LENGTH,
_("%s[%s: %s] Error %d%s"), pre, nm, f->name, exit_code, post);
else
{
const char *s = strsignal (exit_sig);
error (NILF, l + strlen (s) + strlen (dump),
"%s[%s: %s] %s%s%s", pre, nm, f->name, s, dump, post);
}
OUTPUT_UNSET ();
}
/* Handle a dead child. This handler may or may not ever be installed.
If we're using the jobserver feature without pselect(), we need it.
First, installing it ensures the read will interrupt on SIGCHLD. Second,
we close the dup'd read FD to ensure we don't enter another blocking read
without reaping all the dead children. In this case we don't need the
dead_children count.
If we don't have either waitpid or wait3, then make is unreliable, but we
use the dead_children count to reap children as best we can. */
static unsigned int dead_children = 0;
RETSIGTYPE
child_handler (int sig UNUSED)
{
++dead_children;
jobserver_signal ();
#ifdef __EMX__
/* The signal handler must called only once! */
signal (SIGCHLD, SIG_DFL);
#endif
}
extern pid_t shell_function_pid;
/* Reap all dead children, storing the returned status and the new command
state ('cs_finished') in the 'file' member of the 'struct child' for the
dead child, and removing the child from the chain. In addition, if BLOCK
nonzero, we block in this function until we've reaped at least one
complete child, waiting for it to die if necessary. If ERR is nonzero,
print an error message first. */
void
reap_children (int block, int err)
{
#ifndef WINDOWS32
WAIT_T status;
#endif
/* Initially, assume we have some. */
int reap_more = 1;
#ifdef WAIT_NOHANG
# define REAP_MORE reap_more
#else
# define REAP_MORE dead_children
#endif
/* As long as:
We have at least one child outstanding OR a shell function in progress,
AND
We're blocking for a complete child OR there are more children to reap
we'll keep reaping children. */
while ((children != 0 || shell_function_pid != 0)
&& (block || REAP_MORE))
{
unsigned int remote = 0;
pid_t pid;
int exit_code, exit_sig, coredump;
struct child *lastc, *c;
int child_failed;
int any_remote, any_local;
int dontcare;
if (err && block)
{
static int printed = 0;
/* We might block for a while, so let the user know why.
Only print this message once no matter how many jobs are left. */
fflush (stdout);
if (!printed)
O (error, NILF, _("*** Waiting for unfinished jobs...."));
printed = 1;
}
/* We have one less dead child to reap. As noted in
child_handler() above, this count is completely unimportant for
all modern, POSIX-y systems that support wait3() or waitpid().
The rest of this comment below applies only to early, broken
pre-POSIX systems. We keep the count only because... it's there...
The test and decrement are not atomic; if it is compiled into:
register = dead_children - 1;
dead_children = register;
a SIGCHLD could come between the two instructions.
child_handler increments dead_children.
The second instruction here would lose that increment. But the
only effect of dead_children being wrong is that we might wait
longer than necessary to reap a child, and lose some parallelism;
and we might print the "Waiting for unfinished jobs" message above
when not necessary. */
if (dead_children > 0)
--dead_children;
any_remote = 0;
any_local = shell_function_pid != 0;
for (c = children; c != 0; c = c->next)
{
any_remote |= c->remote;
any_local |= ! c->remote;
DB (DB_JOBS, (_("Live child %p (%s) PID %s %s\n"),
c, c->file->name, pid2str (c->pid),
c->remote ? _(" (remote)") : ""));
#ifdef VMS
break;
#endif
}
/* First, check for remote children. */
if (any_remote)
pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
else
pid = 0;
if (pid > 0)
/* We got a remote child. */
remote = 1;
else if (pid < 0)
{
/* A remote status command failed miserably. Punt. */
remote_status_lose:
pfatal_with_name ("remote_status");
}
else
{
/* No remote children. Check for local children. */
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
if (any_local)
{
#ifdef VMS
/* Todo: This needs more untangling multi-process support */
/* Just do single child process support now */
vmsWaitForChildren (&status);
pid = c->pid;
/* VMS failure status can not be fully translated */
status = $VMS_STATUS_SUCCESS (c->cstatus) ? 0 : (1 << 8);
/* A Posix failure can be exactly translated */
if ((c->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK)
status = (c->cstatus >> 3 & 255) << 8;
#else
#ifdef WAIT_NOHANG
if (!block)
pid = WAIT_NOHANG (&status);
else
#endif
EINTRLOOP (pid, wait (&status));
#endif /* !VMS */
}
else
pid = 0;
if (pid < 0)
{
/* The wait*() failed miserably. Punt. */
pfatal_with_name ("wait");
}
else if (pid > 0)
{
/* We got a child exit; chop the status word up. */
exit_code = WEXITSTATUS (status);
exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
coredump = WCOREDUMP (status);
/* If we have started jobs in this second, remove one. */
if (job_counter)
--job_counter;
}
else
{
/* No local children are dead. */
reap_more = 0;
if (!block || !any_remote)
break;
/* Now try a blocking wait for a remote child. */
pid = remote_status (&exit_code, &exit_sig, &coredump, 1);
if (pid < 0)
goto remote_status_lose;
else if (pid == 0)
/* No remote children either. Finally give up. */
break;
/* We got a remote child. */
remote = 1;
}
#endif /* !__MSDOS__, !Amiga, !WINDOWS32. */
#ifdef __MSDOS__
/* Life is very different on MSDOS. */
pid = dos_pid - 1;
status = dos_status;
exit_code = WEXITSTATUS (status);
if (exit_code == 0xff)
exit_code = -1;
exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
coredump = 0;
#endif /* __MSDOS__ */
#ifdef _AMIGA
/* Same on Amiga */
pid = amiga_pid - 1;
status = amiga_status;
exit_code = amiga_status;
exit_sig = 0;
coredump = 0;
#endif /* _AMIGA */
#ifdef WINDOWS32
{
HANDLE hPID;
HANDLE hcTID, hcPID;
DWORD dwWaitStatus = 0;
exit_code = 0;
exit_sig = 0;
coredump = 0;
/* Record the thread ID of the main process, so that we
could suspend it in the signal handler. */
if (!main_thread)
{
hcTID = GetCurrentThread ();
hcPID = GetCurrentProcess ();
if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0,
FALSE, DUPLICATE_SAME_ACCESS))
{
DWORD e = GetLastError ();
fprintf (stderr,
"Determine main thread ID (Error %ld: %s)\n",
e, map_windows32_error_to_string (e));
}
else
DB (DB_VERBOSE, ("Main thread handle = %p\n", main_thread));
}
/* wait for anything to finish */
hPID = process_wait_for_any (block, &dwWaitStatus);
if (hPID)
{
/* was an error found on this process? */
int werr = process_last_err (hPID);
/* get exit data */
exit_code = process_exit_code (hPID);
if (werr)
fprintf (stderr, "make (e=%d): %s", exit_code,
map_windows32_error_to_string (exit_code));
/* signal */
exit_sig = process_signal (hPID);
/* cleanup process */
process_cleanup (hPID);
coredump = 0;
}
else if (dwWaitStatus == WAIT_FAILED)
{
/* The WaitForMultipleObjects() failed miserably. Punt. */
pfatal_with_name ("WaitForMultipleObjects");
}
else if (dwWaitStatus == WAIT_TIMEOUT)
{
/* No child processes are finished. Give up waiting. */
reap_more = 0;
break;
}
pid = (pid_t) hPID;
}
#endif /* WINDOWS32 */
}
/* Check if this is the child of the 'shell' function. */
if (!remote && pid == shell_function_pid)
{
shell_completed (exit_code, exit_sig);
break;
}
/* Search for a child matching the deceased one. */
lastc = 0;
for (c = children; c != 0; lastc = c, c = c->next)
if (c->pid == pid && c->remote == remote)
break;
if (c == 0)
/* An unknown child died.
Ignore it; it was inherited from our invoker. */
continue;
/* Determine the failure status: 0 for success, 1 for updating target in
question mode, 2 for anything else. */
if (exit_sig == 0 && exit_code == 0)
child_failed = MAKE_SUCCESS;
else if (exit_sig == 0 && exit_code == 1 && question_flag && c->recursive)
child_failed = MAKE_TROUBLE;
else
child_failed = MAKE_FAILURE;
DB (DB_JOBS, (child_failed
? _("Reaping losing child %p PID %s %s\n")
: _("Reaping winning child %p PID %s %s\n"),
c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
if (c->sh_batch_file)
{
int rm_status;
DB (DB_JOBS, (_("Cleaning up temp batch file %s\n"),
c->sh_batch_file));
errno = 0;
rm_status = remove (c->sh_batch_file);
if (rm_status)
DB (DB_JOBS, (_("Cleaning up temp batch file %s failed (%d)\n"),
c->sh_batch_file, errno));
/* all done with memory */
free (c->sh_batch_file);
c->sh_batch_file = NULL;
}
/* If this child had the good stdin, say it is now free. */
if (c->good_stdin)
good_stdin_used = 0;
dontcare = c->dontcare;
if (child_failed && !c->noerror && !ignore_errors_flag)
{
/* The commands failed. Write an error message,
delete non-precious targets, and abort. */
static int delete_on_error = -1;
if (!dontcare && child_failed == MAKE_FAILURE)
child_error (c, exit_code, exit_sig, coredump, 0);
c->file->update_status = child_failed == MAKE_FAILURE ? us_failed : us_question;
if (delete_on_error == -1)
{
struct file *f = lookup_file (".DELETE_ON_ERROR");
delete_on_error = f != 0 && f->is_target;
}
if (exit_sig != 0 || delete_on_error)
delete_child_targets (c);
}
else
{
if (child_failed)
{
/* The commands failed, but we don't care. */
child_error (c, exit_code, exit_sig, coredump, 1);
child_failed = 0;
}
/* If there are more commands to run, try to start them. */
if (job_next_command (c))
{
if (handling_fatal_signal)
{
/* Never start new commands while we are dying.
Since there are more commands that wanted to be run,
the target was not completely remade. So we treat
this as if a command had failed. */
c->file->update_status = us_failed;
}
else
{
#ifndef NO_OUTPUT_SYNC
/* If we're sync'ing per line, write the previous line's
output before starting the next one. */
if (output_sync == OUTPUT_SYNC_LINE)
output_dump (&c->output);
#endif
/* Check again whether to start remotely.
Whether or not we want to changes over time.
Also, start_remote_job may need state set up
by start_remote_job_p. */
c->remote = start_remote_job_p (0);
start_job_command (c);
/* Fatal signals are left blocked in case we were
about to put that child on the chain. But it is
already there, so it is safe for a fatal signal to
arrive now; it will clean up this child's targets. */
unblock_sigs ();
if (c->file->command_state == cs_running)
/* We successfully started the new command.
Loop to reap more children. */
continue;
}
if (c->file->update_status != us_success)
/* We failed to start the commands. */
delete_child_targets (c);
}
else
/* There are no more commands. We got through them all
without an unignored error. Now the target has been
successfully updated. */
c->file->update_status = us_success;
}
/* When we get here, all the commands for c->file are finished. */
#ifndef NO_OUTPUT_SYNC
/* Synchronize any remaining parallel output. */
output_dump (&c->output);
#endif
/* At this point c->file->update_status is success or failed. But
c->file->command_state is still cs_running if all the commands
ran; notice_finish_file looks for cs_running to tell it that
it's interesting to check the file's modtime again now. */
if (! handling_fatal_signal)
/* Notice if the target of the commands has been changed.
This also propagates its values for command_state and
update_status to its also_make files. */
notice_finished_file (c->file);
DB (DB_JOBS, (_("Removing child %p PID %s%s from chain.\n"),
c, pid2str (c->pid), c->remote ? _(" (remote)") : ""));
/* Block fatal signals while frobnicating the list, so that
children and job_slots_used are always consistent. Otherwise
a fatal signal arriving after the child is off the chain and
before job_slots_used is decremented would believe a child was
live and call reap_children again. */
block_sigs ();
/* There is now another slot open. */
if (job_slots_used > 0)
--job_slots_used;
/* Remove the child from the chain and free it. */
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
unblock_sigs ();
/* If the job failed, and the -k flag was not given, die,
unless we are already in the process of dying. */
if (!err && child_failed && !dontcare && !keep_going_flag &&
/* fatal_error_signal will die with the right signal. */
!handling_fatal_signal)
die (child_failed);
/* Only block for one child. */
block = 0;
}
return;
}
/* Free the storage allocated for CHILD. */
static void
free_child (struct child *child)
{
output_close (&child->output);
if (!jobserver_tokens)
ONS (fatal, NILF, "INTERNAL: Freeing child %p (%s) but no tokens left!\n",
child, child->file->name);
/* If we're using the jobserver and this child is not the only outstanding
job, put a token back into the pipe for it. */
if (jobserver_enabled () && jobserver_tokens > 1)
{
jobserver_release (1);
DB (DB_JOBS, (_("Released token for child %p (%s).\n"),
child, child->file->name));
}
--jobserver_tokens;
if (handling_fatal_signal) /* Don't bother free'ing if about to die. */
return;
if (child->command_lines != 0)
{
register unsigned int i;
for (i = 0; i < child->file->cmds->ncommand_lines; ++i)
free (child->command_lines[i]);
free (child->command_lines);
}
if (child->environment != 0)
{
register char **ep = child->environment;
while (*ep != 0)
free (*ep++);
free (child->environment);
}
free (child);
}
#ifdef POSIX
extern sigset_t fatal_signal_set;
#endif
void
block_sigs (void)
{
#ifdef POSIX
(void) sigprocmask (SIG_BLOCK, &fatal_signal_set, (sigset_t *) 0);
#else
# ifdef HAVE_SIGSETMASK
(void) sigblock (fatal_signal_mask);
# endif
#endif
}
#ifdef POSIX
void
unblock_sigs (void)
{
sigset_t empty;
sigemptyset (&empty);
sigprocmask (SIG_SETMASK, &empty, (sigset_t *) 0);
}
#endif
/* Start a job to run the commands specified in CHILD.
CHILD is updated to reflect the commands and ID of the child process.
NOTE: On return fatal signals are blocked! The caller is responsible
for calling 'unblock_sigs', once the new child is safely on the chain so
it can be cleaned up in the event of a fatal signal. */
static void
start_job_command (struct child *child)
{
int flags;
char *p;
#ifdef VMS
char *argv;
#else
char **argv;
#endif
/* If we have a completely empty commandset, stop now. */
if (!child->command_ptr)
goto next_command;
/* Combine the flags parsed for the line itself with
the flags specified globally for this target. */
flags = (child->file->command_flags
| child->file->cmds->lines_flags[child->command_line - 1]);
p = child->command_ptr;
child->noerror = ((flags & COMMANDS_NOERROR) != 0);
while (*p != '\0')
{
if (*p == '@')
flags |= COMMANDS_SILENT;
else if (*p == '+')
flags |= COMMANDS_RECURSE;
else if (*p == '-')
child->noerror = 1;
/* Don't skip newlines. */
else if (!ISBLANK (*p))
break;
++p;
}
child->recursive = ((flags & COMMANDS_RECURSE) != 0);
/* Update the file's command flags with any new ones we found. We only
keep the COMMANDS_RECURSE setting. Even this isn't 100% correct; we are
now marking more commands recursive than should be in the case of
multiline define/endef scripts where only one line is marked "+". In
order to really fix this, we'll have to keep a lines_flags for every
actual line, after expansion. */
child->file->cmds->lines_flags[child->command_line - 1] |= flags & COMMANDS_RECURSE;
/* POSIX requires that a recipe prefix after a backslash-newline should
be ignored. Remove it now so the output is correct. */
{
char prefix = child->file->cmds->recipe_prefix;
char *p1, *p2;
p1 = p2 = p;
while (*p1 != '\0')
{
*(p2++) = *p1;
if (p1[0] == '\n' && p1[1] == prefix)
++p1;
++p1;
}
*p2 = *p1;
}
/* Figure out an argument list from this command line. */
{
char *end = 0;
#ifdef VMS
/* Skip any leading whitespace */
while (*p)
{
if (!ISSPACE (*p))
{
if (*p != '\\')
break;
if ((p[1] != '\n') && (p[1] != 'n') && (p[1] != 't'))
break;
}
p++;
}
argv = p;
/* Although construct_command_argv contains some code for VMS, it was/is
not called/used. Please note, for VMS argv is a string (not an array
of strings) which contains the complete command line, which for
multi-line variables still includes the newlines. So detect newlines
and set 'end' (which is used for child->command_ptr) instead of
(re-)writing construct_command_argv */
if (!one_shell)
{
char *s = p;
int instring = 0;
while (*s)
{
if (*s == '"')
instring = !instring;
else if (*s == '\\' && !instring && *(s+1) != 0)
s++;
else if (*s == '\n' && !instring)
{
end = s;
break;
}
++s;
}
}
#else
argv = construct_command_argv (p, &end, child->file,
child->file->cmds->lines_flags[child->command_line - 1],
&child->sh_batch_file);
#endif
if (end == NULL)
child->command_ptr = NULL;
else
{
*end++ = '\0';
child->command_ptr = end;
}
}
/* If -q was given, say that updating 'failed' if there was any text on the
command line, or 'succeeded' otherwise. The exit status of 1 tells the
user that -q is saying 'something to do'; the exit status for a random
error is 2. */
if (argv != 0 && question_flag && !(flags & COMMANDS_RECURSE))
{
#ifndef VMS
free (argv[0]);
free (argv);
#endif
#ifdef VMS
/* On VMS, argv[0] can be a null string here */
if (argv[0] != 0)
{
#endif
child->file->update_status = us_question;
notice_finished_file (child->file);
return;
#ifdef VMS
}
#endif
}
if (touch_flag && !(flags & COMMANDS_RECURSE))
{
/* Go on to the next command. It might be the recursive one.
We construct ARGV only to find the end of the command line. */
#ifndef VMS
if (argv)
{
free (argv[0]);
free (argv);
}
#endif
argv = 0;
}
if (argv == 0)
{
next_command:
#ifdef __MSDOS__
execute_by_shell = 0; /* in case construct_command_argv sets it */
#endif
/* This line has no commands. Go to the next. */
if (job_next_command (child))
start_job_command (child);
else
{
/* No more commands. Make sure we're "running"; we might not be if
(e.g.) all commands were skipped due to -n. */
set_command_state (child->file, cs_running);
child->file->update_status = us_success;
notice_finished_file (child->file);
}
OUTPUT_UNSET();
return;
}
/* Are we going to synchronize this command's output? Do so if either we're
in SYNC_RECURSE mode or this command is not recursive. We'll also check
output_sync separately below in case it changes due to error. */
child->output.syncout = output_sync && (output_sync == OUTPUT_SYNC_RECURSE
|| !(flags & COMMANDS_RECURSE));
OUTPUT_SET (&child->output);
#ifndef NO_OUTPUT_SYNC
if (! child->output.syncout)
/* We don't want to sync this command: to avoid misordered
output ensure any already-synced content is written. */
output_dump (&child->output);
#endif
/* Print the command if appropriate. */
if (just_print_flag || trace_flag
|| (!(flags & COMMANDS_SILENT) && !silent_flag))
OS (message, 0, "%s", p);
/* Tell update_goal_chain that a command has been started on behalf of
this target. It is important that this happens here and not in
reap_children (where we used to do it), because reap_children might be
reaping children from a different target. We want this increment to
guaranteedly indicate that a command was started for the dependency
chain (i.e., update_file recursion chain) we are processing. */
++commands_started;
/* Optimize an empty command. People use this for timestamp rules,
so avoid forking a useless shell. Do this after we increment
commands_started so make still treats this special case as if it
performed some action (makes a difference as to what messages are
printed, etc. */
#if !defined(VMS) && !defined(_AMIGA)
if (
#if defined __MSDOS__ || defined (__EMX__)
unixy_shell /* the test is complicated and we already did it */
#else
(argv[0] && is_bourne_compatible_shell (argv[0]))
#endif
&& (argv[1] && argv[1][0] == '-'
&&
((argv[1][1] == 'c' && argv[1][2] == '\0')
||
(argv[1][1] == 'e' && argv[1][2] == 'c' && argv[1][3] == '\0')))
&& (argv[2] && argv[2][0] == ':' && argv[2][1] == '\0')
&& argv[3] == NULL)
{
free (argv[0]);
free (argv);
goto next_command;
}
#endif /* !VMS && !_AMIGA */
/* If -n was given, recurse to get the next line in the sequence. */
if (just_print_flag && !(flags & COMMANDS_RECURSE))
{
#ifndef VMS
free (argv[0]);
free (argv);
#endif
goto next_command;
}
/* We're sure we're going to invoke a command: set up the output. */
output_start ();
/* Flush the output streams so they won't have things written twice. */
fflush (stdout);
fflush (stderr);
/* Decide whether to give this child the 'good' standard input
(one that points to the terminal or whatever), or the 'bad' one
that points to the read side of a broken pipe. */
child->good_stdin = !good_stdin_used;
if (child->good_stdin)
good_stdin_used = 1;
child->deleted = 0;
#ifndef _AMIGA
/* Set up the environment for the child. */
if (child->environment == 0)
child->environment = target_environment (child->file);
#endif
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
#ifndef VMS
/* start_waiting_job has set CHILD->remote if we can start a remote job. */
if (child->remote)
{
int is_remote, id, used_stdin;
if (start_remote_job (argv, child->environment,
child->good_stdin ? 0 : get_bad_stdin (),
&is_remote, &id, &used_stdin))
/* Don't give up; remote execution may fail for various reasons. If
so, simply run the job locally. */
goto run_local;
else
{
if (child->good_stdin && !used_stdin)
{
child->good_stdin = 0;
good_stdin_used = 0;
}
child->remote = is_remote;
child->pid = id;
}
}
else
#endif /* !VMS */
{
/* Fork the child process. */
char **parent_environ;
run_local:
block_sigs ();
child->remote = 0;
#ifdef VMS
if (!child_execute_job (child, argv))
{
/* Fork failed! */
perror_with_name ("fork", "");
goto error;
}
#else
parent_environ = environ;
jobserver_pre_child (flags & COMMANDS_RECURSE);
child->pid = child_execute_job (&child->output, child->good_stdin, argv, child->environment);
environ = parent_environ; /* Restore value child may have clobbered. */
jobserver_post_child (flags & COMMANDS_RECURSE);
if (child->pid < 0)
{
/* Fork failed! */
unblock_sigs ();
perror_with_name ("fork", "");
goto error;
}
#endif /* !VMS */
}
#else /* __MSDOS__ or Amiga or WINDOWS32 */
#ifdef __MSDOS__
{
int proc_return;
block_sigs ();
dos_status = 0;
/* We call 'system' to do the job of the SHELL, since stock DOS
shell is too dumb. Our 'system' knows how to handle long
command lines even if pipes/redirection is needed; it will only
call COMMAND.COM when its internal commands are used. */
if (execute_by_shell)
{
char *cmdline = argv[0];
/* We don't have a way to pass environment to 'system',
so we need to save and restore ours, sigh... */
char **parent_environ = environ;
environ = child->environment;
/* If we have a *real* shell, tell 'system' to call
it to do everything for us. */
if (unixy_shell)
{
/* A *real* shell on MSDOS may not support long
command lines the DJGPP way, so we must use 'system'. */
cmdline = argv[2]; /* get past "shell -c" */
}
dos_command_running = 1;
proc_return = system (cmdline);
environ = parent_environ;
execute_by_shell = 0; /* for the next time */
}
else
{
dos_command_running = 1;
proc_return = spawnvpe (P_WAIT, argv[0], argv, child->environment);
}
/* Need to unblock signals before turning off
dos_command_running, so that child's signals
will be treated as such (see fatal_error_signal). */
unblock_sigs ();
dos_command_running = 0;
/* If the child got a signal, dos_status has its
high 8 bits set, so be careful not to alter them. */
if (proc_return == -1)
dos_status |= 0xff;
else
dos_status |= (proc_return & 0xff);
++dead_children;
child->pid = dos_pid++;
}
#endif /* __MSDOS__ */
#ifdef _AMIGA
amiga_status = MyExecute (argv);
++dead_children;
child->pid = amiga_pid++;
if (amiga_batch_file)
{
amiga_batch_file = 0;
DeleteFile (amiga_bname); /* Ignore errors. */
}
#endif /* Amiga */
#ifdef WINDOWS32
{
HANDLE hPID;
char* arg0;
int outfd = FD_STDOUT;
int errfd = FD_STDERR;
/* make UNC paths safe for CreateProcess -- backslash format */
arg0 = argv[0];
if (arg0 && arg0[0] == '/' && arg0[1] == '/')
for ( ; arg0 && *arg0; arg0++)
if (*arg0 == '/')
*arg0 = '\\';
/* make sure CreateProcess() has Path it needs */
sync_Path_environment ();
#ifndef NO_OUTPUT_SYNC
/* Divert child output if output_sync in use. */
if (child->output.syncout)
{
if (child->output.out >= 0)
outfd = child->output.out;
if (child->output.err >= 0)
errfd = child->output.err;
}
#else
outfd = errfd = -1;
#endif
hPID = process_easy (argv, child->environment, outfd, errfd);
if (hPID != INVALID_HANDLE_VALUE)
child->pid = (pid_t) hPID;
else
{
int i;
unblock_sigs ();
fprintf (stderr,
_("process_easy() failed to launch process (e=%ld)\n"),
process_last_err (hPID));
for (i = 0; argv[i]; i++)
fprintf (stderr, "%s ", argv[i]);
fprintf (stderr, _("\nCounted %d args in failed launch\n"), i);
goto error;
}
}
#endif /* WINDOWS32 */
#endif /* __MSDOS__ or Amiga or WINDOWS32 */
/* Bump the number of jobs started in this second. */
++job_counter;
/* We are the parent side. Set the state to
say the commands are running and return. */
set_command_state (child->file, cs_running);
/* Free the storage used by the child's argument list. */
#ifndef VMS
free (argv[0]);
free (argv);
#endif
OUTPUT_UNSET();
return;
error:
child->file->update_status = us_failed;
notice_finished_file (child->file);
OUTPUT_UNSET();
}
/* Try to start a child running.
Returns nonzero if the child was started (and maybe finished), or zero if
the load was too high and the child was put on the 'waiting_jobs' chain. */
static int
start_waiting_job (struct child *c)
{
struct file *f = c->file;
/* If we can start a job remotely, we always want to, and don't care about
the local load average. We record that the job should be started
remotely in C->remote for start_job_command to test. */
c->remote = start_remote_job_p (1);
/* If we are running at least one job already and the load average
is too high, make this one wait. */
if (!c->remote
&& ((job_slots_used > 0 && load_too_high ())
#ifdef WINDOWS32
|| (process_used_slots () >= MAXIMUM_WAIT_OBJECTS)
#endif
))
{
/* Put this child on the chain of children waiting for the load average
to go down. */
set_command_state (f, cs_running);
c->next = waiting_jobs;
waiting_jobs = c;
return 0;
}
/* Start the first command; reap_children will run later command lines. */
start_job_command (c);
switch (f->command_state)
{
case cs_running:
c->next = children;
DB (DB_JOBS, (_("Putting child %p (%s) PID %s%s on the chain.\n"),
c, c->file->name, pid2str (c->pid),
c->remote ? _(" (remote)") : ""));
children = c;
/* One more job slot is in use. */
++job_slots_used;
unblock_sigs ();
break;
case cs_not_started:
/* All the command lines turned out to be empty. */
f->update_status = us_success;
/* FALLTHROUGH */
case cs_finished:
notice_finished_file (f);
free_child (c);
break;
default:
assert (f->command_state == cs_finished);
break;
}
return 1;
}
/* Create a 'struct child' for FILE and start its commands running. */
void
new_job (struct file *file)
{
struct commands *cmds = file->cmds;
struct child *c;
char **lines;
unsigned int i;
/* Let any previously decided-upon jobs that are waiting
for the load to go down start before this new one. */
start_waiting_jobs ();
/* Reap any children that might have finished recently. */
reap_children (0, 0);
/* Chop the commands up into lines if they aren't already. */
chop_commands (cmds);
/* Start the command sequence, record it in a new
'struct child', and add that to the chain. */
c = xcalloc (sizeof (struct child));
output_init (&c->output);
c->file = file;
c->sh_batch_file = NULL;
/* Cache dontcare flag because file->dontcare can be changed once we
return. Check dontcare inheritance mechanism for details. */
c->dontcare = file->dontcare;
/* Start saving output in case the expansion uses $(info ...) etc. */
OUTPUT_SET (&c->output);
/* Expand the command lines and store the results in LINES. */
lines = xmalloc (cmds->ncommand_lines * sizeof (char *));
for (i = 0; i < cmds->ncommand_lines; ++i)
{
/* Collapse backslash-newline combinations that are inside variable
or function references. These are left alone by the parser so
that they will appear in the echoing of commands (where they look
nice); and collapsed by construct_command_argv when it tokenizes.
But letting them survive inside function invocations loses because
we don't want the functions to see them as part of the text. */
char *in, *out, *ref;
/* IN points to where in the line we are scanning.
OUT points to where in the line we are writing.
When we collapse a backslash-newline combination,
IN gets ahead of OUT. */
in = out = cmds->command_lines[i];
while ((ref = strchr (in, '$')) != 0)
{
++ref; /* Move past the $. */
if (out != in)
/* Copy the text between the end of the last chunk
we processed (where IN points) and the new chunk
we are about to process (where REF points). */
memmove (out, in, ref - in);
/* Move both pointers past the boring stuff. */
out += ref - in;
in = ref;
if (*ref == '(' || *ref == '{')
{
char openparen = *ref;
char closeparen = openparen == '(' ? ')' : '}';
char *outref;
int count;
char *p;
*out++ = *in++; /* Copy OPENPAREN. */
outref = out;
/* IN now points past the opening paren or brace.
Count parens or braces until it is matched. */
count = 0;
while (*in != '\0')
{
if (*in == closeparen && --count < 0)
break;
else if (*in == '\\' && in[1] == '\n')
{
/* We have found a backslash-newline inside a
variable or function reference. Eat it and
any following whitespace. */
int quoted = 0;
for (p = in - 1; p > ref && *p == '\\'; --p)
quoted = !quoted;
if (quoted)
/* There were two or more backslashes, so this is
not really a continuation line. We don't collapse
the quoting backslashes here as is done in
collapse_continuations, because the line will
be collapsed again after expansion. */
*out++ = *in++;
else
{
/* Skip the backslash, newline, and whitespace. */
in += 2;
NEXT_TOKEN (in);
/* Discard any preceding whitespace that has
already been written to the output. */
while (out > outref && ISBLANK (out[-1]))
--out;
/* Replace it all with a single space. */
*out++ = ' ';
}
}
else
{
if (*in == openparen)
++count;
*out++ = *in++;
}
}
}
}
/* There are no more references in this line to worry about.
Copy the remaining uninteresting text to the output. */
if (out != in)
memmove (out, in, strlen (in) + 1);
/* Finally, expand the line. */
cmds->fileinfo.offset = i;
lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
file);
}
cmds->fileinfo.offset = 0;
c->command_lines = lines;
/* Fetch the first command line to be run. */
job_next_command (c);
/* Wait for a job slot to be freed up. If we allow an infinite number
don't bother; also job_slots will == 0 if we're using the jobserver. */
if (job_slots != 0)
while (job_slots_used == job_slots)
reap_children (1, 0);
#ifdef MAKE_JOBSERVER
/* If we are controlling multiple jobs make sure we have a token before
starting the child. */
/* This can be inefficient. There's a decent chance that this job won't
actually have to run any subprocesses: the command script may be empty
or otherwise optimized away. It would be nice if we could defer
obtaining a token until just before we need it, in start_job_command.
To do that we'd need to keep track of whether we'd already obtained a
token (since start_job_command is called for each line of the job, not
just once). Also more thought needs to go into the entire algorithm;
this is where the old parallel job code waits, so... */
else if (jobserver_enabled ())
while (1)
{
int got_token;
DB (DB_JOBS, ("Need a job token; we %shave children\n",
children ? "" : "don't "));
/* If we don't already have a job started, use our "free" token. */
if (!jobserver_tokens)
break;
/* Prepare for jobserver token acquisition. */
jobserver_pre_acquire ();
/* Reap anything that's currently waiting. */
reap_children (0, 0);
/* Kick off any jobs we have waiting for an opportunity that
can run now (i.e., waiting for load). */
start_waiting_jobs ();
/* If our "free" slot is available, use it; we don't need a token. */
if (!jobserver_tokens)
break;
/* There must be at least one child already, or we have no business
waiting for a token. */
if (!children)
O (fatal, NILF, "INTERNAL: no children as we go to sleep on read\n");
/* Get a token. */
got_token = jobserver_acquire (waiting_jobs != NULL);
/* If we got one, we're done here. */
if (got_token == 1)
{
DB (DB_JOBS, (_("Obtained token for child %p (%s).\n"),
c, c->file->name));
break;
}
}
#endif
++jobserver_tokens;
/* Trace the build.
Use message here so that changes to working directories are logged. */
if (trace_flag)
{
char *newer = allocated_variable_expand_for_file ("$?", c->file);
const char *nm;
if (! cmds->fileinfo.filenm)
nm = _("");
else
{
char *n = alloca (strlen (cmds->fileinfo.filenm) + 1 + 11 + 1);
sprintf (n, "%s:%lu", cmds->fileinfo.filenm, cmds->fileinfo.lineno);
nm = n;
}
if (newer[0] == '\0')
OSS (message, 0,
_("%s: target '%s' does not exist"), nm, c->file->name);
else
OSSS (message, 0,
_("%s: update target '%s' due to: %s"), nm, c->file->name, newer);
free (newer);
}
/* The job is now primed. Start it running.
(This will notice if there is in fact no recipe.) */
start_waiting_job (c);
if (job_slots == 1 || not_parallel)
/* Since there is only one job slot, make things run linearly.
Wait for the child to die, setting the state to 'cs_finished'. */
while (file->command_state == cs_running)
reap_children (1, 0);
OUTPUT_UNSET ();
return;
}
/* Move CHILD's pointers to the next command for it to execute.
Returns nonzero if there is another command. */
static int
job_next_command (struct child *child)
{
while (child->command_ptr == 0 || *child->command_ptr == '\0')
{
/* There are no more lines in the expansion of this line. */
if (child->command_line == child->file->cmds->ncommand_lines)
{
/* There are no more lines to be expanded. */
child->command_ptr = 0;
child->file->cmds->fileinfo.offset = 0;
return 0;
}
else
/* Get the next line to run. */
child->command_ptr = child->command_lines[child->command_line++];
}
child->file->cmds->fileinfo.offset = child->command_line - 1;
return 1;
}
/* Determine if the load average on the system is too high to start a new job.
The real system load average is only recomputed once a second. However, a
very parallel make can easily start tens or even hundreds of jobs in a
second, which brings the system to its knees for a while until that first
batch of jobs clears out.
To avoid this we use a weighted algorithm to try to account for jobs which
have been started since the last second, and guess what the load average
would be now if it were computed.
This algorithm was provided by Thomas Riedl ,
who writes:
! calculate something load-oid and add to the observed sys.load,
! so that latter can catch up:
! - every job started increases jobctr;
! - every dying job decreases a positive jobctr;
! - the jobctr value gets zeroed every change of seconds,
! after its value*weight_b is stored into the 'backlog' value last_sec
! - weight_a times the sum of jobctr and last_sec gets
! added to the observed sys.load.
!
! The two weights have been tried out on 24 and 48 proc. Sun Solaris-9
! machines, using a several-thousand-jobs-mix of cpp, cc, cxx and smallish
! sub-shelled commands (rm, echo, sed...) for tests.
! lowering the 'direct influence' factor weight_a (e.g. to 0.1)
! resulted in significant excession of the load limit, raising it
! (e.g. to 0.5) took bad to small, fast-executing jobs and didn't
! reach the limit in most test cases.
!
! lowering the 'history influence' weight_b (e.g. to 0.1) resulted in
! exceeding the limit for longer-running stuff (compile jobs in
! the .5 to 1.5 sec. range),raising it (e.g. to 0.5) overrepresented
! small jobs' effects.
*/
#define LOAD_WEIGHT_A 0.25
#define LOAD_WEIGHT_B 0.25
static int
load_too_high (void)
{
#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__)
return 1;
#else
static double last_sec;
static time_t last_now;
double load, guess;
time_t now;
#ifdef WINDOWS32
/* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS children */
if (process_used_slots () >= MAXIMUM_WAIT_OBJECTS)
return 1;
#endif
if (max_load_average < 0)
return 0;
/* Find the real system load average. */
make_access ();
if (getloadavg (&load, 1) != 1)
{
static int lossage = -1;
/* Complain only once for the same error. */
if (lossage == -1 || errno != lossage)
{
if (errno == 0)
/* An errno value of zero means getloadavg is just unsupported. */
O (error, NILF,
_("cannot enforce load limits on this operating system"));
else
perror_with_name (_("cannot enforce load limit: "), "getloadavg");
}
lossage = errno;
load = 0;
}
user_access ();
/* If we're in a new second zero the counter and correct the backlog
value. Only keep the backlog for one extra second; after that it's 0. */
now = time (NULL);
if (last_now < now)
{
if (last_now == now - 1)
last_sec = LOAD_WEIGHT_B * job_counter;
else
last_sec = 0.0;
job_counter = 0;
last_now = now;
}
/* Try to guess what the load would be right now. */
guess = load + (LOAD_WEIGHT_A * (job_counter + last_sec));
DB (DB_JOBS, ("Estimated system load = %f (actual = %f) (max requested = %f)\n",
guess, load, max_load_average));
return guess >= max_load_average;
#endif
}
/* Start jobs that are waiting for the load to be lower. */
void
start_waiting_jobs (void)
{
struct child *job;
if (waiting_jobs == 0)
return;
do
{
/* Check for recently deceased descendants. */
reap_children (0, 0);
/* Take a job off the waiting list. */
job = waiting_jobs;
waiting_jobs = job->next;
/* Try to start that job. We break out of the loop as soon
as start_waiting_job puts one back on the waiting list. */
}
while (start_waiting_job (job) && waiting_jobs != 0);
return;
}
#ifndef WINDOWS32
/* EMX: Start a child process. This function returns the new pid. */
# if defined __EMX__
int
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
{
int pid;
int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
int fdout = FD_STDOUT;
int fderr = FD_STDERR;
int save_fdin = -1;
int save_fdout = -1;
int save_fderr = -1;
/* Divert child output if we want to capture output. */
if (out && out->syncout)
{
if (out->out >= 0)
fdout = out->out;
if (out->err >= 0)
fderr = out->err;
}
/* For each FD which needs to be redirected first make a dup of the standard
FD to save and mark it close on exec so our child won't see it. Then
dup2() the standard FD to the redirect FD, and also mark the redirect FD
as close on exec. */
if (fdin != FD_STDIN)
{
save_fdin = dup (FD_STDIN);
if (save_fdin < 0)
O (fatal, NILF, _("no more file handles: could not duplicate stdin\n"));
CLOSE_ON_EXEC (save_fdin);
dup2 (fdin, FD_STDIN);
CLOSE_ON_EXEC (fdin);
}
if (fdout != FD_STDOUT)
{
save_fdout = dup (FD_STDOUT);
if (save_fdout < 0)
O (fatal, NILF,
_("no more file handles: could not duplicate stdout\n"));
CLOSE_ON_EXEC (save_fdout);
dup2 (fdout, FD_STDOUT);
CLOSE_ON_EXEC (fdout);
}
if (fderr != FD_STDERR)
{
if (fderr != fdout)
{
save_fderr = dup (FD_STDERR);
if (save_fderr < 0)
O (fatal, NILF,
_("no more file handles: could not duplicate stderr\n"));
CLOSE_ON_EXEC (save_fderr);
}
dup2 (fderr, FD_STDERR);
CLOSE_ON_EXEC (fderr);
}
/* Run the command. */
pid = exec_command (argv, envp);
/* Restore stdout/stdin/stderr of the parent and close temporary FDs. */
if (save_fdin >= 0)
{
if (dup2 (save_fdin, FD_STDIN) != FD_STDIN)
O (fatal, NILF, _("Could not restore stdin\n"));
else
close (save_fdin);
}
if (save_fdout >= 0)
{
if (dup2 (save_fdout, FD_STDOUT) != FD_STDOUT)
O (fatal, NILF, _("Could not restore stdout\n"));
else
close (save_fdout);
}
if (save_fderr >= 0)
{
if (dup2 (save_fderr, FD_STDERR) != FD_STDERR)
O (fatal, NILF, _("Could not restore stderr\n"));
else
close (save_fderr);
}
return pid;
}
#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS)
/* POSIX:
Create a child process executing the command in ARGV.
ENVP is the environment of the new program. Returns the PID or -1. */
int
child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
{
int r;
int pid;
int fdin = good_stdin ? FD_STDIN : get_bad_stdin ();
int fdout = FD_STDOUT;
int fderr = FD_STDERR;
/* Divert child output if we want to capture it. */
if (out && out->syncout)
{
if (out->out >= 0)
fdout = out->out;
if (out->err >= 0)
fderr = out->err;
}
pid = vfork();
if (pid != 0)
return pid;
/* We are the child. */
unblock_sigs ();
#ifdef SET_STACK_SIZE
/* Reset limits, if necessary. */
if (stack_limit.rlim_cur)
setrlimit (RLIMIT_STACK, &stack_limit);
#endif
/* For any redirected FD, dup2() it to the standard FD.
They are all marked close-on-exec already. */
if (fdin != FD_STDIN)
EINTRLOOP (r, dup2 (fdin, FD_STDIN));
if (fdout != FD_STDOUT)
EINTRLOOP (r, dup2 (fdout, FD_STDOUT));
if (fderr != FD_STDERR)
EINTRLOOP (r, dup2 (fderr, FD_STDERR));
/* Run the command. */
exec_command (argv, envp);
}
#endif /* !AMIGA && !__MSDOS__ && !VMS */
#endif /* !WINDOWS32 */
#ifndef _AMIGA
/* Replace the current process with one running the command in ARGV,
with environment ENVP. This function does not return. */
/* EMX: This function returns the pid of the child process. */
# ifdef __EMX__
int
# else
void
# endif
exec_command (char **argv, char **envp)
{
#ifdef VMS
/* to work around a problem with signals and execve: ignore them */
#ifdef SIGCHLD
signal (SIGCHLD,SIG_IGN);
#endif
/* Run the program. */
execve (argv[0], argv, envp);
perror_with_name ("execve: ", argv[0]);
_exit (EXIT_FAILURE);
#else
#ifdef WINDOWS32
HANDLE hPID;
HANDLE hWaitPID;
int exit_code = EXIT_FAILURE;
/* make sure CreateProcess() has Path it needs */
sync_Path_environment ();
/* launch command */
hPID = process_easy (argv, envp, -1, -1);
/* make sure launch ok */
if (hPID == INVALID_HANDLE_VALUE)
{
int i;
fprintf (stderr, _("process_easy() failed to launch process (e=%ld)\n"),
process_last_err (hPID));
for (i = 0; argv[i]; i++)
fprintf (stderr, "%s ", argv[i]);
fprintf (stderr, _("\nCounted %d args in failed launch\n"), i);
exit (EXIT_FAILURE);
}
/* wait and reap last child */
hWaitPID = process_wait_for_any (1, 0);
while (hWaitPID)
{
/* was an error found on this process? */
int err = process_last_err (hWaitPID);
/* get exit data */
exit_code = process_exit_code (hWaitPID);
if (err)
fprintf (stderr, "make (e=%d, rc=%d): %s",
err, exit_code, map_windows32_error_to_string (err));
/* cleanup process */
process_cleanup (hWaitPID);
/* expect to find only last pid, warn about other pids reaped */
if (hWaitPID == hPID)
break;
else
{
char *pidstr = xstrdup (pid2str ((pid_t)hWaitPID));
fprintf (stderr,
_("make reaped child pid %s, still waiting for pid %s\n"),
pidstr, pid2str ((pid_t)hPID));
free (pidstr);
}
}
/* return child's exit code as our exit code */
exit (exit_code);
#else /* !WINDOWS32 */
# ifdef __EMX__
int pid;
# endif
/* Be the user, permanently. */
child_access ();
# ifdef __EMX__
/* Run the program. */
pid = spawnvpe (P_NOWAIT, argv[0], argv, envp);
if (pid >= 0)
return pid;
/* the file might have a strange shell extension */
if (errno == ENOENT)
errno = ENOEXEC;
# else
/* Run the program. */
environ = envp;
execvp (argv[0], argv);
# endif /* !__EMX__ */
switch (errno)
{
case ENOENT:
/* We are in the child: don't use the output buffer.
It's not right to run fprintf() here! */
if (makelevel == 0)
fprintf (stderr, _("%s: %s: Command not found\n"), program, argv[0]);
else
fprintf (stderr, _("%s[%u]: %s: Command not found\n"),
program, makelevel, argv[0]);
break;
case ENOEXEC:
{
/* The file is not executable. Try it as a shell script. */
const char *shell;
char **new_argv;
int argc;
int i=1;
# ifdef __EMX__
/* Do not use $SHELL from the environment */
struct variable *p = lookup_variable ("SHELL", 5);
if (p)
shell = p->value;
else
shell = 0;
# else
shell = getenv ("SHELL");
# endif
if (shell == 0)
shell = default_shell;
argc = 1;
while (argv[argc] != 0)
++argc;
# ifdef __EMX__
if (!unixy_shell)
++argc;
# endif
new_argv = alloca ((1 + argc + 1) * sizeof (char *));
new_argv[0] = (char *)shell;
# ifdef __EMX__
if (!unixy_shell)
{
new_argv[1] = "/c";
++i;
--argc;
}
# endif
new_argv[i] = argv[0];
while (argc > 0)
{
new_argv[i + argc] = argv[argc];
--argc;
}
# ifdef __EMX__
pid = spawnvpe (P_NOWAIT, shell, new_argv, envp);
if (pid >= 0)
break;
# else
execvp (shell, new_argv);
# endif
if (errno == ENOENT)
OS (error, NILF, _("%s: Shell program not found"), shell);
else
perror_with_name ("execvp: ", shell);
break;
}
# ifdef __EMX__
case EINVAL:
/* this nasty error was driving me nuts :-( */
O (error, NILF, _("spawnvpe: environment space might be exhausted"));
/* FALLTHROUGH */
# endif
default:
perror_with_name ("execvp: ", argv[0]);
break;
}
# ifdef __EMX__
return pid;
# else
_exit (127);
# endif
#endif /* !WINDOWS32 */
#endif /* !VMS */
}
#else /* On Amiga */
void
exec_command (char **argv)
{
MyExecute (argv);
}
void clean_tmp (void)
{
DeleteFile (amiga_bname);
}
#endif /* On Amiga */
#ifndef VMS
/* Figure out the argument list necessary to run LINE as a command. Try to
avoid using a shell. This routine handles only ' quoting, and " quoting
when no backslash, $ or ' characters are seen in the quotes. Starting
quotes may be escaped with a backslash. If any of the characters in
sh_chars is seen, or any of the builtin commands listed in sh_cmds
is the first word of a line, the shell is used.
If RESTP is not NULL, *RESTP is set to point to the first newline in LINE.
If *RESTP is NULL, newlines will be ignored.
SHELL is the shell to use, or nil to use the default shell.
IFS is the value of $IFS, or nil (meaning the default).
FLAGS is the value of lines_flags for this command line. It is
used in the WINDOWS32 port to check whether + or $(MAKE) were found
in this command line, in which case the effect of just_print_flag
is overridden. */
static char **
construct_command_argv_internal (char *line, char **restp, const char *shell,
const char *shellflags, const char *ifs,
int flags, char **batch_filename UNUSED)
{
#ifdef __MSDOS__
/* MSDOS supports both the stock DOS shell and ports of Unixy shells.
We call 'system' for anything that requires ''slow'' processing,
because DOS shells are too dumb. When $SHELL points to a real
(unix-style) shell, 'system' just calls it to do everything. When
$SHELL points to a DOS shell, 'system' does most of the work
internally, calling the shell only for its internal commands.
However, it looks on the $PATH first, so you can e.g. have an
external command named 'mkdir'.
Since we call 'system', certain characters and commands below are
actually not specific to COMMAND.COM, but to the DJGPP implementation
of 'system'. In particular:
The shell wildcard characters are in DOS_CHARS because they will
not be expanded if we call the child via 'spawnXX'.
The ';' is in DOS_CHARS, because our 'system' knows how to run
multiple commands on a single line.
DOS_CHARS also include characters special to 4DOS/NDOS, so we
won't have to tell one from another and have one more set of
commands and special characters. */
static const char *sh_chars_dos = "*?[];|<>%^&()";
static const char *sh_cmds_dos[] =
{ "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date",
"del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md",
"mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren",
"rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":",
0 };
static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^";
static const char *sh_cmds_sh[] =
{ "cd", "echo", "eval", "exec", "exit", "login", "logout", "set", "umask",
"wait", "while", "for", "case", "if", ":", ".", "break", "continue",
"export", "read", "readonly", "shift", "times", "trap", "switch",
"unset", "ulimit", 0 };
const char *sh_chars;
const char **sh_cmds;
#elif defined (__EMX__)
static const char *sh_chars_dos = "*?[];|<>%^&()";
static const char *sh_cmds_dos[] =
{ "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date",
"del", "dir", "echo", "erase", "exit", "for", "goto", "if", "md",
"mkdir", "path", "pause", "prompt", "rd", "rmdir", "rem", "ren",
"rename", "set", "shift", "time", "type", "ver", "verify", "vol", ":",
0 };
static const char *sh_chars_os2 = "*?[];|<>%^()\"'&";
static const char *sh_cmds_os2[] =
{ "call", "cd", "chcp", "chdir", "cls", "copy", "date", "del", "detach",
"dir", "echo", "endlocal", "erase", "exit", "for", "goto", "if", "keys",
"md", "mkdir", "move", "path", "pause", "prompt", "rd", "rem", "ren",
"rename", "rmdir", "set", "setlocal", "shift", "start", "time", "type",
"ver", "verify", "vol", ":", 0 };
static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~'";
static const char *sh_cmds_sh[] =
{ "echo", "cd", "eval", "exec", "exit", "login", "logout", "set", "umask",
"wait", "while", "for", "case", "if", ":", ".", "break", "continue",
"export", "read", "readonly", "shift", "times", "trap", "switch",
"unset", 0 };
const char *sh_chars;
const char **sh_cmds;
#elif defined (_AMIGA)
static const char *sh_chars = "#;\"|<>()?*$`";
static const char *sh_cmds[] =
{ "cd", "eval", "if", "delete", "echo", "copy", "rename", "set", "setenv",
"date", "makedir", "skip", "else", "endif", "path", "prompt", "unset",
"unsetenv", "version", 0 };
#elif defined (WINDOWS32)
/* We used to have a double quote (") in sh_chars_dos[] below, but
that caused any command line with quoted file names be run
through a temporary batch file, which introduces command-line
limit of 4K charcaters imposed by cmd.exe. Since CreateProcess
can handle quoted file names just fine, removing the quote lifts
the limit from a very frequent use case, because using quoted
file names is commonplace on MS-Windows. */
static const char *sh_chars_dos = "|&<>";
static const char *sh_cmds_dos[] =
{ "assoc", "break", "call", "cd", "chcp", "chdir", "cls", "color", "copy",
"ctty", "date", "del", "dir", "echo", "echo.", "endlocal", "erase",
"exit", "for", "ftype", "goto", "if", "if", "md", "mkdir", "move",
"path", "pause", "prompt", "rd", "rem", "ren", "rename", "rmdir",
"set", "setlocal", "shift", "time", "title", "type", "ver", "verify",
"vol", ":", 0 };
static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^";
static const char *sh_cmds_sh[] =
{ "cd", "eval", "exec", "exit", "login", "logout", "set", "umask", "wait",
"while", "for", "case", "if", ":", ".", "break", "continue", "export",
"read", "readonly", "shift", "times", "trap", "switch", "test",
#ifdef BATCH_MODE_ONLY_SHELL
"echo",
#endif
0 };
const char *sh_chars;
const char **sh_cmds;
#elif defined(__riscos__)
static const char *sh_chars = "";
static const char *sh_cmds[] = { 0 };
#else /* must be UNIX-ish */
static const char *sh_chars = "#;\"*?[]&|<>(){}$`^~!";
static const char *sh_cmds[] =
{ ".", ":", "break", "case", "cd", "continue", "eval", "exec", "exit",
"export", "for", "if", "login", "logout", "read", "readonly", "set",
"shift", "switch", "test", "times", "trap", "ulimit", "umask", "unset",
"wait", "while", 0 };
# ifdef HAVE_DOS_PATHS
/* This is required if the MSYS/Cygwin ports (which do not define
WINDOWS32) are compiled with HAVE_DOS_PATHS defined, which uses
sh_chars_sh directly (see below). The value must be identical
to that of sh_chars immediately above. */
static const char *sh_chars_sh = "#;\"*?[]&|<>(){}$`^~!";
# endif /* HAVE_DOS_PATHS */
#endif
int i;
char *p;
#ifndef NDEBUG
char *end;
#endif
char *ap;
const char *cap;
const char *cp;
int instring, word_has_equals, seen_nonequals, last_argument_was_empty;
char **new_argv = 0;
char *argstr = 0;
#ifdef WINDOWS32
int slow_flag = 0;
if (!unixy_shell)
{
sh_cmds = sh_cmds_dos;
sh_chars = sh_chars_dos;
}
else
{
sh_cmds = sh_cmds_sh;
sh_chars = sh_chars_sh;
}
#endif /* WINDOWS32 */
if (restp != NULL)
*restp = NULL;
/* Make sure not to bother processing an empty line but stop at newline. */
while (ISBLANK (*line))
++line;
if (*line == '\0')
return 0;
if (shellflags == 0)
shellflags = posix_pedantic ? "-ec" : "-c";
/* See if it is safe to parse commands internally. */
if (shell == 0)
shell = default_shell;
#ifdef WINDOWS32
else if (strcmp (shell, default_shell))
{
char *s1 = _fullpath (NULL, shell, 0);
char *s2 = _fullpath (NULL, default_shell, 0);
slow_flag = strcmp ((s1 ? s1 : ""), (s2 ? s2 : ""));
free (s1);
free (s2);
}
if (slow_flag)
goto slow;
#else /* not WINDOWS32 */
#if defined (__MSDOS__) || defined (__EMX__)
else if (strcasecmp (shell, default_shell))
{
extern int _is_unixy_shell (const char *_path);
DB (DB_BASIC, (_("$SHELL changed (was '%s', now '%s')\n"),
default_shell, shell));
unixy_shell = _is_unixy_shell (shell);
/* we must allocate a copy of shell: construct_command_argv() will free
* shell after this function returns. */
default_shell = xstrdup (shell);
}
if (unixy_shell)
{
sh_chars = sh_chars_sh;
sh_cmds = sh_cmds_sh;
}
else
{
sh_chars = sh_chars_dos;
sh_cmds = sh_cmds_dos;
# ifdef __EMX__
if (_osmode == OS2_MODE)
{
sh_chars = sh_chars_os2;
sh_cmds = sh_cmds_os2;
}
# endif
}
#else /* !__MSDOS__ */
else if (strcmp (shell, default_shell))
goto slow;
#endif /* !__MSDOS__ && !__EMX__ */
#endif /* not WINDOWS32 */
if (ifs)
for (cap = ifs; *cap != '\0'; ++cap)
if (*cap != ' ' && *cap != '\t' && *cap != '\n')
goto slow;
if (shellflags)
if (shellflags[0] != '-'
|| ((shellflags[1] != 'c' || shellflags[2] != '\0')
&& (shellflags[1] != 'e' || shellflags[2] != 'c' || shellflags[3] != '\0')))
goto slow;
i = strlen (line) + 1;
/* More than 1 arg per character is impossible. */
new_argv = xmalloc (i * sizeof (char *));
/* All the args can fit in a buffer as big as LINE is. */
ap = new_argv[0] = argstr = xmalloc (i);
#ifndef NDEBUG
end = ap + i;
#endif
/* I is how many complete arguments have been found. */
i = 0;
instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0;
for (p = line; *p != '\0'; ++p)
{
assert (ap <= end);
if (instring)
{
/* Inside a string, just copy any char except a closing quote
or a backslash-newline combination. */
if (*p == instring)
{
instring = 0;
if (ap == new_argv[0] || *(ap-1) == '\0')
last_argument_was_empty = 1;
}
else if (*p == '\\' && p[1] == '\n')
{
/* Backslash-newline is handled differently depending on what
kind of string we're in: inside single-quoted strings you
keep them; in double-quoted strings they disappear. For
DOS/Windows/OS2, if we don't have a POSIX shell, we keep the
pre-POSIX behavior of removing the backslash-newline. */
if (instring == '"'
#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32)
|| !unixy_shell
#endif
)
++p;
else
{
*(ap++) = *(p++);
*(ap++) = *p;
}
}
else if (*p == '\n' && restp != NULL)
{
/* End of the command line. */
*restp = p;
goto end_of_line;
}
/* Backslash, $, and ` are special inside double quotes.
If we see any of those, punt.
But on MSDOS, if we use COMMAND.COM, double and single
quotes have the same effect. */
else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell)
goto slow;
#ifdef WINDOWS32
/* Quoted wildcard characters must be passed quoted to the
command, so give up the fast route. */
else if (instring == '"' && strchr ("*?", *p) != 0 && !unixy_shell)
goto slow;
else if (instring == '"' && strncmp (p, "\\\"", 2) == 0)
*ap++ = *++p;
#endif
else
*ap++ = *p;
}
else if (strchr (sh_chars, *p) != 0)
/* Not inside a string, but it's a special char. */
goto slow;
else if (one_shell && *p == '\n')
/* In .ONESHELL mode \n is a separator like ; or && */
goto slow;
#ifdef __MSDOS__
else if (*p == '.' && p[1] == '.' && p[2] == '.' && p[3] != '.')
/* '...' is a wildcard in DJGPP. */
goto slow;
#endif
else
/* Not a special char. */
switch (*p)
{
case '=':
/* Equals is a special character in leading words before the
first word with no equals sign in it. This is not the case
with sh -k, but we never get here when using nonstandard
shell flags. */
if (! seen_nonequals && unixy_shell)
goto slow;
word_has_equals = 1;
*ap++ = '=';
break;
case '\\':
/* Backslash-newline has special case handling, ref POSIX.
We're in the fastpath, so emulate what the shell would do. */
if (p[1] == '\n')
{
/* Throw out the backslash and newline. */
++p;
/* At the beginning of the argument, skip any whitespace other
than newline before the start of the next word. */
if (ap == new_argv[i])
while (ISBLANK (p[1]))
++p;
}
#ifdef WINDOWS32
/* Backslash before whitespace is not special if our shell
is not Unixy. */
else if (ISSPACE (p[1]) && !unixy_shell)
{
*ap++ = *p;
break;
}
#endif
else if (p[1] != '\0')
{
#ifdef HAVE_DOS_PATHS
/* Only remove backslashes before characters special to Unixy
shells. All other backslashes are copied verbatim, since
they are probably DOS-style directory separators. This
still leaves a small window for problems, but at least it
should work for the vast majority of naive users. */
#ifdef __MSDOS__
/* A dot is only special as part of the "..."
wildcard. */
if (strneq (p + 1, ".\\.\\.", 5))
{
*ap++ = '.';
*ap++ = '.';
p += 4;
}
else
#endif
if (p[1] != '\\' && p[1] != '\''
&& !ISSPACE (p[1])
&& strchr (sh_chars_sh, p[1]) == 0)
/* back up one notch, to copy the backslash */
--p;
#endif /* HAVE_DOS_PATHS */
/* Copy and skip the following char. */
*ap++ = *++p;
}
break;
case '\'':
case '"':
instring = *p;
break;
case '\n':
if (restp != NULL)
{
/* End of the command line. */
*restp = p;
goto end_of_line;
}
else
/* Newlines are not special. */
*ap++ = '\n';
break;
case ' ':
case '\t':
/* We have the end of an argument.
Terminate the text of the argument. */
*ap++ = '\0';
new_argv[++i] = ap;
last_argument_was_empty = 0;
/* Update SEEN_NONEQUALS, which tells us if every word
heretofore has contained an '='. */
seen_nonequals |= ! word_has_equals;
if (word_has_equals && ! seen_nonequals)
/* An '=' in a word before the first
word without one is magical. */
goto slow;
word_has_equals = 0; /* Prepare for the next word. */
/* 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] != 0; ++j)
{
if (streq (sh_cmds[j], new_argv[0]))
goto slow;
#if defined(__EMX__) || defined(WINDOWS32)
/* Non-Unix shells are case insensitive. */
if (!unixy_shell
&& strcasecmp (sh_cmds[j], new_argv[0]) == 0)
goto slow;
#endif
}
}
/* Skip whitespace chars, but not newlines. */
while (ISBLANK (p[1]))
++p;
break;
default:
*ap++ = *p;
break;
}
}
end_of_line:
if (instring)
/* Let the shell deal with an unterminated quote. */
goto slow;
/* Terminate the last argument and the argument list. */
*ap = '\0';
if (new_argv[i][0] != '\0' || last_argument_was_empty)
++i;
new_argv[i] = 0;
if (i == 1)
{
register int j;
for (j = 0; sh_cmds[j] != 0; ++j)
if (streq (sh_cmds[j], new_argv[0]))
goto slow;
}
if (new_argv[0] == 0)
{
/* Line was empty. */
free (argstr);
free (new_argv);
return 0;
}
return new_argv;
slow:;
/* We must use the shell. */
if (new_argv != 0)
{
/* Free the old argument list we were working on. */
free (argstr);
free (new_argv);
}
#ifdef __MSDOS__
execute_by_shell = 1; /* actually, call 'system' if shell isn't unixy */
#endif
#ifdef _AMIGA
{
char *ptr;
char *buffer;
char *dptr;
buffer = xmalloc (strlen (line)+1);
ptr = line;
for (dptr=buffer; *ptr; )
{
if (*ptr == '\\' && ptr[1] == '\n')
ptr += 2;
else if (*ptr == '@') /* Kludge: multiline commands */
{
ptr += 2;
*dptr++ = '\n';
}
else
*dptr++ = *ptr++;
}
*dptr = 0;
new_argv = xmalloc (2 * sizeof (char *));
new_argv[0] = buffer;
new_argv[1] = 0;
}
#else /* Not Amiga */
#ifdef WINDOWS32
/*
* Not eating this whitespace caused things like
*
* sh -c "\n"
*
* which gave the shell fits. I think we have to eat
* whitespace here, but this code should be considered
* suspicious if things start failing....
*/
/* Make sure not to bother processing an empty line. */
NEXT_TOKEN (line);
if (*line == '\0')
return 0;
#endif /* WINDOWS32 */
{
/* SHELL may be a multi-word command. Construct a command line
"$(SHELL) $(.SHELLFLAGS) LINE", with all special chars in LINE escaped.
Then recurse, expanding this command line to get the final
argument list. */
char *new_line;
unsigned int shell_len = strlen (shell);
unsigned int line_len = strlen (line);
unsigned int sflags_len = shellflags ? strlen (shellflags) : 0;
#ifdef WINDOWS32
char *command_ptr = NULL; /* used for batch_mode_shell mode */
#endif
# ifdef __EMX__ /* is this necessary? */
if (!unixy_shell && shellflags)
shellflags[0] = '/'; /* "/c" */
# endif
/* In .ONESHELL mode we are allowed to throw the entire current
recipe string at a single shell and trust that the user
has configured the shell and shell flags, and formatted
the string, appropriately. */
if (one_shell)
{
/* If the shell is Bourne compatible, we must remove and ignore
interior special chars [@+-] because they're meaningless to
the shell itself. If, however, we're in .ONESHELL mode and
have changed SHELL to something non-standard, we should
leave those alone because they could be part of the
script. In this case we must also leave in place
any leading [@+-] for the same reason. */
/* Remove and ignore interior prefix chars [@+-] because they're
meaningless given a single shell. */
#if defined __MSDOS__ || defined (__EMX__)
if (unixy_shell) /* the test is complicated and we already did it */
#else
if (is_bourne_compatible_shell (shell)
#ifdef WINDOWS32
/* If we didn't find any sh.exe, don't behave is if we did! */
&& !no_default_sh_exe
#endif
)
#endif
{
const char *f = line;
char *t = line;
/* Copy the recipe, removing and ignoring interior prefix chars
[@+-]: they're meaningless in .ONESHELL mode. */
while (f[0] != '\0')
{
int esc = 0;
/* This is the start of a new recipe line. Skip whitespace
and prefix characters but not newlines. */
while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+')
++f;
/* Copy until we get to the next logical recipe line. */
while (*f != '\0')
{
*(t++) = *(f++);
if (f[-1] == '\\')
esc = !esc;
else
{
/* On unescaped newline, we're done with this line. */
if (f[-1] == '\n' && ! esc)
break;
/* Something else: reset the escape sequence. */
esc = 0;
}
}
}
*t = '\0';
}
#ifdef WINDOWS32
else /* non-Posix shell (cmd.exe etc.) */
{
const char *f = line;
char *t = line;
char *tstart = t;
int temp_fd;
FILE* batch = NULL;
int id = GetCurrentProcessId ();
PATH_VAR(fbuf);
/* Generate a file name for the temporary batch file. */
sprintf (fbuf, "make%d", id);
*batch_filename = create_batch_file (fbuf, 0, &temp_fd);
DB (DB_JOBS, (_("Creating temporary batch file %s\n"),
*batch_filename));
/* Create a FILE object for the batch file, and write to it the
commands to be executed. Put the batch file in TEXT mode. */
_setmode (temp_fd, _O_TEXT);
batch = _fdopen (temp_fd, "wt");
fputs ("@echo off\n", batch);
DB (DB_JOBS, (_("Batch file contents:\n\t@echo off\n")));
/* Copy the recipe, removing and ignoring interior prefix chars
[@+-]: they're meaningless in .ONESHELL mode. */
while (*f != '\0')
{
/* This is the start of a new recipe line. Skip whitespace
and prefix characters but not newlines. */
while (ISBLANK (*f) || *f == '-' || *f == '@' || *f == '+')
++f;
/* Copy until we get to the next logical recipe line. */
while (*f != '\0')
{
/* Remove the escaped newlines in the command, and the
blanks that follow them. Windows shells cannot handle
escaped newlines. */
if (*f == '\\' && f[1] == '\n')
{
f += 2;
while (ISBLANK (*f))
++f;
}
*(t++) = *(f++);
/* On an unescaped newline, we're done with this
line. */
if (f[-1] == '\n')
break;
}
/* Write another line into the batch file. */
if (t > tstart)
{
char c = *t;
*t = '\0';
fputs (tstart, batch);
DB (DB_JOBS, ("\t%s", tstart));
tstart = t;
*t = c;
}
}
DB (DB_JOBS, ("\n"));
fclose (batch);
/* Create an argv list for the shell command line that
will run the batch file. */
new_argv = xmalloc (2 * sizeof (char *));
new_argv[0] = xstrdup (*batch_filename);
new_argv[1] = NULL;
return new_argv;
}
#endif /* WINDOWS32 */
/* Create an argv list for the shell command line. */
{
int n = 0;
new_argv = xmalloc ((4 + sflags_len/2) * sizeof (char *));
new_argv[n++] = xstrdup (shell);
/* Chop up the shellflags (if any) and assign them. */
if (! shellflags)
new_argv[n++] = xstrdup ("");
else
{
const char *s = shellflags;
char *t;
unsigned int len;
while ((t = find_next_token (&s, &len)) != 0)
new_argv[n++] = xstrndup (t, len);
}
/* Set the command to invoke. */
new_argv[n++] = line;
new_argv[n++] = NULL;
}
return new_argv;
}
new_line = xmalloc ((shell_len*2) + 1 + sflags_len + 1
+ (line_len*2) + 1);
ap = new_line;
/* Copy SHELL, escaping any characters special to the shell. If
we don't escape them, construct_command_argv_internal will
recursively call itself ad nauseam, or until stack overflow,
whichever happens first. */
for (cp = shell; *cp != '\0'; ++cp)
{
if (strchr (sh_chars, *cp) != 0)
*(ap++) = '\\';
*(ap++) = *cp;
}
*(ap++) = ' ';
if (shellflags)
memcpy (ap, shellflags, sflags_len);
ap += sflags_len;
*(ap++) = ' ';
#ifdef WINDOWS32
command_ptr = ap;
#endif
for (p = line; *p != '\0'; ++p)
{
if (restp != NULL && *p == '\n')
{
*restp = p;
break;
}
else if (*p == '\\' && p[1] == '\n')
{
/* POSIX says we keep the backslash-newline. If we don't have a
POSIX shell on DOS/Windows/OS2, mimic the pre-POSIX behavior
and remove the backslash/newline. */
#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32)
# define PRESERVE_BSNL unixy_shell
#else
# define PRESERVE_BSNL 1
#endif
if (PRESERVE_BSNL)
{
*(ap++) = '\\';
/* Only non-batch execution needs another backslash,
because it will be passed through a recursive
invocation of this function. */
if (!batch_mode_shell)
*(ap++) = '\\';
*(ap++) = '\n';
}
++p;
continue;
}
/* DOS shells don't know about backslash-escaping. */
if (unixy_shell && !batch_mode_shell &&
(*p == '\\' || *p == '\'' || *p == '"'
|| ISSPACE (*p)
|| strchr (sh_chars, *p) != 0))
*ap++ = '\\';
#ifdef __MSDOS__
else if (unixy_shell && strneq (p, "...", 3))
{
/* The case of '...' wildcard again. */
strcpy (ap, "\\.\\.\\");
ap += 5;
p += 2;
}
#endif
*ap++ = *p;
}
if (ap == new_line + shell_len + sflags_len + 2)
{
/* Line was empty. */
free (new_line);
return 0;
}
*ap = '\0';
#ifdef WINDOWS32
/* Some shells do not work well when invoked as 'sh -c xxx' to run a
command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these
cases, run commands via a script file. */
if (just_print_flag && !(flags & COMMANDS_RECURSE))
{
/* Need to allocate new_argv, although it's unused, because
start_job_command will want to free it and its 0'th element. */
new_argv = xmalloc (2 * sizeof (char *));
new_argv[0] = xstrdup ("");
new_argv[1] = NULL;
}
else if ((no_default_sh_exe || batch_mode_shell) && batch_filename)
{
int temp_fd;
FILE* batch = NULL;
int id = GetCurrentProcessId ();
PATH_VAR (fbuf);
/* create a file name */
sprintf (fbuf, "make%d", id);
*batch_filename = create_batch_file (fbuf, unixy_shell, &temp_fd);
DB (DB_JOBS, (_("Creating temporary batch file %s\n"),
*batch_filename));
/* Create a FILE object for the batch file, and write to it the
commands to be executed. Put the batch file in TEXT mode. */
_setmode (temp_fd, _O_TEXT);
batch = _fdopen (temp_fd, "wt");
if (!unixy_shell)
fputs ("@echo off\n", batch);
fputs (command_ptr, batch);
fputc ('\n', batch);
fclose (batch);
DB (DB_JOBS, (_("Batch file contents:%s\n\t%s\n"),
!unixy_shell ? "\n\t@echo off" : "", command_ptr));
/* create argv */
new_argv = xmalloc (3 * sizeof (char *));
if (unixy_shell)
{
new_argv[0] = xstrdup (shell);
new_argv[1] = *batch_filename; /* only argv[0] gets freed later */
}
else
{
new_argv[0] = xstrdup (*batch_filename);
new_argv[1] = NULL;
}
new_argv[2] = NULL;
}
else
#endif /* WINDOWS32 */
if (unixy_shell)
new_argv = construct_command_argv_internal (new_line, 0, 0, 0, 0,
flags, 0);
#ifdef __EMX__
else if (!unixy_shell)
{
/* new_line is local, must not be freed therefore
We use line here instead of new_line because we run the shell
manually. */
size_t line_len = strlen (line);
char *p = new_line;
char *q = new_line;
memcpy (new_line, line, line_len + 1);
/* Replace all backslash-newline combination and also following tabs.
Important: stop at the first '\n' because that's what the loop above
did. The next line starting at restp[0] will be executed during the
next call of this function. */
while (*q != '\0' && *q != '\n')
{
if (q[0] == '\\' && q[1] == '\n')
q += 2; /* remove '\\' and '\n' */
else
*p++ = *q++;
}
*p = '\0';
# ifndef NO_CMD_DEFAULT
if (strnicmp (new_line, "echo", 4) == 0
&& (new_line[4] == ' ' || new_line[4] == '\t'))
{
/* the builtin echo command: handle it separately */
size_t echo_len = line_len - 5;
char *echo_line = new_line + 5;
/* special case: echo 'x="y"'
cmd works this way: a string is printed as is, i.e., no quotes
are removed. But autoconf uses a command like echo 'x="y"' to
determine whether make works. autoconf expects the output x="y"
so we will do exactly that.
Note: if we do not allow cmd to be the default shell
we do not need this kind of voodoo */
if (echo_line[0] == '\''
&& echo_line[echo_len - 1] == '\''
&& strncmp (echo_line + 1, "ac_maketemp=",
strlen ("ac_maketemp=")) == 0)
{
/* remove the enclosing quotes */
memmove (echo_line, echo_line + 1, echo_len - 2);
echo_line[echo_len - 2] = '\0';
}
}
# endif
{
/* Let the shell decide what to do. Put the command line into the
2nd command line argument and hope for the best ;-) */
size_t sh_len = strlen (shell);
/* exactly 3 arguments + NULL */
new_argv = xmalloc (4 * sizeof (char *));
/* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times
the trailing '\0' */
new_argv[0] = xmalloc (sh_len + line_len + 5);
memcpy (new_argv[0], shell, sh_len + 1);
new_argv[1] = new_argv[0] + sh_len + 1;
memcpy (new_argv[1], "/c", 3);
new_argv[2] = new_argv[1] + 3;
memcpy (new_argv[2], new_line, line_len + 1);
new_argv[3] = NULL;
}
}
#elif defined(__MSDOS__)
else
{
/* With MSDOS shells, we must construct the command line here
instead of recursively calling ourselves, because we
cannot backslash-escape the special characters (see above). */
new_argv = xmalloc (sizeof (char *));
line_len = strlen (new_line) - shell_len - sflags_len - 2;
new_argv[0] = xmalloc (line_len + 1);
strncpy (new_argv[0],
new_line + shell_len + sflags_len + 2, line_len);
new_argv[0][line_len] = '\0';
}
#else
else
fatal (NILF, CSTRLEN (__FILE__) + INTSTR_LENGTH,
_("%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n"),
__FILE__, __LINE__);
#endif
free (new_line);
}
#endif /* ! AMIGA */
return new_argv;
}
#endif /* !VMS */
/* Figure out the argument list necessary to run LINE as a command. Try to
avoid using a shell. This routine handles only ' quoting, and " quoting
when no backslash, $ or ' characters are seen in the quotes. Starting
quotes may be escaped with a backslash. If any of the characters in
sh_chars is seen, or any of the builtin commands listed in sh_cmds
is the first word of a line, the shell is used.
If RESTP is not NULL, *RESTP is set to point to the first newline in LINE.
If *RESTP is NULL, newlines will be ignored.
FILE is the target whose commands these are. It is used for
variable expansion for $(SHELL) and $(IFS). */
char **
construct_command_argv (char *line, char **restp, struct file *file,
int cmd_flags, char **batch_filename)
{
char *shell, *ifs, *shellflags;
char **argv;
#ifdef VMS
char *cptr;
int argc;
argc = 0;
cptr = line;
for (;;)
{
while ((*cptr != 0) && (ISSPACE (*cptr)))
cptr++;
if (*cptr == 0)
break;
while ((*cptr != 0) && (!ISSPACE (*cptr)))
cptr++;
argc++;
}
argv = xmalloc (argc * sizeof (char *));
if (argv == 0)
abort ();
cptr = line;
argc = 0;
for (;;)
{
while ((*cptr != 0) && (ISSPACE (*cptr)))
cptr++;
if (*cptr == 0)
break;
DB (DB_JOBS, ("argv[%d] = [%s]\n", argc, cptr));
argv[argc++] = cptr;
while ((*cptr != 0) && (!ISSPACE (*cptr)))
cptr++;
if (*cptr != 0)
*cptr++ = 0;
}
#else
{
/* Turn off --warn-undefined-variables while we expand SHELL and IFS. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
shell = allocated_variable_expand_for_file ("$(SHELL)", file);
#ifdef WINDOWS32
/*
* Convert to forward slashes so that construct_command_argv_internal()
* is not confused.
*/
if (shell)
{
char *p = w32ify (shell, 0);
strcpy (shell, p);
}
#endif
#ifdef __EMX__
{
static const char *unixroot = NULL;
static const char *last_shell = "";
static int init = 0;
if (init == 0)
{
unixroot = getenv ("UNIXROOT");
/* unixroot must be NULL or not empty */
if (unixroot && unixroot[0] == '\0') unixroot = NULL;
init = 1;
}
/* if we have an unixroot drive and if shell is not default_shell
(which means it's either cmd.exe or the test has already been
performed) and if shell is an absolute path without drive letter,
try whether it exists e.g.: if "/bin/sh" does not exist use
"$UNIXROOT/bin/sh" instead. */
if (unixroot && shell && strcmp (shell, last_shell) != 0
&& (shell[0] == '/' || shell[0] == '\\'))
{
/* trying a new shell, check whether it exists */
size_t size = strlen (shell);
char *buf = xmalloc (size + 7);
memcpy (buf, shell, size);
memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */
if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0)
{
/* try the same for the unixroot drive */
memmove (buf + 2, buf, size + 5);
buf[0] = unixroot[0];
buf[1] = unixroot[1];
if (access (buf, F_OK) == 0)
/* we have found a shell! */
/* free(shell); */
shell = buf;
else
free (buf);
}
else
free (buf);
}
}
#endif /* __EMX__ */
shellflags = allocated_variable_expand_for_file ("$(.SHELLFLAGS)", file);
ifs = allocated_variable_expand_for_file ("$(IFS)", file);
warn_undefined_variables_flag = save;
}
argv = construct_command_argv_internal (line, restp, shell, shellflags, ifs,
cmd_flags, batch_filename);
free (shell);
free (shellflags);
free (ifs);
#endif /* !VMS */
return argv;
}
#if !defined(HAVE_DUP2) && !defined(_AMIGA)
int
dup2 (int old, int new)
{
int fd;
(void) close (new);
EINTRLOOP (fd, dup (old));
if (fd != new)
{
(void) close (fd);
errno = EMFILE;
return -1;
}
return fd;
}
#endif /* !HAVE_DUP2 && !_AMIGA */
/* On VMS systems, include special VMS functions. */
#ifdef VMS
#include "vmsjobs.c"
#endif
make-4.2.1/os.h 0000644 0001750 0001750 00000005711 12720141540 010146 0000000 0000000 /* Declarations for operating system interfaces for GNU Make.
Copyright (C) 2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* This section provides OS-specific functions to support the jobserver. */
#ifdef MAKE_JOBSERVER
/* Returns 1 if the jobserver is enabled, else 0. */
unsigned int jobserver_enabled (void);
/* Called in the master instance to set up the jobserver initially. */
unsigned int jobserver_setup (int job_slots);
/* Called in a child instance to connect to the jobserver. */
unsigned int jobserver_parse_auth (const char* auth);
/* Returns an allocated buffer used to pass to child instances. */
char *jobserver_get_auth (void);
/* Clear this instance's jobserver configuration. */
void jobserver_clear (void);
/* Recover all the jobserver tokens and return the number we got. */
unsigned int jobserver_acquire_all (void);
/* Release a jobserver token. If it fails and is_fatal is 1, fatal. */
void jobserver_release (int is_fatal);
/* Notify the jobserver that a child exited. */
void jobserver_signal (void);
/* Get ready to start a non-recursive child. */
void jobserver_pre_child (int);
/* Complete starting a non-recursive child. */
void jobserver_post_child (int);
/* Set up to acquire a new token. */
void jobserver_pre_acquire (void);
/* Wait until we can acquire a jobserver token.
TIMEOUT is 1 if we have other jobs waiting for the load to go down;
in this case we won't wait forever, so we can check the load.
Returns 1 if we got a token, or 0 if we stopped waiting due to a child
exiting or a timeout. */
unsigned int jobserver_acquire (int timeout);
#else
#define jobserver_enabled() (0)
#define jobserver_setup(_slots) (0)
#define jobserver_parse_auth(_auth) (0)
#define jobserver_get_auth() (NULL)
#define jobserver_clear() (void)(0)
#define jobserver_release(_fatal) (void)(0)
#define jobserver_acquire_all() (0)
#define jobserver_signal() (void)(0)
#define jobserver_pre_child(_r) (void)(0)
#define jobserver_post_child(_r) (void)(0)
#define jobserver_pre_acquire() (void)(0)
#define jobserver_acquire(_tmout) (0)
#endif
/* Create a "bad" file descriptor for stdin when parallel jobs are run. */
#if !defined(VMD) && !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__)
int get_bad_stdin (void);
#else
# define get_bad_stdin() (-1)
#endif
make-4.2.1/COPYING 0000644 0001750 0001750 00000104513 12074551137 010420 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc.
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE 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.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Copyright (C)
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
.
make-4.2.1/output.c 0000644 0001750 0001750 00000042456 12720141610 011065 0000000 0000000 /* Output to stdout / stderr for GNU make
Copyright (C) 2013-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include "job.h"
/* GNU make no longer supports pre-ANSI89 environments. */
#include
#include
#include
#ifdef HAVE_UNISTD_H
# include
#endif
#ifdef HAVE_FCNTL_H
# include
#else
# include
#endif
#ifdef WINDOWS32
# include
# include
# include "sub_proc.h"
#endif /* WINDOWS32 */
struct output *output_context = NULL;
unsigned int stdio_traced = 0;
#define OUTPUT_NONE (-1)
#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
#ifdef HAVE_FCNTL_H
# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
#else
# define STREAM_OK(_s) 1
#endif
/* Write a string to the current STDOUT or STDERR. */
static void
_outputs (struct output *out, int is_err, const char *msg)
{
if (! out || ! out->syncout)
{
FILE *f = is_err ? stderr : stdout;
fputs (msg, f);
fflush (f);
}
else
{
int fd = is_err ? out->err : out->out;
int len = strlen (msg);
int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
while (1)
{
EINTRLOOP (r, write (fd, msg, len));
if (r == len || r <= 0)
break;
len -= r;
msg += r;
}
}
}
/* Write a message indicating that we've just entered or
left (according to ENTERING) the current directory. */
static int
log_working_directory (int entering)
{
static char *buf = NULL;
static unsigned int len = 0;
unsigned int need;
const char *fmt;
char *p;
/* Get enough space for the longest possible output. */
need = strlen (program) + INTSTR_LENGTH + 2 + 1;
if (starting_directory)
need += strlen (starting_directory);
/* Use entire sentences to give the translators a fighting chance. */
if (makelevel == 0)
if (starting_directory == 0)
if (entering)
fmt = _("%s: Entering an unknown directory\n");
else
fmt = _("%s: Leaving an unknown directory\n");
else
if (entering)
fmt = _("%s: Entering directory '%s'\n");
else
fmt = _("%s: Leaving directory '%s'\n");
else
if (starting_directory == 0)
if (entering)
fmt = _("%s[%u]: Entering an unknown directory\n");
else
fmt = _("%s[%u]: Leaving an unknown directory\n");
else
if (entering)
fmt = _("%s[%u]: Entering directory '%s'\n");
else
fmt = _("%s[%u]: Leaving directory '%s'\n");
need += strlen (fmt);
if (need > len)
{
buf = xrealloc (buf, need);
len = need;
}
p = buf;
if (print_data_base_flag)
{
*(p++) = '#';
*(p++) = ' ';
}
if (makelevel == 0)
if (starting_directory == 0)
sprintf (p, fmt , program);
else
sprintf (p, fmt, program, starting_directory);
else if (starting_directory == 0)
sprintf (p, fmt, program, makelevel);
else
sprintf (p, fmt, program, makelevel, starting_directory);
_outputs (NULL, 0, buf);
return 1;
}
/* Set a file descriptor to be in O_APPEND mode.
If it fails, just ignore it. */
static void
set_append_mode (int fd)
{
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
int flags = fcntl (fd, F_GETFL, 0);
if (flags >= 0)
fcntl (fd, F_SETFL, flags | O_APPEND);
#endif
}
#ifndef NO_OUTPUT_SYNC
/* Semaphore for use in -j mode with output_sync. */
static sync_handle_t sync_handle = -1;
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
/* Set up the sync handle. Disables output_sync on error. */
static int
sync_init (void)
{
int combined_output = 0;
#ifdef WINDOWS32
if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
|| (sync_handle = create_mutex ()) == -1)
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
else
{
combined_output = same_stream (stdout, stderr);
prepare_mutex_handle_string (sync_handle);
}
#else
if (STREAM_OK (stdout))
{
struct stat stbuf_o, stbuf_e;
sync_handle = fileno (stdout);
combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
&& fstat (fileno (stderr), &stbuf_e) == 0
&& stbuf_o.st_dev == stbuf_e.st_dev
&& stbuf_o.st_ino == stbuf_e.st_ino);
}
else if (STREAM_OK (stderr))
sync_handle = fileno (stderr);
else
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
#endif
return combined_output;
}
/* Support routine for output_sync() */
static void
pump_from_tmp (int from, FILE *to)
{
static char buffer[8192];
#ifdef WINDOWS32
int prev_mode;
/* "from" is opened by open_tmpfd, which does it in binary mode, so
we need the mode of "to" to match that. */
prev_mode = _setmode (fileno (to), _O_BINARY);
#endif
if (lseek (from, 0, SEEK_SET) == -1)
perror ("lseek()");
while (1)
{
int len;
EINTRLOOP (len, read (from, buffer, sizeof (buffer)));
if (len < 0)
perror ("read()");
if (len <= 0)
break;
if (fwrite (buffer, len, 1, to) < 1)
{
perror ("fwrite()");
break;
}
fflush (to);
}
#ifdef WINDOWS32
/* Switch "to" back to its original mode, so that log messages by
Make have the same EOL format as without --output-sync. */
_setmode (fileno (to), prev_mode);
#endif
}
/* Obtain the lock for writing output. */
static void *
acquire_semaphore (void)
{
static struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
return &fl;
perror ("fcntl()");
return NULL;
}
/* Release the lock for writing output. */
static void
release_semaphore (void *sem)
{
struct flock *flp = (struct flock *)sem;
flp->l_type = F_UNLCK;
if (fcntl (sync_handle, F_SETLKW, flp) == -1)
perror ("fcntl()");
}
/* Returns a file descriptor to a temporary file. The file is automatically
closed/deleted on exit. Don't use a FILE* stream. */
int
output_tmpfd (void)
{
int fd = -1;
FILE *tfile = tmpfile ();
if (! tfile)
pfatal_with_name ("tmpfile");
/* Create a duplicate so we can close the stream. */
fd = dup (fileno (tfile));
if (fd < 0)
pfatal_with_name ("dup");
fclose (tfile);
set_append_mode (fd);
return fd;
}
/* Adds file descriptors to the child structure to support output_sync; one
for stdout and one for stderr as long as they are open. If stdout and
stderr share a device they can share a temp file too.
Will reset output_sync on error. */
static void
setup_tmpfile (struct output *out)
{
/* Is make's stdout going to the same place as stderr? */
static int combined_output = -1;
if (combined_output < 0)
combined_output = sync_init ();
if (STREAM_OK (stdout))
{
int fd = output_tmpfd ();
if (fd < 0)
goto error;
CLOSE_ON_EXEC (fd);
out->out = fd;
}
if (STREAM_OK (stderr))
{
if (out->out != OUTPUT_NONE && combined_output)
out->err = out->out;
else
{
int fd = output_tmpfd ();
if (fd < 0)
goto error;
CLOSE_ON_EXEC (fd);
out->err = fd;
}
}
return;
/* If we failed to create a temp file, disable output sync going forward. */
error:
output_close (out);
output_sync = OUTPUT_SYNC_NONE;
}
/* Synchronize the output of jobs in -j mode to keep the results of
each job together. This is done by holding the results in temp files,
one for stdout and potentially another for stderr, and only releasing
them to "real" stdout/stderr when a semaphore can be obtained. */
void
output_dump (struct output *out)
{
int outfd_not_empty = FD_NOT_EMPTY (out->out);
int errfd_not_empty = FD_NOT_EMPTY (out->err);
if (outfd_not_empty || errfd_not_empty)
{
int traced = 0;
/* Try to acquire the semaphore. If it fails, dump the output
unsynchronized; still better than silently discarding it.
We want to keep this lock for as little time as possible. */
void *sem = acquire_semaphore ();
/* Log the working directory for this dump. */
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
traced = log_working_directory (1);
if (outfd_not_empty)
pump_from_tmp (out->out, stdout);
if (errfd_not_empty && out->err != out->out)
pump_from_tmp (out->err, stderr);
if (traced)
log_working_directory (0);
/* Exit the critical section. */
if (sem)
release_semaphore (sem);
/* Truncate and reset the output, in case we use it again. */
if (out->out != OUTPUT_NONE)
{
int e;
lseek (out->out, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (out->out, 0));
}
if (out->err != OUTPUT_NONE && out->err != out->out)
{
int e;
lseek (out->err, 0, SEEK_SET);
EINTRLOOP (e, ftruncate (out->err, 0));
}
}
}
#endif /* NO_OUTPUT_SYNC */
/* Provide support for temporary files. */
#ifndef HAVE_STDLIB_H
# ifdef HAVE_MKSTEMP
int mkstemp (char *template);
# else
char *mktemp (char *template);
# endif
#endif
FILE *
output_tmpfile (char **name, const char *template)
{
#ifdef HAVE_FDOPEN
int fd;
#endif
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
# define TEMPLATE_LEN strlen (template)
#else
# define TEMPLATE_LEN L_tmpnam
#endif
*name = xmalloc (TEMPLATE_LEN + 1);
strcpy (*name, template);
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
/* It's safest to use mkstemp(), if we can. */
fd = mkstemp (*name);
if (fd == -1)
return 0;
return fdopen (fd, "w");
#else
# ifdef HAVE_MKTEMP
(void) mktemp (*name);
# else
(void) tmpnam (*name);
# endif
# ifdef HAVE_FDOPEN
/* Can't use mkstemp(), but guard against a race condition. */
EINTRLOOP (fd, open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600));
if (fd == -1)
return 0;
return fdopen (fd, "w");
# else
/* Not secure, but what can we do? */
return fopen (*name, "w");
# endif
#endif
}
/* This code is stolen from gnulib.
If/when we abandon the requirement to work with K&R compilers, we can
remove this (and perhaps other parts of GNU make!) and migrate to using
gnulib directly.
This is called only through atexit(), which means die() has already been
invoked. So, call exit() here directly. Apparently that works...?
*/
/* Close standard output, exiting with status 'exit_failure' on failure.
If a program writes *anything* to stdout, that program should close
stdout and make sure that it succeeds before exiting. Otherwise,
suppose that you go to the extreme of checking the return status
of every function that does an explicit write to stdout. The last
printf can succeed in writing to the internal stream buffer, and yet
the fclose(stdout) could still fail (due e.g., to a disk full error)
when it tries to write out that buffered data. Thus, you would be
left with an incomplete output file and the offending program would
exit successfully. Even calling fflush is not always sufficient,
since some file systems (NFS and CODA) buffer written/flushed data
until an actual close call.
Besides, it's wasteful to check the return value from every call
that writes to stdout -- just let the internal stream state record
the failure. That's what the ferror test is checking below.
It's important to detect such failures and exit nonzero because many
tools (most notably 'make' and other build-management systems) depend
on being able to detect failure in other tools via their exit status. */
static void
close_stdout (void)
{
int prev_fail = ferror (stdout);
int fclose_fail = fclose (stdout);
if (prev_fail || fclose_fail)
{
if (fclose_fail)
perror_with_name (_("write error: stdout"), "");
else
O (error, NILF, _("write error: stdout"));
exit (MAKE_TROUBLE);
}
}
void
output_init (struct output *out)
{
if (out)
{
out->out = out->err = OUTPUT_NONE;
out->syncout = !!output_sync;
return;
}
/* Configure this instance of make. Be sure stdout is line-buffered. */
#ifdef HAVE_SETVBUF
# ifdef SETVBUF_REVERSED
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
# else /* setvbuf not reversed. */
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
# endif /* setvbuf reversed. */
#elif HAVE_SETLINEBUF
setlinebuf (stdout);
#endif /* setlinebuf missing. */
/* Force stdout/stderr into append mode. This ensures parallel jobs won't
lose output due to overlapping writes. */
set_append_mode (fileno (stdout));
set_append_mode (fileno (stderr));
#ifdef HAVE_ATEXIT
if (STREAM_OK (stdout))
atexit (close_stdout);
#endif
}
void
output_close (struct output *out)
{
if (! out)
{
if (stdio_traced)
log_working_directory (0);
return;
}
#ifndef NO_OUTPUT_SYNC
output_dump (out);
#endif
if (out->out >= 0)
close (out->out);
if (out->err >= 0 && out->err != out->out)
close (out->err);
output_init (out);
}
/* We're about to generate output: be sure it's set up. */
void
output_start (void)
{
#ifndef NO_OUTPUT_SYNC
/* If we're syncing output make sure the temporary file is set up. */
if (output_context && output_context->syncout)
if (! OUTPUT_ISSET(output_context))
setup_tmpfile (output_context);
#endif
/* If we're not syncing this output per-line or per-target, make sure we emit
the "Entering..." message where appropriate. */
if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
if (! stdio_traced && print_directory_flag)
stdio_traced = log_working_directory (1);
}
void
outputs (int is_err, const char *msg)
{
if (! msg || *msg == '\0')
return;
output_start ();
_outputs (output_context, is_err, msg);
}
static struct fmtstring
{
char *buffer;
size_t size;
} fmtbuf = { NULL, 0 };
static char *
get_buffer (size_t need)
{
/* Make sure we have room. NEED includes space for \0. */
if (need > fmtbuf.size)
{
fmtbuf.size += need * 2;
fmtbuf.buffer = xrealloc (fmtbuf.buffer, fmtbuf.size);
}
fmtbuf.buffer[need-1] = '\0';
return fmtbuf.buffer;
}
/* Print a message on stdout. */
void
message (int prefix, size_t len, const char *fmt, ...)
{
va_list args;
char *p;
len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
p = get_buffer (len);
if (prefix)
{
if (makelevel == 0)
sprintf (p, "%s: ", program);
else
sprintf (p, "%s[%u]: ", program, makelevel);
p += strlen (p);
}
va_start (args, fmt);
vsprintf (p, fmt, args);
va_end (args);
strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0');
outputs (0, fmtbuf.buffer);
}
/* Print an error message. */
void
error (const floc *flocp, size_t len, const char *fmt, ...)
{
va_list args;
char *p;
len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 4 + 1 + 1);
p = get_buffer (len);
if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
else if (makelevel == 0)
sprintf (p, "%s: ", program);
else
sprintf (p, "%s[%u]: ", program, makelevel);
p += strlen (p);
va_start (args, fmt);
vsprintf (p, fmt, args);
va_end (args);
strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0');
outputs (1, fmtbuf.buffer);
}
/* Print an error message and exit. */
void
fatal (const floc *flocp, size_t len, const char *fmt, ...)
{
va_list args;
const char *stop = _(". Stop.\n");
char *p;
len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 8 + strlen (stop) + 1);
p = get_buffer (len);
if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
else if (makelevel == 0)
sprintf (p, "%s: *** ", program);
else
sprintf (p, "%s[%u]: *** ", program, makelevel);
p += strlen (p);
va_start (args, fmt);
vsprintf (p, fmt, args);
va_end (args);
strcat (p, stop);
assert (fmtbuf.buffer[len-1] == '\0');
outputs (1, fmtbuf.buffer);
die (MAKE_FAILURE);
}
/* Print an error message from errno. */
void
perror_with_name (const char *str, const char *name)
{
const char *err = strerror (errno);
OSSS (error, NILF, _("%s%s: %s"), str, name, err);
}
/* Print an error message from errno and exit. */
void
pfatal_with_name (const char *name)
{
const char *err = strerror (errno);
OSS (fatal, NILF, _("%s: %s"), name, err);
/* NOTREACHED */
}
make-4.2.1/remake.c 0000644 0001750 0001750 00000155432 12723235206 011000 0000000 0000000 /* Basic dependency engine for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include "filedef.h"
#include "job.h"
#include "commands.h"
#include "dep.h"
#include "variable.h"
#include "debug.h"
#include
#ifdef HAVE_FCNTL_H
#include
#else
#include
#endif
#ifdef VMS
#include
#endif
#ifdef WINDOWS32
#include
#endif
/* The test for circular dependencies is based on the 'updating' bit in
'struct file'. However, double colon targets have separate 'struct
file's; make sure we always use the base of the double colon chain. */
#define start_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
->updating = 1)
#define finish_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
->updating = 0)
#define is_updating(_f) (((_f)->double_colon ? (_f)->double_colon : (_f))\
->updating)
/* Incremented when a command is started (under -n, when one would be). */
unsigned int commands_started = 0;
/* Set to the goal dependency. Mostly needed for remaking makefiles. */
static struct goaldep *goal_list;
static struct dep *goal_dep;
/* Current value for pruning the scan of the goal chain.
All files start with considered == 0. */
static unsigned int considered = 0;
static enum update_status update_file (struct file *file, unsigned int depth);
static enum update_status update_file_1 (struct file *file, unsigned int depth);
static enum update_status check_dep (struct file *file, unsigned int depth,
FILE_TIMESTAMP this_mtime, int *must_make);
static enum update_status touch_file (struct file *file);
static void remake_file (struct file *file);
static FILE_TIMESTAMP name_mtime (const char *name);
static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
/* Remake all the goals in the 'struct dep' chain GOALS. Return -1 if nothing
was done, 0 if all goals were updated successfully, or 1 if a goal failed.
If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q,
and -n should be disabled for them unless they were also command-line
targets, and we should only make one goal at a time and return as soon as
one goal whose 'changed' member is nonzero is successfully made. */
enum update_status
update_goal_chain (struct goaldep *goaldeps)
{
int t = touch_flag, q = question_flag, n = just_print_flag;
enum update_status status = us_none;
/* Duplicate the chain so we can remove things from it. */
struct dep *goals = copy_dep_chain ((struct dep *)goaldeps);
goal_list = rebuilding_makefiles ? goaldeps : NULL;
#define MTIME(file) (rebuilding_makefiles ? file_mtime_no_search (file) \
: file_mtime (file))
/* Start a fresh batch of consideration. */
++considered;
/* Update all the goals until they are all finished. */
while (goals != 0)
{
register struct dep *g, *lastgoal;
/* Start jobs that are waiting for the load to go down. */
start_waiting_jobs ();
/* Wait for a child to die. */
reap_children (1, 0);
lastgoal = 0;
g = goals;
while (g != 0)
{
/* Iterate over all double-colon entries for this file. */
struct file *file;
int stop = 0, any_not_updated = 0;
goal_dep = g;
for (file = g->file->double_colon ? g->file->double_colon : g->file;
file != NULL;
file = file->prev)
{
unsigned int ocommands_started;
enum update_status fail;
file->dontcare = ANY_SET (g->flags, RM_DONTCARE);
check_renamed (file);
if (rebuilding_makefiles)
{
if (file->cmd_target)
{
touch_flag = t;
question_flag = q;
just_print_flag = n;
}
else
touch_flag = question_flag = just_print_flag = 0;
}
/* Save the old value of 'commands_started' so we can compare
later. It will be incremented when any commands are
actually run. */
ocommands_started = commands_started;
fail = update_file (file, rebuilding_makefiles ? 1 : 0);
check_renamed (file);
/* Set the goal's 'changed' flag if any commands were started
by calling update_file above. We check this flag below to
decide when to give an "up to date" diagnostic. */
if (commands_started > ocommands_started)
g->changed = 1;
stop = 0;
if ((fail || file->updated) && status < us_question)
{
/* We updated this goal. Update STATUS and decide whether
to stop. */
if (file->update_status)
{
/* Updating failed, or -q triggered. The STATUS value
tells our caller which. */
status = file->update_status;
/* If -q just triggered, stop immediately. It doesn't
matter how much more we run, since we already know
the answer to return. */
stop = (question_flag && !keep_going_flag
&& !rebuilding_makefiles);
}
else
{
FILE_TIMESTAMP mtime = MTIME (file);
check_renamed (file);
if (file->updated && g->changed &&
mtime != file->mtime_before_update)
{
/* Updating was done. If this is a makefile and
just_print_flag or question_flag is set (meaning
-n or -q was given and this file was specified
as a command-line target), don't change STATUS.
If STATUS is changed, we will get re-exec'd, and
enter an infinite loop. */
if (!rebuilding_makefiles
|| (!just_print_flag && !question_flag))
status = us_success;
if (rebuilding_makefiles && file->dontcare)
/* This is a default makefile; stop remaking. */
stop = 1;
}
}
}
/* Keep track if any double-colon entry is not finished.
When they are all finished, the goal is finished. */
any_not_updated |= !file->updated;
file->dontcare = 0;
if (stop)
break;
}
/* Reset FILE since it is null at the end of the loop. */
file = g->file;
if (stop || !any_not_updated)
{
/* If we have found nothing whatever to do for the goal,
print a message saying nothing needs doing. */
if (!rebuilding_makefiles
/* If the update_status is success, we updated successfully
or not at all. G->changed will have been set above if
any commands were actually started for this goal. */
&& file->update_status == us_success && !g->changed
/* Never give a message under -s or -q. */
&& !silent_flag && !question_flag)
OS (message, 1, ((file->phony || file->cmds == 0)
? _("Nothing to be done for '%s'.")
: _("'%s' is up to date.")),
file->name);
/* This goal is finished. Remove it from the chain. */
if (lastgoal == 0)
goals = g->next;
else
lastgoal->next = g->next;
/* Free the storage. */
free (g);
g = lastgoal == 0 ? goals : lastgoal->next;
if (stop)
break;
}
else
{
lastgoal = g;
g = g->next;
}
}
/* If we reached the end of the dependency graph update CONSIDERED
for the next pass. */
if (g == 0)
++considered;
}
if (rebuilding_makefiles)
{
touch_flag = t;
question_flag = q;
just_print_flag = n;
}
return status;
}
/* If we're rebuilding an included makefile that failed, and we care
about errors, show an error message the first time. */
void
show_goal_error (void)
{
struct goaldep *goal;
if ((goal_dep->flags & (RM_INCLUDED|RM_DONTCARE)) != RM_INCLUDED)
return;
for (goal = goal_list; goal; goal = goal->next)
if (goal_dep->file == goal->file)
{
if (goal->error)
{
OSS (error, &goal->floc, "%s: %s",
goal->file->name, strerror ((int)goal->error));
goal->error = 0;
}
return;
}
}
/* If FILE is not up to date, execute the commands for it.
Return 0 if successful, non-0 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 double-colon entries for FILE,
each is considered in turn. */
static enum update_status
update_file (struct file *file, unsigned int depth)
{
enum update_status status = us_success;
struct file *f;
f = file->double_colon ? file->double_colon : file;
/* Prune the dependency graph: if we've already been here on _this_
pass through the dependency graph, we don't have to go any further.
We won't reap_children until we start the next pass, so no state
change is possible below here until then. */
if (f->considered == considered)
{
/* Check for the case where a target has been tried and failed but
the diagnostics haven't been issued. If we need the diagnostics
then we will have to continue. */
if (!(f->updated && f->update_status > us_none
&& !f->dontcare && f->no_diag))
{
DBF (DB_VERBOSE, _("Pruning file '%s'.\n"));
return f->command_state == cs_finished ? f->update_status : us_success;
}
}
/* This loop runs until we start commands for a double colon rule, or until
the chain is exhausted. */
for (; f != 0; f = f->prev)
{
enum update_status new;
f->considered = considered;
new = update_file_1 (f, depth);
check_renamed (f);
/* Clean up any alloca() used during the update. */
alloca (0);
/* If we got an error, don't bother with double_colon etc. */
if (new && !keep_going_flag)
return new;
if (f->command_state == cs_running
|| f->command_state == cs_deps_running)
/* Don't run other :: rules for this target until
this rule is finished. */
return us_success;
if (new > status)
status = new;
}
/* Process the remaining rules in the double colon chain so they're marked
considered. Start their prerequisites, too. */
if (file->double_colon)
for (; f != 0 ; f = f->prev)
{
struct dep *d;
f->considered = considered;
for (d = f->deps; d != 0; d = d->next)
{
enum update_status new = update_file (d->file, depth + 1);
if (new > status)
status = new;
}
}
return status;
}
/* Show a message stating the target failed to build. */
static void
complain (struct file *file)
{
/* If this file has no_diag set then it means we tried to update it
before in the dontcare mode and failed. The target that actually
failed is not necessarily this file but could be one of its direct
or indirect dependencies. So traverse this file's dependencies and
find the one that actually caused the failure. */
struct dep *d;
for (d = file->deps; d != 0; d = d->next)
{
if (d->file->updated && d->file->update_status > us_none && file->no_diag)
{
complain (d->file);
break;
}
}
if (d == 0)
{
show_goal_error ();
/* Didn't find any dependencies to complain about. */
if (file->parent)
{
size_t l = strlen (file->name) + strlen (file->parent->name) + 4;
const char *m = _("%sNo rule to make target '%s', needed by '%s'%s");
if (!keep_going_flag)
fatal (NILF, l, m, "", file->name, file->parent->name, "");
error (NILF, l, m, "*** ", file->name, file->parent->name, ".");
}
else
{
size_t l = strlen (file->name) + 4;
const char *m = _("%sNo rule to make target '%s'%s");
if (!keep_going_flag)
fatal (NILF, l, m, "", file->name, "");
error (NILF, l, m, "*** ", file->name, ".");
}
file->no_diag = 0;
}
}
/* Consider a single 'struct file' and update it as appropriate.
Return 0 on success, or non-0 on failure. */
static enum update_status
update_file_1 (struct file *file, unsigned int depth)
{
enum update_status dep_status = us_success;
FILE_TIMESTAMP this_mtime;
int noexist, must_make, deps_changed;
struct file *ofile;
struct dep *d, *ad;
struct dep amake;
int running = 0;
DBF (DB_VERBOSE, _("Considering target file '%s'.\n"));
if (file->updated)
{
if (file->update_status > us_none)
{
DBF (DB_VERBOSE,
_("Recently tried and failed to update file '%s'.\n"));
/* If the file we tried to make is marked no_diag then no message
was printed about it when it failed during the makefile rebuild.
If we're trying to build it again in the normal rebuild, print a
message now. */
if (file->no_diag && !file->dontcare)
complain (file);
return file->update_status;
}
DBF (DB_VERBOSE, _("File '%s' was considered already.\n"));
return 0;
}
switch (file->command_state)
{
case cs_not_started:
case cs_deps_running:
break;
case cs_running:
DBF (DB_VERBOSE, _("Still updating file '%s'.\n"));
return 0;
case cs_finished:
DBF (DB_VERBOSE, _("Finished updating file '%s'.\n"));
return file->update_status;
default:
abort ();
}
/* Determine whether the diagnostics will be issued should this update
fail. */
file->no_diag = file->dontcare;
++depth;
/* Notice recursive update of the same file. */
start_updating (file);
/* We might change file if we find a different one via vpath;
remember this one to turn off updating. */
ofile = file;
/* Looking at the file's modtime beforehand allows the possibility
that its name may be changed by a VPATH search, and thus it may
not need an implicit rule. If this were not done, the file
might get implicit commands that apply to its initial name, only
to have that name replaced with another found by VPATH search. */
this_mtime = file_mtime (file);
check_renamed (file);
noexist = this_mtime == NONEXISTENT_MTIME;
if (noexist)
DBF (DB_BASIC, _("File '%s' does not exist.\n"));
else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX
&& file->low_resolution_time)
{
/* Avoid spurious rebuilds due to low resolution time stamps. */
int ns = FILE_TIMESTAMP_NS (this_mtime);
if (ns != 0)
OS (error, NILF,
_("*** Warning: .LOW_RESOLUTION_TIME file '%s' has a high resolution time stamp"),
file->name);
this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
}
must_make = noexist;
/* 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))
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
else
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
file->tried_implicit = 1;
}
if (file->cmds == 0 && !file->is_target
&& default_file != 0 && default_file->cmds != 0)
{
DBF (DB_IMPLICIT, _("Using default recipe for '%s'.\n"));
file->cmds = default_file->cmds;
}
/* Update all non-intermediate files we depend on, if necessary, and see
whether any of them is more recent than this file. We need to walk our
deps, AND the deps of any also_make targets to ensure everything happens
in the correct order. */
amake.file = file;
amake.next = file->also_make;
ad = &amake;
while (ad)
{
struct dep *lastd = 0;
/* Find the deps we're scanning */
d = ad->file->deps;
ad = ad->next;
while (d)
{
enum update_status new;
FILE_TIMESTAMP mtime;
int maybe_make;
int dontcare = 0;
check_renamed (d->file);
mtime = file_mtime (d->file);
check_renamed (d->file);
if (is_updating (d->file))
{
OSS (error, NILF, _("Circular %s <- %s dependency dropped."),
file->name, d->file->name);
/* We cannot free D here because our the caller will still have
a reference to it when we were called recursively via
check_dep below. */
if (lastd == 0)
file->deps = d->next;
else
lastd->next = d->next;
d = d->next;
continue;
}
d->file->parent = file;
maybe_make = must_make;
/* Inherit dontcare flag from our parent. */
if (rebuilding_makefiles)
{
dontcare = d->file->dontcare;
d->file->dontcare = file->dontcare;
}
new = check_dep (d->file, depth, this_mtime, &maybe_make);
if (new > dep_status)
dep_status = new;
/* Restore original dontcare flag. */
if (rebuilding_makefiles)
d->file->dontcare = dontcare;
if (! d->ignore_mtime)
must_make = maybe_make;
check_renamed (d->file);
{
register struct file *f = d->file;
if (f->double_colon)
f = f->double_colon;
do
{
running |= (f->command_state == cs_running
|| f->command_state == cs_deps_running);
f = f->prev;
}
while (f != 0);
}
if (dep_status && !keep_going_flag)
break;
if (!running)
/* The prereq is considered changed if the timestamp has changed
while it was built, OR it doesn't exist. */
d->changed = ((file_mtime (d->file) != mtime)
|| (mtime == NONEXISTENT_MTIME));
lastd = d;
d = d->next;
}
}
/* Now we know whether this target needs updating.
If it does, update all the intermediate files we depend on. */
if (must_make || always_make_flag)
{
for (d = file->deps; d != 0; d = d->next)
if (d->file->intermediate)
{
enum update_status new;
int dontcare = 0;
FILE_TIMESTAMP mtime = file_mtime (d->file);
check_renamed (d->file);
d->file->parent = file;
/* Inherit dontcare flag from our parent. */
if (rebuilding_makefiles)
{
dontcare = d->file->dontcare;
d->file->dontcare = file->dontcare;
}
/* We may have already considered this file, when we didn't know
we'd need to update it. Force update_file() to consider it and
not prune it. */
d->file->considered = 0;
new = update_file (d->file, depth);
if (new > dep_status)
dep_status = new;
/* Restore original dontcare flag. */
if (rebuilding_makefiles)
d->file->dontcare = dontcare;
check_renamed (d->file);
{
register struct file *f = d->file;
if (f->double_colon)
f = f->double_colon;
do
{
running |= (f->command_state == cs_running
|| f->command_state == cs_deps_running);
f = f->prev;
}
while (f != 0);
}
if (dep_status && !keep_going_flag)
break;
if (!running)
d->changed = ((file->phony && file->cmds != 0)
|| file_mtime (d->file) != mtime);
}
}
finish_updating (file);
finish_updating (ofile);
DBF (DB_VERBOSE, _("Finished prerequisites of target file '%s'.\n"));
if (running)
{
set_command_state (file, cs_deps_running);
--depth;
DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n"));
return 0;
}
/* If any dependency failed, give up now. */
if (dep_status)
{
/* I'm not sure if we can't just assign dep_status... */
file->update_status = dep_status == us_none ? us_failed : dep_status;
notice_finished_file (file);
--depth;
DBF (DB_VERBOSE, _("Giving up on target file '%s'.\n"));
if (depth == 0 && keep_going_flag
&& !just_print_flag && !question_flag)
OS (error, NILF,
_("Target '%s' not remade because of errors."), file->name);
return dep_status;
}
if (file->command_state == cs_deps_running)
/* The commands for some deps were running on the last iteration, but
they have finished now. Reset the command_state to not_started to
simplify later bookkeeping. It is important that we do this only
when the prior state was cs_deps_running, because that prior state
was definitely propagated to FILE's also_make's by set_command_state
(called above), but in another state an also_make may have
independently changed to finished state, and we would confuse that
file's bookkeeping (updated, but not_started is bogus state). */
set_command_state (file, cs_not_started);
/* Now record which prerequisites are more
recent than this file, so we can define $?. */
deps_changed = 0;
for (d = file->deps; d != 0; d = d->next)
{
FILE_TIMESTAMP d_mtime = file_mtime (d->file);
check_renamed (d->file);
if (! d->ignore_mtime)
{
#if 1
/* %%% In version 4, remove this code completely to
implement not remaking deps if their deps are newer
than their parents. */
if (d_mtime == NONEXISTENT_MTIME && !d->file->intermediate)
/* We must remake if this dep does not
exist and is not intermediate. */
must_make = 1;
#endif
/* Set DEPS_CHANGED if this dep actually changed. */
deps_changed |= d->changed;
}
/* Set D->changed if either this dep actually changed,
or its dependent, FILE, is older or does not exist. */
d->changed |= noexist || d_mtime > this_mtime;
if (!noexist && ISDB (DB_BASIC|DB_VERBOSE))
{
const char *fmt = 0;
if (d->ignore_mtime)
{
if (ISDB (DB_VERBOSE))
fmt = _("Prerequisite '%s' is order-only for target '%s'.\n");
}
else if (d_mtime == NONEXISTENT_MTIME)
{
if (ISDB (DB_BASIC))
fmt = _("Prerequisite '%s' of target '%s' does not exist.\n");
}
else if (d->changed)
{
if (ISDB (DB_BASIC))
fmt = _("Prerequisite '%s' is newer than target '%s'.\n");
}
else if (ISDB (DB_VERBOSE))
fmt = _("Prerequisite '%s' is older than target '%s'.\n");
if (fmt)
{
print_spaces (depth);
printf (fmt, dep_name (d), file->name);
fflush (stdout);
}
}
}
/* Here depth returns to the value it had when we were called. */
depth--;
if (file->double_colon && file->deps == 0)
{
must_make = 1;
DBF (DB_BASIC,
_("Target '%s' is double-colon and has no prerequisites.\n"));
}
else if (!noexist && file->is_target && !deps_changed && file->cmds == 0
&& !always_make_flag)
{
must_make = 0;
DBF (DB_VERBOSE,
_("No recipe for '%s' and no prerequisites actually changed.\n"));
}
else if (!must_make && file->cmds != 0 && always_make_flag)
{
must_make = 1;
DBF (DB_VERBOSE, _("Making '%s' due to always-make flag.\n"));
}
if (!must_make)
{
if (ISDB (DB_VERBOSE))
{
print_spaces (depth);
printf (_("No need to remake target '%s'"), file->name);
if (!streq (file->name, file->hname))
printf (_("; using VPATH name '%s'"), file->hname);
puts (".");
fflush (stdout);
}
notice_finished_file (file);
/* Since we don't need to remake the file, convert it to use the
VPATH filename if we found one. hfile will be either the
local name if no VPATH or the VPATH name if one was found. */
while (file)
{
file->name = file->hname;
file = file->prev;
}
return 0;
}
DBF (DB_BASIC, _("Must remake target '%s'.\n"));
/* It needs to be remade. If it's VPATH and not reset via GPATH, toss the
VPATH. */
if (!streq (file->name, file->hname))
{
DB (DB_BASIC, (_(" Ignoring VPATH name '%s'.\n"), file->hname));
file->ignore_vpath = 1;
}
/* Now, take appropriate actions to remake the file. */
remake_file (file);
if (file->command_state != cs_finished)
{
DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n"));
return 0;
}
switch (file->update_status)
{
case us_failed:
DBF (DB_BASIC, _("Failed to remake target file '%s'.\n"));
break;
case us_success:
DBF (DB_BASIC, _("Successfully remade target file '%s'.\n"));
break;
case us_question:
DBF (DB_BASIC, _("Target file '%s' needs to be remade under -q.\n"));
break;
case us_none:
break;
}
file->updated = 1;
return file->update_status;
}
/* Set FILE's 'updated' flag and re-check its mtime and the mtime's of all
files listed in its 'also_make' member. Under -t, this function also
touches FILE.
On return, FILE->update_status will no longer be us_none if it was. */
void
notice_finished_file (struct file *file)
{
struct dep *d;
int ran = file->command_state == cs_running;
int touched = 0;
file->command_state = cs_finished;
file->updated = 1;
if (touch_flag
/* The update status will be:
us_success if 0 or more commands (+ or ${MAKE}) were run and won;
us_none if this target was not remade;
>us_none if some commands were run and lost.
We touch the target if it has commands which either were not run
or won when they ran (i.e. status is 0). */
&& file->update_status == us_success)
{
if (file->cmds != 0 && file->cmds->any_recurse)
{
/* If all the command lines were recursive,
we don't want to do the touching. */
unsigned int i;
for (i = 0; i < file->cmds->ncommand_lines; ++i)
if (!(file->cmds->lines_flags[i] & COMMANDS_RECURSE))
goto have_nonrecursing;
}
else
{
have_nonrecursing:
if (file->phony)
file->update_status = us_success;
/* According to POSIX, -t doesn't affect targets with no cmds. */
else if (file->cmds != 0)
{
/* Should set file's modification date and do nothing else. */
file->update_status = touch_file (file);
/* Pretend we ran a real touch command, to suppress the
"'foo' is up to date" message. */
commands_started++;
/* Request for the timestamp to be updated (and distributed
to the double-colon entries). Simply setting ran=1 would
almost have done the trick, but messes up with the also_make
updating logic below. */
touched = 1;
}
}
}
if (file->mtime_before_update == UNKNOWN_MTIME)
file->mtime_before_update = file->last_mtime;
if ((ran && !file->phony) || touched)
{
int i = 0;
/* If -n, -t, or -q and all the commands are recursive, we ran them so
really check the target's mtime again. Otherwise, assume the target
would have been updated. */
if ((question_flag || just_print_flag || touch_flag) && file->cmds)
{
for (i = file->cmds->ncommand_lines; i > 0; --i)
if (! (file->cmds->lines_flags[i-1] & COMMANDS_RECURSE))
break;
}
/* If there were no commands at all, it's always new. */
else if (file->is_target && file->cmds == 0)
i = 1;
file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME;
}
if (file->double_colon)
{
/* If this is a double colon rule and it is the last one to be
updated, propagate the change of modification time to all the
double-colon entries for this file.
We do it on the last update because it is important to handle
individual entries as separate rules with separate timestamps
while they are treated as targets and then as one rule with the
unified timestamp when they are considered as a prerequisite
of some target. */
struct file *f;
FILE_TIMESTAMP max_mtime = file->last_mtime;
/* Check that all rules were updated and at the same time find
the max timestamp. We assume UNKNOWN_MTIME is newer then
any other value. */
for (f = file->double_colon; f != 0 && f->updated; f = f->prev)
if (max_mtime != UNKNOWN_MTIME
&& (f->last_mtime == UNKNOWN_MTIME || f->last_mtime > max_mtime))
max_mtime = f->last_mtime;
if (f == 0)
for (f = file->double_colon; f != 0; f = f->prev)
f->last_mtime = max_mtime;
}
if (ran && file->update_status != us_none)
/* We actually tried to update FILE, which has
updated its also_make's as well (if it worked).
If it didn't work, it wouldn't work again for them.
So mark them as updated with the same status. */
for (d = file->also_make; d != 0; d = d->next)
{
d->file->command_state = cs_finished;
d->file->updated = 1;
d->file->update_status = file->update_status;
if (ran && !d->file->phony)
/* Fetch the new modification time.
We do this instead of just invalidating the cached time
so that a vpath_search can happen. Otherwise, it would
never be done because the target is already updated. */
f_mtime (d->file, 0);
}
else if (file->update_status == us_none)
/* Nothing was done for FILE, but it needed nothing done.
So mark it now as "succeeded". */
file->update_status = us_success;
}
/* 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. */
static enum update_status
check_dep (struct file *file, unsigned int depth,
FILE_TIMESTAMP this_mtime, int *must_make_ptr)
{
struct file *ofile;
struct dep *d;
enum update_status dep_status = us_success;
++depth;
start_updating (file);
/* We might change file if we find a different one via vpath;
remember this one to turn off updating. */
ofile = file;
if (file->phony || !file->intermediate)
{
/* If this is a non-intermediate file, update it and record whether it
is newer than THIS_MTIME. */
FILE_TIMESTAMP mtime;
dep_status = update_file (file, depth);
check_renamed (file);
mtime = file_mtime (file);
check_renamed (file);
if (mtime == NONEXISTENT_MTIME || mtime > this_mtime)
*must_make_ptr = 1;
}
else
{
/* FILE is an intermediate file. */
FILE_TIMESTAMP mtime;
if (!file->phony && file->cmds == 0 && !file->tried_implicit)
{
if (try_implicit_rule (file, depth))
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
else
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
file->tried_implicit = 1;
}
if (file->cmds == 0 && !file->is_target
&& default_file != 0 && default_file->cmds != 0)
{
DBF (DB_IMPLICIT, _("Using default commands for '%s'.\n"));
file->cmds = default_file->cmds;
}
check_renamed (file);
mtime = file_mtime (file);
check_renamed (file);
if (mtime != NONEXISTENT_MTIME && mtime > this_mtime)
/* If the intermediate file actually exists and is newer, then we
should remake from it. */
*must_make_ptr = 1;
else
{
/* Otherwise, 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. */
struct dep *ld;
int deps_running = 0;
/* If this target is not running, set it's state so that we check it
fresh. It could be it was checked as part of an order-only
prerequisite and so wasn't rebuilt then, but should be now. */
if (file->command_state != cs_running)
{
/* If the target was waiting for a dependency it has to be
reconsidered, as that dependency might have finished. */
if (file->command_state == cs_deps_running)
file->considered = 0;
set_command_state (file, cs_not_started);
}
ld = 0;
d = file->deps;
while (d != 0)
{
enum update_status new;
int maybe_make;
if (is_updating (d->file))
{
OSS (error, NILF, _("Circular %s <- %s dependency dropped."),
file->name, d->file->name);
if (ld == 0)
{
file->deps = d->next;
free_dep (d);
d = file->deps;
}
else
{
ld->next = d->next;
free_dep (d);
d = ld->next;
}
continue;
}
d->file->parent = file;
maybe_make = *must_make_ptr;
new = check_dep (d->file, depth, this_mtime, &maybe_make);
if (new > dep_status)
dep_status = new;
if (! d->ignore_mtime)
*must_make_ptr = maybe_make;
check_renamed (d->file);
if (dep_status && !keep_going_flag)
break;
if (d->file->command_state == cs_running
|| d->file->command_state == cs_deps_running)
deps_running = 1;
ld = d;
d = d->next;
}
if (deps_running)
/* Record that some of FILE's deps are still being made.
This tells the upper levels to wait on processing it until the
commands are finished. */
set_command_state (file, cs_deps_running);
}
}
finish_updating (file);
finish_updating (ofile);
return dep_status;
}
/* Touch FILE. Return us_success if successful, us_failed if not. */
#define TOUCH_ERROR(call) do{ perror_with_name ((call), file->name); \
return us_failed; }while(0)
static enum update_status
touch_file (struct file *file)
{
if (!silent_flag)
OS (message, 0, "touch %s", file->name);
/* Print-only (-n) takes precedence over touch (-t). */
if (just_print_flag)
return us_success;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
return ar_touch (file->name) ? us_failed : us_success;
else
#endif
{
int fd;
EINTRLOOP (fd, open (file->name, O_RDWR | O_CREAT, 0666));
if (fd < 0)
TOUCH_ERROR ("touch: open: ");
else
{
struct stat statbuf;
char buf = 'x';
int e;
EINTRLOOP (e, fstat (fd, &statbuf));
if (e < 0)
TOUCH_ERROR ("touch: fstat: ");
/* Rewrite character 0 same as it already is. */
EINTRLOOP (e, read (fd, &buf, 1));
if (e < 0)
TOUCH_ERROR ("touch: read: ");
{
off_t o;
EINTRLOOP (o, lseek (fd, 0L, 0));
if (o < 0L)
TOUCH_ERROR ("touch: lseek: ");
}
EINTRLOOP (e, write (fd, &buf, 1));
if (e < 0)
TOUCH_ERROR ("touch: write: ");
/* If file length was 0, we just changed it, so change it back. */
if (statbuf.st_size == 0)
{
(void) close (fd);
EINTRLOOP (fd, open (file->name, O_RDWR | O_TRUNC, 0666));
if (fd < 0)
TOUCH_ERROR ("touch: open: ");
}
(void) close (fd);
}
}
return us_success;
}
/* Having checked and updated the dependencies of FILE,
do whatever is appropriate to remake FILE itself.
Return the status from executing FILE's commands. */
static void
remake_file (struct file *file)
{
if (file->cmds == 0)
{
if (file->phony)
/* Phony target. Pretend it succeeded. */
file->update_status = us_success;
else if (file->is_target)
/* This is a nonexistent target file we cannot make.
Pretend it was successfully remade. */
file->update_status = us_success;
else
{
/* This is a dependency file we cannot remake. Fail. */
if (!rebuilding_makefiles || !file->dontcare)
complain (file);
file->update_status = us_failed;
}
}
else
{
chop_commands (file->cmds);
/* The normal case: start some commands. */
if (!touch_flag || file->cmds->any_recurse)
{
execute_file_commands (file);
return;
}
/* This tells notice_finished_file it is ok to touch the file. */
file->update_status = us_success;
}
/* This does the touching under -t. */
notice_finished_file (file);
}
/* 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, and SEARCH is nonzero, VPATH searching and
replacement is done. If that fails, a library (-lLIBNAME) is tried and
the library's actual name (/lib/libLIBNAME.a, etc.) is substituted into
FILE. */
FILE_TIMESTAMP
f_mtime (struct file *file, int search)
{
FILE_TIMESTAMP mtime;
int propagate_timestamp;
/* File's mtime is not known; must get it from the system. */
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
/* This file is an archive-member reference. */
char *arname, *memname;
struct file *arfile;
time_t member_date;
/* Find the archive's name. */
ar_parse_name (file->name, &arname, &memname);
/* Find the modification time of the archive itself.
Also allow for its name to be changed via VPATH search. */
arfile = lookup_file (arname);
if (arfile == 0)
arfile = enter_file (strcache_add (arname));
mtime = f_mtime (arfile, search);
check_renamed (arfile);
if (search && strcmp (arfile->hname, arname))
{
/* The archive's name has changed.
Change the archive-member reference accordingly. */
char *name;
unsigned int arlen, memlen;
arlen = strlen (arfile->hname);
memlen = strlen (memname);
name = alloca (arlen + 1 + memlen + 2);
memcpy (name, arfile->hname, arlen);
name[arlen] = '(';
memcpy (name + arlen + 1, memname, memlen);
name[arlen + 1 + memlen] = ')';
name[arlen + 1 + memlen + 1] = '\0';
/* If the archive was found with GPATH, make the change permanent;
otherwise defer it until later. */
if (arfile->name == arfile->hname)
rename_file (file, strcache_add (name));
else
rehash_file (file, strcache_add (name));
check_renamed (file);
}
free (arname);
file->low_resolution_time = 1;
if (mtime == NONEXISTENT_MTIME)
/* The archive doesn't exist, so its members don't exist either. */
return NONEXISTENT_MTIME;
member_date = ar_member_date (file->hname);
mtime = (member_date == (time_t) -1
? NONEXISTENT_MTIME
: file_timestamp_cons (file->hname, member_date, 0));
}
else
#endif
{
mtime = name_mtime (file->name);
if (mtime == NONEXISTENT_MTIME && search && !file->ignore_vpath)
{
/* If name_mtime failed, search VPATH. */
const char *name = vpath_search (file->name, &mtime, NULL, NULL);
if (name
/* Last resort, is it a library (-lxxx)? */
|| (file->name[0] == '-' && file->name[1] == 'l'
&& (name = library_search (file->name, &mtime)) != 0))
{
int name_len;
if (mtime != UNKNOWN_MTIME)
/* vpath_search and library_search store UNKNOWN_MTIME
if they didn't need to do a stat call for their work. */
file->last_mtime = mtime;
/* If we found it in VPATH, see if it's in GPATH too; if so,
change the name right now; if not, defer until after the
dependencies are updated. */
#ifndef VMS
name_len = strlen (name) - strlen (file->name) - 1;
#else
name_len = strlen (name) - strlen (file->name);
if (name[name_len - 1] == '/')
name_len--;
#endif
if (gpath_search (name, name_len))
{
rename_file (file, name);
check_renamed (file);
return file_mtime (file);
}
rehash_file (file, name);
check_renamed (file);
/* If the result of a vpath search is -o or -W, preserve it.
Otherwise, find the mtime of the resulting file. */
if (mtime != OLD_MTIME && mtime != NEW_MTIME)
mtime = name_mtime (name);
}
}
}
/* Files can have bogus timestamps that nothing newly made will be
"newer" than. Updating their dependents could just result in loops.
So notify the user of the anomaly with a warning.
We only need to do this once, for now. */
if (!clock_skew_detected
&& mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME
&& !file->updated)
{
static FILE_TIMESTAMP adjusted_now;
FILE_TIMESTAMP adjusted_mtime = mtime;
#if defined(WINDOWS32) || defined(__MSDOS__)
/* Experimentation has shown that FAT filesystems can set file times
up to 3 seconds into the future! Play it safe. */
#define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3
FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS;
if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime)
adjusted_mtime -= adjustment;
#elif defined(__EMX__)
/* FAT filesystems round time to the nearest even second!
Allow for any file (NTFS or FAT) to perhaps suffer from this
brain damage. */
FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0
&& FILE_TIMESTAMP_NS (adjusted_mtime) == 0)
? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS
: 0);
#endif
/* If the file's time appears to be in the future, update our
concept of the present and try once more. */
if (adjusted_now < adjusted_mtime)
{
int resolution;
FILE_TIMESTAMP now = file_timestamp_now (&resolution);
adjusted_now = now + (resolution - 1);
if (adjusted_now < adjusted_mtime)
{
#ifdef NO_FLOAT
OS (error, NILF,
_("Warning: File '%s' has modification time in the future"),
file->name);
#else
double from_now =
(FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now)
+ ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now))
/ 1e9));
char from_now_string[100];
if (from_now >= 99 && from_now <= ULONG_MAX)
sprintf (from_now_string, "%lu", (unsigned long) from_now);
else
sprintf (from_now_string, "%.2g", from_now);
OSS (error, NILF,
_("Warning: File '%s' has modification time %s s in the future"),
file->name, from_now_string);
#endif
clock_skew_detected = 1;
}
}
}
/* Store the mtime into all the entries for this file for which it is safe
to do so: avoid propagating timestamps to double-colon rules that haven't
been examined so they're run or not based on the pre-update timestamp. */
if (file->double_colon)
file = file->double_colon;
propagate_timestamp = file->updated;
do
{
/* If this file is not implicit but it is intermediate then it was
made so by the .INTERMEDIATE target. If this file has never
been built by us but was found now, it existed before make
started. So, turn off the intermediate bit so make doesn't
delete it, since it didn't create it. */
if (mtime != NONEXISTENT_MTIME && file->command_state == cs_not_started
&& !file->tried_implicit && file->intermediate)
file->intermediate = 0;
if (file->updated == propagate_timestamp)
file->last_mtime = mtime;
file = file->prev;
}
while (file != 0);
return mtime;
}
/* Return the mtime of the file or archive-member reference NAME. */
/* First, we check with stat(). If the file does not exist, then we return
NONEXISTENT_MTIME. If it does, and the symlink check flag is set, then
examine each indirection of the symlink and find the newest mtime.
This causes one duplicate stat() when -L is being used, but the code is
much cleaner. */
static FILE_TIMESTAMP
name_mtime (const char *name)
{
FILE_TIMESTAMP mtime;
struct stat st;
int e;
EINTRLOOP (e, stat (name, &st));
if (e == 0)
mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st);
else if (errno == ENOENT || errno == ENOTDIR)
mtime = NONEXISTENT_MTIME;
else
{
perror_with_name ("stat: ", name);
return NONEXISTENT_MTIME;
}
/* If we get here we either found it, or it doesn't exist.
If it doesn't exist see if we can use a symlink mtime instead. */
#ifdef MAKE_SYMLINKS
#ifndef S_ISLNK
# define S_ISLNK(_m) (((_m)&S_IFMT)==S_IFLNK)
#endif
if (check_symlink_flag)
{
PATH_VAR (lpath);
/* Check each symbolic link segment (if any). Find the latest mtime
amongst all of them (and the target file of course).
Note that we have already successfully dereferenced all the links
above. So, if we run into any error trying to lstat(), or
readlink(), or whatever, something bizarre-o happened. Just give up
and use whatever mtime we've already computed at that point. */
strcpy (lpath, name);
while (1)
{
FILE_TIMESTAMP ltime;
PATH_VAR (lbuf);
long llen;
char *p;
EINTRLOOP (e, lstat (lpath, &st));
if (e)
{
/* Just take what we have so far. */
if (errno != ENOENT && errno != ENOTDIR)
perror_with_name ("lstat: ", lpath);
break;
}
/* If this is not a symlink, we're done (we started with the real
file's mtime so we don't need to test it again). */
if (!S_ISLNK (st.st_mode))
break;
/* If this mtime is newer than what we had, keep the new one. */
ltime = FILE_TIMESTAMP_STAT_MODTIME (lpath, st);
if (ltime > mtime)
mtime = ltime;
/* Set up to check the file pointed to by this link. */
EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX));
if (llen < 0)
{
/* Eh? Just take what we have. */
perror_with_name ("readlink: ", lpath);
break;
}
lbuf[llen] = '\0';
/* If the target is fully-qualified or the source is just a
filename, then the new path is the target. Otherwise it's the
source directory plus the target. */
if (lbuf[0] == '/' || (p = strrchr (lpath, '/')) == NULL)
strcpy (lpath, lbuf);
else if ((p - lpath) + llen + 2 > GET_PATH_MAX)
/* Eh? Path too long! Again, just go with what we have. */
break;
else
/* Create the next step in the symlink chain. */
strcpy (p+1, lbuf);
}
}
#endif
return mtime;
}
/* Search for a library file specified as -lLIBNAME, searching for a
suitable library file in the system library directories and the VPATH
directories. */
static const char *
library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
{
static const char *dirs[] =
{
#ifndef _AMIGA
"/lib",
"/usr/lib",
#endif
#if defined(WINDOWS32) && !defined(LIBDIR)
/*
* This is completely up to the user at product install time. Just define
* a placeholder.
*/
#define LIBDIR "."
#endif
LIBDIR, /* Defined by configuration. */
0
};
const char *file = 0;
char *libpatterns;
FILE_TIMESTAMP mtime;
/* Loop variables for the libpatterns value. */
char *p;
const char *p2;
unsigned int len;
unsigned int liblen;
/* Information about the earliest (in the vpath sequence) match. */
unsigned int best_vpath = 0, best_path = 0;
const char **dp;
libpatterns = xstrdup (variable_expand ("$(.LIBPATTERNS)"));
/* Skip the '-l'. */
lib += 2;
liblen = strlen (lib);
/* Loop through all the patterns in .LIBPATTERNS, and search on each one.
To implement the linker-compatible behavior we have to search through
all entries in .LIBPATTERNS and choose the "earliest" one. */
p2 = libpatterns;
while ((p = find_next_token (&p2, &len)) != 0)
{
static char *buf = NULL;
static unsigned int buflen = 0;
static int libdir_maxlen = -1;
static unsigned int std_dirs = 0;
char *libbuf = variable_expand ("");
/* Expand the pattern using LIB as a replacement. */
{
char c = p[len];
char *p3, *p4;
p[len] = '\0';
p3 = find_percent (p);
if (!p3)
{
/* Give a warning if there is no pattern. */
OS (error, NILF,
_(".LIBPATTERNS element '%s' is not a pattern"), p);
p[len] = c;
continue;
}
p4 = variable_buffer_output (libbuf, p, p3-p);
p4 = variable_buffer_output (p4, lib, liblen);
p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
p[len] = c;
}
/* Look first for 'libNAME.a' in the current directory. */
mtime = name_mtime (libbuf);
if (mtime != NONEXISTENT_MTIME)
{
if (mtime_ptr != 0)
*mtime_ptr = mtime;
file = strcache_add (libbuf);
/* This by definition will have the best index, so stop now. */
break;
}
/* Now try VPATH search on that. */
{
unsigned int vpath_index, path_index;
const char* f = vpath_search (libbuf, mtime_ptr ? &mtime : NULL,
&vpath_index, &path_index);
if (f)
{
/* If we have a better match, record it. */
if (file == 0 ||
vpath_index < best_vpath ||
(vpath_index == best_vpath && path_index < best_path))
{
file = f;
best_vpath = vpath_index;
best_path = path_index;
if (mtime_ptr != 0)
*mtime_ptr = mtime;
}
}
}
/* Now try the standard set of directories. */
if (!buflen)
{
for (dp = dirs; *dp != 0; ++dp)
{
int l = strlen (*dp);
if (l > libdir_maxlen)
libdir_maxlen = l;
std_dirs++;
}
buflen = strlen (libbuf);
buf = xmalloc (libdir_maxlen + buflen + 2);
}
else if (buflen < strlen (libbuf))
{
buflen = strlen (libbuf);
buf = xrealloc (buf, libdir_maxlen + buflen + 2);
}
{
/* Use the last std_dirs index for standard directories. This
was it will always be greater than the VPATH index. */
unsigned int vpath_index = ~((unsigned int)0) - std_dirs;
for (dp = dirs; *dp != 0; ++dp)
{
sprintf (buf, "%s/%s", *dp, libbuf);
mtime = name_mtime (buf);
if (mtime != NONEXISTENT_MTIME)
{
if (file == 0 || vpath_index < best_vpath)
{
file = strcache_add (buf);
best_vpath = vpath_index;
if (mtime_ptr != 0)
*mtime_ptr = mtime;
}
}
vpath_index++;
}
}
}
free (libpatterns);
return file;
}
make-4.2.1/commands.h 0000644 0001750 0001750 00000003627 12720141610 011330 0000000 0000000 /* Definition of data structures describing shell commands for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* Structure that gives the commands to make a file
and information about where these commands came from. */
struct commands
{
floc fileinfo; /* Where commands were defined. */
char *commands; /* Commands text. */
char **command_lines; /* Commands chopped up into lines. */
unsigned char *lines_flags; /* One set of flag bits for each line. */
unsigned short ncommand_lines;/* Number of command lines. */
char recipe_prefix; /* Recipe prefix for this command set. */
unsigned int any_recurse:1; /* Nonzero if any 'lines_flags' elt has */
/* the COMMANDS_RECURSE bit set. */
};
/* Bits in 'lines_flags'. */
#define COMMANDS_RECURSE 1 /* Recurses: + or $(MAKE). */
#define COMMANDS_SILENT 2 /* Silent: @. */
#define COMMANDS_NOERROR 4 /* No errors: -. */
RETSIGTYPE fatal_error_signal (int sig);
void execute_file_commands (struct file *file);
void print_commands (const struct commands *cmds);
void delete_child_targets (struct child *child);
void chop_commands (struct commands *cmds);
void set_file_variables (struct file *file);
make-4.2.1/vms_progname.c 0000644 0001750 0001750 00000034401 12664631374 012233 0000000 0000000 /* File: vms_progname.c
*
* This module provides a fixup of the program name.
*
* This module is designed to be a plug in replacement for the
* progname module used by many GNU utilities with a few enhancements
* needed for GNU Make.
*
* It does not support the HAVE_DECL_PROGRAM_INVOCATION_* macros at this
* time.
*
* Make sure that the program_name string is set as close as possible to
* what the original command was given.
*
* When run from DCL, The argv[0] element is initialized with an absolute
* path name. The decc$ feature logical names can control the format
* of this pathname. In some cases it causes the UNIX format name to be
* formatted incorrectly.
*
* This DCL provided name is usually incompatible with what is expected to
* be provided by Unix programs and needs to be replaced.
*
* When run from an exec() call, the argv[0] element is initialized by the
* program. This name is compatible with what is expected to be provided
* by Unix programs and should be passed through unchanged.
*
* The DCL provided name can be detected because it always contains the
* device name.
*
* DCL examples:
* devname:[dir]program.exe;1 Normal VMS - remove path and .EXE;n
* devname:[dir]facility$program.exe;1 Facility also needs removal.
* /devname/dir/program.exe
* /DISK$VOLUME/dir/program.exe.1 Bug version should not be there.
* /DISK$VOLUME/dir/program. Bug Period should not be there.
*
*/
/* Copyright (C) 2014-2016 Free Software Foundation, Inc.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* Per copyright assignment agreement with the Free Software Foundation
this software may be available under under other license agreements
and copyrights. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef USE_PROGNAME_H
# include "progname.h"
#endif
#pragma member_alignment save
#pragma nomember_alignment longword
struct item_list_3
{
unsigned short len;
unsigned short code;
void * bufadr;
unsigned short * retlen;
};
struct filescan_itmlst_2
{
unsigned short length;
unsigned short itmcode;
char * component;
};
#pragma member_alignment
int
SYS$GETDVIW (unsigned long efn,
unsigned short chan,
const struct dsc$descriptor_s * devnam,
const struct item_list_3 * itmlst,
void * iosb,
void (* astadr)(unsigned long),
unsigned long astprm,
void * nullarg);
int
SYS$FILESCAN (const struct dsc$descriptor_s * srcstr,
struct filescan_itmlst_2 * valuelist,
unsigned long * fldflags,
struct dsc$descriptor_s *auxout,
unsigned short * retlen);
/* String containing name the program is called with.
To be initialized by main(). */
const char *program_name = NULL;
static int internal_need_vms_symbol = 0;
static char vms_new_nam[256];
int
need_vms_symbol (void)
{
return internal_need_vms_symbol;
}
void
set_program_name (const char *argv0)
{
int status;
int result;
#ifdef DEBUG
printf ("original argv0 = %s\n", argv0);
#endif
/* Posix requires non-NULL argv[0] */
if (argv0 == NULL)
{
fputs ("A NULL argv[0] was passed through an exec system call.\n",
stderr);
abort ();
}
program_name = argv0;
result = 0;
internal_need_vms_symbol = 0;
/* If the path name starts with a /, then it is an absolute path */
/* that may have been generated by the CRTL instead of the command name */
/* If it is the device name between the slashes, then this was likely */
/* from the run command and needs to be fixed up. */
/* If the DECC$POSIX_COMPLIANT_PATHNAMES is set to 2, then it is the */
/* DISK$VOLUME that will be present, and it will still need to be fixed. */
if (argv0[0] == '/')
{
char * nextslash;
int length;
struct item_list_3 itemlist[3];
unsigned short dvi_iosb[4];
char alldevnam[64];
unsigned short alldevnam_len;
struct dsc$descriptor_s devname_dsc;
char diskvolnam[256];
unsigned short diskvolnam_len;
internal_need_vms_symbol = 1;
/* Get some information about the disk */
/*--------------------------------------*/
itemlist[0].len = (sizeof alldevnam) - 1;
itemlist[0].code = DVI$_ALLDEVNAM;
itemlist[0].bufadr = alldevnam;
itemlist[0].retlen = &alldevnam_len;
itemlist[1].len = (sizeof diskvolnam) - 1 - 5;
itemlist[1].code = DVI$_VOLNAM;
itemlist[1].bufadr = &diskvolnam[5];
itemlist[1].retlen = &diskvolnam_len;
itemlist[2].len = 0;
itemlist[2].code = 0;
/* Add the prefix for the volume name. */
/* SYS$GETDVI will append the volume name to this */
strcpy (diskvolnam, "DISK$");
nextslash = strchr (&argv0[1], '/');
if (nextslash != NULL)
{
length = nextslash - argv0 - 1;
/* Cast needed for HP C compiler diagnostic */
devname_dsc.dsc$a_pointer = (char *)&argv0[1];
devname_dsc.dsc$w_length = length;
devname_dsc.dsc$b_dtype = DSC$K_DTYPE_T;
devname_dsc.dsc$b_class = DSC$K_CLASS_S;
status = SYS$GETDVIW (EFN$C_ENF, 0, &devname_dsc, itemlist,
dvi_iosb, NULL, 0, 0);
if (!$VMS_STATUS_SUCCESS (status))
{
/* If the sys$getdviw fails, then this path was passed by */
/* An exec() program and not from DCL, so do nothing */
/* An example is "/tmp/program" where tmp: does not exist */
#ifdef DEBUG
printf ("sys$getdviw failed with status %d\n", status);
#endif
result = 0;
}
else if (!$VMS_STATUS_SUCCESS (dvi_iosb[0]))
{
#ifdef DEBUG
printf ("sys$getdviw failed with iosb %d\n", dvi_iosb[0]);
#endif
result = 0;
}
else
{
char * devnam;
int devnam_len;
char argv_dev[64];
/* Null terminate the returned alldevnam */
alldevnam[alldevnam_len] = 0;
devnam = alldevnam;
devnam_len = alldevnam_len;
/* Need to skip past any leading underscore */
if (devnam[0] == '_')
{
devnam++;
devnam_len--;
}
/* And remove the trailing colon */
if (devnam[devnam_len - 1] == ':')
{
devnam_len--;
devnam[devnam_len] = 0;
}
/* Null terminate the returned volnam */
diskvolnam_len += 5;
diskvolnam[diskvolnam_len] = 0;
/* Check first for normal CRTL behavior */
if (devnam_len == length)
{
strncpy (vms_new_nam, &argv0[1], length);
vms_new_nam[length] = 0;
result = (strcasecmp (devnam, vms_new_nam) == 0);
}
/* If we have not got a match, check for POSIX Compliant */
/* behavior. To be more accurate, we could also check */
/* to see if that feature is active. */
if ((result == 0) && (diskvolnam_len == length))
{
strncpy (vms_new_nam, &argv0[1], length);
vms_new_nam[length] = 0;
result = (strcasecmp (diskvolnam, vms_new_nam) == 0);
}
}
}
}
else
{
/* The path did not start with a slash, so it could be VMS format */
/* If it is vms format, it has a volume/device in it as it must */
/* be an absolute path */
struct dsc$descriptor_s path_desc;
int status;
unsigned long field_flags;
struct filescan_itmlst_2 item_list[5];
char * volume;
char * name;
int name_len;
char * ext;
path_desc.dsc$a_pointer = (char *)argv0; /* cast ok */
path_desc.dsc$w_length = strlen (argv0);
path_desc.dsc$b_dtype = DSC$K_DTYPE_T;
path_desc.dsc$b_class = DSC$K_CLASS_S;
/* Don't actually need to initialize anything buf itmcode */
/* I just do not like uninitialized input values */
/* Sanity check, this must be the same length as input */
item_list[0].itmcode = FSCN$_FILESPEC;
item_list[0].length = 0;
item_list[0].component = NULL;
/* If the device is present, then it if a VMS spec */
item_list[1].itmcode = FSCN$_DEVICE;
item_list[1].length = 0;
item_list[1].component = NULL;
/* we need the program name and type */
item_list[2].itmcode = FSCN$_NAME;
item_list[2].length = 0;
item_list[2].component = NULL;
item_list[3].itmcode = FSCN$_TYPE;
item_list[3].length = 0;
item_list[3].component = NULL;
/* End the list */
item_list[4].itmcode = 0;
item_list[4].length = 0;
item_list[4].component = NULL;
status = SYS$FILESCAN ((const struct dsc$descriptor_s *)&path_desc,
item_list, &field_flags, NULL, NULL);
if ($VMS_STATUS_SUCCESS (status) &&
(item_list[0].length == path_desc.dsc$w_length) &&
(item_list[1].length != 0))
{
char * dollar;
int keep_ext;
int i;
/* We need the filescan to be successful, */
/* same length as input, and a volume to be present */
internal_need_vms_symbol = 1;
/* We will assume that we only get to this path on a version */
/* of VMS that does not support the EFS character set */
/* There may be a xxx$ prefix on the image name. Linux */
/* programs do not handle that well, so strip the prefix */
name = item_list[2].component;
name_len = item_list[2].length;
dollar = strrchr (name, '$');
if (dollar != NULL)
{
dollar++;
name_len = name_len - (dollar - name);
name = dollar;
}
strncpy (vms_new_nam, name, name_len);
vms_new_nam[name_len] = 0;
/* Commit to using the new name */
program_name = vms_new_nam;
/* We only keep the extension if it is not ".exe" */
keep_ext = 0;
ext = item_list[3].component;
if (item_list[3].length != 1)
{
keep_ext = 1;
if (item_list[3].length == 4)
{
if ((ext[1] == 'e' || ext[1] == 'E') &&
(ext[2] == 'x' || ext[2] == 'X') &&
(ext[3] == 'e' || ext[3] == 'E'))
keep_ext = 0;
}
}
if (keep_ext == 1)
strncpy (&vms_new_nam[name_len], ext, item_list[3].length);
}
}
if (result)
{
char * lastslash;
char * dollar;
char * dotexe;
char * lastdot;
char * extension;
/* This means it is probably the name from a DCL command */
/* Find the last slash which separates the file from the */
/* path. */
lastslash = strrchr (argv0, '/');
if (lastslash != NULL) {
int i;
lastslash++;
/* There may be a xxx$ prefix on the image name. Linux */
/* programs do not handle that well, so strip the prefix */
dollar = strrchr (lastslash, '$');
if (dollar != NULL) {
dollar++;
lastslash = dollar;
}
strcpy (vms_new_nam, lastslash);
/* In UNIX mode + EFS character set, there should not be a */
/* version present, as it is not possible when parsing to */
/* tell if it is a version or part of the UNIX filename as */
/* UNIX programs use numeric extensions for many reasons. */
lastdot = strrchr (vms_new_nam, '.');
if (lastdot != NULL) {
int i;
i = 1;
while (isdigit (lastdot[i])) {
i++;
}
if (lastdot[i] == 0) {
*lastdot = 0;
}
}
/* Find the .exe on the name (case insenstive) and toss it */
dotexe = strrchr (vms_new_nam, '.');
if (dotexe != NULL) {
if ((dotexe[1] == 'e' || dotexe[1] == 'E') &&
(dotexe[2] == 'x' || dotexe[2] == 'X') &&
(dotexe[3] == 'e' || dotexe[3] == 'E') &&
(dotexe[4] == 0)) {
*dotexe = 0;
} else {
/* Also need to handle a null extension because of a */
/* CRTL bug. */
if (dotexe[1] == 0) {
*dotexe = 0;
}
}
}
/* Commit to new name */
program_name = vms_new_nam;
} else {
/* There is no way that the code should ever get here */
/* As we already verified that the '/' was present */
fprintf (stderr, "Sanity failure somewhere we lost a '/'\n");
}
}
}
#ifdef DEBUG
int
main (int argc, char ** argv, char **env)
{
char command[1024];
set_program_name (argv[0]);
printf ("modified argv[0] = %s\n", program_name);
return 0;
}
#endif
make-4.2.1/README 0000444 0001750 0001750 00000015225 12726643532 010251 0000000 0000000 This directory contains the 4.2.1 release of GNU Make.
See the file NEWS for the user-visible changes from previous releases.
In addition, there have been bugs fixed.
Please check the system-specific notes below for any caveats related to
your operating system.
For general building and installation instructions, see the file INSTALL.
If you need to build GNU Make and have no other 'make' program to use,
you can use the shell script 'build.sh' instead. To do this, first run
'configure' as described in INSTALL. Then, instead of typing 'make' to
build the program, type 'sh build.sh'. This should compile the program
in the current directory. Then you will have a Make program that you can
use for './make install', or whatever else.
Some systems' Make programs are broken and cannot process the Makefile for
GNU Make. If you get errors from your system's Make when building GNU
Make, try using 'build.sh' instead.
GNU Make is free software. See the file COPYING for copying conditions.
GNU Make is copyright by the Free Software Foundation. Copyright notices
condense sequential years into a range; e.g. "1987-1994" means all years
from 1987 to 1994 inclusive.
Downloading
-----------
GNU Make can be obtained in many different ways. See a description here:
http://www.gnu.org/software/software.html
Documentation
-------------
GNU make is fully documented in the GNU Make manual, which is contained
in this distribution as the file make.texinfo. You can also find
on-line and preformatted (PostScript and DVI) versions at the FSF's web
site. There is information there about ordering hardcopy documentation.
http://www.gnu.org/
http://www.gnu.org/doc/doc.html
http://www.gnu.org/manual/manual.html
Development
-----------
GNU Make development is hosted by Savannah, the FSF's online development
management tool. Savannah is here:
http://savannah.gnu.org
And the GNU Make development page is here:
http://savannah.gnu.org/projects/make/
You can find most information concerning the development of GNU Make at
this site.
Bug Reporting
-------------
You can send GNU make bug reports to . Please see the
section of the GNU make manual entitled 'Problems and Bugs' for
information on submitting useful and complete bug reports.
You can also use the online bug tracking system in the Savannah GNU Make
project to submit new problem reports or search for existing ones:
http://savannah.gnu.org/bugs/?group=make
If you need help using GNU make, try these forums:
help-make@gnu.org
help-utils@gnu.org
news:gnu.utils.help
news:gnu.utils.bug
Git Access
----------
The GNU make source repository is available via Git from the
GNU Savannah Git server; look here for details:
http://savannah.gnu.org/git/?group=make
Please note: you won't be able to build GNU make from Git without
installing appropriate maintainer's tools, such as GNU m4, automake,
autoconf, Perl, GNU make, and GCC. See the README.git file for hints on
how to build GNU make once these tools are available. We make no
guarantees about the contents or quality of the latest code in the Git
repository: it is not unheard of for code that is known to be broken to
be checked in. Use at your own risk.
System-specific Notes
---------------------
It has been reported that the XLC 1.2 compiler on AIX 3.2 is buggy such
that if you compile make with 'cc -O' on AIX 3.2, it will not work
correctly. It is said that using 'cc' without '-O' does work.
The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be
used to configure GNU make. Please install a different shell such as
bash or pdksh in order to run "configure". See this message for more
information:
http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html
One area that is often a problem in configuration and porting is the code
to check the system's current load average. To make it easier to test and
debug this code, you can do 'make check-loadavg' to see if it works
properly on your system. (You must run 'configure' beforehand, but you
need not build Make itself to run this test.)
Another potential source of porting problems is the support for large
files (LFS) in configure for those operating systems that provide it.
Please report any bugs that you find in this area. If you run into
difficulties, then as a workaround you should be able to disable LFS by
adding the '--disable-largefile' option to the 'configure' script.
On systems that support micro- and nano-second timestamp values and
where stat(2) provides this information, GNU make will use it when
comparing timestamps to get the most accurate possible result. However,
note that many current implementations of tools that *set* timestamps do
not preserve micro- or nano-second granularity. This means that "cp -p"
and other similar tools (tar, etc.) may not exactly duplicate timestamps
with micro- and nano-second granularity on some systems. If your build
system contains rules that depend on proper behavior of tools like "cp
-p", you should consider using the .LOW_RESOLUTION_TIME pseudo-target to
force make to treat them properly. See the manual for details.
Ports
-----
- See README.customs for details on integrating GNU make with the
Customs distributed build environment from the Pmake distribution.
- See README.VMS for details about GNU Make on OpenVMS.
- See README.Amiga for details about GNU Make on AmigaDOS.
- See README.W32 for details about GNU Make on Windows NT, 95, or 98.
- See README.DOS for compilation instructions on MS-DOS and MS-Windows
using DJGPP tools.
A precompiled binary of the MSDOS port of GNU Make is available as part
of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more
information.
Please note there are two _separate_ ports of GNU make for Microsoft
systems: a native Windows tool built with (for example) MSVC or Cygwin,
and a DOS-based tool built with DJGPP. Please be sure you are looking
at the right README!
-------------------------------------------------------------------------------
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
make-4.2.1/rule.c 0000644 0001750 0001750 00000036120 12702707624 010500 0000000 0000000 /* Pattern and suffix rule internals for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
#include "rule.h"
static void freerule (struct rule *rule, struct rule *lastrule);
/* Chain of all pattern rules. */
struct rule *pattern_rules;
/* Pointer to last rule in the chain, so we can add onto the end. */
struct rule *last_pattern_rule;
/* Number of rules in the chain. */
unsigned int num_pattern_rules;
/* Maximum number of target patterns of any pattern rule. */
unsigned int max_pattern_targets;
/* Maximum number of dependencies of any pattern rule. */
unsigned int max_pattern_deps;
/* Maximum length of the name of a dependencies of any pattern rule. */
unsigned int max_pattern_dep_length;
/* Pointer to structure for the file .SUFFIXES
whose dependencies are the suffixes to be searched. */
struct file *suffix_file;
/* Maximum length of a suffix. */
unsigned int maxsuffix;
/* Compute the maximum dependency length and maximum number of
dependencies of all implicit rules. Also sets the subdir
flag for a rule when appropriate, possibly removing the rule
completely when appropriate. */
void
count_implicit_rule_limits (void)
{
char *name;
int namelen;
struct rule *rule;
num_pattern_rules = max_pattern_targets = max_pattern_deps = 0;
max_pattern_dep_length = 0;
name = 0;
namelen = 0;
rule = pattern_rules;
while (rule != 0)
{
unsigned int ndeps = 0;
struct dep *dep;
struct rule *next = rule->next;
++num_pattern_rules;
if (rule->num > max_pattern_targets)
max_pattern_targets = rule->num;
for (dep = rule->deps; dep != 0; dep = dep->next)
{
const char *dname = dep_name (dep);
unsigned int len = strlen (dname);
#ifdef VMS
const char *p = strrchr (dname, ']');
const char *p2;
if (p == 0)
p = strrchr (dname, ':');
p2 = p != 0 ? strchr (dname, '%') : 0;
#else
const char *p = strrchr (dname, '/');
const char *p2 = p != 0 ? strchr (dname, '%') : 0;
#endif
ndeps++;
if (len > max_pattern_dep_length)
max_pattern_dep_length = len;
if (p != 0 && p2 > p)
{
/* There is a slash before the % in the dep name.
Extract the directory name. */
if (p == dname)
++p;
if (p - dname > namelen)
{
namelen = p - dname;
name = xrealloc (name, namelen + 1);
}
memcpy (name, dname, p - dname);
name[p - dname] = '\0';
/* In the deps of an implicit rule the 'changed' flag
actually indicates that the dependency is in a
nonexistent subdirectory. */
dep->changed = !dir_file_exists_p (name, "");
}
else
/* This dependency does not reside in a subdirectory. */
dep->changed = 0;
}
if (ndeps > max_pattern_deps)
max_pattern_deps = ndeps;
rule = next;
}
free (name);
}
/* Create a pattern rule from a suffix rule.
TARGET is the target suffix; SOURCE is the source suffix.
CMDS are the commands.
If TARGET is nil, it means the target pattern should be '(%.o)'.
If SOURCE is nil, it means there should be no deps. */
static void
convert_suffix_rule (const char *target, const char *source,
struct commands *cmds)
{
const char **names, **percents;
struct dep *deps;
names = xmalloc (sizeof (const char *));
percents = xmalloc (sizeof (const char *));
if (target == 0)
{
/* Special case: TARGET being nil means we are defining a '.X.a' suffix
rule; the target pattern is always '(%.o)'. */
#ifdef VMS
*names = strcache_add_len ("(%.obj)", 7);
#else
*names = strcache_add_len ("(%.o)", 5);
#endif
*percents = *names + 1;
}
else
{
/* Construct the target name. */
unsigned int len = strlen (target);
char *p = alloca (1 + len + 1);
p[0] = '%';
memcpy (p + 1, target, len + 1);
*names = strcache_add_len (p, len + 1);
*percents = *names;
}
if (source == 0)
deps = 0;
else
{
/* Construct the dependency name. */
unsigned int len = strlen (source);
char *p = alloca (1 + len + 1);
p[0] = '%';
memcpy (p + 1, source, len + 1);
deps = alloc_dep ();
deps->name = strcache_add_len (p, len + 1);
}
create_pattern_rule (names, percents, 1, 0, deps, cmds, 0);
}
/* Convert old-style suffix rules to pattern rules.
All rules for the suffixes on the .SUFFIXES list are converted and added to
the chain of pattern rules. */
void
convert_to_pattern (void)
{
struct dep *d, *d2;
char *rulename;
/* We will compute every potential suffix rule (.x.y) from the list of
suffixes in the .SUFFIXES target's dependencies and see if it exists.
First find the longest of the suffixes. */
maxsuffix = 0;
for (d = suffix_file->deps; d != 0; d = d->next)
{
unsigned int l = strlen (dep_name (d));
if (l > maxsuffix)
maxsuffix = l;
}
/* Space to construct the suffix rule target name. */
rulename = alloca ((maxsuffix * 2) + 1);
for (d = suffix_file->deps; d != 0; d = d->next)
{
unsigned int slen;
/* Make a rule that is just the suffix, with no deps or commands.
This rule exists solely to disqualify match-anything rules. */
convert_suffix_rule (dep_name (d), 0, 0);
if (d->file->cmds != 0)
/* Record a pattern for this suffix's null-suffix rule. */
convert_suffix_rule ("", dep_name (d), d->file->cmds);
/* Add every other suffix to this one and see if it exists as a
two-suffix rule. */
slen = strlen (dep_name (d));
memcpy (rulename, dep_name (d), slen);
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
struct file *f;
unsigned int s2len;
s2len = strlen (dep_name (d2));
/* Can't build something from itself. */
if (slen == s2len && streq (dep_name (d), dep_name (d2)))
continue;
memcpy (rulename + slen, dep_name (d2), s2len + 1);
f = lookup_file (rulename);
if (f == 0 || f->cmds == 0)
continue;
if (s2len == 2 && rulename[slen] == '.' && rulename[slen + 1] == 'a')
/* A suffix rule '.X.a:' generates the pattern rule '(%.o): %.X'.
It also generates a normal '%.a: %.X' rule below. */
convert_suffix_rule (NULL, /* Indicates '(%.o)'. */
dep_name (d),
f->cmds);
/* The suffix rule '.X.Y:' is converted
to the pattern rule '%.Y: %.X'. */
convert_suffix_rule (dep_name (d2), dep_name (d), f->cmds);
}
}
}
/* 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).
If this rule duplicates a previous one (identical target and dependencies),
the old one is replaced if OVERRIDE is nonzero, otherwise this new one is
thrown out. When an old rule is replaced, the new one is put at the end of
the list. Return nonzero if RULE is used; zero if not. */
static int
new_pattern_rule (struct rule *rule, int override)
{
struct rule *r, *lastrule;
unsigned int i, j;
rule->in_use = 0;
rule->terminal = 0;
rule->next = 0;
/* Search for an identical rule. */
lastrule = 0;
for (r = pattern_rules; r != 0; lastrule = r, r = r->next)
for (i = 0; i < rule->num; ++i)
{
for (j = 0; j < r->num; ++j)
if (!streq (rule->targets[i], r->targets[j]))
break;
/* If all the targets matched... */
if (j == r->num)
{
struct dep *d, *d2;
for (d = rule->deps, d2 = r->deps;
d != 0 && d2 != 0; d = d->next, d2 = d2->next)
if (!streq (dep_name (d), dep_name (d2)))
break;
if (d == 0 && d2 == 0)
{
/* All the dependencies matched. */
if (override)
{
/* Remove the old rule. */
freerule (r, lastrule);
/* Install the new one. */
if (pattern_rules == 0)
pattern_rules = rule;
else
last_pattern_rule->next = rule;
last_pattern_rule = rule;
/* We got one. Stop looking. */
goto matched;
}
else
{
/* The old rule stays intact. Destroy the new one. */
freerule (rule, (struct rule *) 0);
return 0;
}
}
}
}
matched:;
if (r == 0)
{
/* There was no rule to replace. */
if (pattern_rules == 0)
pattern_rules = rule;
else
last_pattern_rule->next = rule;
last_pattern_rule = rule;
}
return 1;
}
/* 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 of default implicit pattern rules.
TERMINAL specifies what the 'terminal' field of the rule should be. */
void
install_pattern_rule (struct pspec *p, int terminal)
{
struct rule *r;
const char *ptr;
r = xmalloc (sizeof (struct rule));
r->num = 1;
r->targets = xmalloc (sizeof (const char *));
r->suffixes = xmalloc (sizeof (const char *));
r->lens = xmalloc (sizeof (unsigned int));
r->lens[0] = strlen (p->target);
r->targets[0] = p->target;
r->suffixes[0] = find_percent_cached (&r->targets[0]);
assert (r->suffixes[0] != NULL);
++r->suffixes[0];
ptr = p->dep;
r->deps = PARSE_SIMPLE_SEQ ((char **)&ptr, struct dep);
if (new_pattern_rule (r, 0))
{
r->terminal = terminal;
r->cmds = xmalloc (sizeof (struct commands));
r->cmds->fileinfo.filenm = 0;
r->cmds->fileinfo.lineno = 0;
r->cmds->fileinfo.offset = 0;
/* These will all be string literals, but we malloc space for them
anyway because somebody might want to free them later. */
r->cmds->commands = xstrdup (p->commands);
r->cmds->command_lines = 0;
r->cmds->recipe_prefix = RECIPEPREFIX_DEFAULT;
}
}
/* Free all the storage used in RULE and take it out of the
pattern_rules chain. LASTRULE is the rule whose next pointer
points to RULE. */
static void
freerule (struct rule *rule, struct rule *lastrule)
{
struct rule *next = rule->next;
free_dep_chain (rule->deps);
/* MSVC erroneously warns without a cast here. */
free ((void *)rule->targets);
free ((void *)rule->suffixes);
free (rule->lens);
/* We can't free the storage for the commands because there
are ways that they could be in more than one place:
* If the commands came from a suffix rule, they could also be in
the 'struct file's for other suffix rules or plain targets given
on the same makefile line.
* If two suffixes that together make a two-suffix rule were each
given twice in the .SUFFIXES list, and in the proper order, two
identical pattern rules would be created and the second one would
be discarded here, but both would contain the same 'struct commands'
pointer from the 'struct file' for the suffix rule. */
free (rule);
if (pattern_rules == rule)
if (lastrule != 0)
abort ();
else
pattern_rules = next;
else if (lastrule != 0)
lastrule->next = next;
if (last_pattern_rule == rule)
last_pattern_rule = lastrule;
}
/* Create a new pattern rule with the targets in the nil-terminated array
TARGETS. TARGET_PERCENTS is an array of pointers to the % in each element
of TARGETS. N is the number of items in the array (not counting the nil
element). The new rule has dependencies DEPS and commands from COMMANDS.
It is a terminal rule if TERMINAL is nonzero. This rule overrides
identical rules with different commands if OVERRIDE is nonzero.
The storage for TARGETS and its elements and TARGET_PERCENTS is used and
must not be freed until the rule is destroyed. */
void
create_pattern_rule (const char **targets, const char **target_percents,
unsigned int n, int terminal, struct dep *deps,
struct commands *commands, int override)
{
unsigned int i;
struct rule *r = xmalloc (sizeof (struct rule));
r->num = n;
r->cmds = commands;
r->deps = deps;
r->targets = targets;
r->suffixes = target_percents;
r->lens = xmalloc (n * sizeof (unsigned int));
for (i = 0; i < n; ++i)
{
r->lens[i] = strlen (targets[i]);
assert (r->suffixes[i] != NULL);
++r->suffixes[i];
}
if (new_pattern_rule (r, override))
r->terminal = terminal;
}
/* Print the data base of rules. */
static void /* Useful to call from gdb. */
print_rule (struct rule *r)
{
unsigned int i;
for (i = 0; i < r->num; ++i)
{
fputs (r->targets[i], stdout);
putchar ((i + 1 == r->num) ? ':' : ' ');
}
if (r->terminal)
putchar (':');
print_prereqs (r->deps);
if (r->cmds != 0)
print_commands (r->cmds);
}
void
print_rule_data_base (void)
{
unsigned int rules, terminal;
struct rule *r;
puts (_("\n# Implicit Rules"));
rules = terminal = 0;
for (r = pattern_rules; r != 0; r = r->next)
{
++rules;
putchar ('\n');
print_rule (r);
if (r->terminal)
++terminal;
}
if (rules == 0)
puts (_("\n# No implicit rules."));
else
{
printf (_("\n# %u implicit rules, %u"), rules, terminal);
#ifndef NO_FLOAT
printf (" (%.1f%%)", (double) terminal / (double) rules * 100.0);
#else
{
int f = (terminal * 1000 + 5) / rules;
printf (" (%d.%d%%)", f/10, f%10);
}
#endif
puts (_(" terminal."));
}
if (num_pattern_rules != rules)
{
/* This can happen if a fatal error was detected while reading the
makefiles and thus count_implicit_rule_limits wasn't called yet. */
if (num_pattern_rules != 0)
ONN (fatal, NILF, _("BUG: num_pattern_rules is wrong! %u != %u"),
num_pattern_rules, rules);
}
}
make-4.2.1/config.ami 0000444 0001750 0001750 00000023012 12726643532 011317 0000000 0000000 /* config.h -- hand-massaged for Amiga -*-C-*-
Copyright (C) 1995-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* Define if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* #undef _ALL_SOURCE */
#endif
/* Define if using alloca.c. */
#define C_ALLOCA
/* Define if the closedir function returns void instead of int. */
/* #undef CLOSEDIR_VOID */
/* Define to empty if the keyword does not work. */
/* #undef const */
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
This function is required for alloca.c support on those systems. */
/* #undef CRAY_STACKSEG_END */
/* Define for DGUX with . */
/* #undef DGUX */
/* Define if the 'getloadavg' function needs to be run setuid or setgid. */
/* #undef GETLOADAVG_PRIVILEGED */
/* Define to 'unsigned long' or 'unsigned long long'
if doesn't define. */
#define uintmax_t unsigned long
/* Define to 'int' if doesn't define. */
#define gid_t int
/* Define if you have alloca, as a function or macro. */
/* #undef HAVE_ALLOCA */
/* Define if you have and it should be used (not on Ultrix). */
/* #undef HAVE_ALLOCA_H */
/* Define if your system has a working fnmatch function. */
/* #undef HAVE_FNMATCH */
/* Define if your system has its own 'getloadavg' function. */
/* #undef HAVE_GETLOADAVG */
/* Define if you have the getmntent function. */
/* #undef HAVE_GETMNTENT */
/* Embed GNU Guile support */
/* #undef HAVE_GUILE */
/* Define if the 'long double' type works. */
/* #undef HAVE_LONG_DOUBLE */
/* Define if you support file names longer than 14 characters. */
#define HAVE_LONG_FILE_NAMES 1
/* Define if you have a working 'mmap' system call. */
/* #undef HAVE_MMAP */
/* Define if system calls automatically restart after interruption
by a signal. */
/* #undef HAVE_RESTARTABLE_SYSCALLS */
/* Define if your struct stat has st_blksize. */
/* #undef HAVE_ST_BLKSIZE */
/* Define if your struct stat has st_blocks. */
/* #undef HAVE_ST_BLOCKS */
/* Define if you have the strcoll function and it is properly defined. */
#define HAVE_STRCOLL 1
/* Define if your struct stat has st_rdev. */
#define HAVE_ST_RDEV 1
/* Define if you have the strftime function. */
#define HAVE_STRFTIME 1
/* Define if you have that is POSIX.1 compatible. */
/* #undef HAVE_SYS_WAIT_H */
/* Define if your struct tm has tm_zone. */
/* #undef HAVE_TM_ZONE */
/* Define if you don't have tm_zone but do have the external array
tzname. */
#define HAVE_TZNAME 1
/* Define if you have . */
#define HAVE_UNISTD_H 1
/* Define if utime(file, NULL) sets file's timestamp to the present. */
/* #undef HAVE_UTIME_NULL */
/* Define if you have the wait3 system call. */
/* #undef HAVE_WAIT3 */
/* Define if on MINIX. */
/* #undef _MINIX */
/* Define if your struct nlist has an n_un member. */
/* #undef NLIST_NAME_UNION */
/* Define if you have . */
/* #undef NLIST_STRUCT */
/* Define if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Define to 'int' if doesn't define. */
#define pid_t int
/* Define if the system does not provide POSIX.1 features except
with this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define if you need to in order for stat and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Define if the setvbuf function takes the buffering type as its second
argument and the buffer pointer as the third, as on System V
before release 3. */
/* #undef SETVBUF_REVERSED */
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
#define STACK_DIRECTION -1
/* Define if the 'S_IS*' macros in do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS
/* Define on System V Release 4. */
/* #undef SVR4 */
/* Define if 'sys_siglist' is declared by . */
/* #undef SYS_SIGLIST_DECLARED */
/* Define to 'int' if doesn't define. */
#define uid_t int
/* Define for Encore UMAX. */
/* #undef UMAX */
/* Define for Encore UMAX 4.3 that has
instead of . */
/* #undef UMAX4_3 */
/* Name of this package (needed by automake) */
#define PACKAGE "make"
/* Version of this package (needed by automake) */
#define VERSION "4.2.1"
/* Define to the name of the SCCS 'get' command. */
#define SCCS_GET "get"
/* Define this if the SCCS 'get' command understands the '-G' option. */
/* #undef SCCS_GET_MINUS_G */
/* Define this to enable job server support in GNU make. */
/* #undef MAKE_JOBSERVER */
/* Define to be the nanoseconds member of struct stat's st_mtim,
if it exists. */
/* #undef ST_MTIM_NSEC */
/* Define this if the C library defines the variable 'sys_siglist'. */
/* #undef HAVE_SYS_SIGLIST */
/* Define this if the C library defines the variable '_sys_siglist'. */
/* #undef HAVE__SYS_SIGLIST */
/* Define this if you have the 'union wait' type in . */
/* #undef HAVE_UNION_WAIT */
/* Define if you have the dup2 function. */
/* #undef HAVE_DUP2 */
/* Define if you have the getcwd function. */
#define HAVE_GETCWD 1
/* Define if you have the getgroups function. */
/* #undef HAVE_GETGROUPS */
/* Define if you have the gethostbyname function. */
/* #undef HAVE_GETHOSTBYNAME */
/* Define if you have the gethostname function. */
/* #undef HAVE_GETHOSTNAME */
/* Define if you have the memmove function. */
#define HAVE_MEMMOVE 1
/* Define if you have the mktemp function. */
#define HAVE_MKTEMP 1
/* Define if you have the psignal function. */
/* #undef HAVE_PSIGNAL */
/* Define if you have the pstat_getdynamic function. */
/* #undef HAVE_PSTAT_GETDYNAMIC */
/* Define if you have the setegid function. */
/* #undef HAVE_SETEGID */
/* Define if you have the seteuid function. */
/* #undef HAVE_SETEUID */
/* Define if you have the setlinebuf function. */
/* #undef HAVE_SETLINEBUF */
/* Define if you have the setregid function. */
/* #undef HAVE_SETREGID */
/* Define if you have the setreuid function. */
/* #undef HAVE_SETREUID */
/* Define if you have the sigsetmask function. */
/* #undef HAVE_SIGSETMASK */
/* Define if you have the socket function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if you have the strcasecmp function. */
/* #undef HAVE_STRCASECMP */
/* Define to 1 if you have the strcmpi function. */
/* #undef HAVE_STRCMPI */
/* Define to 1 if you have the stricmp function. */
/* #undef HAVE_STRICMP */
/* Define if you have the strerror function. */
#define HAVE_STRERROR 1
/* Define if you have the strsignal function. */
/* #undef HAVE_STRSIGNAL */
/* Define if you have the wait3 function. */
/* #undef HAVE_WAIT3 */
/* Define if you have the waitpid function. */
/* #undef HAVE_WAITPID */
/* Define if you have the header file. */
#define HAVE_DIRENT_H 1
/* Define if you have the header file. */
#define HAVE_FCNTL_H 1
/* Define if you have the header file. */
#define HAVE_LIMITS_H 1
/* Define if you have the header file. */
/* #undef HAVE_MACH_MACH_H */
/* Define if you have the header file. */
/* #undef HAVE_MEMORY_H */
/* Define if you have the header file. */
/* #undef HAVE_NDIR_H */
/* Define if you have the header file. */
/* #undef HAVE_STDLIB_H */
/* Define if you have the header file. */
#define HAVE_STRING_H 1
/* Define if you have the header file. */
#define HAVE_SYS_DIR_H 1
/* Define if you have the header file. */
/* #undef HAVE_SYS_NDIR_H */
/* Define if you have the header file. */
/* #undef HAVE_SYS_PARAM_H */
/* Define if you have the header file. */
/* #undef HAVE_SYS_TIMEB_H */
/* Define if you have the header file. */
/* #undef HAVE_SYS_WAIT_H */
/* Define if you have the header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the dgc library (-ldgc). */
/* #undef HAVE_LIBDGC */
/* Define if you have the kstat library (-lkstat). */
/* #undef HAVE_LIBKSTAT */
/* Define to 1 if you have the `isatty' function. */
/* #undef HAVE_ISATTY */
/* Define to 1 if you have the `ttyname' function. */
/* #undef HAVE_TTYNAME */
/* Define if you have the sun library (-lsun). */
/* #undef HAVE_LIBSUN */
/* Output sync sypport */
#define NO_OUTPUT_SYNC
/* Define for Case Insensitve behavior */
#define HAVE_CASE_INSENSITIVE_FS
/* Build host information. */
#define MAKE_HOST "Amiga"
make-4.2.1/misc.c 0000644 0001750 0001750 00000040010 12702264703 010451 0000000 0000000 /* Miscellaneous generic support functions for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include "filedef.h"
#include "dep.h"
#include "debug.h"
/* GNU make no longer supports pre-ANSI89 environments. */
#include
#ifdef HAVE_FCNTL_H
# include
#else
# include
#endif
/* 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 (const void *v1, const void *v2)
{
const char *s1 = *((char **)v1);
const char *s2 = *((char **)v2);
if (*s1 != *s2)
return *s1 - *s2;
return strcmp (s1, s2);
}
/* Discard each backslash-newline combination from LINE.
Backslash-backslash-newline combinations become backslash-newlines.
This is done by copying the text at LINE into itself. */
void
collapse_continuations (char *line)
{
char *in, *out, *p;
in = strchr (line, '\n');
if (in == 0)
return;
out = in;
while (out > line && out[-1] == '\\')
--out;
while (*in != '\0')
{
/* BS_WRITE gets the number of quoted backslashes at
the end just before IN, and BACKSLASH gets nonzero
if the next character is quoted. */
unsigned int backslash = 0;
unsigned int bs_write = 0;
for (p = in - 1; p >= line && *p == '\\'; --p)
{
if (backslash)
++bs_write;
backslash = !backslash;
/* It should be impossible to go back this far without exiting,
but if we do, we can't get the right answer. */
if (in == out - 1)
abort ();
}
/* Output the appropriate number of backslashes. */
while (bs_write-- > 0)
*out++ = '\\';
/* Skip the newline. */
++in;
if (backslash)
{
/* Backslash/newline handling:
In traditional GNU make all trailing whitespace, consecutive
backslash/newlines, and any leading non-newline whitespace on the
next line is reduced to a single space.
In POSIX, each backslash/newline and is replaced by a space. */
while (ISBLANK (*in))
++in;
if (! posix_pedantic)
while (out > line && ISBLANK (out[-1]))
--out;
*out++ = ' ';
}
else
/* If the newline isn't quoted, put it in the output. */
*out++ = '\n';
/* Now copy the following line to the output.
Stop when we find backslashes followed by a newline. */
while (*in != '\0')
if (*in == '\\')
{
p = in + 1;
while (*p == '\\')
++p;
if (*p == '\n')
{
in = p;
break;
}
while (in < p)
*out++ = *in++;
}
else
*out++ = *in++;
}
*out = '\0';
}
/* Print N spaces (used in debug for target-depth). */
void
print_spaces (unsigned int n)
{
while (n-- > 0)
putchar (' ');
}
/* Return a string whose contents concatenate the NUM strings provided
This string lives in static, re-used memory. */
const char *
concat (unsigned int num, ...)
{
static unsigned int rlen = 0;
static char *result = NULL;
unsigned int ri = 0;
va_list args;
va_start (args, num);
while (num-- > 0)
{
const char *s = va_arg (args, const char *);
unsigned int l = xstrlen (s);
if (l == 0)
continue;
if (ri + l > rlen)
{
rlen = ((rlen ? rlen : 60) + l) * 2;
result = xrealloc (result, rlen);
}
memcpy (result + ri, s, l);
ri += l;
}
va_end (args);
/* Get some more memory if we don't have enough space for the
terminating '\0'. */
if (ri == rlen)
{
rlen = (rlen ? rlen : 60) * 2;
result = xrealloc (result, rlen);
}
result[ri] = '\0';
return result;
}
#ifndef HAVE_STRERROR
#undef strerror
char *
strerror (int errnum)
{
extern int errno, sys_nerr;
#ifndef __DECC
extern char *sys_errlist[];
#endif
static char buf[] = "Unknown error 12345678901234567890";
if (errno < sys_nerr)
return sys_errlist[errnum];
sprintf (buf, _("Unknown error %d"), errnum);
return buf;
}
#endif
/* Like malloc but get fatal error if memory is exhausted. */
/* Don't bother if we're using dmalloc; it provides these for us. */
#ifndef HAVE_DMALLOC_H
#undef xmalloc
#undef xcalloc
#undef xrealloc
#undef xstrdup
void *
xmalloc (unsigned int size)
{
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = malloc (size ? size : 1);
if (result == 0)
OUT_OF_MEM();
return result;
}
void *
xcalloc (unsigned int size)
{
/* Make sure we don't allocate 0, for pre-ISO implementations. */
void *result = calloc (size ? size : 1, 1);
if (result == 0)
OUT_OF_MEM();
return result;
}
void *
xrealloc (void *ptr, unsigned int size)
{
void *result;
/* Some older implementations of realloc() don't conform to ISO. */
if (! size)
size = 1;
result = ptr ? realloc (ptr, size) : malloc (size);
if (result == 0)
OUT_OF_MEM();
return result;
}
char *
xstrdup (const char *ptr)
{
char *result;
#ifdef HAVE_STRDUP
result = strdup (ptr);
#else
result = malloc (strlen (ptr) + 1);
#endif
if (result == 0)
OUT_OF_MEM();
#ifdef HAVE_STRDUP
return result;
#else
return strcpy (result, ptr);
#endif
}
#endif /* HAVE_DMALLOC_H */
char *
xstrndup (const char *str, unsigned int length)
{
char *result;
#ifdef HAVE_STRNDUP
result = strndup (str, length);
if (result == 0)
OUT_OF_MEM();
#else
result = xmalloc (length + 1);
if (length > 0)
strncpy (result, str, length);
result[length] = '\0';
#endif
return result;
}
/* Limited INDEX:
Search through the string STRING, which ends at LIMIT, for the character C.
Returns a pointer to the first occurrence, or nil if none is found.
Like INDEX except that the string searched ends where specified
instead of at the first null. */
char *
lindex (const char *s, const char *limit, int c)
{
while (s < limit)
if (*s++ == c)
return (char *)(s - 1);
return 0;
}
/* Return the address of the first whitespace or null in the string S. */
char *
end_of_token (const char *s)
{
END_OF_TOKEN (s);
return (char *)s;
}
/* Return the address of the first nonwhitespace or null in the string S. */
char *
next_token (const char *s)
{
NEXT_TOKEN (s);
return (char *)s;
}
/* Find the next token in PTR; return the address of it, and store the length
of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end
of the token, so this function can be called repeatedly in a loop. */
char *
find_next_token (const char **ptr, unsigned int *lengthptr)
{
const char *p = next_token (*ptr);
if (*p == '\0')
return 0;
*ptr = end_of_token (p);
if (lengthptr != 0)
*lengthptr = *ptr - p;
return (char *)p;
}
/* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */
struct dep *
copy_dep_chain (const struct dep *d)
{
struct dep *firstnew = 0;
struct dep *lastnew = 0;
while (d != 0)
{
struct dep *c = xmalloc (sizeof (struct dep));
memcpy (c, d, sizeof (struct dep));
if (c->need_2nd_expansion)
c->name = xstrdup (c->name);
c->next = 0;
if (firstnew == 0)
firstnew = lastnew = c;
else
lastnew = lastnew->next = c;
d = d->next;
}
return firstnew;
}
/* Free a chain of struct nameseq.
For struct dep chains use free_dep_chain. */
void
free_ns_chain (struct nameseq *ns)
{
while (ns != 0)
{
struct nameseq *t = ns;
ns = ns->next;
free_ns (t);
}
}
#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
for it, define our own version. */
int
strcasecmp (const char *s1, const char *s2)
{
while (1)
{
int c1 = (int) *(s1++);
int c2 = (int) *(s2++);
if (isalpha (c1))
c1 = tolower (c1);
if (isalpha (c2))
c2 = tolower (c2);
if (c1 != '\0' && c1 == c2)
continue;
return (c1 - c2);
}
}
#endif
#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
/* If we don't have strncasecmp() (from POSIX), or anything that can
substitute for it, define our own version. */
int
strncasecmp (const char *s1, const char *s2, int n)
{
while (n-- > 0)
{
int c1 = (int) *(s1++);
int c2 = (int) *(s2++);
if (isalpha (c1))
c1 = tolower (c1);
if (isalpha (c2))
c2 = tolower (c2);
if (c1 != '\0' && c1 == c2)
continue;
return (c1 - c2);
}
return 0;
}
#endif
#ifdef GETLOADAVG_PRIVILEGED
#ifdef POSIX
/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
for example) which claim to be POSIX.1 also have the BSD setreuid and
setregid functions, but they don't work as in BSD and only the POSIX.1
way works. */
#undef HAVE_SETREUID
#undef HAVE_SETREGID
#else /* Not POSIX. */
/* Some POSIX.1 systems have the seteuid and setegid functions. In a
POSIX-like system, they are the best thing to use. However, some
non-POSIX systems have them too but they do not work in the POSIX style
and we must use setreuid and setregid instead. */
#undef HAVE_SETEUID
#undef HAVE_SETEGID
#endif /* POSIX. */
#ifndef HAVE_UNISTD_H
extern int getuid (), getgid (), geteuid (), getegid ();
extern int setuid (), setgid ();
#ifdef HAVE_SETEUID
extern int seteuid ();
#else
#ifdef HAVE_SETREUID
extern int setreuid ();
#endif /* Have setreuid. */
#endif /* Have seteuid. */
#ifdef HAVE_SETEGID
extern int setegid ();
#else
#ifdef HAVE_SETREGID
extern int setregid ();
#endif /* Have setregid. */
#endif /* Have setegid. */
#endif /* No . */
/* Keep track of the user and group IDs for user- and make- access. */
static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
#define access_inited (user_uid != -1)
static enum { make, user } current_access;
/* Under -d, write a message describing the current IDs. */
static void
log_access (const char *flavor)
{
if (! ISDB (DB_JOBS))
return;
/* All the other debugging messages go to stdout,
but we write this one to stderr because it might be
run in a child fork whose stdout is piped. */
fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
(unsigned long) getegid (), (unsigned long) getgid ());
fflush (stderr);
}
static void
init_access (void)
{
#ifndef VMS
user_uid = getuid ();
user_gid = getgid ();
make_uid = geteuid ();
make_gid = getegid ();
/* Do these ever fail? */
if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
pfatal_with_name ("get{e}[gu]id");
log_access (_("Initialized access"));
current_access = make;
#endif
}
#endif /* GETLOADAVG_PRIVILEGED */
/* Give the process appropriate permissions for access to
user data (i.e., to stat files, or to spawn a child process). */
void
user_access (void)
{
#ifdef GETLOADAVG_PRIVILEGED
if (!access_inited)
init_access ();
if (current_access == user)
return;
/* We are in "make access" mode. This means that the effective user and
group IDs are those of make (if it was installed setuid or setgid).
We now want to set the effective user and group IDs to the real IDs,
which are the IDs of the process that exec'd make. */
#ifdef HAVE_SETEUID
/* Modern systems have the seteuid/setegid calls which set only the
effective IDs, which is ideal. */
if (seteuid (user_uid) < 0)
pfatal_with_name ("user_access: seteuid");
#else /* Not HAVE_SETEUID. */
#ifndef HAVE_SETREUID
/* System V has only the setuid/setgid calls to set user/group IDs.
There is an effective ID, which can be set by setuid/setgid.
It can be set (unless you are root) only to either what it already is
(returned by geteuid/getegid, now in make_uid/make_gid),
the real ID (return by getuid/getgid, now in user_uid/user_gid),
or the saved set ID (what the effective ID was before this set-ID
executable (make) was exec'd). */
if (setuid (user_uid) < 0)
pfatal_with_name ("user_access: setuid");
#else /* HAVE_SETREUID. */
/* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
They may be set to themselves or each other. So you have two alternatives
at any one time. If you use setuid/setgid, the effective will be set to
the real, leaving only one alternative. Using setreuid/setregid, however,
you can toggle between your two alternatives by swapping the values in a
single setreuid or setregid call. */
if (setreuid (make_uid, user_uid) < 0)
pfatal_with_name ("user_access: setreuid");
#endif /* Not HAVE_SETREUID. */
#endif /* HAVE_SETEUID. */
#ifdef HAVE_SETEGID
if (setegid (user_gid) < 0)
pfatal_with_name ("user_access: setegid");
#else
#ifndef HAVE_SETREGID
if (setgid (user_gid) < 0)
pfatal_with_name ("user_access: setgid");
#else
if (setregid (make_gid, user_gid) < 0)
pfatal_with_name ("user_access: setregid");
#endif
#endif
current_access = user;
log_access (_("User access"));
#endif /* GETLOADAVG_PRIVILEGED */
}
/* Give the process appropriate permissions for access to
make data (i.e., the load average). */
void
make_access (void)
{
#ifdef GETLOADAVG_PRIVILEGED
if (!access_inited)
init_access ();
if (current_access == make)
return;
/* See comments in user_access, above. */
#ifdef HAVE_SETEUID
if (seteuid (make_uid) < 0)
pfatal_with_name ("make_access: seteuid");
#else
#ifndef HAVE_SETREUID
if (setuid (make_uid) < 0)
pfatal_with_name ("make_access: setuid");
#else
if (setreuid (user_uid, make_uid) < 0)
pfatal_with_name ("make_access: setreuid");
#endif
#endif
#ifdef HAVE_SETEGID
if (setegid (make_gid) < 0)
pfatal_with_name ("make_access: setegid");
#else
#ifndef HAVE_SETREGID
if (setgid (make_gid) < 0)
pfatal_with_name ("make_access: setgid");
#else
if (setregid (user_gid, make_gid) < 0)
pfatal_with_name ("make_access: setregid");
#endif
#endif
current_access = make;
log_access (_("Make access"));
#endif /* GETLOADAVG_PRIVILEGED */
}
/* Give the process appropriate permissions for a child process.
This is like user_access, but you can't get back to make_access. */
void
child_access (void)
{
#ifdef GETLOADAVG_PRIVILEGED
if (!access_inited)
abort ();
/* Set both the real and effective UID and GID to the user's.
They cannot be changed back to make's. */
#ifndef HAVE_SETREUID
if (setuid (user_uid) < 0)
pfatal_with_name ("child_access: setuid");
#else
if (setreuid (user_uid, user_uid) < 0)
pfatal_with_name ("child_access: setreuid");
#endif
#ifndef HAVE_SETREGID
if (setgid (user_gid) < 0)
pfatal_with_name ("child_access: setgid");
#else
if (setregid (user_gid, user_gid) < 0)
pfatal_with_name ("child_access: setregid");
#endif
log_access (_("Child access"));
#endif /* GETLOADAVG_PRIVILEGED */
}
#ifdef NEED_GET_PATH_MAX
unsigned int
get_path_max (void)
{
static unsigned int value;
if (value == 0)
{
long int x = pathconf ("/", _PC_PATH_MAX);
if (x > 0)
value = x;
else
return MAXPATHLEN;
}
return value;
}
#endif
make-4.2.1/gettext.h 0000644 0001750 0001750 00000004727 12664631374 011237 0000000 0000000 /* Convenience header for conditional use of GNU .
Copyright (C) 1995-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#ifndef _LIBGETTEXT_H
#define _LIBGETTEXT_H 1
/* NLS can be disabled through the configure --disable-nls option. */
#if ENABLE_NLS
/* Get declarations of GNU message catalog functions. */
# include
#else
/* Disabled NLS.
The casts to 'const char *' serve the purpose of producing warnings
for invalid uses of the value returned from these functions.
On pre-ANSI systems without 'const', the config.h file is supposed to
contain "#define const". */
# define gettext(Msgid) ((const char *) (Msgid))
# define dgettext(Domainname, Msgid) ((const char *) (Msgid))
# define dcgettext(Domainname, Msgid, Category) ((const char *) (Msgid))
# define ngettext(Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dngettext(Domainname, Msgid1, Msgid2, N) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \
((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
# define textdomain(Domainname) ((const char *) (Domainname))
# define bindtextdomain(Domainname, Dirname) ((const char *) (Dirname))
# define bind_textdomain_codeset(Domainname, Codeset) ((const char *) (Codeset))
#endif
/* A pseudo function call that serves as a marker for the automated
extraction of messages, but does not call gettext(). The run-time
translation is done at a different place in the code.
The argument, String, should be a literal string. Concatenated strings
and other string expressions won't work.
The macro's expansion is not parenthesized, so that it is suitable as
initializer for static 'char[]' or 'const char[]' variables. */
#define gettext_noop(String) String
#endif /* _LIBGETTEXT_H */
make-4.2.1/config.h.W32 0000444 0001750 0001750 00000035712 12726643532 011364 0000000 0000000 /* config.h.W32 -- hand-massaged config.h file for Windows builds -*-C-*-
Copyright (C) 1996-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* Suppress some Visual C++ warnings.
Maybe after the code cleanup for ISO C we can remove some/all of these. */
#if _MSC_VER > 1000
# pragma warning(disable:4100) /* unreferenced formal parameter */
# pragma warning(disable:4102) /* unreferenced label */
# pragma warning(disable:4127) /* conditional expression is constant */
# pragma warning(disable:4131) /* uses old-style declarator */
# pragma warning(disable:4702) /* unreachable code */
# define _CRT_SECURE_NO_WARNINGS /* function or variable may be unsafe */
# define _CRT_NONSTDC_NO_WARNINGS /* functions w/o a leading underscore */
#endif
/* Define to 1 if the 'closedir' function returns void instead of 'int'. */
/* #undef CLOSEDIR_VOID */
/* Define to one of '_getb67', 'GETB67', 'getb67' for Cray-2 and Cray-YMP
systems. This function is required for 'alloca.c' support on those systems.
*/
/* #undef CRAY_STACKSEG_END */
/* Define to 1 if using 'alloca.c'. */
/* #undef C_ALLOCA */
/* Define to 1 if using 'getloadavg.c'. */
#define C_GETLOADAVG 1
/* Define to 1 for DGUX with . */
/* #undef DGUX */
/* Define to 1 if translation of program messages to the user's native
language is requested. */
/* #undef ENABLE_NLS */
/* Use high resolution file timestamps if nonzero. */
#define FILE_TIMESTAMP_HI_RES 0
/* Define to 1 if the 'getloadavg' function needs to be run setuid or setgid.
*/
/* #undef GETLOADAVG_PRIVILEGED */
/* Define to 1 if you have 'alloca', as a function or macro. */
#define HAVE_ALLOCA 1
/* Define to 1 if you have and it should be used (not on Ultrix).
*/
/* #undef HAVE_ALLOCA_H */
/* Define to 1 if you have the 'atexit' function. */
#define HAVE_ATEXIT 1
/* Use case insensitive file names */
/* #undef HAVE_CASE_INSENSITIVE_FS */
/* Define to 1 if you have the clock_gettime function. */
/* #undef HAVE_CLOCK_GETTIME */
/* Embed GNU Guile support. Windows build sets this on the
compilation command line. */
/* #undef HAVE_GUILE */
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
/* #undef HAVE_DCGETTEXT */
/* Define to 1 if you have the declaration of 'bsd_signal', and to 0 if you
don't. */
#define HAVE_DECL_BSD_SIGNAL 0
/* Define to 1 if you have the declaration of 'sys_siglist', and to 0 if you
don't. */
#define HAVE_DECL_SYS_SIGLIST 0
/* Define to 1 if you have the declaration of '_sys_siglist', and to 0 if you
don't. */
#define HAVE_DECL__SYS_SIGLIST 0
/* Define to 1 if you have the declaration of '__sys_siglist', and to 0 if you
don't. */
#define HAVE_DECL___SYS_SIGLIST 0
/* Define to 1 if you have the header file, and it defines 'DIR'.
*/
#define HAVE_DIRENT_H 1
/* Define to 1 if you have the header file, and it defines getcwd()
and chdir().
*/
#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__INTERIX)
# define HAVE_DIRECT_H 1
#endif
/* Use platform specific coding */
#define HAVE_DOS_PATHS 1
/* Define to 1 if you have the 'dup2' function. */
#define HAVE_DUP2 1
/* Define to 1 if you have the header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the 'fdopen' function. */
#ifdef __MINGW32__
#define HAVE_FDOPEN 1
#endif
/* Define to 1 if you have the 'fileno' function. */
#define HAVE_FILENO 1
/* Define to 1 if you have the 'getcwd' function. */
#define HAVE_GETCWD 1
/* Define to 1 if you have the 'getgroups' function. */
/* #undef HAVE_GETGROUPS */
/* Define to 1 if you have the 'gethostbyname' function. */
/* #undef HAVE_GETHOSTBYNAME */
/* Define to 1 if you have the 'gethostname' function. */
/* #undef HAVE_GETHOSTNAME */
/* Define to 1 if you have the 'getloadavg' function. */
/* #undef HAVE_GETLOADAVG */
/* Define to 1 if you have the 'getrlimit' function. */
/* #undef HAVE_GETRLIMIT */
/* Define if the GNU gettext() function is already present or preinstalled. */
/* #undef HAVE_GETTEXT */
/* Define to 1 if you have a standard gettimeofday function */
#ifdef __MINGW32__
#define HAVE_GETTIMEOFDAY 1
#endif
/* Define if you have the iconv() function. */
/* #undef HAVE_ICONV */
/* Define to 1 if you have the header file. */
#ifdef __MINGW32__
#define HAVE_INTTYPES_H 1
#endif
/* Define to 1 if you have the 'dgc' library (-ldgc). */
/* #undef HAVE_LIBDGC */
/* Define to 1 if you have the 'kstat' library (-lkstat). */
/* #undef HAVE_LIBKSTAT */
/* Define to 1 if you have the header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the header file. */
/*#define HAVE_LOCALE_H 1*/
/* Define to 1 if you have the 'lstat' function. */
/* #undef HAVE_LSTAT */
/* Define to 1 if you have the header file. */
/* #undef HAVE_MACH_MACH_H */
/* Define to 1 if you have the header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the 'mkstemp' function. */
/* #undef HAVE_MKSTEMP */
/* Define to 1 if you have the 'mktemp' function. */
#define HAVE_MKTEMP 1
/* Define to 1 if you have the header file, and it defines 'DIR'. */
/* #undef HAVE_NDIR_H */
/* Define to 1 if you have the header file. */
/* #undef HAVE_NLIST_H */
/* Define to 1 if you have the 'pipe' function. */
/* #undef HAVE_PIPE */
/* Define to 1 if you have the 'pstat_getdynamic' function. */
/* #undef HAVE_PSTAT_GETDYNAMIC */
/* Define to 1 if you have the 'readlink' function. */
/* #undef HAVE_READLINK */
/* Define to 1 if you have the 'realpath' function. */
/* #undef HAVE_REALPATH */
/* Define to 1 if defines the SA_RESTART constant. */
/* #undef HAVE_SA_RESTART */
/* Define to 1 if you have the 'setegid' function. */
/* #undef HAVE_SETEGID */
/* Define to 1 if you have the 'seteuid' function. */
/* #undef HAVE_SETEUID */
/* Define to 1 if you have the 'setlinebuf' function. */
/* #undef HAVE_SETLINEBUF */
/* Define to 1 if you have the 'setlocale' function. */
/*#define HAVE_SETLOCALE 1*/
/* Define to 1 if you have the 'setregid' function. */
/* #undef HAVE_SETREGID */
/* Define to 1 if you have the 'setreuid' function. */
/* #undef HAVE_SETREUID */
/* Define to 1 if you have the 'setrlimit' function. */
/* #undef HAVE_SETRLIMIT */
/* Define to 1 if you have the 'setvbuf' function. */
#define HAVE_SETVBUF 1
/* Define to 1 if you have the 'sigaction' function. */
/* #undef HAVE_SIGACTION */
/* Define to 1 if you have the 'sigsetmask' function. */
/* #undef HAVE_SIGSETMASK */
/* Define to 1 if you have the 'socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if you have the header file. */
#ifdef __MINGW32__
#define HAVE_STDINT_H 1
#endif
/* Define to 1 if you have the header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the 'strcasecmp' function. */
#ifdef __MINGW32__
#define HAVE_STRCASECMP 1
#endif
/* Define to 1 if you have the 'strcmpi' function. */
#define HAVE_STRCMPI 1
/* Define to 1 if you have the 'strcoll' function and it is properly defined.
*/
#define HAVE_STRCOLL 1
/* Define to 1 if you have the 'strdup' function. */
#define HAVE_STRDUP 1
/* Define to 1 if you have the 'strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the 'stricmp' function. */
#define HAVE_STRICMP 1
/* Define to 1 if you have the header file. */
/* #define HAVE_STRINGS_H 1 */
/* Define to 1 if you have the header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the 'strncasecmp' function. */
#ifdef __MINGW32__
#define HAVE_STRNCASECMP 1
#endif
/* Define to 1 if you have the 'strncmpi' function. */
/* #undef HAVE_STRNCMPI */
/* Define to 1 if you have the 'strndup' function. */
/* #undef HAVE_STRNDUP */
/* Define to 1 if you have the 'strnicmp' function. */
#ifdef __MINGW32__
#define HAVE_STRNICMP 1
#endif
/* Define to 1 if you have the 'strsignal' function. */
/* #undef HAVE_STRSIGNAL */
/* Define to 1 if you have the `isatty' function. */
#define HAVE_ISATTY 1
/* Define to 1 if you have the `ttyname' function. */
#define HAVE_TTYNAME 1
char *ttyname (int);
/* Define to 1 if 'n_un.n_name' is a member of 'struct nlist'. */
/* #undef HAVE_STRUCT_NLIST_N_UN_N_NAME */
/* Define to 1 if you have the header file, and it defines 'DIR'.
*/
/* #undef HAVE_SYS_DIR_H */
/* Define to 1 if you have the header file, and it defines 'DIR'.
*/
/* #undef HAVE_SYS_NDIR_H */
/* Define to 1 if you have the header file. */
#ifdef __MINGW32__
#define HAVE_SYS_PARAM_H 1
#endif
/* Define to 1 if you have the header file. */
/* #undef HAVE_SYS_RESOURCE_H */
/* Define to 1 if you have the header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the header file. */
#define HAVE_SYS_TIMEB_H 1
/* Define to 1 if you have the header file. */
#ifdef __MINGW32__
#define HAVE_SYS_TIME_H 1
#endif
/* Define to 1 if you have the header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the header file. */
/* #undef HAVE_SYS_WAIT_H */
/* Define to 1 if you have the \'union wait' type in . */
/* #undef HAVE_UNION_WAIT */
/* Define to 1 if you have the header file. */
#ifdef __MINGW32__
#define HAVE_UNISTD_H 1
#endif
/* Define to 1 if you have the 'wait3' function. */
/* #undef HAVE_WAIT3 */
/* Define to 1 if you have the 'waitpid' function. */
/* #undef HAVE_WAITPID */
/* Build host information. */
#define MAKE_HOST "Windows32"
/* Define to 1 to enable job server support in GNU make. */
#define MAKE_JOBSERVER 1
/* Define to 1 to enable 'load' support in GNU make. */
#define MAKE_LOAD 1
/* Define to 1 to enable symbolic link timestamp checking. */
/* #undef MAKE_SYMLINKS */
/* Define to 1 if your 'struct nlist' has an 'n_un' member. Obsolete, depend
on 'HAVE_STRUCT_NLIST_N_UN_N_NAME */
/* #undef NLIST_NAME_UNION */
/* Define to 1 if struct nlist.n_name is a pointer rather than an array. */
/* #undef NLIST_STRUCT */
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
/* #undef NO_MINUS_C_MINUS_O */
/* Name of this package (needed by automake) */
#define PACKAGE "make"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "bug-make@gnu.org"
/* Define to the full name of this package. */
#define PACKAGE_NAME "GNU make"
/* Define to the home page for this package. */
#define PACKAGE_URL "http://www.gnu.org/software/make/"
/* Define to the version of this package. */
#define PACKAGE_VERSION "4.2.1"
/* Define to the character that separates directories in PATH. */
#define PATH_SEPARATOR_CHAR ';'
/* Define as the return type of signal handlers ('int' or 'void'). */
#define RETSIGTYPE void
/* Define to the name of the SCCS 'get' command. */
#define SCCS_GET "echo no sccs get"
/* Define this if the SCCS 'get' command understands the '-G' option. */
/* #undef SCCS_GET_MINUS_G */
/* Define to 1 if the 'setvbuf' function takes the buffering type as its
second argument and the buffer pointer as the third, as on System V before
release 3. */
/* #undef SETVBUF_REVERSED */
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */
/* Define to 1 if the 'S_IS*' macros in do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if struct stat contains a nanoseconds field */
/* #undef ST_MTIM_NSEC */
/* Define to 1 on System V Release 4. */
/* #undef SVR4 */
/* Define to 1 if you can safely include both and . */
#ifdef __MINGW32__
#define TIME_WITH_SYS_TIME 1
#endif
/* Define to 1 for Encore UMAX. */
/* #undef UMAX */
/* Define to 1 for Encore UMAX 4.3 that has instead of
. */
/* #undef UMAX4_3 */
/* Version number of package */
#define VERSION "4.2.1"
/* Define if using the dmalloc debugging malloc package */
/* #undef WITH_DMALLOC */
/* Define to 1 if on AIX 3.
System headers sometimes define this.
We just want to avoid a redefinition error message. */
#ifndef _ALL_SOURCE
/* # undef _ALL_SOURCE */
#endif
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to 1 if on MINIX. */
/* #undef _MINIX */
/* Define to 2 if the system does not provide POSIX.1 features except with
this defined. */
/* #undef _POSIX_1_SOURCE */
/* Define to 1 if you need to in order for 'stat' and other things to work. */
/* #undef _POSIX_SOURCE */
/* Define to empty if 'const' does not conform to ANSI C. */
/* #undef const */
#include
/* Define to 'int' if doesn't define. */
#define gid_t int
/* Define to 'int' if does not define. */
/* GCC 4.x reportedly defines pid_t. */
#ifndef _PID_T_
#ifdef _WIN64
#define pid_t __int64
#else
#define pid_t int
#endif
#endif
/* Define to 'int' if doesn't define. */
#define uid_t int
/* Define uintmax_t if not defined in or . */
#if !HAVE_STDINT_H && !HAVE_INTTYPES_H
#define uintmax_t unsigned long
#endif
/* Define if you have that is POSIX.1 compatible. */
/* #undef HAVE_SYS_WAIT_H */
/* Define to the installation directory for locales. */
#define LOCALEDIR ""
/*
* Refer to README.W32 for info on the following settings
*/
/*
* If you have a shell that does not grok 'sh -c quoted-command-line'
* correctly, you need this setting. Please see below for specific
* shell support.
*/
/*#define BATCH_MODE_ONLY_SHELL 1 */
/*
* Define if you have the Cygnus "Cygwin" GNU Windows32 tool set.
* Do NOT define BATCH_MODE_ONLY_SHELL if you define HAVE_CYGWIN_SHELL
*/
/*#define HAVE_CYGWIN_SHELL 1 */
/*
* Define if you have the MKS tool set or shell. Do NOT define
* BATCH_MODE_ONLY_SHELL if you define HAVE_MKS_SHELL
*/
/*#define HAVE_MKS_SHELL 1 */
/*
* Enforce the mutual exclusivity restriction.
*/
#ifdef HAVE_MKS_SHELL
#undef BATCH_MODE_ONLY_SHELL
#endif
#ifdef HAVE_CYGWIN_SHELL
#undef BATCH_MODE_ONLY_SHELL
#endif
make-4.2.1/Makefile.DOS 0000444 0001750 0001750 00000057243 12726643532 011463 0000000 0000000 # -*-Makefile-*- template for DJGPP
# Makefile.in generated automatically by automake 1.2 from Makefile.am
#
# Copyright (C) 1994-2016 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
SHELL = /bin/sh
srcdir = .
VPATH = $(srcdir)
# $DJDIR is defined automatically by DJGPP to point
# to the root of the DJGPP installation tree.
prefix = /dev/env/DJDIR
exec_prefix = ${prefix}
bindir = /bin
datadir = /share
libdir = /lib
infodir = /info
mandir = /man
includedir = /include
oldincludedir = c:/djgpp/include
DESTDIR = /dev/env/DJDIR
pkgdatadir = $(datadir)/make
pkglibdir = $(libdir)/make
pkgincludedir = $(includedir)/make
localedir = $(datadir)/locale
INSTALL = ${exec_prefix}/bin/ginstall -c
INSTALL_PROGRAM = ${exec_prefix}/bin/ginstall -c
INSTALL_DATA = ${exec_prefix}/bin/ginstall -c -m 644
INSTALL_SCRIPT = ${exec_prefix}/bin/ginstall -c
transform = s,x,x,
# This will fail even if they don't have a Unix-like shell (stock DOS
# shell doesn't know about `false'). The only difference is that they
# get "Error -1" instead of "Error 1".
EXIT_FAIL = false
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
EXEEXT = .exe
OBJEXT = o
AR = ar
AWK = gawk
CC = gcc
CPP = gcc -E
LIBOBJS =
MAKEINFO = ${exec_prefix}/bin/makeinfo
PACKAGE = make
PERL = perl
RANLIB = ranlib
REMOTE = stub
VERSION = 4.2.1
AUTOMAKE_OPTIONS = 1.2
bin_PROGRAMS = make$(EXEEXT)
make_SOURCES = ar.c arscan.c commands.c default.c dir.c expand.c file.c function.c getopt.c getopt1.c guile.c implicit.c job.c load.c loadapi.c main.c misc.c posixos.c output.c read.c remake.c rule.c signame.c strcache.c variable.c version.c vpath.c hash.c remote-$(REMOTE).c
# This should include the glob/ prefix
libglob_a_SOURCES = glob/fnmatch.c glob/glob.c glob/fnmatch.h glob/glob.h
make_LDADD = glob/libglob.a
man_MANS = make.1
INCLUDES = -I$(srcdir)/glob -DLIBDIR=\"$(prefix)$(libdir)\" -DINCLUDEDIR=\"$(prefix)$(includedir)\" -DLOCALEDIR=\"$(prefix)$(localedir)\"
BUILT_SOURCES = README build.sh-in
EXTRA_DIST = $(BUILT_SOURCES) $(man_MANS) README.customs remote-cstms.c make-stds.texi texinfo.tex SCOPTIONS SMakefile Makefile.ami README.Amiga config.ami amiga.c amiga.h NMakefile README.DOS configh.dos configure.bat makefile.com README.W32 build_w32.bat config.h-W32 subproc.bat make.lnk config.h-vms makefile.vms README.VMS vmsdir.h vmsfunctions.c vmsify.c gmk-default.scm gmk-default.h
SUBDIRS = glob doc
mkinstalldirs = ${exec_prefix}/bin/gmkdir -p
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = build.sh
PROGRAMS = $(bin_PROGRAMS)
MAKE_HOST = i386-pc-msdosdjgpp
DEFS = -I. -I$(srcdir) -I.
CPPFLAGS = -DHAVE_CONFIG_H
LDFLAGS =
LIBS =
make_OBJECTS = ar.o arscan.o commands.o default.o dir.o expand.o file.o function.o getopt.o getopt1.o guile.o implicit.o job.o load.o loadapi.o main.o misc.o posixos.o output.o read.o remake.o rule.o signame.o strcache.o variable.o version.o vpath.o hash.o remote-$(REMOTE).o
make_DEPENDENCIES = glob/libglob.a
make_LDFLAGS =
libglob_a_LIBADD =
libglob_a_OBJECTS = fnmatch.o glob.o
noinst_LIBRARIES = glob/libglob.a
CFLAGS = -O2 -g
COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CPPFLAGS) $(CFLAGS)
LINK = $(CC) $(CFLAGS) $(LDFLAGS) -o $@
TEXI2DVI = texi2dvi
TEXINFO_TEX = $(srcdir)/config/texinfo.tex
INFO_DEPS = doc/make.info
DVIS = doc/make.dvi
TEXINFOS = doc/make.texi
noinst_TEXINFOS = doc/fdl.texi doc/make-stds.texi
man1dir = $(mandir)/man1
MANS = $(man_MANS)
NROFF = nroff
DIST_COMMON = README ABOUT-NLS AUTHORS COPYING ChangeLog INSTALL Makefile.am Makefile.in NEWS acconfig.h aclocal.m4 alloca.c build.sh-in config.h-in configure configure.ac getloadavg.c
DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST)
TAR = gtar
GZIP = --best
SOURCES = $(make_SOURCES)
OBJECTS = $(make_OBJECTS)
HEADERS = $(wildcard $(srcdir)/*.h)
default: all
.SUFFIXES:
.SUFFIXES: .c .dvi .info .o .obj .ps .texi .tex .html
mostlyclean-hdr:
clean-hdr:
distclean-hdr:
-rm -f config.h
maintainer-clean-hdr:
mostlyclean-binPROGRAMS:
clean-binPROGRAMS:
-test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS)
distclean-binPROGRAMS:
maintainer-clean-binPROGRAMS:
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do if test -f $$p; then echo " $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p | sed '$(transform)'`"; $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p | sed '$(transform)'`; else :; fi; done
uninstall-binPROGRAMS:
$(NORMAL_UNINSTALL)
list='$(bin_PROGRAMS)'; for p in $$list; do rm -f $(DESTDIR)$(bindir)/`echo $$p|sed '$(transform)'`.exe; done
.c.o:
$(COMPILE) -c $<
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
mostlyclean-compile:
-rm -f *.$(OBJEXT) *$(EXEEXT) make.new core
clean-compile:
distclean-compile:
-rm -f *.tab.c *_tab.c
maintainer-clean-compile:
make$(EXEEXT): $(make_OBJECTS) $(make_DEPENDENCIES)
@command.com /c if exist make del make
@command.com /c if exist make.exe del make.exe
$(LINK) $(make_LDFLAGS) $(make_OBJECTS) $(make_LDADD) $(LIBS)
# Documentation
make.info: make.texi
make.dvi: make.texi
make.ps: make.dvi make.texi
make.html: make.texi
DVIPS = dvips
.texi.info:
@command.com /c if exist make.info* del make.info*
@command.com /c if exist make.i* del make.i*
$(MAKEINFO) -I$(srcdir) --no-split $< -o ./$@
.texi:
@command.com /c if exist make.info* del make.info*
@command.com /c if exist make.i* del make.i*
$(MAKEINFO) -I$(srcdir) --no-split $< -o ./$@
.texi.dvi:
TEXINPUTS="$(srcdir);$$TEXINPUTS" MAKEINFO='$(MAKEINFO) -I $(srcdir)' $(TEXI2DVI) $<
.dvi.ps:
$(DVIPS) $< -o $@
# Other documentation formats
html: html-recursive
.texi.html:
@command.com /c if exist make.html* del make.html*
$(MAKEINFO) --html -I$(srcdir) --no-split $< -o ./$@
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(infodir)
@for file in $(INFO_DEPS); do iifile=`echo $$file | sed "s|doc/||"`; d=$(srcdir); for ifile in `cd $$d && echo $$file`; do if test -f $$d/$$ifile; then echo " $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$iifile"; $(INSTALL_DATA) $$d/$$ifile $(DESTDIR)$(infodir)/$$iifile; else : ; fi; done; done
@$(POST_INSTALL)
@if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then for file in $(INFO_DEPS); do iifile=`echo $$file | sed "s|doc/||"`; echo " install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$iifile"; install-info --info-dir=$(DESTDIR)$(infodir) $(DESTDIR)$(infodir)/$$iifile || :; done; else : ; fi
uninstall-info:
$(PRE_UNINSTALL)
@if $(SHELL) -c 'install-info --version | sed 1q | fgrep -s -v -i debian' >/dev/null 2>&1; then ii=yes; else ii=; fi; for file in $(INFO_DEPS); do test -z $ii || install-info --info-dir=$(DESTDIR)$(infodir) --remove $$file; done
$(NORMAL_UNINSTALL)
for file in $(INFO_DEPS); do (cd $(DESTDIR)$(infodir) && rm -f $$file); done
dist-info: $(INFO_DEPS)
for base in $(INFO_DEPS); do d=$(srcdir); for file in `cd $$d && eval echo $$base*`; do test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; done
mostlyclean-aminfo:
-rm -f $(srcdir)/doc/make.aux $(srcdir)/doc/make.cp $(srcdir)/doc/make.cps $(srcdir)/doc/make.dvi \
$(srcdir)/doc/make.fn $(srcdir)/doc/make.fns $(srcdir)/doc/make.ky $(srcdir)/doc/make.kys \
$(srcdir)/doc/make.ps $(srcdir)/doc/make.log $(srcdir)/doc/make.pg $(srcdir)/doc/make.toc \
$(srcdir)/doc/make.tp $(srcdir)/doc/make.tps $(srcdir)/doc/make.vr $(srcdir)/doc/make.vrs \
$(srcdir)/doc/make.op $(srcdir)/doc/make.tr $(srcdir)/doc/make.cv $(srcdir)/doc/make.cn \
$(srcdir)/doc/make.html
clean-aminfo:
distclean-aminfo:
maintainer-clean-aminfo:
for i in $(INFO_DEPS); do rm -f $$i*; done
install-man1:
$(mkinstalldirs) $(DESTDIR)$(man1dir)
@list='$(man1_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
done
uninstall-man1:
@list='$(man1_MANS)'; \
l2='$(man_MANS)'; for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
rm -f $(DESTDIR)$(man1dir)/$$inst; \
done
install-man: $(MANS)
@$(NORMAL_INSTALL)
$(MAKE) install-man1
uninstall-man:
@$(NORMAL_UNINSTALL)
$(MAKE) uninstall-man1
# Assume that the only thing to do in glob is to build libglob.a,
# but do a sanity check: if $SUBDIRS will ever have more than
# a single directory, yell bloody murder.
all-recursive:
ifeq ($(findstring glob, $(SUBDIRS)), glob)
@command.com /c if not exist glob\\nul md glob
@echo Making all in glob
$(MAKE) -C glob -f ../Makefile INCLUDES='-I$(srcdir) -I$(srcdir)/glob' DEFS='-I.. -I$(srcdir)' VPATH=$(srcdir)/glob libglob.a
endif
$(SUBDIRS):
command.com /c md $@
libglob.a: $(libglob_a_OBJECTS)
command.com /c if exist libglob.a del libglob.a
$(AR) cru libglob.a $(libglob_a_OBJECTS) $(libglob_a_LIBADD)
$(RANLIB) libglob.a
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive check-recursive:
ifeq ($(words $(SUBDIRS)), 2)
@echo Making $(shell echo $@ | sed s/-recursive//) in glob
$(MAKE) -C glob -f ../Makefile $(shell echo $@ | sed s/-recursive//)-am
@echo Making $(shell echo $@ | sed s/-recursive//) in doc
$(MAKE) -C doc -f ../Makefile $(shell echo $@ | sed s/-recursive//)-am
else
@echo FATAL: There is more than two directory in "($(SUBDIRS))"
@$(EXIT_FAIL)
endif
tags-in-glob: $(libglob_a_SOURCES)
etags $(addprefix $(srcdir)/,$^) -o ./glob/TAGS
tags-recursive:
ifeq ($(words $(SUBDIRS)), 2)
$(MAKE) tags-in-glob
else
@echo FATAL: There is more than two directory in "($(SUBDIRS))"
@$(EXIT_FAIL)
endif
tags: TAGS
ID: $(HEADERS) $(SOURCES)
mkid $(srcdir)/$(SOURCES) $(srcdir)/$(libglob_a_SOURCES) ./config.h $(HEADERS)
TAGS: tags-recursive $(HEADERS) $(srcdir)/$(SOURCES) config.h $(TAGS_DEPENDENCIES)
etags -i ./glob/TAGS $(ETAGS_ARGS) $(srcdir)/$(SOURCES) ./config.h $(HEADERS)
mostlyclean-tags:
clean-tags:
distclean-tags:
-rm -f TAGS ID
maintainer-clean-tags:
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
rm -rf $(distdir)
GZIP=$(GZIP) $(TAR) zxf $(distdir).tar.gz
mkdir $(distdir)/=build
mkdir $(distdir)/=inst
dc_install_base=`cd $(distdir)/=inst && pwd`; cd $(distdir)/=build && ../configure --srcdir=.. --prefix=$$dc_install_base && $(MAKE) && $(MAKE) dvi && $(MAKE) check && $(MAKE) install && $(MAKE) installcheck && $(MAKE) dist
rm -rf $(distdir)
@echo "========================"; echo "$(distdir).tar.gz is ready for distribution"; echo "========================"
dist: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
rm -rf $(distdir)
dist-all: distdir
-chmod -R a+r $(distdir)
GZIP=$(GZIP) $(TAR) chozf $(distdir).tar.gz $(distdir)
rm -rf $(distdir)
distdir: $(DISTFILES)
rm -rf $(distdir)
mkdir $(distdir)
-chmod 777 $(distdir)
@for file in $(DISTFILES); do d=$(srcdir); test -f $(distdir)/$$file || ln $$d/$$file $(distdir)/$$file 2> /dev/null || cp -p $$d/$$file $(distdir)/$$file; done; for subdir in $(SUBDIRS); do test -d $(distdir)/$$subdir || mkdir $(distdir)/$$subdir || exit 1; chmod 777 $(distdir)/$$subdir; (cd $$subdir && $(MAKE) top_distdir=../$(top_distdir)/$$subdir distdir=../$(distdir)/$$subdir distdir) || exit 1; done
$(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-info
$(MAKE) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook
info: info-recursive
info-recursive:
ifeq ($(findstring doc, $(SUBDIRS)), doc)
@command.com /c if not exist doc\\nul md doc
@echo Making all in doc
$(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.info
endif
dvi: dvi-recursive
dvi-recursive:
ifeq ($(findstring doc, $(SUBDIRS)), doc)
@command.com /c if not exist doc\\nul md doc
@echo Making all in doc
$(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.dvi
endif
ps: ps-recursive
ps-recursive:
ifeq ($(findstring doc, $(SUBDIRS)), doc)
@command.com /c if not exist doc\\nul md doc
@echo Making all in doc
$(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.ps
endif
html-recursive:
ifeq ($(findstring doc, $(SUBDIRS)), doc)
@command.com /c if not exist doc\\nul md doc
@echo Making all in doc
$(MAKE) -C doc -f ../Makefile VPATH=$(srcdir)/doc make.html
endif
check: all-am check-recursive check-local
@:
installcheck: installcheck-recursive
all-recursive-am: config.h
$(MAKE) all-recursive
all-am: Makefile $(PROGRAMS) config.h info
install-exec-am: install-binPROGRAMS
install-data-am: install-info-am
uninstall-am: uninstall-binPROGRAMS uninstall-info
install-exec: install-exec-recursive install-exec-am
@$(NORMAL_INSTALL)
install-data: install-data-recursive install-data-am
@$(NORMAL_INSTALL)
install-recursive uninstall-recursive:
@:
install: install-recursive install-exec-am install-data-am
@:
uninstall: uninstall-recursive uninstall-am
all: all-recursive-am all-am
install-strip:
$(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' INSTALL_SCRIPT='$(INSTALL_PROGRAM)' install
installdirs: installdirs-recursive
$(mkinstalldirs) $(bindir) $(infodir)
mostlyclean-generic:
-test -z "$(MOSTLYCLEANFILES)" || rm -f $(MOSTLYCLEANFILES)
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-rm -f Makefile $(DISTCLEANFILES)
-rm -f config.cache config.log stamp-h stamp-h[0-9]*
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
-test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
mostlyclean-am: mostlyclean-hdr mostlyclean-binPROGRAMS mostlyclean-compile mostlyclean-aminfo mostlyclean-tags mostlyclean-generic
clean-am: clean-hdr clean-binPROGRAMS clean-compile clean-aminfo clean-tags clean-generic mostlyclean-am
distclean-am: distclean-hdr distclean-binPROGRAMS distclean-compile distclean-aminfo distclean-tags distclean-generic clean-am
maintainer-clean-am: maintainer-clean-hdr maintainer-clean-binPROGRAMS maintainer-clean-compile maintainer-clean-aminfo maintainer-clean-tags maintainer-clean-generic distclean-am
mostlyclean: mostlyclean-recursive mostlyclean-am
clean: clean-noinstLIBRARIES clean-recursive clean-am
distclean: distclean-recursive distclean-am
rm -f config.status
maintainer-clean: maintainer-clean-recursive maintainer-clean-am
@echo "This command is intended for maintainers to use;"
@echo "it deletes files that may require special tools to rebuild."
rm -f config.status
.PHONY: default mostlyclean-hdr distclean-hdr clean-hdr \
maintainer-clean-hdr mostlyclean-binPROGRAMS distclean-binPROGRAMS \
clean-binPROGRAMS maintainer-clean-binPROGRAMS uninstall-binPROGRAMS \
install-binPROGRAMS mostlyclean-compile distclean-compile clean-compile \
maintainer-clean-compile install-info-am uninstall-info \
mostlyclean-aminfo distclean-aminfo clean-aminfo \
maintainer-clean-aminfo install-data-recursive uninstall-data-recursive \
install-exec-recursive uninstall-exec-recursive installdirs-recursive \
uninstalldirs-recursive all-recursive check-recursive check-am \
installcheck-recursive info-recursive dvi-recursive \
mostlyclean-recursive distclean-recursive clean-recursive \
maintainer-clean-recursive tags tags-recursive mostlyclean-tags \
distclean-tags clean-tags maintainer-clean-tags distdir \
mostlyclean-depend distclean-depend clean-depend \
maintainer-clean-depend info dvi check-local installcheck \
all-recursive-am all-am install-exec-am install-data-am uninstall-am \
install-exec install-data install uninstall all installdirs \
mostlyclean-generic distclean-generic clean-generic \
maintainer-clean-generic clean mostlyclean distclean maintainer-clean \
html
# --------------- Local DIST Section
# Install the w32 subdirectory
#
dist-hook:
(cd $(srcdir); \
w32=`find w32 -follow \( -name .git -prune \) -o -type f -print`; \
tar chf - $$w32) \
| (cd $(distdir); tar xfBp -)
# --------------- Local CHECK Section
# Note: check-loadavg is NOT a prerequisite of check-local, since
# there's no uptime utility, and the test it does doesn't make sense
# on MSDOS anyway.
check-local: check-shell check-regression
@banner=" Regression PASSED: GNU Make $(VERSION) ($(MAKE_HOST)) built with $(CC) "; \
dashes=`echo "$$banner" | sed s/./=/g`; \
echo; \
echo "$$dashes"; \
echo "$$banner"; \
echo "$$dashes"; \
echo
.PHONY: check-loadavg check-shell check-regression
# > check-shell
#
# check-shell is designed to fail if they don't have a Unixy shell
# installed. The test suite requires such a shell.
check-shell:
@echo If Make says Error -1, you do not have Unix-style shell installed
@foo=bar.exe :
# > check-loadavg
#
loadavg: loadavg.c config.h
@rm -f loadavg
$(LINK) -DTEST $(make_LDFLAGS) loadavg.c $(LIBS)
# We copy getloadavg.c into a different file rather than compiling it
# directly because some compilers clobber getloadavg.o in the process.
loadavg.c: getloadavg.c
ln $(srcdir)/getloadavg.c loadavg.c || \
cp $(srcdir)/getloadavg.c loadavg.c
check-loadavg: loadavg
@echo The system uptime program believes the load average to be:
-uptime
@echo The GNU load average checking code believes:
-./loadavg
# > check-regression
#
# Look for the make test suite, and run it if found. Look in MAKE_TEST if
# specified, or else in the srcdir or the distdir, their parents, and _their_
# parents.
#
check-regression:
@if test -f "$(srcdir)/tests/run_make_tests"; then \
if $(PERL) -v >/dev/null 2>&1; then \
case `cd $(srcdir); pwd` in `pwd`) : ;; \
*) test -d tests || mkdir tests; \
for f in run_make_tests run_make_tests.pl test_driver.pl scripts; do \
rm -rf tests/$$f; cp -pr $(srcdir)/tests/$$f tests; \
done ;; \
esac; \
echo "cd tests && $(PERL) ./run_make_tests.pl -make ../make.exe $(MAKETESTFLAGS)"; \
cd tests && $(PERL) ./run_make_tests.pl -make ../make.exe $(MAKETESTFLAGS); \
else \
echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \
fi; \
else \
echo "Can't find the GNU Make test suite ($(srcdir)/tests)."; \
fi
# --------------- Maintainer's Section
# Note this requires GNU make. Not to worry, since it will only be included
# in the Makefile if we're in the maintainer's environment.
#include $(srcdir)/maintMakefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
# --------------- DEPENDENCIES
# --------------- DEPENDENCIES
#
# .deps/alloca.Po
# dummy
# .deps/ar.Po
ar.o: ar.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h
# .deps/arscan.Po
arscan.o: arscan.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
# .deps/commands.Po
commands.o: commands.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h variable.h job.h output.h \
commands.h
# .deps/default.Po
default.o: default.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h variable.h rule.h dep.h job.h \
output.h \
commands.h
# .deps/dir.Po
dir.o: dir.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
hash.h \
filedef.h dep.h \
# .deps/expand.Po
expand.o: expand.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h job.h output.h \
commands.h variable.h rule.h
# .deps/file.Po
file.o: file.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h job.h output.h \
commands.h variable.h \
debug.h
# .deps/function.Po
function.o: function.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h variable.h dep.h job.h output.h \
commands.h debug.h
# .deps/getloadavg.Po
# dummy
# .deps/getopt.Po
getopt.o: getopt.c config.h \
# .deps/getopt1.Po
getopt1.o: getopt1.c config.h getopt.h \
# .deps/guile.Po
guile.o: guile.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
debug.h filedef.h hash.h dep.h variable.h \
gmk-default.h
# .deps/hash.Po
hash.o: hash.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
hash.h
# .deps/implicit.Po
implicit.o: implicit.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h rule.h dep.h debug.h variable.h job.h output.h \
commands.h
# .deps/job.Po
job.o: job.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
job.h output.h \
debug.h filedef.h hash.h \
commands.h variable.h os.h
# .deps/load.Po
load.o: load.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
debug.h \
filedef.h hash.h variable.h
# .deps/loadapi.Po
loadapi.o: loadapi.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h variable.h dep.h
# .deps/loadavg-getloadavg.Po
# dummy
# .deps/main.Po
main.o: main.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
os.h \
filedef.h hash.h dep.h variable.h job.h output.h \
commands.h rule.h debug.h \
getopt.h
# .deps/misc.Po
misc.o: misc.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h debug.h \
# .deps/output.Po
output.o: output.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
job.h \
output.h \
# .deps/posixos.Po
posixos.o: posixos.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
debug.h job.h output.h os.h
# .deps/read.Po
read.o: read.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h job.h output.h \
commands.h variable.h rule.h \
debug.h
# .deps/remake.Po
remake.o: remake.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h job.h output.h \
commands.h dep.h variable.h \
debug.h
# .deps/remote-cstms.Po
# dummy
# .deps/remote-stub.Po
remote-stub.o: remote-stub.c makeint.h \
config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h job.h output.h \
commands.h
# .deps/rule.Po
rule.o: rule.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h job.h output.h \
commands.h variable.h rule.h
# .deps/signame.Po
signame.o: signame.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
# .deps/strcache.Po
strcache.o: strcache.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
hash.h
# .deps/variable.Po
variable.o: variable.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h dep.h job.h output.h \
commands.h variable.h rule.h
# .deps/version.Po
version.o: version.c config.h
# .deps/vmsjobs.Po
# dummy
# .deps/vpath.Po
vpath.o: vpath.c makeint.h config.h \
gnumake.h \
getopt.h \
gettext.h \
filedef.h hash.h variable.h
make-4.2.1/build_w32.bat 0000755 0001750 0001750 00000016767 12720141451 011657 0000000 0000000 @echo off
rem Copyright (C) 1996-2016 Free Software Foundation, Inc.
rem This file is part of GNU Make.
rem
rem GNU Make is free software; you can redistribute it and/or modify it under
rem the terms of the GNU General Public License as published by the Free
rem Software Foundation; either version 3 of the License, or (at your option)
rem any later version.
rem
rem GNU Make is distributed in the hope that it will be useful, but WITHOUT
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for.
rem more details.
rem
rem You should have received a copy of the GNU General Public License along
rem with this program. If not, see .
call :Reset
if "%1" == "-h" goto Usage
if "%1" == "--help" goto Usage
set MAKE=gnumake
set GUILE=Y
set COMPILER=msvc
:ParseSW
if "%1" == "--debug" goto SetDebug
if "%1" == "--without-guile" goto NoGuile
if "%1" == "gcc" goto SetCC
if "%1" == "" goto DoneSW
:SetDebug
set DEBUG=Y
shift
goto ParseSW
:NoGuile
set GUILE=N
echo Building without Guile
shift
goto ParseSW
:SetCC
set COMPILER=gcc
echo Building with GCC
shift
goto ParseSW
rem Build with Guile is supported only on NT and later versions
:DoneSW
echo.
echo Creating GNU Make for Windows 9X/NT/2K/XP/Vista/7/8
if "%DEBUG%" == "Y" echo Building without compiler optimizations
if "%COMPILER%" == "gcc" goto GccBuild
set OUTDIR=.\WinRel
set "OPTS=/O2 /D NDEBUG"
set LINKOPTS=
if "%DEBUG%" == "Y" set OUTDIR=.\WinDebug
if "%DEBUG%" == "Y" set "OPTS=/Zi /Od /D _DEBUG"
if "%DEBUG%" == "Y" set LINKOPTS=/DEBUG
call :Build
goto Done
:GccBuild
set OUTDIR=.\GccRel
set OPTS=-O2
if "%DEBUG%" == "Y" set OPTS=-O0
if "%DEBUG%" == "Y" set OUTDIR=.\GccDebug
call :Build
goto Done
:Done
call :Reset
goto :EOF
:Build
:: Clean the directory if it exists
if exist %OUTDIR%\nul rmdir /S /Q %OUTDIR%
:: Recreate it
mkdir %OUTDIR%
mkdir %OUTDIR%\glob
mkdir %OUTDIR%\w32
mkdir %OUTDIR%\w32\compat
mkdir %OUTDIR%\w32\subproc
if "%GUILE%" == "Y" call :ChkGuile
echo.
echo Compiling %OUTDIR% version
if exist config.h.W32.template call :ConfigSCM
copy config.h.W32 %OUTDIR%\config.h
call :Compile ar
call :Compile arscan
call :Compile commands
call :Compile default
call :Compile dir
call :Compile expand
call :Compile file
call :Compile function
call :Compile getloadavg
call :Compile getopt
call :Compile getopt1
call :Compile glob\fnmatch
call :Compile glob\glob
call :Compile guile GUILE
call :Compile hash
call :Compile implicit
call :Compile job
call :Compile load
call :Compile loadapi
call :Compile main GUILE
call :Compile misc
call :Compile output
call :Compile read
call :Compile remake
call :Compile remote-stub
call :Compile rule
call :Compile signame
call :Compile strcache
call :Compile variable
call :Compile version
call :Compile vpath
call :Compile w32\compat\posixfcn
call :Compile w32\pathstuff
call :Compile w32\subproc\misc
call :Compile w32\subproc\sub_proc
call :Compile w32\subproc\w32err
call :Compile w32\w32os
if not "%COMPILER%" == "gcc" call :Compile w32\compat\dirent
call :Link
echo.
if not exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build FAILED!
if exist %OUTDIR%\%MAKE%.exe echo %OUTDIR% build succeeded.
goto :EOF
:Compile
set EXTRAS=
if "%2" == "GUILE" set "EXTRAS=%GUILECFLAGS%"
if "%COMPILER%" == "gcc" goto GccCompile
:: MSVC Compile
echo on
cl.exe /nologo /MT /W4 /EHsc %OPTS% /I %OUTDIR% /I . /I glob /I w32/include /D WINDOWS32 /D WIN32 /D _CONSOLE /D HAVE_CONFIG_H /FR%OUTDIR% /Fp%OUTDIR%\%MAKE%.pch /Fo%OUTDIR%\%1.obj /Fd%OUTDIR%\%MAKE%.pdb %EXTRAS% /c %1.c
@echo off
echo %OUTDIR%\%1.obj >>%OUTDIR%\link.sc
goto :EOF
:GccCompile
:: GCC Compile
echo on
gcc -mthreads -Wall -std=gnu99 -gdwarf-2 -g3 %OPTS% -I%OUTDIR% -I. -I./glob -I./w32/include -DWINDOWS32 -DHAVE_CONFIG_H %EXTRAS% -o %OUTDIR%\%1.o -c %1.c
@echo off
goto :EOF
:Link
echo Linking %OUTDIR%/%MAKE%.exe
if "%COMPILER%" == "gcc" goto GccLink
:: MSVC Link
echo %GUILELIBS% kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib >>%OUTDIR%\link.sc
echo on
link.exe /NOLOGO /SUBSYSTEM:console /PDB:%OUTDIR%\%MAKE%.pdb %LINKOPTS% /OUT:%OUTDIR%\%MAKE%.exe @%OUTDIR%\link.sc
@echo off
goto :EOF
:GccLink
:: GCC Link
echo on
gcc -mthreads -gdwarf-2 -g3 -o %OUTDIR%\%MAKE%.exe %OUTDIR%\variable.o %OUTDIR%\rule.o %OUTDIR%\remote-stub.o %OUTDIR%\commands.o %OUTDIR%\file.o %OUTDIR%\getloadavg.o %OUTDIR%\default.o %OUTDIR%\signame.o %OUTDIR%\expand.o %OUTDIR%\dir.o %OUTDIR%\main.o %OUTDIR%\getopt1.o %OUTDIR%\guile.o %OUTDIR%\job.o %OUTDIR%\output.o %OUTDIR%\read.o %OUTDIR%\version.o %OUTDIR%\getopt.o %OUTDIR%\arscan.o %OUTDIR%\remake.o %OUTDIR%\misc.o %OUTDIR%\hash.o %OUTDIR%\strcache.o %OUTDIR%\ar.o %OUTDIR%\function.o %OUTDIR%\vpath.o %OUTDIR%\implicit.o %OUTDIR%\loadapi.o %OUTDIR%\load.o %OUTDIR%\glob\glob.o %OUTDIR%\glob\fnmatch.o %OUTDIR%\w32\pathstuff.o %OUTDIR%\w32\compat\posixfcn.o %OUTDIR%\w32\w32os.o %OUTDIR%\w32\subproc\misc.o %OUTDIR%\w32\subproc\sub_proc.o %OUTDIR%\w32\subproc\w32err.o %GUILELIBS% -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lole32 -loleaut32 -luuid -lodbc32 -lodbccp32 -Wl,--out-implib=%OUTDIR%\libgnumake-1.dll.a
@echo off
goto :EOF
:ConfigSCM
echo Generating config from SCM templates
sed -n "s/^AC_INIT(\[GNU make\],\[\([^]]\+\)\].*/s,%%VERSION%%,\1,g/p" configure.ac > %OUTDIR%\config.h.W32.sed
echo s,%%PACKAGE%%,make,g >> %OUTDIR%\config.h.W32.sed
sed -f %OUTDIR%\config.h.W32.sed config.h.W32.template > config.h.W32
echo static const char *const GUILE_module_defn = ^" \> gmk-default.h
sed -e "s/;.*//" -e "/^[ \t]*$/d" -e "s/\"/\\\\\"/g" -e "s/$/ \\\/" gmk-default.scm >> gmk-default.h
echo ^";>> gmk-default.h
goto :EOF
:ChkGuile
if not "%OS%" == "Windows_NT" goto NoGuile
pkg-config --help > %OUTDIR%\guile.tmp 2> NUL
if ERRORLEVEL 1 goto NoPkgCfg
echo Checking for Guile 2.0
if not "%COMPILER%" == "gcc" set PKGMSC=--msvc-syntax
pkg-config --cflags --short-errors "guile-2.0" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
pkg-config --libs --static --short-errors %PKGMSC% "guile-2.0" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
if not "%GUILECFLAGS%" == "" goto GuileDone
echo Checking for Guile 1.8
pkg-config --cflags --short-errors "guile-1.8" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILECFLAGS= < %OUTDIR%\guile.tmp
pkg-config --libs --static --short-errors %PKGMSC% "guile-1.8" > %OUTDIR%\guile.tmp
if not ERRORLEVEL 1 set /P GUILELIBS= < %OUTDIR%\guile.tmp
if not "%GUILECFLAGS%" == "" goto GuileDone
echo No Guile found, building without Guile
goto GuileDone
:NoPkgCfg
echo pkg-config not found, building without Guile
:GuileDone
if "%GUILECFLAGS%" == "" goto :EOF
echo Guile found, building with Guile
set "GUILECFLAGS=%GUILECFLAGS% -DHAVE_GUILE"
goto :EOF
:Usage
echo Usage: %0 [options] [gcc]
echo Options:
echo. --debug For GCC only, make a debug build
echo. (MSVC build always makes both debug and release)
echo. --without-guile Do not compile Guile support even if found
echo. --help Display these instructions and exit
goto :EOF
:Reset
set COMPILER=
set DEBUG=
set GUILE=
set GUILECFLAGS=
set GUILELIBS=
set LINKOPTS=
set MAKE=
set NOGUILE=
set OPTS=
set OUTDIR=
set PKGMSC=
goto :EOF
make-4.2.1/make.lnk 0000644 0001750 0001750 00000000564 12664631374 011020 0000000 0000000 FROM LIB:cres.o "commands.o"+"job.o"+"dir.o"+"file.o"+"misc.o"+"main.o"+"read.o"+"remake.o"+"rule.o"+"implicit.o"+"default.o"+"variable.o"+"expand.o"+"function.o"+"vpath.o"+"version.o"+"ar.o"+"arscan.o"+"signame.o"+"remote-stub.o"+"getopt.o"+"getopt1.o"+"alloca.o"+"amiga.o"+"hash.o"+"strcache.o"+"output.o"
TO "make.new"
LIB glob/glob.lib LIB:sc.lib LIB:amiga.lib
QUIET
make-4.2.1/vmsify.c 0000644 0001750 0001750 00000044305 12664631374 011057 0000000 0000000 /* vmsify.c -- Module for vms <-> unix file name conversion
Copyright (C) 1996-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* Written by Klaus Kämpf (kkaempf@progis.de)
of proGIS Software, Aachen, Germany */
#include
#include
#include
#include "makeint.h"
#if VMS
#include
#include
#include
#include
#include
#include
#include
#include
/* Initialize a string descriptor (struct dsc$descriptor_s) for an
arbitrary string. ADDR is a pointer to the first character
of the string, and LEN is the length of the string. */
#define INIT_DSC_S(dsc, addr, len) do { \
(dsc).dsc$b_dtype = DSC$K_DTYPE_T; \
(dsc).dsc$b_class = DSC$K_CLASS_S; \
(dsc).dsc$w_length = (len); \
(dsc).dsc$a_pointer = (addr); \
} while (0)
/* Initialize a string descriptor (struct dsc$descriptor_s) for a
NUL-terminated string. S is a pointer to the string; the length
is determined by calling strlen(). */
#define INIT_DSC_CSTRING(dsc, s) INIT_DSC_S(dsc, s, strlen(s))
#endif
/*
copy 'from' to 'to' up to but not including 'upto'
return 0 if eos on from
return 1 if upto found
return 'to' at last char + 1
return 'from' at match + 1 or eos if no match
if as_dir == 1, change all '.' to '_'
else change all '.' but the last to '_'
*/
static int
copyto (char **to, const char **from, char upto, int as_dir)
{
const char *s;
s = strrchr (*from, '.');
while (**from)
{
if (**from == upto)
{
do
{
(*from)++;
}
while (**from == upto);
return 1;
}
if (**from == '.')
{
if ((as_dir == 1)
|| (*from != s))
**to = '_';
else
**to = '.';
}
else
{
#ifdef HAVE_CASE_INSENSITIVE_FS
if (isupper ((unsigned char)**from))
**to = tolower ((unsigned char)**from);
else
#endif
**to = **from;
}
(*to)++;
(*from)++;
}
return 0;
}
/*
get translation of logical name
*/
static char *
trnlog (const char *name)
{
int stat;
static char reslt[1024];
$DESCRIPTOR (reslt_dsc, reslt);
short resltlen;
struct dsc$descriptor_s name_dsc;
char *s;
/*
* the string isn't changed, but there is no string descriptor with
* "const char *dsc$a_pointer"
*/
INIT_DSC_CSTRING (name_dsc, (char *)name);
stat = lib$sys_trnlog (&name_dsc, &resltlen, &reslt_dsc);
if ((stat&1) == 0)
{
return "";
}
if (stat == SS$_NOTRAN)
{
return "";
}
reslt[resltlen] = '\0';
s = xmalloc (resltlen+1);
strcpy (s, reslt);
return s;
}
static char *
showall (char *s)
{
static char t[512];
char *pt;
pt = t;
if (strchr (s, '\\') == 0)
return s;
while (*s)
{
if (*s == '\\')
{
*pt++ = *s;
}
*pt++ = *s++;
}
return pt;
}
enum namestate { N_START, N_DEVICE, N_OPEN, N_DOT, N_CLOSED, N_DONE };
/*
convert unix style name to vms style
type = 0 -> name is a full name (directory and filename part)
type = 1 -> name is a directory
type = 2 -> name is a filename without directory
The following conversions are applied
(0) (1) (2)
input full name dir name file name
1 ./ [] .dir
2 ../ .dir
3 // : :[000000] :000000.dir
4 //a a: a: a:
5 //a/ a: a: a:000000.dir
9 / [000000] [000000] 000000.dir
10 /a [000000]a [a] [000000]a
11 /a/ [a] [a] [000000]a.dir
12 /a/b [a]b [a.b] [a]b
13 /a/b/ [a.b] [a.b] [a]b.dir
14 /a/b/c [a.b]c [a.b.c] [a.b]c
15 /a/b/c/ [a.b.c] [a.b.c] [a.b]c.dir
16 a a [.a] a
17 a/ [.a] [.a] a.dir
18 a/b [.a]b [.a.b] [.a]b
19 a/b/ [.a.b] [.a.b] [.a]b.dir
20 a/b/c [.a.b]c [.a.b.c] [.a.b]c
21 a/b/c/ [.a.b.c] [.a.b.c] [.a.b]c.dir
22 a.b.c a_b.c [.a_b_c] a_b_c.dir
23 [x][y]z [x.y]z [x.y]z [x.y]z
24 [x][.y]z [x.y]z [x.y]z [x.y]z
25 filenames with '$' are left unchanged if they contain no '/'
25 filenames with ':' are left unchanged
26 filenames with a single pair of '[' ']' are left unchanged
The input string is not written to. The result is also const because
it's a static buffer; we don't want to change it.
*/
const char *
vmsify (const char *name, int type)
{
/* max 255 device
max 39 directory
max 39 filename
max 39 filetype
max 5 version
*/
/* todo: VMSMAXPATHLEN is defined for ODS2 names: it needs to be adjusted. */
#define VMSMAXPATHLEN 512
enum namestate nstate;
static char vmsname[VMSMAXPATHLEN+1];
const char *fptr;
const char *t;
char *vptr;
int as_dir;
int count;
const char *s;
const char *s1;
const char *s2;
if (name == 0)
return 0;
fptr = name;
vptr = vmsname;
nstate = N_START;
/* case 25a */
t = strpbrk (name, "$:");
if (t != 0)
{
// const char *s1;
// const char *s2;
if (type == 1)
{
s1 = strchr (t+1, '[');
s2 = strchr (t+1, ']');
}
if (*t == '$')
{
if (strchr (name, '/') == 0)
{
strcpy (vmsname, name);
if ((type == 1) && (s1 != 0) && (s2 == 0))
strcat (vmsname, "]");
return vmsname;
}
}
else
{
strcpy (vmsname, name);
if ((type == 1) && (s1 != 0) && (s2 == 0))
strcat (vmsname, "]");
return vmsname;
}
}
/* case 26 */
t = strchr (name, '[');
if (t != 0)
{
// const char *s;
// const char *s1 = strchr (t+1, '[');
s1 = strchr (t+1, '[');
if (s1 == 0)
{
strcpy (vmsname, name);
if ((type == 1) && (strchr (t+1, ']') == 0))
strcat (vmsname, "]");
return vmsname;
}
s1--;
if (*s1 != ']')
{
strcpy (vmsname, name);
return vmsname; /* not ][, keep unchanged */
}
/* we have ][ */
s = name;
/* s -> starting char
s1 -> ending ']' */
do
{
strncpy (vptr, s, s1-s); /* copy up to but not including ']' */
vptr += s1-s;
if (*s1 == 0)
break;
s = s1 + 1; /* s -> char behind ']' */
if (*s != '[') /* was '][' ? */
break; /* no, last ] found, exit */
s++;
if (*s != '.')
*vptr++ = '.';
s1 = strchr (s, ']');
if (s1 == 0) /* no closing ] */
s1 = s + strlen (s);
}
while (1);
*vptr++ = ']';
fptr = s;
}
else /* no [ in name */
{
int state = 0;
int rooted = 1; /* flag if logical is rooted, else insert [000000] */
do
{
switch (state)
{
case 0: /* start of loop */
if (*fptr == '/')
{
fptr++;
state = 1;
}
else if (*fptr == '.')
{
fptr++;
state = 10;
}
else
state = 2;
break;
case 1: /* '/' at start */
if (*fptr == '/')
{
fptr++;
state = 3;
}
else
state = 4;
break;
case 2: /* no '/' at start */
{
const char *s = strchr (fptr, '/');
if (s == 0) /* no '/' (16) */
{
if (type == 1)
{
strcpy (vptr, "[.");
vptr += 2;
}
copyto (&vptr, &fptr, 0, (type==1));
if (type == 1)
*vptr++ = ']';
state = -1;
}
else /* found '/' (17..21) */
{
if ((type == 2)
&& (*(s+1) == 0)) /* 17(2) */
{
copyto (&vptr, &fptr, '/', 1);
state = 7;
}
else
{
strcpy (vptr, "[.");
vptr += 2;
copyto (&vptr, &fptr, '/', 1);
nstate = N_OPEN;
state = 9;
}
}
break;
}
case 3: /* '//' at start */
{
// const char *s;
// const char *s1;
char *vp;
while (*fptr == '/') /* collapse all '/' */
fptr++;
if (*fptr == 0) /* just // */
{
char cwdbuf[VMSMAXPATHLEN+1];
s1 = getcwd(cwdbuf, VMSMAXPATHLEN);
if (s1 == 0)
{
vmsname[0] = '\0';
return vmsname; /* FIXME, err getcwd */
}
s = strchr (s1, ':');
if (s == 0)
{
vmsname[0] = '\0';
return vmsname; /* FIXME, err no device */
}
strncpy (vptr, s1, s-s1+1);
vptr += s-s1+1;
state = -1;
break;
}
s = vptr;
if (copyto (&vptr, &fptr, '/', 1) == 0) /* copy device part */
{
*vptr++ = ':';
state = -1;
break;
}
*vptr = ':';
nstate = N_DEVICE;
if (*fptr == 0) /* just '//a/' */
{
strcpy (vptr+1, "[000000]");
vptr += 9;
state = -1;
break;
}
*vptr = 0;
/* check logical for [000000] insertion */
vp = trnlog (s);
if (*vp != '\0')
{ /* found translation */
for (;;) /* loop over all nested logicals */
{
char *vp2 = vp + strlen (vp) - 1;
if (*vp2 == ':') /* translation ends in ':' */
{
vp2 = trnlog (vp);
free (vp);
if (*vp2 == 0)
{
rooted = 0;
break;
}
vp = vp2;
continue; /* next iteration */
}
if (*vp2 == ']') /* translation ends in ']' */
{
if (*(vp2-1) == '.') /* ends in '.]' */
{
if (strncmp (fptr, "000000", 6) != 0)
rooted = 0;
}
else
{
strcpy (vmsname, s1);
vp = strchr (vmsname, ']');
*vp = '.';
nstate = N_DOT;
vptr = vp;
}
}
break;
}
free (vp);
}
else
rooted = 0;
if (*vptr == 0)
{
nstate = N_DEVICE;
*vptr++ = ':';
}
else
vptr++;
if (rooted == 0)
{
nstate = N_DOT;
strcpy (vptr, "[000000.");
vptr += 8;
vp = vptr-1;
}
else
vp = 0;
/* vp-> '.' after 000000 or NULL */
s = strchr (fptr, '/');
if (s == 0)
{ /* no next '/' */
if (*(vptr-1) == '.')
*(vptr-1) = ']';
else if (rooted == 0)
*vptr++ = ']';
copyto (&vptr, &fptr, 0, (type == 1));
state = -1;
break;
}
else
{
while (*(s+1) == '/') /* skip multiple '/' */
s++;
}
if ((rooted != 0)
&& (*(vptr-1) != '.'))
{
*vptr++ = '[';
nstate = N_DOT;
}
else
if ((nstate == N_DOT)
&& (vp != 0)
&& (*(s+1) == 0))
{
if (type == 2)
{
*vp = ']';
nstate = N_CLOSED;
}
}
state = 9;
break;
}
case 4: /* single '/' at start (9..15) */
if (*fptr == 0)
state = 5;
else
state = 6;
break;
case 5: /* just '/' at start (9) */
if (type != 2)
{
*vptr++ = '[';
nstate = N_OPEN;
}
strcpy (vptr, "000000");
vptr += 6;
if (type == 2)
state = 7;
else
state = 8;
break;
case 6: /* chars following '/' at start 10..15 */
{
const char *s;
*vptr++ = '[';
nstate = N_OPEN;
s = strchr (fptr, '/');
if (s == 0) /* 10 */
{
if (type != 1)
{
strcpy (vptr, "000000]");
vptr += 7;
}
copyto (&vptr, &fptr, 0, (type == 1));
if (type == 1)
{
*vptr++ = ']';
}
state = -1;
}
else /* 11..15 */
{
if ( (type == 2)
&& (*(s+1) == 0)) /* 11(2) */
{
strcpy (vptr, "000000]");
nstate = N_CLOSED;
vptr += 7;
}
copyto (&vptr, &fptr, '/', (*(vptr-1) != ']'));
state = 9;
}
break;
}
case 7: /* add '.dir' and exit */
if ((nstate == N_OPEN)
|| (nstate == N_DOT))
{
char *vp = vptr-1;
while (vp > vmsname)
{
if (*vp == ']')
{
break;
}
if (*vp == '.')
{
*vp = ']';
break;
}
vp--;
}
}
strcpy (vptr, ".dir");
vptr += 4;
state = -1;
break;
case 8: /* add ']' and exit */
*vptr++ = ']';
state = -1;
break;
case 9: /* 17..21, fptr -> 1st '/' + 1 */
{
const char *s;
if (*fptr == 0)
{
if (type == 2)
{
state = 7;
}
else
state = 8;
break;
}
s = strchr (fptr, '/');
if (s == 0)
{
if (type != 1)
{
if (nstate == N_OPEN)
{
*vptr++ = ']';
nstate = N_CLOSED;
}
as_dir = 0;
}
else
{
if (nstate == N_OPEN)
{
*vptr++ = '.';
nstate = N_DOT;
}
as_dir = 1;
}
}
else
{
while (*(s+1) == '/')
s++;
if ( (type == 2)
&& (*(s+1) == 0)) /* 19(2), 21(2)*/
{
if (nstate != N_CLOSED)
{
*vptr++ = ']';
nstate = N_CLOSED;
}
as_dir = 1;
}
else
{
if (nstate == N_OPEN)
{
*vptr++ = '.';
nstate = N_DOT;
}
as_dir = 1;
}
}
if ( (*fptr == '.') /* check for '..' or '../' */
&& (*(fptr+1) == '.')
&& ((*(fptr+2) == '/')
|| (*(fptr+2) == 0)) )
{
char *vp;
fptr += 2;
if (*fptr == '/')
{
do
{
fptr++;
}
while (*fptr == '/');
}
else if (*fptr == 0)
type = 1;
vptr--; /* vptr -> '.' or ']' */
vp = vptr;
for (;;)
{
vp--;
if (*vp == '.') /* one back */
{
vptr = vp;
nstate = N_OPEN;
break;
}
if (*vp == '[') /* top level reached */
{
if (*fptr == 0)
{
strcpy (vp, "[000000]");
vptr = vp + 8;
nstate = N_CLOSED;
s = 0;
break;
}
else
{
vptr = vp+1;
nstate = N_OPEN;
break;
}
}
}
}
else
{
copyto (&vptr, &fptr, '/', as_dir);
if (nstate == N_DOT)
nstate = N_OPEN;
}
if (s == 0)
{ /* 18,20 */
if (type == 1)
*vptr++ = ']';
state = -1;
}
else
{
if (*(s+1) == 0)
{
if (type == 2) /* 19,21 */
{
state = 7;
}
else
{
*vptr++ = ']';
state = -1;
}
}
}
break;
}
case 10: /* 1,2 first is '.' */
if (*fptr == '.')
{
fptr++;
state = 11;
}
else
state = 12;
break;
case 11: /* 2, '..' at start */
count = 1;
if (*fptr != 0)
{
if (*fptr != '/') /* got ..xxx */
{
strcpy (vmsname, name);
return vmsname;
}
do /* got ../ */
{
fptr++;
while (*fptr == '/') fptr++;
if (*fptr != '.')
break;
if (*(fptr+1) != '.')
break;
fptr += 2;
if ((*fptr == 0)
|| (*fptr == '/'))
count++;
}
while (*fptr == '/');
}
{ /* got '..' or '../' */
char *vp;
char cwdbuf[VMSMAXPATHLEN+1];
vp = getcwd(cwdbuf, VMSMAXPATHLEN);
if (vp == 0)
{
vmsname[0] = '\0';
return vmsname; /* FIXME, err getcwd */
}
strcpy (vptr, vp);
vp = strchr (vptr, ']');
if (vp != 0)
{
nstate = N_OPEN;
while (vp > vptr)
{
vp--;
if (*vp == '[')
{
vp++;
strcpy (vp, "000000]");
state = -1;
break;
}
else if (*vp == '.')
{
if (--count == 0)
{
if (*fptr == 0) /* had '..' or '../' */
{
*vp++ = ']';
state = -1;
}
else /* had '../xxx' */
{
state = 9;
}
*vp = '\0';
break;
}
}
}
}
vptr += strlen (vptr);
}
break;
case 12: /* 1, '.' at start */
if (*fptr != 0)
{
if (*fptr != '/')
{
strcpy (vmsname, name);
return vmsname;
}
while (*fptr == '/')
fptr++;
}
{
char *vp;
char cwdbuf[VMSMAXPATHLEN+1];
vp = getcwd(cwdbuf, VMSMAXPATHLEN);
if (vp == 0)
{
vmsname[0] = '\0';
return vmsname; /*FIXME, err getcwd */
}
strcpy (vptr, vp);
}
if (*fptr == 0)
{
state = -1;
break;
}
else
{
char *vp = strchr (vptr, ']');
if (vp == 0)
{
state = -1;
break;
}
*vp = '\0';
nstate = N_OPEN;
vptr += strlen (vptr);
state = 9;
}
break;
}
}
while (state > 0);
}
/* directory conversion done
fptr -> filename part of input string
vptr -> free space in vmsname
*/
*vptr++ = 0;
return vmsname;
}
/*
convert from vms-style to unix-style
dev:[dir1.dir2] //dev/dir1/dir2/
*/
const char *
unixify (const char *name)
{
static char piece[512];
const char *s;
char *p;
if (strchr (name, '/') != 0) /* already in unix style */
{
strcpy (piece, name);
return piece;
}
p = piece;
*p = 0;
/* device part */
s = strchr (name, ':');
if (s != 0)
{
int l = s - name;
*p++ = '/';
*p++ = '/';
strncpy (p, name, l);
p += l;
}
/* directory part */
*p++ = '/';
s = strchr (name, '[');
if (s != 0)
{
s++;
switch (*s)
{
case ']': /* [] */
strcat (p, "./");
break;
case '-': /* [- */
strcat (p, "../");
break;
case '.':
strcat (p, "./"); /* [. */
break;
default:
s--;
break;
}
s++;
while (*s)
{
if (*s == '.')
*p++ = '/';
else
*p++ = *s;
s++;
if (*s == ']')
{
s++;
break;
}
}
if (*s != 0) /* more after ']' ?? */
{
if (*(p-1) != '/')
*p++ = '/';
strcpy (p, s); /* copy it anyway */
}
}
else /* no '[' anywhere */
{
*p++ = 0;
}
/* force end with '/' */
if (*(p-1) != '/')
*p++ = '/';
*p = 0;
return piece;
}
/* EOF */
make-4.2.1/glob/ 0000755 0001750 0001750 00000000000 12726643532 010371 5 0000000 0000000 make-4.2.1/glob/glob.h 0000644 0001750 0001750 00000016447 12141576670 011420 0000000 0000000 /* Copyright (C) 1991, 1992, 1995, 1996, 1997, 1998 Free Software Foundation,
Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA. */
#ifndef _GLOB_H
#define _GLOB_H 1
#ifdef __cplusplus
extern "C" {
#endif
#undef __ptr_t
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
# if !defined __GLIBC__
# undef __P
# undef __PMT
# define __P(protos) protos
# define __PMT(protos) protos
# if !defined __GNUC__ || __GNUC__ < 2
# undef __const
# define __const const
# endif
# endif
# define __ptr_t void *
#else /* Not C++ or ANSI C. */
# undef __P
# undef __PMT
# define __P(protos) ()
# define __PMT(protos) ()
# undef __const
# define __const
# define __ptr_t char *
#endif /* C++ or ANSI C. */
/* We need `size_t' for the following definitions. */
#ifndef __size_t
# if defined __FreeBSD__
# define __size_t size_t
# else
# if defined __GNUC__ && __GNUC__ >= 2
typedef __SIZE_TYPE__ __size_t;
# else
/* This is a guess. */
/*hb
* Conflicts with DECCs already defined type __size_t.
* Defining an own type with a name beginning with '__' is no good.
* Anyway if DECC is used and __SIZE_T is defined then __size_t is
* already defined (and I hope it's exactly the one we need here).
*/
# if !(defined __DECC && defined __SIZE_T)
typedef unsigned long int __size_t;
# endif
# endif
# endif
#else
/* The GNU CC stddef.h version defines __size_t as empty. We need a real
definition. */
# undef __size_t
# define __size_t size_t
#endif
/* Bits set in the FLAGS argument to `glob'. */
#define GLOB_ERR (1 << 0)/* Return on read errors. */
#define GLOB_MARK (1 << 1)/* Append a slash to each name. */
#define GLOB_NOSORT (1 << 2)/* Don't sort the names. */
#define GLOB_DOOFFS (1 << 3)/* Insert PGLOB->gl_offs NULLs. */
#define GLOB_NOCHECK (1 << 4)/* If nothing matches, return the pattern. */
#define GLOB_APPEND (1 << 5)/* Append to results of a previous call. */
#define GLOB_NOESCAPE (1 << 6)/* Backslashes don't quote metacharacters. */
#define GLOB_PERIOD (1 << 7)/* Leading `.' can be matched by metachars. */
#if (!defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _BSD_SOURCE \
|| defined _GNU_SOURCE)
# define GLOB_MAGCHAR (1 << 8)/* Set in gl_flags if any metachars seen. */
# define GLOB_ALTDIRFUNC (1 << 9)/* Use gl_opendir et al functions. */
# define GLOB_BRACE (1 << 10)/* Expand "{a,b}" to "a" "b". */
# define GLOB_NOMAGIC (1 << 11)/* If no magic chars, return the pattern. */
# define GLOB_TILDE (1 << 12)/* Expand ~user and ~ to home directories. */
# define GLOB_ONLYDIR (1 << 13)/* Match only directories. */
# define GLOB_TILDE_CHECK (1 << 14)/* Like GLOB_TILDE but return an error
if the user name is not available. */
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
GLOB_PERIOD|GLOB_ALTDIRFUNC|GLOB_BRACE| \
GLOB_NOMAGIC|GLOB_TILDE|GLOB_ONLYDIR|GLOB_TILDE_CHECK)
#else
# define __GLOB_FLAGS (GLOB_ERR|GLOB_MARK|GLOB_NOSORT|GLOB_DOOFFS| \
GLOB_NOESCAPE|GLOB_NOCHECK|GLOB_APPEND| \
GLOB_PERIOD)
#endif
/* Error returns from `glob'. */
#define GLOB_NOSPACE 1 /* Ran out of memory. */
#define GLOB_ABORTED 2 /* Read error. */
#define GLOB_NOMATCH 3 /* No matches found. */
#define GLOB_NOSYS 4 /* Not implemented. */
#ifdef _GNU_SOURCE
/* Previous versions of this file defined GLOB_ABEND instead of
GLOB_ABORTED. Provide a compatibility definition here. */
# define GLOB_ABEND GLOB_ABORTED
#endif
/* Structure describing a globbing run. */
#if !defined _AMIGA && !defined VMS /* Buggy compiler. */
struct stat;
#endif
typedef struct
{
__size_t gl_pathc; /* Count of paths matched by the pattern. */
char **gl_pathv; /* List of matched pathnames. */
__size_t gl_offs; /* Slots to reserve in `gl_pathv'. */
int gl_flags; /* Set to FLAGS, maybe | GLOB_MAGCHAR. */
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
void (*gl_closedir) __PMT ((void *));
struct dirent *(*gl_readdir) __PMT ((void *));
__ptr_t (*gl_opendir) __PMT ((__const char *));
int (*gl_lstat) __PMT ((__const char *, struct stat *));
#if defined(VMS) && defined(__DECC) && !defined(_POSIX_C_SOURCE)
int (*gl_stat) __PMT ((__const char *, struct stat *, ...));
#else
int (*gl_stat) __PMT ((__const char *, struct stat *));
#endif
} glob_t;
#ifdef _LARGEFILE64_SOURCE
struct stat64;
typedef struct
{
__size_t gl_pathc;
char **gl_pathv;
__size_t gl_offs;
int gl_flags;
/* If the GLOB_ALTDIRFUNC flag is set, the following functions
are used instead of the normal file access functions. */
void (*gl_closedir) __PMT ((void *));
struct dirent64 *(*gl_readdir) __PMT ((void *));
__ptr_t (*gl_opendir) __PMT ((__const char *));
int (*gl_lstat) __PMT ((__const char *, struct stat64 *));
int (*gl_stat) __PMT ((__const char *, struct stat64 *));
} glob64_t;
#endif
#if _FILE_OFFSET_BITS == 64 && __GNUC__ < 2
# define glob glob64
# define globfree globfree64
#else
# ifdef _LARGEFILE64_SOURCE
extern int glob64 __P ((__const char *__pattern, int __flags,
int (*__errfunc) (__const char *, int),
glob64_t *__pglob));
extern void globfree64 __P ((glob64_t *__pglob));
# endif
#endif
/* Do glob searching for PATTERN, placing results in PGLOB.
The bits defined above may be set in FLAGS.
If a directory cannot be opened or read and ERRFUNC is not nil,
it is called with the pathname that caused the error, and the
`errno' value from the failing call; if it returns non-zero
`glob' returns GLOB_ABEND; if it returns zero, the error is ignored.
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
Otherwise, `glob' returns zero. */
#if _FILE_OFFSET_BITS != 64 || __GNUC__ < 2
extern int glob __P ((__const char *__pattern, int __flags,
int (*__errfunc) (__const char *, int),
glob_t *__pglob));
/* Free storage allocated in PGLOB by a previous `glob' call. */
extern void globfree __P ((glob_t *__pglob));
#else
extern int glob __P ((__const char *__pattern, int __flags,
int (*__errfunc) (__const char *, int),
glob_t *__pglob)) __asm__ ("glob64");
extern void globfree __P ((glob_t *__pglob)) __asm__ ("globfree64");
#endif
#ifdef _GNU_SOURCE
/* Return nonzero if PATTERN contains any metacharacters.
Metacharacters can be quoted with backslashes if QUOTE is nonzero.
This function is not part of the interface specified by POSIX.2
but several programs want to use it. */
extern int glob_pattern_p __P ((__const char *__pattern, int __quote));
#endif
#ifdef __cplusplus
}
#endif
#endif /* glob.h */
make-4.2.1/glob/COPYING.LIB 0000644 0001750 0001750 00000061257 12074551137 011757 0000000 0000000 GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
675 Mass Ave, Cambridge, MA 02139, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision 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 generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
Copyright (C)
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!
make-4.2.1/glob/fnmatch.h 0000644 0001750 0001750 00000005563 12074551137 012106 0000000 0000000 /* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999 Free Software
Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA. */
#ifndef _FNMATCH_H
#define _FNMATCH_H 1
#ifdef __cplusplus
extern "C" {
#endif
#if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32
# if !defined __GLIBC__
# undef __P
# define __P(protos) protos
# endif
#else /* Not C++ or ANSI C. */
# undef __P
# define __P(protos) ()
/* We can get away without defining `const' here only because in this file
it is used only inside the prototype for `fnmatch', which is elided in
non-ANSI C where `const' is problematical. */
#endif /* C++ or ANSI C. */
#ifndef const
# if (defined __STDC__ && __STDC__) || defined __cplusplus || defined WINDOWS32
# define __const const
# else
# define __const
# endif
#endif
/* We #undef these before defining them because some losing systems
(HP-UX A.08.07 for example) define these in . */
#undef FNM_PATHNAME
#undef FNM_NOESCAPE
#undef FNM_PERIOD
/* Bits set in the FLAGS argument to `fnmatch'. */
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
#if !defined _POSIX_C_SOURCE || _POSIX_C_SOURCE < 2 || defined _GNU_SOURCE
# define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
# define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
# define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
#endif
/* Value returned by `fnmatch' if STRING does not match PATTERN. */
#define FNM_NOMATCH 1
/* This value is returned if the implementation does not support
`fnmatch'. Since this is not the case here it will never be
returned but the conformance test suites still require the symbol
to be defined. */
#ifdef _XOPEN_SOURCE
# define FNM_NOSYS (-1)
#endif
/* Match NAME against the filename pattern PATTERN,
returning zero if it matches, FNM_NOMATCH if not. */
extern int fnmatch __P ((__const char *__pattern, __const char *__name,
int __flags));
#ifdef __cplusplus
}
#endif
#endif /* fnmatch.h */
make-4.2.1/glob/fnmatch.c 0000644 0001750 0001750 00000031122 12074551137 012067 0000000 0000000 /* Copyright (C) 1991, 1992, 1993, 1996, 1997, 1998, 1999 Free Software
Foundation, Inc.
This file is part of the GNU C Library.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA. */
#if HAVE_CONFIG_H
# include
#endif
/* Enable GNU extensions in fnmatch.h. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#include
#include
#include
#if HAVE_STRING_H || defined _LIBC
# include
#else
# include
#endif
#if defined STDC_HEADERS || defined _LIBC
# include
#endif
/* For platform which support the ISO C amendement 1 functionality we
support user defined character classes. */
#if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* Solaris 2.5 has a bug: must be included before . */
# include
# include
#endif
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#if defined _LIBC || !defined __GNU_LIBRARY__
# if defined STDC_HEADERS || !defined isascii
# define ISASCII(c) 1
# else
# define ISASCII(c) isascii(c)
# endif
# ifdef isblank
# define ISBLANK(c) (ISASCII (c) && isblank (c))
# else
# define ISBLANK(c) ((c) == ' ' || (c) == '\t')
# endif
# ifdef isgraph
# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
# else
# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
# endif
# define ISPRINT(c) (ISASCII (c) && isprint (c))
# define ISDIGIT(c) (ISASCII (c) && isdigit (c))
# define ISALNUM(c) (ISASCII (c) && isalnum (c))
# define ISALPHA(c) (ISASCII (c) && isalpha (c))
# define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
# define ISLOWER(c) (ISASCII (c) && islower (c))
# define ISPUNCT(c) (ISASCII (c) && ispunct (c))
# define ISSPACE(c) (ISASCII (c) && isspace (c))
# define ISUPPER(c) (ISASCII (c) && isupper (c))
# define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
# define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
/* The GNU C library provides support for user-defined character classes
and the functions from ISO C amendement 1. */
# ifdef CHARCLASS_NAME_MAX
# define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX
# else
/* This shouldn't happen but some implementation might still have this
problem. Use a reasonable default value. */
# define CHAR_CLASS_MAX_LENGTH 256
# endif
# ifdef _LIBC
# define IS_CHAR_CLASS(string) __wctype (string)
# else
# define IS_CHAR_CLASS(string) wctype (string)
# endif
# else
# define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
# define IS_CHAR_CLASS(string) \
(STREQ (string, "alpha") || STREQ (string, "upper") \
|| STREQ (string, "lower") || STREQ (string, "digit") \
|| STREQ (string, "alnum") || STREQ (string, "xdigit") \
|| STREQ (string, "space") || STREQ (string, "print") \
|| STREQ (string, "punct") || STREQ (string, "graph") \
|| STREQ (string, "cntrl") || STREQ (string, "blank"))
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
# if !defined _LIBC && !defined getenv
extern char *getenv ();
# endif
# ifndef errno
extern int errno;
# endif
/* This function doesn't exist on most systems. */
# if !defined HAVE___STRCHRNUL && !defined _LIBC
static char *
__strchrnul (s, c)
const char *s;
int c;
{
char *result = strchr (s, c);
if (result == NULL)
result = strchr (s, '\0');
return result;
}
# endif
# ifndef internal_function
/* Inside GNU libc we mark some function in a special way. In other
environments simply ignore the marking. */
# define internal_function
# endif
/* Match STRING against the filename pattern PATTERN, returning zero if
it matches, nonzero if not. */
static int internal_fnmatch __P ((const char *pattern, const char *string,
int no_leading_period, int flags))
internal_function;
static int
internal_function
internal_fnmatch (pattern, string, no_leading_period, flags)
const char *pattern;
const char *string;
int no_leading_period;
int flags;
{
register const char *p = pattern, *n = string;
register unsigned char c;
/* Note that this evaluates C many times. */
# ifdef _LIBC
# define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
# else
# define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
# endif
while ((c = *p++) != '\0')
{
c = FOLD (c);
switch (c)
{
case '?':
if (*n == '\0')
return FNM_NOMATCH;
else if (*n == '/' && (flags & FNM_FILE_NAME))
return FNM_NOMATCH;
else if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
break;
case '\\':
if (!(flags & FNM_NOESCAPE))
{
c = *p++;
if (c == '\0')
/* Trailing \ loses. */
return FNM_NOMATCH;
c = FOLD (c);
}
if (FOLD ((unsigned char) *n) != c)
return FNM_NOMATCH;
break;
case '*':
if (*n == '.' && no_leading_period
&& (n == string
|| (n[-1] == '/' && (flags & FNM_FILE_NAME))))
return FNM_NOMATCH;
for (c = *p++; c == '?' || c == '*'; c = *p++)
{
if (*n == '/' && (flags & FNM_FILE_NAME))
/* A slash does not match a wildcard under FNM_FILE_NAME. */
return FNM_NOMATCH;
else if (c == '?')
{
/* A ? needs to match one character. */
if (*n == '\0')
/* There isn't another character; no match. */
return FNM_NOMATCH;
else
/* One character of the string is consumed in matching
this ? wildcard, so *??? won't match if there are
less than three characters. */
++n;
}
}
if (c == '\0')
/* The wildcard(s) is/are the last element of the pattern.
If the name is a file name and contains another slash
this does mean it cannot match. */
return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL
? FNM_NOMATCH : 0);
else
{
const char *endp;
endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
if (c == '[')
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));
for (--p; n < endp; ++n)
if (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2)
== 0)
return 0;
}
else if (c == '/' && (flags & FNM_FILE_NAME))
{
while (*n != '\0' && *n != '/')
++n;
if (*n == '/'
&& (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
flags) == 0))
return 0;
}
else
{
int flags2 = ((flags & FNM_FILE_NAME)
? flags : (flags & ~FNM_PERIOD));
if (c == '\\' && !(flags & FNM_NOESCAPE))
c = *p;
c = FOLD (c);
for (--p; n < endp; ++n)
if (FOLD ((unsigned char) *n) == c
&& (internal_fnmatch (p, n,
(no_leading_period
&& (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME)))),
flags2) == 0))
return 0;
}
}
/* If we come here no match is possible with the wildcard. */
return FNM_NOMATCH;
case '[':
{
/* Nonzero if the sense of the character class is inverted. */
static int posixly_correct;
register int not;
char cold;
if (posixly_correct == 0)
posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
if (*n == '\0')
return FNM_NOMATCH;
if (*n == '.' && no_leading_period && (n == string
|| (n[-1] == '/'
&& (flags
& FNM_FILE_NAME))))
return FNM_NOMATCH;
if (*n == '/' && (flags & FNM_FILE_NAME))
/* `/' cannot be matched. */
return FNM_NOMATCH;
not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
if (not)
++p;
c = *p++;
for (;;)
{
unsigned char fn = FOLD ((unsigned char) *n);
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
c = FOLD ((unsigned char) *p);
++p;
if (c == fn)
goto matched;
}
else if (c == '[' && *p == ':')
{
/* Leave room for the null. */
char str[CHAR_CLASS_MAX_LENGTH + 1];
size_t c1 = 0;
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wctype_t wt;
# endif
const char *startp = p;
for (;;)
{
if (c1 == CHAR_CLASS_MAX_LENGTH)
/* The name is too long and therefore the pattern
is ill-formed. */
return FNM_NOMATCH;
c = *++p;
if (c == ':' && p[1] == ']')
{
p += 2;
break;
}
if (c < 'a' || c >= 'z')
{
/* This cannot possibly be a character class name.
Match it as a normal range. */
p = startp;
c = '[';
goto normal_bracket;
}
str[c1++] = c;
}
str[c1] = '\0';
# if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
wt = IS_CHAR_CLASS (str);
if (wt == 0)
/* Invalid character class name. */
return FNM_NOMATCH;
if (__iswctype (__btowc ((unsigned char) *n), wt))
goto matched;
# else
if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
|| (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
|| (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
|| (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
|| (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
|| (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
|| (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
|| (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
|| (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
|| (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
|| (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
|| (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
goto matched;
# endif
}
else if (c == '\0')
/* [ (unterminated) loses. */
return FNM_NOMATCH;
else
{
normal_bracket:
if (FOLD (c) == fn)
goto matched;
cold = c;
c = *p++;
if (c == '-' && *p != ']')
{
/* It is a range. */
unsigned char cend = *p++;
if (!(flags & FNM_NOESCAPE) && cend == '\\')
cend = *p++;
if (cend == '\0')
return FNM_NOMATCH;
if (cold <= fn && fn <= FOLD (cend))
goto matched;
c = *p++;
}
}
if (c == ']')
break;
}
if (!not)
return FNM_NOMATCH;
break;
matched:
/* Skip the rest of the [...] that already matched. */
while (c != ']')
{
if (c == '\0')
/* [... (unterminated) loses. */
return FNM_NOMATCH;
c = *p++;
if (!(flags & FNM_NOESCAPE) && c == '\\')
{
if (*p == '\0')
return FNM_NOMATCH;
/* XXX 1003.2d11 is unclear if this is right. */
++p;
}
else if (c == '[' && *p == ':')
{
do
if (*++p == '\0')
return FNM_NOMATCH;
while (*p != ':' || p[1] == ']');
p += 2;
c = *p;
}
}
if (not)
return FNM_NOMATCH;
}
break;
default:
if (c != FOLD ((unsigned char) *n))
return FNM_NOMATCH;
}
++n;
}
if (*n == '\0')
return 0;
if ((flags & FNM_LEADING_DIR) && *n == '/')
/* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
return 0;
return FNM_NOMATCH;
# undef FOLD
}
int
fnmatch (pattern, string, flags)
const char *pattern;
const char *string;
int flags;
{
return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
}
#endif /* _LIBC or not __GNU_LIBRARY__. */
make-4.2.1/glob/SCOPTIONS 0000644 0001750 0001750 00000000303 12074551137 011604 0000000 0000000 ERRORREXX
OPTIMIZE
NOVERSION
OPTIMIZERTIME
OPTIMIZERALIAS
DEFINE INCLUDEDIR="include:"
DEFINE LIBDIR="lib:"
DEFINE NO_ALLOCA
DEFINE NO_FLOAT
DEFINE NO_ARCHIVES
IGNORE=161
IGNORE=100
STARTUP=cres
make-4.2.1/glob/Makefile.am 0000644 0001750 0001750 00000002144 12074551137 012341 0000000 0000000 # -*-Makefile-*-, or close enough
# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
AUTOMAKE_OPTIONS = foreign
# Only build the library when the system doesn't already have GNU glob.
if USE_LOCAL_GLOB
noinst_LIBRARIES = libglob.a
endif
libglob_a_SOURCES = glob.c glob.h fnmatch.c fnmatch.h
EXTRA_DIST = COPYING.LIB Makefile.ami SCOPTIONS SMakefile \
configure.bat
make-4.2.1/glob/SMakefile 0000644 0001750 0001750 00000003763 12074551137 012100 0000000 0000000 # Makefile for standalone distribution of libglob.a (fnmatch, glob).
# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
# Ultrix 2.2 make doesn't expand the value of VPATH.
VPATH = /glob/
# This must repeat the value, because configure will remove `VPATH = .'.
srcdir = /glob/
CC = sc
CPPFLAGS =
CFLAGS =
MAKE = smake
RM = delete
# Information determined by configure.
DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \
Define HAVE_DIRENT_H
# How to invoke ar.
AR = join
ARFLAGS = as
# How to invoke ranlib.
RANLIB = ;
.PHONY: all
all: glob.lib
glob.lib : glob.o fnmatch.o
$(AR) $(ARFLAGS) $@ glob.o fnmatch.o
$(RANLIB) $@
# For some reason, Unix make wants the dependencies on the source files.
# Otherwise it refuses to use an implicit rule!
# And, get this: it doesn't work to use $(srcdir)foo.c!!
glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c
fnmatch.o: $(srcdir)fnmatch.h fnmatch.c
.c.o:
$(CC) IDir "" \
$(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION)
.PHONY: clean realclean glob-clean glob-realclean distclean
clean glob-clean:
-$(RM) -f glob.lib *.o core
distclean glob-realclean: clean
-$(RM) -f TAGS tags Makefile config.status config.h config.log
realcean: distclean
# For inside the C library.
glob.tar glob.tar.Z:
$(MAKE) -C .. $@
make-4.2.1/glob/configure.bat 0000644 0001750 0001750 00000003324 12074551137 012757 0000000 0000000 @echo off
rem Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
rem 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
rem This file is part of GNU Make.
rem
rem GNU Make is free software; you can redistribute it and/or modify it under
rem the terms of the GNU General Public License as published by the Free
rem Software Foundation; either version 3 of the License, or (at your option)
rem any later version.
rem
rem GNU Make is distributed in the hope that it will be useful, but WITHOUT
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for.
rem more details.
rem
rem You should have received a copy of the GNU General Public License along
rem with this program. If not, see .
echo Configuring glob for DJGPP
rem This batch file assumes a unix-type "sed" program
echo # Makefile generated by "configure.bat"> Makefile
if exist config.sed del config.sed
echo "s/@srcdir@/./ ">> config.sed
echo "s/@CC@/gcc/ ">> config.sed
echo "s/@CFLAGS@/-O2 -g/ ">> config.sed
echo "s/@CPPFLAGS@/-DHAVE_CONFIG_H -I../ ">> config.sed
echo "s/@AR@/ar/ ">> config.sed
echo "s/@RANLIB@/ranlib/ ">> config.sed
echo "s/@LDFLAGS@// ">> config.sed
echo "s/@DEFS@// ">> config.sed
echo "s/@ALLOCA@// ">> config.sed
echo "s/@LIBS@// ">> config.sed
echo "s/@LIBOBJS@// ">> config.sed
echo "s/^Makefile *:/_Makefile:/ ">> config.sed
echo "s/^config.h *:/_config.h:/ ">> config.sed
sed -e "s/^\"//" -e "s/\"$//" -e "s/[ ]*$//" config.sed > config2.sed
sed -f config2.sed Makefile.in >> Makefile
del config.sed
del config2.sed
make-4.2.1/glob/Makefile.ami 0000644 0001750 0001750 00000003776 12074551137 012526 0000000 0000000 # Makefile for standalone libglob.a (fnmatch, glob). -*-Makefile-*-
# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006, 2007 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
# Ultrix 2.2 make doesn't expand the value of VPATH.
VPATH = /glob/
# This must repeat the value, because configure will remove `VPATH = .'.
srcdir = /glob/
CC = sc
RM = delete
CPPFLAGS =
CFLAGS =
# Information determined by configure.
DEFS = Define HAVE_HEADER_STDC Define HAVE_UNISTD_H Define HAVE_STRING_H \
Define HAVE_DIRENT_H
# How to invoke ar.
AR = join
ARFLAGS = as
# How to invoke ranlib.
RANLIB = ;
.PHONY: all
all: glob.lib
glob.lib : glob.o fnmatch.o
$(AR) $(ARFLAGS) $@ glob.o fnmatch.o
$(RANLIB) $@
# For some reason, Unix make wants the dependencies on the source files.
# Otherwise it refuses to use an implicit rule!
# And, get this: it doesn't work to use $(srcdir)foo.c!!
glob.o: $(srcdir)glob.h $(srcdir)fnmatch.h glob.c
fnmatch.o: $(srcdir)fnmatch.h fnmatch.c
OUTPUT_OPTION =
.c.o:
$(CC) IDir "" \
$(DEFS) $(CPPFLAGS) $(CFLAGS) $< $(OUTPUT_OPTION)
.PHONY: clean realclean glob-clean glob-realclean distclean
clean glob-clean:
-$(RM) glob.lib "#?.o" core
distclean glob-realclean: clean
-$(RM) TAGS tags Makefile config.status config.h config.log
realcean: distclean
# For inside the C library.
glob.tar glob.tar.Z:
$(MAKE) -C .. $@
make-4.2.1/glob/Makefile.in 0000644 0001750 0001750 00000043565 12726643472 012376 0000000 0000000 # Makefile.in generated by automake 1.15 from Makefile.am.
# @configure_input@
# Copyright (C) 1994-2014 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
# -*-Makefile-*-, or close enough
# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
# This file is part of GNU Make.
#
# GNU Make is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 3 of the License, or (at your option) any later
# version.
#
# GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see .
VPATH = @srcdir@
am__is_gnu_make = { \
if test -z '$(MAKELEVEL)'; then \
false; \
elif test -n '$(MAKE_HOST)'; then \
true; \
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
true; \
else \
false; \
fi; \
}
am__make_running_with_option = \
case $${target_option-} in \
?) ;; \
*) echo "am__make_running_with_option: internal error: invalid" \
"target option '$${target_option-}' specified" >&2; \
exit 1;; \
esac; \
has_opt=no; \
sane_makeflags=$$MAKEFLAGS; \
if $(am__is_gnu_make); then \
sane_makeflags=$$MFLAGS; \
else \
case $$MAKEFLAGS in \
*\\[\ \ ]*) \
bs=\\; \
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
esac; \
fi; \
skip_next=no; \
strip_trailopt () \
{ \
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
}; \
for flg in $$sane_makeflags; do \
test $$skip_next = yes && { skip_next=no; continue; }; \
case $$flg in \
*=*|--*) continue;; \
-*I) strip_trailopt 'I'; skip_next=yes;; \
-*I?*) strip_trailopt 'I';; \
-*O) strip_trailopt 'O'; skip_next=yes;; \
-*O?*) strip_trailopt 'O';; \
-*l) strip_trailopt 'l'; skip_next=yes;; \
-*l?*) strip_trailopt 'l';; \
-[dEDm]) skip_next=yes;; \
-[JT]) skip_next=yes;; \
esac; \
case $$flg in \
*$$target_option*) has_opt=yes; break;; \
esac; \
done; \
test $$has_opt = yes
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
pkgdatadir = $(datadir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
subdir = glob
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/config/dospaths.m4 \
$(top_srcdir)/config/gettext.m4 $(top_srcdir)/config/iconv.m4 \
$(top_srcdir)/config/intlmacosx.m4 \
$(top_srcdir)/config/lib-ld.m4 \
$(top_srcdir)/config/lib-link.m4 \
$(top_srcdir)/config/lib-prefix.m4 \
$(top_srcdir)/config/longlong.m4 $(top_srcdir)/config/nls.m4 \
$(top_srcdir)/config/po.m4 $(top_srcdir)/config/progtest.m4 \
$(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LIBRARIES = $(noinst_LIBRARIES)
ARFLAGS = cru
AM_V_AR = $(am__v_AR_@AM_V@)
am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@)
am__v_AR_0 = @echo " AR " $@;
am__v_AR_1 =
libglob_a_AR = $(AR) $(ARFLAGS)
libglob_a_LIBADD =
am_libglob_a_OBJECTS = glob.$(OBJEXT) fnmatch.$(OBJEXT)
libglob_a_OBJECTS = $(am_libglob_a_OBJECTS)
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
am__v_P_0 = false
am__v_P_1 = :
AM_V_GEN = $(am__v_GEN_@AM_V@)
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
am__v_GEN_1 =
AM_V_at = $(am__v_at_@AM_V@)
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
am__v_at_0 = @
am__v_at_1 =
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
am__depfiles_maybe = depfiles
am__mv = mv -f
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
AM_V_CC = $(am__v_CC_@AM_V@)
am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
am__v_CC_0 = @echo " CC " $@;
am__v_CC_1 =
CCLD = $(CC)
LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
AM_V_CCLD = $(am__v_CCLD_@AM_V@)
am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
am__v_CCLD_0 = @echo " CCLD " $@;
am__v_CCLD_1 =
SOURCES = $(libglob_a_SOURCES)
DIST_SOURCES = $(libglob_a_SOURCES)
am__can_run_installinfo = \
case $$AM_UPDATE_INFO_DIR in \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
# Read a list of newline-separated strings from the standard input,
# and print each of them once, without duplicates. Input order is
# *not* preserved.
am__uniquify_input = $(AWK) '\
BEGIN { nonempty = 0; } \
{ items[$$0] = 1; nonempty = 1; } \
END { if (nonempty) { for (i in items) print i; }; } \
'
# Make sure the list of sources is unique. This is necessary because,
# e.g., the same source file might be shared among _SOURCES variables
# for different programs/libraries.
am__define_uniq_tagged_files = \
list='$(am__tagged_files)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | $(am__uniquify_input)`
ETAGS = etags
CTAGS = ctags
am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/config/depcomp \
COPYING.LIB ChangeLog
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
AM_LDFLAGS = @AM_LDFLAGS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
GETLOADAVG_LIBS = @GETLOADAVG_LIBS@
GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
GLOBINC = @GLOBINC@
GLOBLIB = @GLOBLIB@
GMSGFMT = @GMSGFMT@
GMSGFMT_015 = @GMSGFMT_015@
GREP = @GREP@
GUILE_CFLAGS = @GUILE_CFLAGS@
GUILE_LIBS = @GUILE_LIBS@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INTLLIBS = @INTLLIBS@
INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
KMEM_GROUP = @KMEM_GROUP@
LDFLAGS = @LDFLAGS@
LIBICONV = @LIBICONV@
LIBINTL = @LIBINTL@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBICONV = @LTLIBICONV@
LTLIBINTL = @LTLIBINTL@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MAKE_HOST = @MAKE_HOST@
MKDIR_P = @MKDIR_P@
MSGFMT = @MSGFMT@
MSGFMT_015 = @MSGFMT_015@
MSGMERGE = @MSGMERGE@
NEED_SETGID = @NEED_SETGID@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_URL = @PACKAGE_URL@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
PKG_CONFIG = @PKG_CONFIG@
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
POSUB = @POSUB@
RANLIB = @RANLIB@
REMOTE = @REMOTE@
SED = @SED@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
XGETTEXT_015 = @XGETTEXT_015@
XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
runstatedir = @runstatedir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
AUTOMAKE_OPTIONS = foreign
# Only build the library when the system doesn't already have GNU glob.
@USE_LOCAL_GLOB_TRUE@noinst_LIBRARIES = libglob.a
libglob_a_SOURCES = glob.c glob.h fnmatch.c fnmatch.h
EXTRA_DIST = COPYING.LIB Makefile.ami SCOPTIONS SMakefile \
configure.bat
all: all-am
.SUFFIXES:
.SUFFIXES: .c .o .obj
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
&& { if test -f $@; then exit 0; else break; fi; }; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign glob/Makefile'; \
$(am__cd) $(top_srcdir) && \
$(AUTOMAKE) --foreign glob/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
clean-noinstLIBRARIES:
-test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
libglob.a: $(libglob_a_OBJECTS) $(libglob_a_DEPENDENCIES) $(EXTRA_libglob_a_DEPENDENCIES)
$(AM_V_at)-rm -f libglob.a
$(AM_V_AR)$(libglob_a_AR) libglob.a $(libglob_a_OBJECTS) $(libglob_a_LIBADD)
$(AM_V_at)$(RANLIB) libglob.a
mostlyclean-compile:
-rm -f *.$(OBJEXT)
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fnmatch.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glob.Po@am__quote@
.c.o:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
.c.obj:
@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
ID: $(am__tagged_files)
$(am__define_uniq_tagged_files); mkid -fID $$unique
tags: tags-am
TAGS: tags
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
set x; \
here=`pwd`; \
$(am__define_uniq_tagged_files); \
shift; \
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
test -n "$$unique" || unique=$$empty_fix; \
if test $$# -gt 0; then \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
"$$@" $$unique; \
else \
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$unique; \
fi; \
fi
ctags: ctags-am
CTAGS: ctags
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
$(am__define_uniq_tagged_files); \
test -z "$(CTAGS_ARGS)$$unique" \
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
$$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& $(am__cd) $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) "$$here"
cscopelist: cscopelist-am
cscopelist-am: $(am__tagged_files)
list='$(am__tagged_files)'; \
case "$(srcdir)" in \
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
*) sdir=$(subdir)/$(srcdir) ;; \
esac; \
for i in $$list; do \
if test -f "$$i"; then \
echo "$(subdir)/$$i"; \
else \
echo "$$sdir/$$i"; \
fi; \
done >> $(top_builddir)/cscope.files
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
distdir: $(DISTFILES)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d "$(distdir)/$$file"; then \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
fi; \
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
else \
test -f "$(distdir)/$$file" \
|| cp -p $$d/$$file "$(distdir)/$$file" \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(LIBRARIES)
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
if test -z '$(STRIP)'; then \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
install; \
else \
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
fi
mostlyclean-generic:
clean-generic:
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am
distclean: distclean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
distclean-tags
dvi: dvi-am
dvi-am:
html: html-am
html-am:
info: info-am
info-am:
install-data-am:
install-dvi: install-dvi-am
install-dvi-am:
install-exec-am:
install-html: install-html-am
install-html-am:
install-info: install-info-am
install-info-am:
install-man:
install-pdf: install-pdf-am
install-pdf-am:
install-ps: install-ps-am
install-ps-am:
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -rf ./$(DEPDIR)
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-compile mostlyclean-generic
pdf: pdf-am
pdf-am:
ps: ps-am
ps-am:
uninstall-am:
.MAKE: install-am install-strip
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
clean-noinstLIBRARIES cscopelist-am ctags ctags-am distclean \
distclean-compile distclean-generic distclean-tags distdir dvi \
dvi-am html html-am info info-am install install-am \
install-data install-data-am install-dvi install-dvi-am \
install-exec install-exec-am install-html install-html-am \
install-info install-info-am install-man install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-compile \
mostlyclean-generic pdf pdf-am ps ps-am tags tags-am uninstall \
uninstall-am
.PRECIOUS: Makefile
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
make-4.2.1/glob/glob.c 0000644 0001750 0001750 00000106037 12231007576 011400 0000000 0000000 /* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999 Free
Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to the Free
Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA. */
/* AIX requires this to be the first thing in the file. */
#if defined _AIX && !defined __GNUC__
#pragma alloca
#endif
#ifdef HAVE_CONFIG_H
# include
#endif
/* Enable GNU extensions in glob.h. */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif
#include
#include
#include
/* Outcomment the following line for production quality code. */
/* #define NDEBUG 1 */
#include
#include /* Needed on stupid SunOS for assert. */
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GLOB_INTERFACE_VERSION 1
#if !defined _LIBC && defined __GNU_LIBRARY__ && __GNU_LIBRARY__ > 1
# include
# if _GNU_GLOB_INTERFACE_VERSION == GLOB_INTERFACE_VERSION
# define ELIDE_CODE
# endif
#endif
#ifndef ELIDE_CODE
#if defined STDC_HEADERS || defined __GNU_LIBRARY__
# include
#endif
#if defined HAVE_UNISTD_H || defined _LIBC
# include
# ifndef POSIX
# ifdef _POSIX_VERSION
# define POSIX
# endif
# endif
#endif
#if !defined _AMIGA && !defined VMS && !defined WINDOWS32
# include
#endif
#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS
extern int errno;
#endif
#ifndef __set_errno
# define __set_errno(val) errno = (val)
#endif
#ifndef NULL
# define NULL 0
#endif
#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__
# include
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# ifdef HAVE_SYS_NDIR_H
# include
# endif
# ifdef HAVE_SYS_DIR_H
# include
# endif
# ifdef HAVE_NDIR_H
# include
# endif
# ifdef HAVE_VMSDIR_H
# include "vmsdir.h"
# endif /* HAVE_VMSDIR_H */
#endif
/* In GNU systems, defines this macro for us. */
#ifdef _D_NAMLEN
# undef NAMLEN
# define NAMLEN(d) _D_NAMLEN(d)
#endif
/* When used in the GNU libc the symbol _DIRENT_HAVE_D_TYPE is available
if the `d_type' member for `struct dirent' is available. */
#ifdef _DIRENT_HAVE_D_TYPE
# define HAVE_D_TYPE 1
#endif
#if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__
/* Posix does not require that the d_ino field be present, and some
systems do not provide it. */
# define REAL_DIR_ENTRY(dp) 1
#else
# define REAL_DIR_ENTRY(dp) (dp->d_ino != 0)
#endif /* POSIX */
#if defined STDC_HEADERS || defined __GNU_LIBRARY__
# include
# include
# define ANSI_STRING
#else /* No standard headers. */
extern char *getenv ();
# ifdef HAVE_STRING_H
# include
# define ANSI_STRING
# else
# include
# endif
# ifdef HAVE_MEMORY_H
# include
# endif
extern char *malloc (), *realloc ();
extern void free ();
extern void qsort ();
extern void abort (), exit ();
#endif /* Standard headers. */
#ifndef ANSI_STRING
# ifndef bzero
extern void bzero ();
# endif
# ifndef bcopy
extern void bcopy ();
# endif
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# define strrchr rindex
/* memset is only used for zero here, but let's be paranoid. */
# define memset(s, better_be_zero, n) \
((void) ((better_be_zero) == 0 ? (bzero((s), (n)), 0) : (abort(), 0)))
#endif /* Not ANSI_STRING. */
#if !defined HAVE_STRCOLL && !defined _LIBC
# define strcoll strcmp
#endif
#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1
# define HAVE_MEMPCPY 1
# undef mempcpy
# define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len)
#endif
#if !defined __GNU_LIBRARY__ && !defined __DJGPP__
# ifdef __GNUC__
__inline
# endif
# ifndef __SASC
# ifdef WINDOWS32
static void *
my_realloc (void *p, unsigned int n)
# else
static char *
my_realloc (p, n)
char *p;
unsigned int n;
# endif
{
/* These casts are the for sake of the broken Ultrix compiler,
which warns of illegal pointer combinations otherwise. */
if (p == NULL)
return (char *) malloc (n);
return (char *) realloc (p, n);
}
# define realloc my_realloc
# endif /* __SASC */
#endif /* __GNU_LIBRARY__ || __DJGPP__ */
#if !defined __alloca && !defined __GNU_LIBRARY__
# ifdef __GNUC__
# undef alloca
# define alloca(n) __builtin_alloca (n)
# else /* Not GCC. */
# ifdef HAVE_ALLOCA_H
# include
# else /* Not HAVE_ALLOCA_H. */
# ifndef _AIX
# ifdef WINDOWS32
# include
# else
extern char *alloca ();
# endif /* WINDOWS32 */
# endif /* Not _AIX. */
# endif /* sparc or HAVE_ALLOCA_H. */
# endif /* GCC. */
# define __alloca alloca
#endif
#ifndef __GNU_LIBRARY__
# define __stat stat
# ifdef STAT_MACROS_BROKEN
# undef S_ISDIR
# endif
# ifndef S_ISDIR
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
# endif
#endif
#ifdef _LIBC
# undef strdup
# define strdup(str) __strdup (str)
# define sysconf(id) __sysconf (id)
# define closedir(dir) __closedir (dir)
# define opendir(name) __opendir (name)
# define readdir(str) __readdir (str)
# define getpwnam_r(name, bufp, buf, len, res) \
__getpwnam_r (name, bufp, buf, len, res)
# ifndef __stat
# define __stat(fname, buf) __xstat (_STAT_VER, fname, buf)
# endif
#endif
#if !(defined STDC_HEADERS || defined __GNU_LIBRARY__)
# undef size_t
# define size_t unsigned int
#endif
/* Some system header files erroneously define these.
We want our own definitions from to take precedence. */
#ifndef __GNU_LIBRARY__
# undef FNM_PATHNAME
# undef FNM_NOESCAPE
# undef FNM_PERIOD
#endif
#include
/* Some system header files erroneously define these.
We want our own definitions from to take precedence. */
#ifndef __GNU_LIBRARY__
# undef GLOB_ERR
# undef GLOB_MARK
# undef GLOB_NOSORT
# undef GLOB_DOOFFS
# undef GLOB_NOCHECK
# undef GLOB_APPEND
# undef GLOB_NOESCAPE
# undef GLOB_PERIOD
#endif
#include
#ifdef HAVE_GETLOGIN_R
extern int getlogin_r __P ((char *, size_t));
#else
extern char *getlogin __P ((void));
#endif
static
#if __GNUC__ - 0 >= 2
inline
#endif
const char *next_brace_sub __P ((const char *begin));
static int glob_in_dir __P ((const char *pattern, const char *directory,
int flags,
int (*errfunc) (const char *, int),
glob_t *pglob));
static int prefix_array __P ((const char *prefix, char **array, size_t n));
static int collated_compare __P ((const __ptr_t, const __ptr_t));
#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
int __glob_pattern_p __P ((const char *pattern, int quote));
#endif
/* Find the end of the sub-pattern in a brace expression. We define
this as an inline function if the compiler permits. */
static
#if __GNUC__ - 0 >= 2
inline
#endif
const char *
next_brace_sub (begin)
const char *begin;
{
unsigned int depth = 0;
const char *cp = begin;
while (1)
{
if (depth == 0)
{
if (*cp != ',' && *cp != '}' && *cp != '\0')
{
if (*cp == '{')
++depth;
++cp;
continue;
}
}
else
{
while (*cp != '\0' && (*cp != '}' || depth > 0))
{
if (*cp == '}')
--depth;
++cp;
}
if (*cp == '\0')
/* An incorrectly terminated brace expression. */
return NULL;
continue;
}
break;
}
return cp;
}
/* Do glob searching for PATTERN, placing results in PGLOB.
The bits defined above may be set in FLAGS.
If a directory cannot be opened or read and ERRFUNC is not nil,
it is called with the pathname that caused the error, and the
`errno' value from the failing call; if it returns non-zero
`glob' returns GLOB_ABORTED; if it returns zero, the error is ignored.
If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned.
Otherwise, `glob' returns zero. */
int
glob (pattern, flags, errfunc, pglob)
const char *pattern;
int flags;
int (*errfunc) __P ((const char *, int));
glob_t *pglob;
{
const char *filename;
const char *dirname;
size_t dirlen;
int status;
int oldcount;
if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0)
{
__set_errno (EINVAL);
return -1;
}
/* POSIX requires all slashes to be matched. This means that with
a trailing slash we must match only directories. */
if (pattern[0] && pattern[strlen (pattern) - 1] == '/')
flags |= GLOB_ONLYDIR;
if (flags & GLOB_BRACE)
{
const char *begin = strchr (pattern, '{');
if (begin != NULL)
{
/* Allocate working buffer large enough for our work. Note that
we have at least an opening and closing brace. */
int firstc;
char *alt_start;
const char *p;
const char *next;
const char *rest;
size_t rest_len;
#ifdef __GNUC__
char onealt[strlen (pattern) - 1];
#else
char *onealt = (char *) malloc (strlen (pattern) - 1);
if (onealt == NULL)
{
if (!(flags & GLOB_APPEND))
globfree (pglob);
return GLOB_NOSPACE;
}
#endif
/* We know the prefix for all sub-patterns. */
#ifdef HAVE_MEMPCPY
alt_start = mempcpy (onealt, pattern, begin - pattern);
#else
memcpy (onealt, pattern, begin - pattern);
alt_start = &onealt[begin - pattern];
#endif
/* Find the first sub-pattern and at the same time find the
rest after the closing brace. */
next = next_brace_sub (begin + 1);
if (next == NULL)
{
/* It is an illegal expression. */
#ifndef __GNUC__
free (onealt);
#endif
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
/* Now find the end of the whole brace expression. */
rest = next;
while (*rest != '}')
{
rest = next_brace_sub (rest + 1);
if (rest == NULL)
{
/* It is an illegal expression. */
#ifndef __GNUC__
free (onealt);
#endif
return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob);
}
}
/* Please note that we now can be sure the brace expression
is well-formed. */
rest_len = strlen (++rest) + 1;
/* We have a brace expression. BEGIN points to the opening {,
NEXT points past the terminator of the first element, and END
points past the final }. We will accumulate result names from
recursive runs for each brace alternative in the buffer using
GLOB_APPEND. */
if (!(flags & GLOB_APPEND))
{
/* This call is to set a new vector, so clear out the
vector so we can append to it. */
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
firstc = pglob->gl_pathc;
p = begin + 1;
while (1)
{
int result;
/* Construct the new glob expression. */
#ifdef HAVE_MEMPCPY
mempcpy (mempcpy (alt_start, p, next - p), rest, rest_len);
#else
memcpy (alt_start, p, next - p);
memcpy (&alt_start[next - p], rest, rest_len);
#endif
result = glob (onealt,
((flags & ~(GLOB_NOCHECK|GLOB_NOMAGIC))
| GLOB_APPEND), errfunc, pglob);
/* If we got an error, return it. */
if (result && result != GLOB_NOMATCH)
{
#ifndef __GNUC__
free (onealt);
#endif
if (!(flags & GLOB_APPEND))
globfree (pglob);
return result;
}
if (*next == '}')
/* We saw the last entry. */
break;
p = next + 1;
next = next_brace_sub (p);
assert (next != NULL);
}
#ifndef __GNUC__
free (onealt);
#endif
if (pglob->gl_pathc != firstc)
/* We found some entries. */
return 0;
else if (!(flags & (GLOB_NOCHECK|GLOB_NOMAGIC)))
return GLOB_NOMATCH;
}
}
/* Find the filename. */
filename = strrchr (pattern, '/');
#if defined __MSDOS__ || defined WINDOWS32
/* The case of "d:pattern". Since `:' is not allowed in
file names, we can safely assume that wherever it
happens in pattern, it signals the filename part. This
is so we could some day support patterns like "[a-z]:foo". */
if (filename == NULL)
filename = strchr (pattern, ':');
#endif /* __MSDOS__ || WINDOWS32 */
if (filename == NULL)
{
/* This can mean two things: a simple name or "~name". The later
case is nothing but a notation for a directory. */
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && pattern[0] == '~')
{
dirname = pattern;
dirlen = strlen (pattern);
/* Set FILENAME to NULL as a special flag. This is ugly but
other solutions would require much more code. We test for
this special case below. */
filename = NULL;
}
else
{
filename = pattern;
#ifdef _AMIGA
dirname = "";
#else
dirname = ".";
#endif
dirlen = 0;
}
}
else if (filename == pattern)
{
/* "/pattern". */
dirname = "/";
dirlen = 1;
++filename;
}
else
{
char *newp;
dirlen = filename - pattern;
#if defined __MSDOS__ || defined WINDOWS32
if (*filename == ':'
|| (filename > pattern + 1 && filename[-1] == ':'))
{
char *drive_spec;
++dirlen;
drive_spec = (char *) __alloca (dirlen + 1);
#ifdef HAVE_MEMPCPY
*((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0';
#else
memcpy (drive_spec, pattern, dirlen);
drive_spec[dirlen] = '\0';
#endif
/* For now, disallow wildcards in the drive spec, to
prevent infinite recursion in glob. */
if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE)))
return GLOB_NOMATCH;
/* If this is "d:pattern", we need to copy `:' to DIRNAME
as well. If it's "d:/pattern", don't remove the slash
from "d:/", since "d:" and "d:/" are not the same.*/
}
#endif
newp = (char *) __alloca (dirlen + 1);
#ifdef HAVE_MEMPCPY
*((char *) mempcpy (newp, pattern, dirlen)) = '\0';
#else
memcpy (newp, pattern, dirlen);
newp[dirlen] = '\0';
#endif
dirname = newp;
++filename;
if (filename[0] == '\0'
#if defined __MSDOS__ || defined WINDOWS32
&& dirname[dirlen - 1] != ':'
&& (dirlen < 3 || dirname[dirlen - 2] != ':'
|| dirname[dirlen - 1] != '/')
#endif
&& dirlen > 1)
/* "pattern/". Expand "pattern", appending slashes. */
{
int val = glob (dirname, flags | GLOB_MARK, errfunc, pglob);
if (val == 0)
pglob->gl_flags = ((pglob->gl_flags & ~GLOB_MARK)
| (flags & GLOB_MARK));
return val;
}
}
if (!(flags & GLOB_APPEND))
{
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
}
oldcount = pglob->gl_pathc;
#ifndef VMS
if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~')
{
if (dirname[1] == '\0' || dirname[1] == '/')
{
/* Look up home directory. */
#ifdef VMS
/* This isn't obvious, RTLs of DECC and VAXC know about "HOME" */
const char *home_dir = getenv ("SYS$LOGIN");
#else
const char *home_dir = getenv ("HOME");
#endif
# ifdef _AMIGA
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "SYS:";
# else
# ifdef WINDOWS32
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "c:/users/default"; /* poor default */
# else
# ifdef VMS
/* Again, this isn't obvious, if "HOME" isn't known "SYS$LOGIN" should be set */
if (home_dir == NULL || home_dir[0] == '\0')
home_dir = "SYS$DISK:[]";
# else
if (home_dir == NULL || home_dir[0] == '\0')
{
int success;
char *name;
# if defined HAVE_GETLOGIN_R || defined _LIBC
size_t buflen = sysconf (_SC_LOGIN_NAME_MAX) + 1;
if (buflen == 0)
/* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try
a moderate value. */
buflen = 20;
name = (char *) __alloca (buflen);
success = getlogin_r (name, buflen) >= 0;
# else
success = (name = getlogin ()) != NULL;
# endif
if (success)
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
size_t pwbuflen = sysconf (_SC_GETPW_R_SIZE_MAX);
char *pwtmpbuf;
struct passwd pwbuf;
int save = errno;
if (pwbuflen == -1)
/* `sysconf' does not support _SC_GETPW_R_SIZE_MAX.
Try a moderate value. */
pwbuflen = 1024;
pwtmpbuf = (char *) __alloca (pwbuflen);
while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p)
!= 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
pwbuflen *= 2;
pwtmpbuf = (char *) __alloca (pwbuflen);
__set_errno (save);
}
# else
p = getpwnam (name);
# endif
if (p != NULL)
home_dir = p->pw_dir;
}
}
if (home_dir == NULL || home_dir[0] == '\0')
{
if (flags & GLOB_TILDE_CHECK)
return GLOB_NOMATCH;
else
home_dir = "~"; /* No luck. */
}
# endif /* VMS */
# endif /* WINDOWS32 */
# endif
/* Now construct the full directory. */
if (dirname[1] == '\0')
dirname = home_dir;
else
{
char *newp;
size_t home_len = strlen (home_dir);
newp = (char *) __alloca (home_len + dirlen);
# ifdef HAVE_MEMPCPY
mempcpy (mempcpy (newp, home_dir, home_len),
&dirname[1], dirlen);
# else
memcpy (newp, home_dir, home_len);
memcpy (&newp[home_len], &dirname[1], dirlen);
# endif
dirname = newp;
}
}
# if !defined _AMIGA && !defined WINDOWS32 && !defined VMS
else
{
char *end_name = strchr (dirname, '/');
const char *user_name;
const char *home_dir;
if (end_name == NULL)
user_name = dirname + 1;
else
{
char *newp;
newp = (char *) __alloca (end_name - dirname);
# ifdef HAVE_MEMPCPY
*((char *) mempcpy (newp, dirname + 1, end_name - dirname))
= '\0';
# else
memcpy (newp, dirname + 1, end_name - dirname);
newp[end_name - dirname - 1] = '\0';
# endif
user_name = newp;
}
/* Look up specific user's home directory. */
{
struct passwd *p;
# if defined HAVE_GETPWNAM_R || defined _LIBC
size_t buflen = sysconf (_SC_GETPW_R_SIZE_MAX);
char *pwtmpbuf;
struct passwd pwbuf;
int save = errno;
if (buflen == -1)
/* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a
moderate value. */
buflen = 1024;
pwtmpbuf = (char *) __alloca (buflen);
while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0)
{
if (errno != ERANGE)
{
p = NULL;
break;
}
buflen *= 2;
pwtmpbuf = __alloca (buflen);
__set_errno (save);
}
# else
p = getpwnam (user_name);
# endif
if (p != NULL)
home_dir = p->pw_dir;
else
home_dir = NULL;
}
/* If we found a home directory use this. */
if (home_dir != NULL)
{
char *newp;
size_t home_len = strlen (home_dir);
size_t rest_len = end_name == NULL ? 0 : strlen (end_name);
newp = (char *) __alloca (home_len + rest_len + 1);
# ifdef HAVE_MEMPCPY
*((char *) mempcpy (mempcpy (newp, home_dir, home_len),
end_name, rest_len)) = '\0';
# else
memcpy (newp, home_dir, home_len);
memcpy (&newp[home_len], end_name, rest_len);
newp[home_len + rest_len] = '\0';
# endif
dirname = newp;
}
else
if (flags & GLOB_TILDE_CHECK)
/* We have to regard it as an error if we cannot find the
home directory. */
return GLOB_NOMATCH;
}
# endif /* Not Amiga && not WINDOWS32 && not VMS. */
}
#endif /* Not VMS. */
/* Now test whether we looked for "~" or "~NAME". In this case we
can give the answer now. */
if (filename == NULL)
{
struct stat st;
/* Return the directory if we don't check for error or if it exists. */
if ((flags & GLOB_NOCHECK)
|| (((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_stat) (dirname, &st)
: __stat (dirname, &st)) == 0
&& S_ISDIR (st.st_mode)))
{
pglob->gl_pathv
= (char **) realloc (pglob->gl_pathv,
(pglob->gl_pathc +
((flags & GLOB_DOOFFS) ?
pglob->gl_offs : 0) +
1 + 1) *
sizeof (char *));
if (pglob->gl_pathv == NULL)
return GLOB_NOSPACE;
if (flags & GLOB_DOOFFS)
while (pglob->gl_pathc < pglob->gl_offs)
pglob->gl_pathv[pglob->gl_pathc++] = NULL;
#if defined HAVE_STRDUP || defined _LIBC
pglob->gl_pathv[pglob->gl_pathc] = strdup (dirname);
#else
{
size_t len = strlen (dirname) + 1;
char *dircopy = malloc (len);
if (dircopy != NULL)
pglob->gl_pathv[pglob->gl_pathc] = memcpy (dircopy, dirname,
len);
}
#endif
if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
{
free (pglob->gl_pathv);
return GLOB_NOSPACE;
}
pglob->gl_pathv[++pglob->gl_pathc] = NULL;
pglob->gl_flags = flags;
return 0;
}
/* Not found. */
return GLOB_NOMATCH;
}
if (__glob_pattern_p (dirname, !(flags & GLOB_NOESCAPE)))
{
/* The directory name contains metacharacters, so we
have to glob for the directory, and then glob for
the pattern in each directory found. */
glob_t dirs;
register int i;
status = glob (dirname,
((flags & (GLOB_ERR | GLOB_NOCHECK | GLOB_NOESCAPE))
| GLOB_NOSORT | GLOB_ONLYDIR),
errfunc, &dirs);
if (status != 0)
return status;
/* We have successfully globbed the preceding directory name.
For each name we found, call glob_in_dir on it and FILENAME,
appending the results to PGLOB. */
for (i = 0; i < dirs.gl_pathc; ++i)
{
int old_pathc;
#ifdef SHELL
{
/* Make globbing interruptible in the bash shell. */
extern int interrupt_state;
if (interrupt_state)
{
globfree (&dirs);
globfree (&files);
return GLOB_ABORTED;
}
}
#endif /* SHELL. */
old_pathc = pglob->gl_pathc;
status = glob_in_dir (filename, dirs.gl_pathv[i],
((flags | GLOB_APPEND)
& ~(GLOB_NOCHECK | GLOB_ERR)),
errfunc, pglob);
if (status == GLOB_NOMATCH)
/* No matches in this directory. Try the next. */
continue;
if (status != 0)
{
globfree (&dirs);
globfree (pglob);
return status;
}
/* Stick the directory on the front of each name. */
if (prefix_array (dirs.gl_pathv[i],
&pglob->gl_pathv[old_pathc],
pglob->gl_pathc - old_pathc))
{
globfree (&dirs);
globfree (pglob);
return GLOB_NOSPACE;
}
}
flags |= GLOB_MAGCHAR;
/* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls.
But if we have not found any matching entry and thie GLOB_NOCHECK
flag was set we must return the list consisting of the disrectory
names followed by the filename. */
if (pglob->gl_pathc == oldcount)
{
/* No matches. */
if (flags & GLOB_NOCHECK)
{
size_t filename_len = strlen (filename) + 1;
char **new_pathv;
struct stat st;
/* This is an pessimistic guess about the size. */
pglob->gl_pathv
= (char **) realloc (pglob->gl_pathv,
(pglob->gl_pathc +
((flags & GLOB_DOOFFS) ?
pglob->gl_offs : 0) +
dirs.gl_pathc + 1) *
sizeof (char *));
if (pglob->gl_pathv == NULL)
{
globfree (&dirs);
return GLOB_NOSPACE;
}
if (flags & GLOB_DOOFFS)
while (pglob->gl_pathc < pglob->gl_offs)
pglob->gl_pathv[pglob->gl_pathc++] = NULL;
for (i = 0; i < dirs.gl_pathc; ++i)
{
const char *dir = dirs.gl_pathv[i];
size_t dir_len = strlen (dir);
/* First check whether this really is a directory. */
if (((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_stat) (dir, &st) : __stat (dir, &st)) != 0
|| !S_ISDIR (st.st_mode))
/* No directory, ignore this entry. */
continue;
pglob->gl_pathv[pglob->gl_pathc] = malloc (dir_len + 1
+ filename_len);
if (pglob->gl_pathv[pglob->gl_pathc] == NULL)
{
globfree (&dirs);
globfree (pglob);
return GLOB_NOSPACE;
}
#ifdef HAVE_MEMPCPY
mempcpy (mempcpy (mempcpy (pglob->gl_pathv[pglob->gl_pathc],
dir, dir_len),
"/", 1),
filename, filename_len);
#else
memcpy (pglob->gl_pathv[pglob->gl_pathc], dir, dir_len);
pglob->gl_pathv[pglob->gl_pathc][dir_len] = '/';
memcpy (&pglob->gl_pathv[pglob->gl_pathc][dir_len + 1],
filename, filename_len);
#endif
++pglob->gl_pathc;
}
pglob->gl_pathv[pglob->gl_pathc] = NULL;
pglob->gl_flags = flags;
/* Now we know how large the gl_pathv vector must be. */
new_pathv = (char **) realloc (pglob->gl_pathv,
((pglob->gl_pathc + 1)
* sizeof (char *)));
if (new_pathv != NULL)
pglob->gl_pathv = new_pathv;
}
else
return GLOB_NOMATCH;
}
globfree (&dirs);
}
else
{
status = glob_in_dir (filename, dirname, flags, errfunc, pglob);
if (status != 0)
return status;
if (dirlen > 0)
{
/* Stick the directory on the front of each name. */
int ignore = oldcount;
if ((flags & GLOB_DOOFFS) && ignore < pglob->gl_offs)
ignore = pglob->gl_offs;
if (prefix_array (dirname,
&pglob->gl_pathv[ignore],
pglob->gl_pathc - ignore))
{
globfree (pglob);
return GLOB_NOSPACE;
}
}
}
if (flags & GLOB_MARK)
{
/* Append slashes to directory names. */
int i;
struct stat st;
for (i = oldcount; i < pglob->gl_pathc; ++i)
if (((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_stat) (pglob->gl_pathv[i], &st)
: __stat (pglob->gl_pathv[i], &st)) == 0
&& S_ISDIR (st.st_mode))
{
size_t len = strlen (pglob->gl_pathv[i]) + 2;
char *new = realloc (pglob->gl_pathv[i], len);
if (new == NULL)
{
globfree (pglob);
return GLOB_NOSPACE;
}
strcpy (&new[len - 2], "/");
pglob->gl_pathv[i] = new;
}
}
if (!(flags & GLOB_NOSORT))
{
/* Sort the vector. */
int non_sort = oldcount;
if ((flags & GLOB_DOOFFS) && pglob->gl_offs > oldcount)
non_sort = pglob->gl_offs;
qsort ((__ptr_t) &pglob->gl_pathv[non_sort],
pglob->gl_pathc - non_sort,
sizeof (char *), collated_compare);
}
return 0;
}
/* Free storage allocated in PGLOB by a previous `glob' call. */
void
globfree (pglob)
register glob_t *pglob;
{
if (pglob->gl_pathv != NULL)
{
register int i;
for (i = 0; i < pglob->gl_pathc; ++i)
if (pglob->gl_pathv[i] != NULL)
free ((__ptr_t) pglob->gl_pathv[i]);
free ((__ptr_t) pglob->gl_pathv);
}
}
/* Do a collated comparison of A and B. */
static int
collated_compare (a, b)
const __ptr_t a;
const __ptr_t b;
{
const char *const s1 = *(const char *const * const) a;
const char *const s2 = *(const char *const * const) b;
if (s1 == s2)
return 0;
if (s1 == NULL)
return 1;
if (s2 == NULL)
return -1;
return strcoll (s1, s2);
}
/* Prepend DIRNAME to each of N members of ARRAY, replacing ARRAY's
elements in place. Return nonzero if out of memory, zero if successful.
A slash is inserted between DIRNAME and each elt of ARRAY,
unless DIRNAME is just "/". Each old element of ARRAY is freed. */
static int
prefix_array (dirname, array, n)
const char *dirname;
char **array;
size_t n;
{
register size_t i;
size_t dirlen = strlen (dirname);
#if defined __MSDOS__ || defined WINDOWS32
int sep_char = '/';
# define DIRSEP_CHAR sep_char
#else
# define DIRSEP_CHAR '/'
#endif
if (dirlen == 1 && dirname[0] == '/')
/* DIRNAME is just "/", so normal prepending would get us "//foo".
We want "/foo" instead, so don't prepend any chars from DIRNAME. */
dirlen = 0;
#if defined __MSDOS__ || defined WINDOWS32
else if (dirlen > 1)
{
if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':')
/* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */
--dirlen;
else if (dirname[dirlen - 1] == ':')
{
/* DIRNAME is "d:". Use `:' instead of `/'. */
--dirlen;
sep_char = ':';
}
}
#endif
for (i = 0; i < n; ++i)
{
size_t eltlen = strlen (array[i]) + 1;
char *new = (char *) malloc (dirlen + 1 + eltlen);
if (new == NULL)
{
while (i > 0)
free ((__ptr_t) array[--i]);
return 1;
}
#ifdef HAVE_MEMPCPY
{
char *endp = (char *) mempcpy (new, dirname, dirlen);
*endp++ = DIRSEP_CHAR;
mempcpy (endp, array[i], eltlen);
}
#else
memcpy (new, dirname, dirlen);
new[dirlen] = DIRSEP_CHAR;
memcpy (&new[dirlen + 1], array[i], eltlen);
#endif
free ((__ptr_t) array[i]);
array[i] = new;
}
return 0;
}
/* We must not compile this function twice. */
#if !defined _LIBC || !defined NO_GLOB_PATTERN_P
/* Return nonzero if PATTERN contains any metacharacters.
Metacharacters can be quoted with backslashes if QUOTE is nonzero. */
int
__glob_pattern_p (pattern, quote)
const char *pattern;
int quote;
{
register const char *p;
int open = 0;
for (p = pattern; *p != '\0'; ++p)
switch (*p)
{
case '?':
case '*':
return 1;
case '\\':
if (quote && p[1] != '\0')
++p;
break;
case '[':
open = 1;
break;
case ']':
if (open)
return 1;
break;
}
return 0;
}
# ifdef _LIBC
weak_alias (__glob_pattern_p, glob_pattern_p)
# endif
#endif
/* Like `glob', but PATTERN is a final pathname component,
and matches are searched for in DIRECTORY.
The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done.
The GLOB_APPEND flag is assumed to be set (always appends). */
static int
glob_in_dir (pattern, directory, flags, errfunc, pglob)
const char *pattern;
const char *directory;
int flags;
int (*errfunc) __P ((const char *, int));
glob_t *pglob;
{
__ptr_t stream = NULL;
struct globlink
{
struct globlink *next;
char *name;
};
struct globlink *names = NULL;
size_t nfound;
int meta;
int save;
#ifdef VMS
if (*directory == 0)
directory = "[]";
#endif
meta = __glob_pattern_p (pattern, !(flags & GLOB_NOESCAPE));
if (meta == 0)
{
if (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))
/* We need not do any tests. The PATTERN contains no meta
characters and we must not return an error therefore the
result will always contain exactly one name. */
flags |= GLOB_NOCHECK;
else
{
/* Since we use the normal file functions we can also use stat()
to verify the file is there. */
struct stat st;
size_t patlen = strlen (pattern);
size_t dirlen = strlen (directory);
char *fullname = (char *) __alloca (dirlen + 1 + patlen + 1);
# ifdef HAVE_MEMPCPY
mempcpy (mempcpy (mempcpy (fullname, directory, dirlen),
"/", 1),
pattern, patlen + 1);
# else
memcpy (fullname, directory, dirlen);
fullname[dirlen] = '/';
memcpy (&fullname[dirlen + 1], pattern, patlen + 1);
# endif
if (((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_stat) (fullname, &st)
: __stat (fullname, &st)) == 0)
/* We found this file to be existing. Now tell the rest
of the function to copy this name into the result. */
flags |= GLOB_NOCHECK;
}
nfound = 0;
}
else
{
if (pattern[0] == '\0')
{
/* This is a special case for matching directories like in
"*a/". */
names = (struct globlink *) __alloca (sizeof (struct globlink));
names->name = (char *) malloc (1);
if (names->name == NULL)
goto memory_error;
names->name[0] = '\0';
names->next = NULL;
nfound = 1;
meta = 0;
}
else
{
stream = ((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_opendir) (directory)
: (__ptr_t) opendir (directory));
if (stream == NULL)
{
if (errno != ENOTDIR
&& ((errfunc != NULL && (*errfunc) (directory, errno))
|| (flags & GLOB_ERR)))
return GLOB_ABORTED;
nfound = 0;
meta = 0;
}
else
{
int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0)
| ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)
#if defined HAVE_CASE_INSENSITIVE_FS
| FNM_CASEFOLD
#endif
);
nfound = 0;
flags |= GLOB_MAGCHAR;
while (1)
{
const char *name;
size_t len;
struct dirent *d = ((flags & GLOB_ALTDIRFUNC)
? (*pglob->gl_readdir) (stream)
: readdir ((DIR *) stream));
if (d == NULL)
break;
if (! REAL_DIR_ENTRY (d))
continue;
#ifdef HAVE_D_TYPE
/* If we shall match only directories use the information
provided by the dirent call if possible. */
if ((flags & GLOB_ONLYDIR)
&& d->d_type != DT_UNKNOWN && d->d_type != DT_DIR)
continue;
#endif
name = d->d_name;
if (fnmatch (pattern, name, fnm_flags) == 0)
{
struct globlink *new = (struct globlink *)
__alloca (sizeof (struct globlink));
len = NAMLEN (d);
new->name = (char *) malloc (len + 1);
if (new->name == NULL)
goto memory_error;
#ifdef HAVE_MEMPCPY
*((char *) mempcpy ((__ptr_t) new->name, name, len))
= '\0';
#else
memcpy ((__ptr_t) new->name, name, len);
new->name[len] = '\0';
#endif
new->next = names;
names = new;
++nfound;
}
}
}
}
}
if (nfound == 0 && (flags & GLOB_NOCHECK))
{
size_t len = strlen (pattern);
nfound = 1;
names = (struct globlink *) __alloca (sizeof (struct globlink));
names->next = NULL;
names->name = (char *) malloc (len + 1);
if (names->name == NULL)
goto memory_error;
#ifdef HAVE_MEMPCPY
*((char *) mempcpy (names->name, pattern, len)) = '\0';
#else
memcpy (names->name, pattern, len);
names->name[len] = '\0';
#endif
}
if (nfound != 0)
{
pglob->gl_pathv
= (char **) realloc (pglob->gl_pathv,
(pglob->gl_pathc +
((flags & GLOB_DOOFFS) ? pglob->gl_offs : 0) +
nfound + 1) *
sizeof (char *));
if (pglob->gl_pathv == NULL)
goto memory_error;
if (flags & GLOB_DOOFFS)
while (pglob->gl_pathc < pglob->gl_offs)
pglob->gl_pathv[pglob->gl_pathc++] = NULL;
for (; names != NULL; names = names->next)
pglob->gl_pathv[pglob->gl_pathc++] = names->name;
pglob->gl_pathv[pglob->gl_pathc] = NULL;
pglob->gl_flags = flags;
}
save = errno;
if (stream != NULL)
{
if (flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir) (stream);
else
closedir ((DIR *) stream);
}
__set_errno (save);
return nfound == 0 ? GLOB_NOMATCH : 0;
memory_error:
{
int save = errno;
if (flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir) (stream);
else
closedir ((DIR *) stream);
__set_errno (save);
}
while (names != NULL)
{
if (names->name != NULL)
free ((__ptr_t) names->name);
names = names->next;
}
return GLOB_NOSPACE;
}
#endif /* Not ELIDE_CODE. */
make-4.2.1/glob/ChangeLog 0000644 0001750 0001750 00000015435 12231007746 012063 0000000 0000000 2013-10-20 Paul Smith
* glob.c (glob): Cherry-pick a471e96a5352a5f0bde6d32dd36d33524811a2b1
from git://sourceware.org/git/glibc.git to fix SV 18123,
https://sourceware.org/bugzilla/show_bug.cgi?id=10278
2008-09-28 Juan Manuel Guerrero
* glob.c (my_realloc) [__DJGPP__]: Don't define, and don't
redefine realloc to call it, since the DJGPP's realloc handles
NULL pointers correctly.
2007-12-22 Juan Manuel Guerrero (tiny change)
* glob.c [__GNU_LIBRARY__ && __DJGPP__]: Add a realloc
declaration that matches the one in the DJGPP libc.
2006-02-24 Eli Zaretskii
* glob.c (my_malloc) [WINDOWS32]: Provide a full ISO C prototype,
to avoid compiler warnings.
2005-06-25 Paul D. Smith
* fnmatch.h, glob.h [WINDOWS32]: Fix ifdefs in headers.
Fixes Savannah bug #13477.
2005-03-11 Paul D. Smith
* glob.c (glob_in_dir): Change FNM_CASEFOLD to be enabled if
HAVE_CASE_INSENSITIVE_FS is defined.
2003-01-30 Paul D. Smith
* glob.h: Patch for FreeBSD by Mike Barcroft
Reported by Gerald Pfeifer . On
FreeBSD, declare __size_t to simply size_t.
2002-04-22 Paul D. Smith
* Makefile.am: Use automake 1.6.
Use new automake condition USE_LOCAL_GLOB to decide whether or not
to build the local GNU glob library or use the system one.
1999-09-12 Paul D. Smith
* fnmatch.c: Last GLIBC version wouldn't compile outside of GLIBC
(undefined reference to internal_function). Update to the latest
version
1999-09-11 Paul Eggert
* glob.h (glob): If #defining to glob64, do this before
declaring it, so that all declarations and uses match, and
do not declare glob64, to avoid a declaration clash.
(globfree): Likewise with globfree64.
1999-09-08 Eli Zaretskii
* glob.c (prefix_array) [__MSDOS__,WINDOWS32]: Keep the trailing
slash unless DIRNAME is just "x:/".
1999-09-06 Paul D. Smith
* fnmatch.c: Update to latest version from GLIBC.
1999-07-21 Paul D. Smith
* glob.c, glob.h, fnmatch.c, fnmatch.h: Update to latest version
from GLIBC.
* fnmatch.c (internal_fnmatch): Use K&R definition syntax, not ANSI.
(__strchrnul): This won't exist outside GLIBC, so create one.
* glob.c: Move getlogin{,_r} prototypes below glob.h to get __P()
macro.
1998-08-05 Paul D. Smith
* configure.in: Remove; configuration for glob is handled by the
make configure.in.
1998-07-29 Paul D. Smith
* glob.c, fnmatch.c: New versions from the GLIBC folks (Ulrich
Drepper). Fixes a bug reported by Eli Zaretski. Integrates
DOS/Windows32 support.
1998-07-27 Kaveh R. Ghazi
* glob.c (glob): Cast away const on assignment of pattern to dirname.
Cast the return type of __alloca() for traditional C compilers.
1998-07-23 Paul D. Smith
* glob.c, fnmatch.c: New versions of these files from the GLIBC
folks (Ulrich Drepper). Had to re-integrate some DOS/Windows
code.
1998-07-10 Paul D. Smith
* glob.c (glob_in_dir): If no meta chars exist in PATTERN and
GLOB_NOCHECK is present, don't look for the file--whether it's
found or not, we'll always return it, so why bother searching?
Also, if we are searching and there are no meta chars, don't
bother trying fnmatch() if the strcmp() fails.
1998-05-30 Eli Zaretskii
* glob.c (glob) [__MSDOS__, WINDOWS32]: Compute the directory and
filename parts of the pattern correctly when it includes a drive
spec. Disallow wildcards in the drive spec. Prevent recursion
when dirname is of the form "d:/" or "d:".
(prefix_array) [__MSDOS__, WINDOWS32]: Don't append a slash to
"d:/" and "d:".
1998-05-13 Paul D. Smith
* SMakefile, Makefile.ami, glob.c, glob.h, fnmatch.c: Updated from
the latest glibc version.
1998-04-17 Paul D. Smith
* configure.in: Create a config.h file instead of setting things
on the compile line. This is because when build.sh runs it merely
passes -DHAVE_CONFIG_H to the glob files, just as it does to the
make files.
* config.h.in: Created by autoheader.
Tue Aug 12 10:52:34 1997 Paul D. Smith
* configure.in: Require autoconf 2.12.
* glob: Updates from latest GNU libc glob code.
* glob.c,glob.h,fnmatch.h: Change all WIN32 references to WINDOWS32.
* glob.h: OSF4 defines macros in such a way that GLOB_ALTDIRFUNC
is not defined. Added a test to the #if which defines it if
_GNU_SOURCE is defined; that's set by both glob.c and GNU make.
* glob.c: SunOS4 w/ cc needs #include , since assert.h
requires stderr but doesn't include stdio.h :-/.
(next_brace_sub): De-protoize function definition.
(glob): Cast __alloca(); on SunOS4 it uses the default return type
of int.
(glob): Irix defines getlogin_r() to return a char*; move the
extern for that into the _LIBC area since it isn't used except in
LIBC anyway. Likewise, move extern getlogin() into the "else".
Sat Jul 20 21:55:31 1996 Roland McGrath
Win32 hacks from .
* posix/glob.c [WIN32]: Don't include ; don't use d_ino;
use void * for my_realloc; include for alloca.
(glob) [WIN32]: Use "c:/users/default" for ~ if no HOME variable.
* posix/fnmatch.h [WIN32]: Use prototypes even if [!__STDC__].
* posix/glob.h: Likewise.
Fri Jul 19 16:56:41 1996 Roland McGrath
* posix/glob.h [!_AMIGA && !VMS]: Check this instead of just [!_AMIGA]
for `struct stat;' forward decl.
Sat Jun 22 10:44:09 1996 Roland McGrath
* posix/glob.c: Include only [HAVE_ALLOCA_H], not [sparc].
Fri Jun 21 00:27:51 1996 Roland McGrath
* posix/fnmatch.c (fnmatch): Fix \*[*?]+ case to increment name ptr
only for ?s, not for *s. Fix from Chet Ramey.
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
make-4.2.1/subproc.bat 0000644 0001750 0001750 00000001614 12664632037 011534 0000000 0000000 @echo off
rem Copyright (C) 1996-2016 Free Software Foundation, Inc.
rem This file is part of GNU Make.
rem
rem GNU Make is free software; you can redistribute it and/or modify it under
rem the terms of the GNU General Public License as published by the Free
rem Software Foundation; either version 3 of the License, or (at your option)
rem any later version.
rem
rem GNU Make is distributed in the hope that it will be useful, but WITHOUT
rem ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
rem FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for.
rem more details.
rem
rem You should have received a copy of the GNU General Public License along
rem with this program. If not, see .
cd w32\subproc
set MAKE=%2
set MAKEFILE=%1
if x%2 == x set MAKE=nmake
%MAKE% /f %MAKEFILE%
if ERRORLEVEL 1 exit /B
cd ..\..
make-4.2.1/README.W32 0000444 0001750 0001750 00000033220 12726643532 010616 0000000 0000000 This version of GNU make has been tested on:
Microsoft Windows 2000/XP/2003/Vista/7/8/10
It has also been used on Windows 95/98/NT, and on OS/2.
It builds with the MinGW port of GCC (tested with GCC 3.4.2, 4.8.1,
and 4.9.3).
It also builds with MSVC 2.x, 4.x, 5.x, 6.x, 2003, and 14 (2015) as
well as with .NET 7.x and .NET 2003.
As of version 4.0, a build with Guile is supported (tested with Guile
2.0.3). To build with Guile, you will need, in addition to Guile
itself, its dependency libraries and the pkg-config program. The
latter is used to figure out which compilation and link switches and
libraries need to be mentioned on the compiler command lines to
correctly link with Guile. A Windows port of pkg-config can be found
on ezwinports site:
http://sourceforge.net/projects/ezwinports/
The libraries on which Guile depends can vary depending on your
version and build of Guile. At the very least, the Boehm's GC library
will be needed, and typically also GNU MP, libffi, libunistring, and
libtool's libltdl. Whoever built the port of Guile you have should
also provide you with these dependencies or a URL where to download
them. A precompiled 32-bit Windows build of Guile is available from
the ezwinports site mentioned above.
The Windows port of GNU make is maintained jointly by various people.
It was originally made by Rob Tulloh.
It is currently maintained by Eli Zaretskii.
Do this first, regardless of the build method you choose:
---------------------------------------------------------
1. Edit config.h.W32 to your liking (especially the few shell-related
defines near the end, or HAVE_CASE_INSENSITIVE_FS which corresponds
to './configure --enable-case-insensitive-file-system'). (We don't
recommend to define HAVE_CASE_INSENSITIVE_FS, but you may wish to
consider that if you have a lot of files whose names are in upper
case, while Makefile rules are written for lower-case versions.)
Using make_msvc_net2003.vcproj
------------------------------
2. Open make_msvc_net2003.vcproj in MSVS71 or MSVC71 or any compatible IDE,
then build this project as usual. There's also a solution file for
Studio 2003.
Building with (MinGW-)GCC using build_w32.bat
---------------------------------------------
2. Open a W32 command prompt for your installed (MinGW-)GCC, setup a
correct PATH and other environment variables for it, then execute ...
build_w32.bat gcc
This produces gnumake.exe in the GccRel directory.
If you want a version of GNU make built with debugging enabled,
add the --debug option.
The batch file will probe for Guile installation, and will build
gnumake.exe with Guile if it finds it. If you have Guile
installed, but want to build Make without Guile support, type
build_w32.bat --without-guile gcc
Building with (MSVC++-)cl using build_w32.bat or NMakefile
----------------------------------------------------------
2. Open a W32 command prompt for your installed (MSVC++-)cl, setup a
correct PATH and other environment variables for it (usually via
executing vcvars32.bat or vsvars32.bat from the cl-installation,
e.g. "%VS71COMNTOOLS%vsvars32.bat"; or using a corresponding start
menue entry from the cl-installation), then execute EITHER ...
build_w32.bat
This produces gnumake.exe in the WinRel directory.
If you want a version of GNU make built with debugging enabled,
add the --debug option.
... OR ...
nmake /f NMakefile
(this produces WinDebug/make.exe and WinRel/make.exe).
The batch file will probe for Guile installation, and will build
gnumake.exe with Guile if it finds it. If you have Guile
installed, but want to build Make without Guile support, type
build_w32.bat --without-guile
-------------------
-- Notes/Caveats --
-------------------
GNU make on Windows 32-bit platforms:
This version of make is ported natively to Windows32 platforms
(Windows NT 3.51, Windows NT 4.0, Windows 2000, Windows XP,
Windows 95, and Windows 98). It does not rely on any 3rd party
software or add-on packages for building. The only thing
needed is a Windows compiler. Two compilers supported
officially are the MinGW port of GNU GCC, and the various
versions of the Microsoft C compiler.
Do not confuse this port of GNU make with other Windows32 projects
which provide a GNU make binary. These are separate projects
and are not connected to this port effort.
GNU make and sh.exe:
This port prefers if you have a working sh.exe somewhere on
your system. If you don't have sh.exe, the port falls back to
MSDOS mode for launching programs (via a batch file). The
MSDOS mode style execution has not been tested that carefully
though (The author uses GNU bash as sh.exe).
There are very few true ports of Bourne shell for NT right now.
There is a version of GNU bash available from Cygnus "Cygwin"
porting effort (http://www.cygwin.com/).
Other possibilities are the MKS version of sh.exe, or building
your own with a package like NutCracker (DataFocus) or Portage
(Consensys). Also MinGW includes sh (http://mingw.org/).
GNU make and brain-dead shells (BATCH_MODE_ONLY_SHELL):
Some versions of Bourne shell do not behave well when invoked
as 'sh -c' from CreateProcess(). The main problem is they seem
to have a hard time handling quoted strings correctly. This can
be circumvented by writing commands to be executed to a batch
file and then executing the command by calling 'sh file'.
To work around this difficulty, this version of make supports
a batch mode. When BATCH_MODE_ONLY_SHELL is defined at compile
time, make forces all command lines to be executed via script
files instead of by command line. In this mode you must have a
working sh.exe in order to use parallel builds (-j).
A native Windows32 system with no Bourne shell will also run
in batch mode. All command lines will be put into batch files
and executed via $(COMSPEC) (%COMSPEC%). However, parallel
builds ARE supported with Windows shells (cmd.exe and
command.com). See the next section about some peculiarities
of parallel builds on Windows.
Support for parallel builds
Parallel builds (-jN) are supported in this port, with 1
limitation: The number of concurrent processes has a hard
limit of 64, due to the way this port implements waiting for
its subprocesses.
GNU make and Cygnus GNU Windows32 tools:
Good news! Make now has native support for Cygwin sh. To enable,
define the HAVE_CYGWIN_SHELL in config.h and rebuild make
from scratch. This version of make tested with B20.1 of Cygwin.
Do not define BATCH_MODE_ONLY_SHELL if you use HAVE_CYGWIN_SHELL.
GNU make and the MKS shell:
There is now semi-official support for the MKS shell. To turn this
support on, define HAVE_MKS_SHELL in the config.h.W32 before you
build make. Do not define BATCH_MODE_ONLY_SHELL if you turn
on HAVE_MKS_SHELL.
GNU make handling of drive letters in pathnames (PATH, vpath, VPATH):
There is a caveat that should be noted with respect to handling
single character pathnames on Windows systems. When colon is
used in PATH variables, make tries to be smart about knowing when
you are using colon as a separator versus colon as a drive
letter. Unfortunately, something as simple as the string 'x:/'
could be interpreted 2 ways: (x and /) or (x:/).
Make chooses to interpret a letter plus colon (e.g. x:/) as a
drive letter pathname. If it is necessary to use single
character directories in paths (VPATH, vpath, Path, PATH), the
user must do one of two things:
a. Use semicolon as the separator to disambiguate colon. For
example use 'x;/' if you want to say 'x' and '/' are
separate components.
b. Qualify the directory name so that there is more than
one character in the path(s) used. For example, none
of these settings are ambiguous:
./x:./y
/some/path/x:/some/path/y
x:/some/path/x:x:/some/path/y
Please note that you are free to mix colon and semi-colon in the
specification of paths. Make is able to figure out the intended
result and convert the paths internally to the format needed
when interacting with the operating system, providing the path
is not within quotes, e.g. "x:/test/test.c".
You are encouraged to use colon as the separator character.
This should ease the pain of deciding how to handle various path
problems which exist between platforms. If colon is used on
both Unix and Windows systems, then no ifdef'ing will be
necessary in the makefile source.
GNU make test suite:
I verified all functionality with a slightly modified version
of make-test-4.2.1 (modifications to get test suite to run
on Windows NT). All tests pass in an environment that includes
sh.exe. Tests were performed on both Windows NT and Windows 95.
Pathnames and white space:
Unlike Unix, Windows 95/NT systems encourage pathnames which
contain white space (e.g. C:\Program Files\). These sorts of
pathnames are valid on Unix too, but are never encouraged.
There is at least one place in make (VPATH/vpath handling) where
paths containing white space will simply not work. There may be
others too. I chose to not try and port make in such a way so
that these sorts of paths could be handled. I offer these
suggestions as workarounds:
1. Use 8.3 notation. i.e. "x:/long~1/", which is actually
"x:\longpathtest". Type "dir /x" to view these filenames
within the cmd.exe shell.
2. Rename the directory so it does not contain white space.
If you are unhappy with this choice, this is free software
and you are free to take a crack at making this work. The code
in w32/pathstuff.c and vpath.c would be the places to start.
Pathnames and Case insensitivity:
Unlike Unix, Windows 95/NT systems are case insensitive but case
preserving. For example if you tell the file system to create a
file named "Target", it will preserve the case. Subsequent access to
the file with other case permutations will succeed (i.e. opening a
file named "target" or "TARGET" will open the file "Target").
By default, GNU make retains its case sensitivity when comparing
target names and existing files or directories. It can be
configured, however, into a case preserving and case insensitive
mode by adding a define for HAVE_CASE_INSENSITIVE_FS to
config.h.W32.
For example, the following makefile will create a file named
Target in the directory subdir which will subsequently be used
to satisfy the dependency of SUBDIR/DepTarget on SubDir/TARGET.
Without HAVE_CASE_INSENSITIVE_FS configured, the dependency link
will not be made:
subdir/Target:
touch $@
SUBDIR/DepTarget: SubDir/TARGET
cp $^ $@
Reliance on this behavior also eliminates the ability of GNU make
to use case in comparison of matching rules. For example, it is
not possible to set up a C++ rule using %.C that is different
than a C rule using %.c. GNU make will consider these to be the
same rule and will issue a warning.
SAMBA/NTFS/VFAT:
I have not had any success building the debug version of this
package using SAMBA as my file server. The reason seems to be
related to the way VC++ 4.0 changes the case name of the pdb
filename it is passed on the command line. It seems to change
the name always to to lower case. I contend that the VC++
compiler should not change the casename of files that are passed
as arguments on the command line. I don't think this was a
problem in MSVC 2.x, but I know it is a problem in MSVC 4.x.
The package builds fine on VFAT and NTFS filesystems.
Most all of the development I have done to date has been using
NTFS and long file names. I have not done any considerable work
under VFAT. VFAT users may wish to be aware that this port of
make does respect case sensitivity.
FAT:
Version 3.76 added support for FAT filesystems. Make works
around some difficulties with stat'ing of files and caching of
filenames and directories internally.
Bug reports:
Please submit bugs via the normal bug reporting mechanism which
is described in the GNU make manual and the base README.
-------------------------------------------------------------------------------
Copyright (C) 1996-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see .
make-4.2.1/getopt.c 0000644 0001750 0001750 00000071763 12664631374 011054 0000000 0000000 /* Getopt for GNU.
NOTE: getopt is now part of the C library, so if you don't know what
"Keep this file name-space clean" means, talk to drepper@gnu.org
before changing it!
Copyright (C) 1987-2016 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* This tells Alpha OSF/1 not to define a getopt prototype in .
Ditto for AIX 3.2 and . */
#ifndef _NO_PROTO
# define _NO_PROTO
#endif
#ifdef HAVE_CONFIG_H
# include
#endif
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
# ifndef const
# define const
# endif
#endif
#include
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
# include
# if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
# define ELIDE_CODE
# endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
/* Don't include stdlib.h for non-GNU C libraries because some of them
contain conflicting prototypes for getopt. */
# include
# include
#endif /* GNU C library. */
#ifdef VMS
# include
# if HAVE_STRING_H - 0
# include
# endif
#endif
/* This is for other GNU distributions with internationalized messages.
When compiling libc, the _ macro is predefined. */
#include "gettext.h"
#define _(msgid) gettext (msgid)
/* This version of `getopt' appears to the caller like standard Unix 'getopt'
but it behaves differently for the user, since it allows the user
to intersperse the options with the other arguments.
As `getopt' works, it permutes the elements of ARGV so that,
when it is done, all the options precede everything else. Thus
all application programs are extended to handle flexible argument order.
Setting the environment variable POSIXLY_CORRECT disables permutation.
Then the behavior is completely standard.
GNU application programs can use a third alternative mode in which
they can distinguish the relative order of options and other arguments. */
#include "getopt.h"
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
char *optarg = NULL;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
/* 1003.2 says this must be 1 before any call. */
int optind = 1;
/* Formerly, initialization of getopt depended on optind==0, which
causes problems with re-calling getopt as programs generally don't
know that. */
int __getopt_initialized = 0;
/* The next char to be scanned in the option-element
in which the last option character we returned was found.
This allows us to pick up the scan where we left off.
If this is zero, or a null string, it means resume the scan
by advancing to the next ARGV-element. */
static char *nextchar;
/* Callers store zero here to inhibit the error message
for unrecognized options. */
int opterr = 1;
/* Set to an option character which was unrecognized.
This must be initialized on some systems to avoid linking in the
system's own getopt implementation. */
int optopt = '?';
/* Describe how to deal with options that follow non-option ARGV-elements.
If the caller did not specify anything,
the default is REQUIRE_ORDER if the environment variable
POSIXLY_CORRECT is defined, PERMUTE otherwise.
REQUIRE_ORDER means don't recognize them as options;
stop option processing when the first non-option is seen.
This is what Unix does.
This mode of operation is selected by either setting the environment
variable POSIXLY_CORRECT, or using `+' as the first character
of the list of option characters.
PERMUTE is the default. We permute the contents of ARGV as we scan,
so that eventually all the non-options are at the end. This allows options
to be given in any order, even with programs that were not written to
expect this.
RETURN_IN_ORDER is an option available to programs that were written
to expect options and other ARGV-elements in any order and that care about
the ordering of the two. We describe each non-option ARGV-element
as if it were the argument of an option with character code 1.
Using `-' as the first character of the list of option characters
selects this mode of operation.
The special argument `--' forces an end of option-scanning regardless
of the value of `ordering'. In the case of RETURN_IN_ORDER, only
`--' can cause `getopt' to return -1 with `optind' != ARGC. */
static enum
{
REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
} ordering;
/* Value of POSIXLY_CORRECT environment variable. */
static char *posixly_correct;
#ifdef __GNU_LIBRARY__
/* We want to avoid inclusion of string.h with non-GNU libraries
because there are many ways it can cause trouble.
On some systems, it contains special magic macros that don't work
in GCC. */
# include
# define my_index strchr
#else
# if HAVE_STRING_H
# include
# else
# include
# endif
/* Avoid depending on library functions or files
whose names are inconsistent. */
#ifndef getenv
extern char *getenv ();
#endif
static char *
my_index (const char *str, int chr)
{
while (*str)
{
if (*str == chr)
return (char *) str;
str++;
}
return 0;
}
/* If using GCC, we can safely declare strlen this way.
If not using GCC, it is ok not to declare it. */
#ifdef __GNUC__
/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
That was relevant to code that was here before. */
# if (!defined __STDC__ || !__STDC__) && !defined strlen
/* gcc with -traditional declares the built-in strlen to return int,
and has done so at least since version 2.4.5. -- rms. */
extern int strlen (const char *);
# endif /* not __STDC__ */
#endif /* __GNUC__ */
#endif /* not __GNU_LIBRARY__ */
/* Handle permutation of arguments. */
/* Describe the part of ARGV that contains non-options that have
been skipped. `first_nonopt' is the index in ARGV of the first of them;
`last_nonopt' is the index after the last of them. */
static int first_nonopt;
static int last_nonopt;
#ifdef _LIBC
/* Bash 2.0 gives us an environment variable containing flags
indicating ARGV elements that should not be considered arguments. */
/* Defined in getopt_init.c */
extern char *__getopt_nonoption_flags;
static int nonoption_flags_max_len;
static int nonoption_flags_len;
static int original_argc;
static char *const *original_argv;
/* Make sure the environment variable bash 2.0 puts in the environment
is valid for the getopt call we must make sure that the ARGV passed
to getopt is that one passed to the process. */
static void __attribute__ ((unused))
store_args_and_env (int argc, char *const *argv)
{
/* XXX This is no good solution. We should rather copy the args so
that we can compare them later. But we must not use malloc(3). */
original_argc = argc;
original_argv = argv;
}
# ifdef text_set_element
text_set_element (__libc_subinit, store_args_and_env);
# endif /* text_set_element */
# define SWAP_FLAGS(ch1, ch2) \
if (nonoption_flags_len > 0) \
{ \
char __tmp = __getopt_nonoption_flags[ch1]; \
__getopt_nonoption_flags[ch1] = __getopt_nonoption_flags[ch2]; \
__getopt_nonoption_flags[ch2] = __tmp; \
}
#else /* !_LIBC */
# define SWAP_FLAGS(ch1, ch2)
#endif /* _LIBC */
/* Exchange two adjacent subsequences of ARGV.
One subsequence is elements [first_nonopt,last_nonopt)
which contains all the non-options that have been skipped so far.
The other is elements [last_nonopt,optind), which contains all
the options processed since those non-options were skipped.
`first_nonopt' and `last_nonopt' are relocated so that they describe
the new indices of the non-options in ARGV after they are moved. */
#if defined __STDC__ && __STDC__
static void exchange (char **);
#endif
static void
exchange (char **argv)
{
int bottom = first_nonopt;
int middle = last_nonopt;
int top = optind;
char *tem;
/* Exchange the shorter segment with the far end of the longer segment.
That puts the shorter segment into the right place.
It leaves the longer segment in the right place overall,
but it consists of two parts that need to be swapped next. */
#ifdef _LIBC
/* First make sure the handling of the `__getopt_nonoption_flags'
string can work normally. Our top argument must be in the range
of the string. */
if (nonoption_flags_len > 0 && top >= nonoption_flags_max_len)
{
/* We must extend the array. The user plays games with us and
presents new arguments. */
char *new_str = malloc (top + 1);
if (new_str == NULL)
nonoption_flags_len = nonoption_flags_max_len = 0;
else
{
memset (__mempcpy (new_str, __getopt_nonoption_flags,
nonoption_flags_max_len),
'\0', top + 1 - nonoption_flags_max_len);
nonoption_flags_max_len = top + 1;
__getopt_nonoption_flags = new_str;
}
}
#endif
while (top > middle && middle > bottom)
{
if (top - middle > middle - bottom)
{
/* Bottom segment is the short one. */
int len = middle - bottom;
register int i;
/* Swap it with the top part of the top segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[top - (middle - bottom) + i];
argv[top - (middle - bottom) + i] = tem;
SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
}
/* Exclude the moved bottom segment from further swapping. */
top -= len;
}
else
{
/* Top segment is the short one. */
int len = top - middle;
register int i;
/* Swap it with the bottom part of the bottom segment. */
for (i = 0; i < len; i++)
{
tem = argv[bottom + i];
argv[bottom + i] = argv[middle + i];
argv[middle + i] = tem;
SWAP_FLAGS (bottom + i, middle + i);
}
/* Exclude the moved top segment from further swapping. */
bottom += len;
}
}
/* Update records for the slots the non-options now occupy. */
first_nonopt += (optind - last_nonopt);
last_nonopt = optind;
}
/* Initialize the internal data when the first call is made. */
#if defined __STDC__ && __STDC__
static const char *_getopt_initialize (int, char *const *, const char *);
#endif
static const char *
_getopt_initialize (int argc, char *const *argv, const char *optstring)
{
/* Start processing options with ARGV-element 1 (since ARGV-element 0
is the program name); the sequence of previously skipped
non-option ARGV-elements is empty. */
first_nonopt = last_nonopt = optind;
nextchar = NULL;
posixly_correct = getenv ("POSIXLY_CORRECT");
/* Determine how to handle the ordering of options and nonoptions. */
if (optstring[0] == '-')
{
ordering = RETURN_IN_ORDER;
++optstring;
}
else if (optstring[0] == '+')
{
ordering = REQUIRE_ORDER;
++optstring;
}
else if (posixly_correct != NULL)
ordering = REQUIRE_ORDER;
else
ordering = PERMUTE;
#ifdef _LIBC
if (posixly_correct == NULL
&& argc == original_argc && argv == original_argv)
{
if (nonoption_flags_max_len == 0)
{
if (__getopt_nonoption_flags == NULL
|| __getopt_nonoption_flags[0] == '\0')
nonoption_flags_max_len = -1;
else
{
const char *orig_str = __getopt_nonoption_flags;
int len = nonoption_flags_max_len = strlen (orig_str);
if (nonoption_flags_max_len < argc)
nonoption_flags_max_len = argc;
__getopt_nonoption_flags =
(char *) malloc (nonoption_flags_max_len);
if (__getopt_nonoption_flags == NULL)
nonoption_flags_max_len = -1;
else
memset (__mempcpy (__getopt_nonoption_flags, orig_str, len),
'\0', nonoption_flags_max_len - len);
}
}
nonoption_flags_len = nonoption_flags_max_len;
}
else
nonoption_flags_len = 0;
#endif
return optstring;
}
/* Scan elements of ARGV (whose length is ARGC) for option characters
given in OPTSTRING.
If an element of ARGV starts with '-', and is not exactly "-" or "--",
then it is an option element. The characters of this element
(aside from the initial '-') are option characters. If `getopt'
is called repeatedly, it returns successively each of the option characters
from each of the option elements.
If `getopt' finds another option character, it returns that character,
updating `optind' and `nextchar' so that the next call to `getopt' can
resume the scan with the following option character or ARGV-element.
If there are no more option characters, `getopt' returns -1.
Then `optind' is the index in ARGV of the first ARGV-element
that is not an option. (The ARGV-elements have been permuted
so that those that are not options now come last.)
OPTSTRING is a string containing the legitimate option characters.
If an option character is seen that is not listed in OPTSTRING,
return '?' after printing an error message. If you set `opterr' to
zero, the error message is suppressed but we still return '?'.
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
so the following text in the same ARGV-element, or the text of the following
ARGV-element, is returned in `optarg'. Two colons mean an option that
wants an optional arg; if there is text in the current ARGV-element,
it is returned in `optarg', otherwise `optarg' is set to zero.
If OPTSTRING starts with `-' or `+', it requests different methods of
handling the non-option ARGV-elements.
See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
Long-named options begin with `--' instead of `-'.
Their names may be abbreviated as long as the abbreviation is unique
or is an exact match for some defined option. If they have an
argument, it follows the option name in the same ARGV-element, separated
from the option name by a `=', or else the in next ARGV-element.
When `getopt' finds a long-named option, it returns 0 if that option's
`flag' field is nonzero, the value of the option's `val' field
if the `flag' field is zero.
The elements of ARGV aren't really const, because we permute them.
But we pretend they're const in the prototype to be compatible
with other systems.
LONGOPTS is a vector of `struct option' terminated by an
element containing a name which is zero.
LONGIND returns the index in LONGOPT of the long-named option found.
It is only valid when a long-named option has been found by the most
recent call.
If LONG_ONLY is nonzero, '-' as well as '--' can introduce
long-named options. */
int
_getopt_internal (int argc, char *const *argv, const char *optstring,
const struct option *longopts, int *longind, int long_only)
{
optarg = NULL;
if (optind == 0 || !__getopt_initialized)
{
if (optind == 0)
optind = 1; /* Don't scan ARGV[0], the program name. */
optstring = _getopt_initialize (argc, argv, optstring);
__getopt_initialized = 1;
}
/* Test whether ARGV[optind] points to a non-option argument.
Either it does not have option syntax, or there is an environment flag
from the shell indicating it is not an option. The later information
is only used when the used in the GNU libc. */
#ifdef _LIBC
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0' \
|| (optind < nonoption_flags_len \
&& __getopt_nonoption_flags[optind] == '1'))
#else
# define NONOPTION_P (argv[optind][0] != '-' || argv[optind][1] == '\0')
#endif
if (nextchar == NULL || *nextchar == '\0')
{
/* Advance to the next ARGV-element. */
/* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
moved back by the user (who may also have changed the arguments). */
if (last_nonopt > optind)
last_nonopt = optind;
if (first_nonopt > optind)
first_nonopt = optind;
if (ordering == PERMUTE)
{
/* If we have just processed some options following some non-options,
exchange them so that the options come first. */
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (last_nonopt != optind)
first_nonopt = optind;
/* Skip any additional non-options
and extend the range of non-options previously skipped. */
while (optind < argc && NONOPTION_P)
optind++;
last_nonopt = optind;
}
/* The special ARGV-element `--' means premature end of options.
Skip it like a null option,
then exchange with previous non-options as if it were an option,
then skip everything else like a non-option. */
if (optind != argc && !strcmp (argv[optind], "--"))
{
optind++;
if (first_nonopt != last_nonopt && last_nonopt != optind)
exchange ((char **) argv);
else if (first_nonopt == last_nonopt)
first_nonopt = optind;
last_nonopt = argc;
optind = argc;
}
/* If we have done all the ARGV-elements, stop the scan
and back over any non-options that we skipped and permuted. */
if (optind == argc)
{
/* Set the next-arg-index to point at the non-options
that we previously skipped, so the caller will digest them. */
if (first_nonopt != last_nonopt)
optind = first_nonopt;
return -1;
}
/* If we have come to a non-option and did not permute it,
either stop the scan or describe it to the caller and pass it by. */
if (NONOPTION_P)
{
if (ordering == REQUIRE_ORDER)
return -1;
optarg = argv[optind++];
return 1;
}
/* We have found another option-ARGV-element.
Skip the initial punctuation. */
nextchar = (argv[optind] + 1
+ (longopts != NULL && argv[optind][1] == '-'));
}
/* Decode the current option-ARGV-element. */
/* Check whether the ARGV-element is a long option.
If long_only and the ARGV-element has the form "-f", where f is
a valid short option, don't consider it an abbreviated form of
a long option that starts with f. Otherwise there would be no
way to give the -f short option.
On the other hand, if there's a long option "fubar" and
the ARGV-element is "-fu", do consider that an abbreviation of
the long option, just like "--fu", and not "-f" with arg "u".
This distinction seems to be the most useful approach. */
if (longopts != NULL
&& (argv[optind][1] == '-'
|| (long_only && (argv[optind][2] || !my_index (optstring, argv[optind][1])))))
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = -1;
int option_index;
for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar)
== (unsigned int) strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, _("%s: option '%s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
optopt = 0;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
optind++;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
if (argv[optind - 1][1] == '-')
/* --option */
fprintf (stderr,
_("%s: option '--%s' doesn't allow an argument\n"),
argv[0], pfound->name);
else
/* +option or -option */
fprintf (stderr,
_("%s: option '%c%s' doesn't allow an argument\n"),
argv[0], argv[optind - 1][0], pfound->name);
nextchar += strlen (nextchar);
optopt = pfound->val;
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
_("%s: option '%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
optopt = pfound->val;
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
/* Can't find it as a long option. If this is not getopt_long_only,
or the option starts with '--' or is not a valid short
option, then it's an error.
Otherwise interpret it as a short option. */
if (!long_only || argv[optind][1] == '-'
|| my_index (optstring, *nextchar) == NULL)
{
if (opterr)
{
if (argv[optind][1] == '-')
/* --option */
fprintf (stderr, _("%s: unrecognized option '--%s'\n"),
argv[0], nextchar);
else
/* +option or -option */
fprintf (stderr, _("%s: unrecognized option '%c%s'\n"),
argv[0], argv[optind][0], nextchar);
}
nextchar = (char *) "";
optind++;
optopt = 0;
return '?';
}
}
/* Look at and handle the next short option-character. */
{
char c = *nextchar++;
char *temp = my_index (optstring, c);
/* Increment `optind' when we start to process its last character. */
if (*nextchar == '\0')
++optind;
if (temp == NULL || c == ':')
{
if (opterr)
{
if (posixly_correct)
/* 1003.2 specifies the format of this message. */
fprintf (stderr, _("%s: illegal option -- %c\n"),
argv[0], c);
else
fprintf (stderr, _("%s: invalid option -- %c\n"),
argv[0], c);
}
optopt = c;
return '?';
}
/* Convenience. Treat POSIX -W foo same as long option --foo */
if (temp[0] == 'W' && temp[1] == ';')
{
char *nameend;
const struct option *p;
const struct option *pfound = NULL;
int exact = 0;
int ambig = 0;
int indfound = 0;
int option_index;
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr, _("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
return c;
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
/* optarg is now the argument, see if it's in the
table of longopts. */
for (nextchar = nameend = optarg; *nameend && *nameend != '='; nameend++)
/* Do nothing. */ ;
/* Test all long options for either exact match
or abbreviated matches. */
for (p = longopts, option_index = 0; p->name; p++, option_index++)
if (!strncmp (p->name, nextchar, nameend - nextchar))
{
if ((unsigned int) (nameend - nextchar) == strlen (p->name))
{
/* Exact match found. */
pfound = p;
indfound = option_index;
exact = 1;
break;
}
else if (pfound == NULL)
{
/* First nonexact match found. */
pfound = p;
indfound = option_index;
}
else
/* Second or later nonexact match found. */
ambig = 1;
}
if (ambig && !exact)
{
if (opterr)
fprintf (stderr, _("%s: option '-W %s' is ambiguous\n"),
argv[0], argv[optind]);
nextchar += strlen (nextchar);
optind++;
return '?';
}
if (pfound != NULL)
{
option_index = indfound;
if (*nameend)
{
/* Don't test has_arg with >, because some C compilers don't
allow it to be used on enums. */
if (pfound->has_arg)
optarg = nameend + 1;
else
{
if (opterr)
fprintf (stderr, _("\
%s: option '-W %s' doesn't allow an argument\n"),
argv[0], pfound->name);
nextchar += strlen (nextchar);
return '?';
}
}
else if (pfound->has_arg == 1)
{
if (optind < argc)
optarg = argv[optind++];
else
{
if (opterr)
fprintf (stderr,
_("%s: option '%s' requires an argument\n"),
argv[0], argv[optind - 1]);
nextchar += strlen (nextchar);
return optstring[0] == ':' ? ':' : '?';
}
}
nextchar += strlen (nextchar);
if (longind != NULL)
*longind = option_index;
if (pfound->flag)
{
*(pfound->flag) = pfound->val;
return 0;
}
return pfound->val;
}
nextchar = NULL;
return 'W'; /* Let the application handle it. */
}
if (temp[1] == ':')
{
if (temp[2] == ':')
{
/* This is an option that accepts an argument optionally. */
if (*nextchar != '\0')
{
optarg = nextchar;
optind++;
}
else
optarg = NULL;
nextchar = NULL;
}
else
{
/* This is an option that requires an argument. */
if (*nextchar != '\0')
{
optarg = nextchar;
/* If we end this ARGV-element by taking the rest as an arg,
we must advance to the next element now. */
optind++;
}
else if (optind == argc)
{
if (opterr)
{
/* 1003.2 specifies the format of this message. */
fprintf (stderr,
_("%s: option requires an argument -- %c\n"),
argv[0], c);
}
optopt = c;
if (optstring[0] == ':')
c = ':';
else
c = '?';
}
else
/* We already incremented `optind' once;
increment it again when taking next ARGV-elt as argument. */
optarg = argv[optind++];
nextchar = NULL;
}
}
return c;
}
}
int
getopt (int argc, char *const *argv, const char *optstring)
{
return _getopt_internal (argc, argv, optstring,
(const struct option *) 0,
(int *) 0,
0);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
/* Compile with -DTEST to make an executable for use in testing
the above definition of `getopt'. */
int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
c = getopt (argc, argv, "abc:d:0123456789");
if (c == -1)
break;
switch (c)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */
make-4.2.1/read.c 0000644 0001750 0001750 00000305605 12720141610 010436 0000000 0000000 /* Reading and parsing of makefiles for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#include
#include "filedef.h"
#include "dep.h"
#include "job.h"
#include "commands.h"
#include "variable.h"
#include "rule.h"
#include "debug.h"
#include "hash.h"
#ifdef WINDOWS32
#include
#include "sub_proc.h"
#else /* !WINDOWS32 */
#ifndef _AMIGA
#ifndef VMS
#include
#else
struct passwd *getpwnam (char *name);
#endif
#endif
#endif /* !WINDOWS32 */
/* A 'struct ebuffer' controls the origin of the makefile we are currently
eval'ing.
*/
struct ebuffer
{
char *buffer; /* Start of the current line in the buffer. */
char *bufnext; /* Start of the next line in the buffer. */
char *bufstart; /* Start of the entire buffer. */
unsigned int size; /* Malloc'd size of buffer. */
FILE *fp; /* File, or NULL if this is an internal buffer. */
floc floc; /* Info on the file in fp (if any). */
};
/* Track the modifiers we can have on variable assignments */
struct vmodifiers
{
unsigned int assign_v:1;
unsigned int define_v:1;
unsigned int undefine_v:1;
unsigned int export_v:1;
unsigned int override_v:1;
unsigned int private_v:1;
};
/* Types of "words" that can be read in a makefile. */
enum make_word_type
{
w_bogus, w_eol, w_static, w_variable, w_colon, w_dcolon, w_semicolon,
w_varassign
};
/* A 'struct conditionals' contains the information describing
all the active conditionals in a makefile.
The global variable 'conditionals' contains the conditionals
information for the current makefile. It is initialized from
the static structure 'toplevel_conditionals' and is later changed
to new structures for included makefiles. */
struct conditionals
{
unsigned int if_cmds; /* Depth of conditional nesting. */
unsigned int allocated; /* Elts allocated in following arrays. */
char *ignoring; /* Are we ignoring or interpreting?
0=interpreting, 1=not yet interpreted,
2=already interpreted */
char *seen_else; /* Have we already seen an 'else'? */
};
static struct conditionals toplevel_conditionals;
static struct conditionals *conditionals = &toplevel_conditionals;
/* Default directories to search for include files in */
static const char *default_include_directories[] =
{
#if defined(WINDOWS32) && !defined(INCLUDEDIR)
/* This completely up to the user when they install MSVC or other packages.
This is defined as a placeholder. */
# define INCLUDEDIR "."
#endif
INCLUDEDIR,
#ifndef _AMIGA
"/usr/gnu/include",
"/usr/local/include",
"/usr/include",
#endif
0
};
/* List of directories to search for include files in */
static const char **include_directories;
/* Maximum length of an element of the above. */
static unsigned int max_incl_len;
/* The filename and pointer to line number of the
makefile currently being read in. */
const floc *reading_file = 0;
/* The chain of files read by read_all_makefiles. */
static struct goaldep *read_files = 0;
static struct goaldep *eval_makefile (const char *filename, int flags);
static void eval (struct ebuffer *buffer, int flags);
static long readline (struct ebuffer *ebuf);
static void do_undefine (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
static struct variable *do_define (char *name, enum variable_origin origin,
struct ebuffer *ebuf);
static int conditional_line (char *line, int len, const floc *flocp);
static void record_files (struct nameseq *filenames, const char *pattern,
const char *pattern_percent, char *depstr,
unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon,
char prefix, const floc *flocp);
static void record_target_var (struct nameseq *filenames, char *defn,
enum variable_origin origin,
struct vmodifiers *vmod,
const floc *flocp);
static enum make_word_type get_next_mword (char *buffer, char *delim,
char **startp, unsigned int *length);
static void remove_comments (char *line);
static char *find_char_unquote (char *string, int map);
static char *unescape_char (char *string, int c);
/* Compare a word, both length and contents.
P must point to the word to be tested, and WLEN must be the length.
*/
#define word1eq(s) (wlen == CSTRLEN (s) && strneq (s, p, CSTRLEN (s)))
/* Read in all the makefiles and return a chain of targets to rebuild. */
struct goaldep *
read_all_makefiles (const char **makefiles)
{
unsigned int num_makefiles = 0;
/* Create *_LIST variables, to hold the makefiles, targets, and variables
we will be reading. */
define_variable_cname ("MAKEFILE_LIST", "", o_file, 0);
DB (DB_BASIC, (_("Reading makefiles...\n")));
/* If there's a non-null variable MAKEFILES, its value is 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. */
{
char *value;
char *name, *p;
unsigned int length;
{
/* Turn off --warn-undefined-variables while we expand MAKEFILES. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
value = allocated_variable_expand ("$(MAKEFILES)");
warn_undefined_variables_flag = save;
}
/* Set NAME to the start of next token and LENGTH to its length.
MAKEFILES is updated for finding remaining tokens. */
p = value;
while ((name = find_next_token ((const char **)&p, &length)) != 0)
{
if (*p != '\0')
*p++ = '\0';
eval_makefile (name, RM_NO_DEFAULT_GOAL|RM_INCLUDED|RM_DONTCARE);
}
free (value);
}
/* Read makefiles specified with -f switches. */
if (makefiles != 0)
while (*makefiles != 0)
{
struct goaldep *d = eval_makefile (*makefiles, 0);
if (errno)
perror_with_name ("", *makefiles);
/* Reuse the storage allocated for the read_file. */
*makefiles = dep_name (d);
++num_makefiles;
++makefiles;
}
/* If there were no -f switches, try the default names. */
if (num_makefiles == 0)
{
static const char *default_makefiles[] =
#ifdef VMS
/* all lower case since readdir() (the vms version) 'lowercasifies' */
/* TODO: Above is not always true, this needs more work */
{ "makefile.vms", "gnumakefile", "makefile", 0 };
#else
#ifdef _AMIGA
{ "GNUmakefile", "Makefile", "SMakefile", 0 };
#else /* !Amiga && !VMS */
#ifdef WINDOWS32
{ "GNUmakefile", "makefile", "Makefile", "makefile.mak", 0 };
#else /* !Amiga && !VMS && !WINDOWS32 */
{ "GNUmakefile", "makefile", "Makefile", 0 };
#endif /* !Amiga && !VMS && !WINDOWS32 */
#endif /* AMIGA */
#endif /* VMS */
const char **p = default_makefiles;
while (*p != 0 && !file_exists_p (*p))
++p;
if (*p != 0)
{
eval_makefile (*p, 0);
if (errno)
perror_with_name ("", *p);
}
else
{
/* No default makefile was found. Add the default makefiles to the
'read_files' chain so they will be updated if possible. */
struct goaldep *tail = read_files;
/* Add them to the tail, after any MAKEFILES variable makefiles. */
while (tail != 0 && tail->next != 0)
tail = tail->next;
for (p = default_makefiles; *p != 0; ++p)
{
struct goaldep *d = alloc_goaldep ();
d->file = enter_file (strcache_add (*p));
/* Tell update_goal_chain to bail out as soon as this file is
made, and main not to die if we can't make this file. */
d->flags = RM_DONTCARE;
if (tail == 0)
read_files = d;
else
tail->next = d;
tail = d;
}
if (tail != 0)
tail->next = 0;
}
}
return read_files;
}
/* Install a new conditional and return the previous one. */
static struct conditionals *
install_conditionals (struct conditionals *new)
{
struct conditionals *save = conditionals;
memset (new, '\0', sizeof (*new));
conditionals = new;
return save;
}
/* Free the current conditionals and reinstate a saved one. */
static void
restore_conditionals (struct conditionals *saved)
{
/* Free any space allocated by conditional_line. */
free (conditionals->ignoring);
free (conditionals->seen_else);
/* Restore state. */
conditionals = saved;
}
static struct goaldep *
eval_makefile (const char *filename, int flags)
{
struct goaldep *deps;
struct ebuffer ebuf;
const floc *curfile;
char *expanded = 0;
int makefile_errno;
ebuf.floc.filenm = filename; /* Use the original file name. */
ebuf.floc.lineno = 1;
ebuf.floc.offset = 0;
if (ISDB (DB_VERBOSE))
{
printf (_("Reading makefile '%s'"), filename);
if (flags & RM_NO_DEFAULT_GOAL)
printf (_(" (no default goal)"));
if (flags & RM_INCLUDED)
printf (_(" (search path)"));
if (flags & RM_DONTCARE)
printf (_(" (don't care)"));
if (flags & RM_NO_TILDE)
printf (_(" (no ~ expansion)"));
puts ("...");
}
/* First, get a stream to read. */
/* Expand ~ in FILENAME unless it came from 'include',
in which case it was already done. */
if (!(flags & RM_NO_TILDE) && filename[0] == '~')
{
expanded = tilde_expand (filename);
if (expanded != 0)
filename = expanded;
}
ENULLLOOP (ebuf.fp, fopen (filename, "r"));
/* Save the error code so we print the right message later. */
makefile_errno = errno;
/* Check for unrecoverable errors: out of mem or FILE slots. */
switch (makefile_errno)
{
#ifdef EMFILE
case EMFILE:
#endif
#ifdef ENFILE
case ENFILE:
#endif
case ENOMEM:
{
const char *err = strerror (makefile_errno);
OS (fatal, reading_file, "%s", err);
}
}
/* If the makefile wasn't found and it's either a makefile from
the 'MAKEFILES' variable or an included makefile,
search the included makefile search path for this makefile. */
if (ebuf.fp == 0 && (flags & RM_INCLUDED) && *filename != '/')
{
unsigned int i;
for (i = 0; include_directories[i] != 0; ++i)
{
const char *included = concat (3, include_directories[i],
"/", filename);
ebuf.fp = fopen (included, "r");
if (ebuf.fp)
{
filename = included;
break;
}
}
}
/* Now we have the final name for this makefile. Enter it into
the cache. */
filename = strcache_add (filename);
/* Add FILENAME to the chain of read makefiles. */
deps = alloc_goaldep ();
deps->next = read_files;
read_files = deps;
deps->file = lookup_file (filename);
if (deps->file == 0)
deps->file = enter_file (filename);
filename = deps->file->name;
deps->flags = flags;
free (expanded);
/* If the makefile can't be found at all, give up entirely. */
if (ebuf.fp == 0)
{
/* If we did some searching, errno has the error from the last
attempt, rather from FILENAME itself. Store it in case the
caller wants to use it in a message. */
errno = makefile_errno;
return deps;
}
/* Set close-on-exec to avoid leaking the makefile to children, such as
$(shell ...). */
#ifdef HAVE_FILENO
CLOSE_ON_EXEC (fileno (ebuf.fp));
#endif
/* Add this makefile to the list. */
do_variable_definition (&ebuf.floc, "MAKEFILE_LIST", filename, o_file,
f_append, 0);
/* Evaluate the makefile */
ebuf.size = 200;
ebuf.buffer = ebuf.bufnext = ebuf.bufstart = xmalloc (ebuf.size);
curfile = reading_file;
reading_file = &ebuf.floc;
eval (&ebuf, !(flags & RM_NO_DEFAULT_GOAL));
reading_file = curfile;
fclose (ebuf.fp);
free (ebuf.bufstart);
alloca (0);
errno = 0;
return deps;
}
void
eval_buffer (char *buffer, const floc *flocp)
{
struct ebuffer ebuf;
struct conditionals *saved;
struct conditionals new;
const floc *curfile;
/* Evaluate the buffer */
ebuf.size = strlen (buffer);
ebuf.buffer = ebuf.bufnext = ebuf.bufstart = buffer;
ebuf.fp = NULL;
if (flocp)
ebuf.floc = *flocp;
else if (reading_file)
ebuf.floc = *reading_file;
else
{
ebuf.floc.filenm = NULL;
ebuf.floc.lineno = 1;
ebuf.floc.offset = 0;
}
curfile = reading_file;
reading_file = &ebuf.floc;
saved = install_conditionals (&new);
eval (&ebuf, 1);
restore_conditionals (saved);
reading_file = curfile;
alloca (0);
}
/* Check LINE to see if it's a variable assignment or undefine.
It might use one of the modifiers "export", "override", "private", or it
might be one of the conditional tokens like "ifdef", "include", etc.
If it's not a variable assignment or undefine, VMOD.V_ASSIGN is 0.
Returns LINE.
Returns a pointer to the first non-modifier character, and sets VMOD
based on the modifiers found if any, plus V_ASSIGN is 1.
*/
static char *
parse_var_assignment (const char *line, struct vmodifiers *vmod)
{
const char *p;
memset (vmod, '\0', sizeof (*vmod));
/* Find the start of the next token. If there isn't one we're done. */
NEXT_TOKEN (line);
if (*line == '\0')
return (char *)line;
p = line;
while (1)
{
int wlen;
const char *p2;
struct variable v;
p2 = parse_variable_definition (p, &v);
/* If this is a variable assignment, we're done. */
if (p2)
break;
/* It's not a variable; see if it's a modifier. */
p2 = end_of_token (p);
wlen = p2 - p;
if (word1eq ("export"))
vmod->export_v = 1;
else if (word1eq ("override"))
vmod->override_v = 1;
else if (word1eq ("private"))
vmod->private_v = 1;
else if (word1eq ("define"))
{
/* We can't have modifiers after 'define' */
vmod->define_v = 1;
p = next_token (p2);
break;
}
else if (word1eq ("undefine"))
{
/* We can't have modifiers after 'undefine' */
vmod->undefine_v = 1;
p = next_token (p2);
break;
}
else
/* Not a variable or modifier: this is not a variable assignment. */
return (char *)line;
/* It was a modifier. Try the next word. */
p = next_token (p2);
if (*p == '\0')
return (char *)line;
}
/* Found a variable assignment or undefine. */
vmod->assign_v = 1;
return (char *)p;
}
/* Read file FILENAME as a makefile and add its contents to the data base.
SET_DEFAULT is true if we are allowed to set the default goal. */
static void
eval (struct ebuffer *ebuf, int set_default)
{
char *collapsed = 0;
unsigned int collapsed_length = 0;
unsigned int commands_len = 200;
char *commands;
unsigned int commands_idx = 0;
unsigned int cmds_started, tgts_started;
int ignoring = 0, in_ignored_define = 0;
int no_targets = 0; /* Set when reading a rule without targets. */
struct nameseq *filenames = 0;
char *depstr = 0;
long nlines = 0;
int two_colon = 0;
char prefix = cmd_prefix;
const char *pattern = 0;
const char *pattern_percent;
floc *fstart;
floc fi;
#define record_waiting_files() \
do \
{ \
if (filenames != 0) \
{ \
fi.lineno = tgts_started; \
fi.offset = 0; \
record_files (filenames, pattern, pattern_percent, depstr, \
cmds_started, commands, commands_idx, two_colon, \
prefix, &fi); \
filenames = 0; \
} \
commands_idx = 0; \
no_targets = 0; \
pattern = 0; \
} while (0)
pattern_percent = 0;
cmds_started = tgts_started = 1;
fstart = &ebuf->floc;
fi.filenm = ebuf->floc.filenm;
/* 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.
When you see a "continue" in the loop below, that means we are moving on
to the next line. If you see record_waiting_files(), then the statement
we are parsing also finishes the previous rule. */
commands = xmalloc (200);
while (1)
{
unsigned int linelen;
char *line;
unsigned int wlen;
char *p;
char *p2;
struct vmodifiers vmod;
/* At the top of this loop, we are starting a brand new line. */
/* Grab the next line to be evaluated */
ebuf->floc.lineno += nlines;
nlines = readline (ebuf);
/* If there is nothing left to eval, we're done. */
if (nlines < 0)
break;
line = ebuf->buffer;
/* If this is the first line, check for a UTF-8 BOM and skip it. */
if (ebuf->floc.lineno == 1 && line[0] == (char)0xEF
&& line[1] == (char)0xBB && line[2] == (char)0xBF)
{
line += 3;
if (ISDB(DB_BASIC))
{
if (ebuf->floc.filenm)
printf (_("Skipping UTF-8 BOM in makefile '%s'\n"),
ebuf->floc.filenm);
else
printf (_("Skipping UTF-8 BOM in makefile buffer\n"));
}
}
/* If this line is empty, skip it. */
if (line[0] == '\0')
continue;
linelen = strlen (line);
/* Check for a shell command line first.
If it is not one, we can stop treating cmd_prefix specially. */
if (line[0] == cmd_prefix)
{
if (no_targets)
/* Ignore the commands in a rule with no targets. */
continue;
/* If there is no preceding rule line, don't treat this line
as a command, even though it begins with a recipe prefix.
SunOS 4 make appears to behave this way. */
if (filenames != 0)
{
if (ignoring)
/* Yep, this is a shell command, and we don't care. */
continue;
if (commands_idx == 0)
cmds_started = ebuf->floc.lineno;
/* Append this command line to the line being accumulated.
Skip the initial command prefix character. */
if (linelen + commands_idx > commands_len)
{
commands_len = (linelen + commands_idx) * 2;
commands = xrealloc (commands, commands_len);
}
memcpy (&commands[commands_idx], line + 1, linelen - 1);
commands_idx += linelen - 1;
commands[commands_idx++] = '\n';
continue;
}
}
/* This line is not a shell command line. Don't worry about whitespace.
Get more space if we need it; we don't need to preserve the current
contents of the buffer. */
if (collapsed_length < linelen+1)
{
collapsed_length = linelen+1;
free (collapsed);
/* Don't need xrealloc: we don't need to preserve the content. */
collapsed = xmalloc (collapsed_length);
}
strcpy (collapsed, line);
/* Collapse continuation lines. */
collapse_continuations (collapsed);
remove_comments (collapsed);
/* Get rid if starting space (including formfeed, vtab, etc.) */
p = collapsed;
NEXT_TOKEN (p);
/* See if this is a variable assignment. We need to do this early, to
allow variables with names like 'ifdef', 'export', 'private', etc. */
p = parse_var_assignment (p, &vmod);
if (vmod.assign_v)
{
struct variable *v;
enum variable_origin origin = vmod.override_v ? o_override : o_file;
/* If we're ignoring then we're done now. */
if (ignoring)
{
if (vmod.define_v)
in_ignored_define = 1;
continue;
}
/* Variable assignment ends the previous rule. */
record_waiting_files ();
if (vmod.undefine_v)
{
do_undefine (p, origin, ebuf);
continue;
}
else if (vmod.define_v)
v = do_define (p, origin, ebuf);
else
v = try_variable_definition (fstart, p, origin, 0);
assert (v != NULL);
if (vmod.export_v)
v->export = v_export;
if (vmod.private_v)
v->private_var = 1;
/* This line has been dealt with. */
continue;
}
/* If this line is completely empty, ignore it. */
if (*p == '\0')
continue;
p2 = end_of_token (p);
wlen = p2 - p;
NEXT_TOKEN (p2);
/* If we're in an ignored define, skip this line (but maybe get out). */
if (in_ignored_define)
{
/* See if this is an endef line (plus optional comment). */
if (word1eq ("endef") && STOP_SET (*p2, MAP_COMMENT|MAP_NUL))
in_ignored_define = 0;
continue;
}
/* Check for conditional state changes. */
{
int i = conditional_line (p, wlen, fstart);
if (i != -2)
{
if (i == -1)
O (fatal, fstart, _("invalid syntax in conditional"));
ignoring = i;
continue;
}
}
/* Nothing to see here... move along. */
if (ignoring)
continue;
/* Manage the "export" keyword used outside of variable assignment
as well as "unexport". */
if (word1eq ("export") || word1eq ("unexport"))
{
int exporting = *p == 'u' ? 0 : 1;
/* Export/unexport ends the previous rule. */
record_waiting_files ();
/* (un)export by itself causes everything to be (un)exported. */
if (*p2 == '\0')
export_all_variables = exporting;
else
{
unsigned int l;
const char *cp;
char *ap;
/* Expand the line so we can use indirect and constructed
variable names in an (un)export command. */
cp = ap = allocated_variable_expand (p2);
for (p = find_next_token (&cp, &l); p != 0;
p = find_next_token (&cp, &l))
{
struct variable *v = lookup_variable (p, l);
if (v == 0)
v = define_variable_global (p, l, "", o_file, 0, fstart);
v->export = exporting ? v_export : v_noexport;
}
free (ap);
}
continue;
}
/* Handle the special syntax for vpath. */
if (word1eq ("vpath"))
{
const char *cp;
char *vpat;
unsigned int l;
/* vpath ends the previous rule. */
record_waiting_files ();
cp = variable_expand (p2);
p = find_next_token (&cp, &l);
if (p != 0)
{
vpat = xstrndup (p, l);
p = find_next_token (&cp, &l);
/* No searchpath means remove all previous
selective VPATH's with the same pattern. */
}
else
/* No pattern means remove all previous selective VPATH's. */
vpat = 0;
construct_vpath_list (vpat, p);
free (vpat);
continue;
}
/* Handle include and variants. */
if (word1eq ("include") || word1eq ("-include") || word1eq ("sinclude"))
{
/* We have found an 'include' line specifying a nested
makefile to be read at this point. */
struct conditionals *save;
struct conditionals new_conditionals;
struct nameseq *files;
/* "-include" (vs "include") says no error if the file does not
exist. "sinclude" is an alias for this from SGI. */
int noerror = (p[0] != 'i');
/* Include ends the previous rule. */
record_waiting_files ();
p = allocated_variable_expand (p2);
/* If no filenames, it's a no-op. */
if (*p == '\0')
{
free (p);
continue;
}
/* Parse the list of file names. Don't expand archive references! */
p2 = p;
files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
PARSEFS_NOAR);
free (p);
/* Save the state of conditionals and start
the included makefile with a clean slate. */
save = install_conditionals (&new_conditionals);
/* Record the rules that are waiting so they will determine
the default goal before those in the included makefile. */
record_waiting_files ();
/* Read each included makefile. */
while (files != 0)
{
struct nameseq *next = files->next;
int flags = (RM_INCLUDED | RM_NO_TILDE
| (noerror ? RM_DONTCARE : 0)
| (set_default ? 0 : RM_NO_DEFAULT_GOAL));
struct goaldep *d = eval_makefile (files->name, flags);
if (errno)
{
d->error = (unsigned short)errno;
d->floc = *fstart;
}
free_ns (files);
files = next;
}
/* Restore conditional state. */
restore_conditionals (save);
continue;
}
/* Handle the load operations. */
if (word1eq ("load") || word1eq ("-load"))
{
/* A 'load' line specifies a dynamic object to load. */
struct nameseq *files;
int noerror = (p[0] == '-');
/* Load ends the previous rule. */
record_waiting_files ();
p = allocated_variable_expand (p2);
/* If no filenames, it's a no-op. */
if (*p == '\0')
{
free (p);
continue;
}
/* Parse the list of file names.
Don't expand archive references or strip "./" */
p2 = p;
files = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_NUL, NULL,
PARSEFS_NOAR);
free (p);
/* Load each file. */
while (files != 0)
{
struct nameseq *next = files->next;
const char *name = files->name;
struct goaldep *deps;
int r;
/* Load the file. 0 means failure. */
r = load_file (&ebuf->floc, &name, noerror);
if (! r && ! noerror)
OS (fatal, &ebuf->floc, _("%s: failed to load"), name);
free_ns (files);
files = next;
/* Return of -1 means a special load: don't rebuild it. */
if (r == -1)
continue;
/* It succeeded, so add it to the list "to be rebuilt". */
deps = alloc_goaldep ();
deps->next = read_files;
read_files = deps;
deps->file = lookup_file (name);
if (deps->file == 0)
deps->file = enter_file (name);
deps->file->loaded = 1;
}
continue;
}
/* This line starts with a tab but was not caught above because there
was no preceding target, and the line might have been usable as a
variable definition. But now we know it is definitely lossage. */
if (line[0] == cmd_prefix)
O (fatal, fstart, _("recipe commences before first target"));
/* This line describes some target files. This is complicated by
the existence of target-specific variables, because we can't
expand the entire line until we know if we have one or not. So
we expand the line word by word until we find the first ':',
then check to see if it's a target-specific variable.
In this algorithm, 'lb_next' will point to the beginning of the
unexpanded parts of the input buffer, while 'p2' points to the
parts of the expanded buffer we haven't searched yet. */
{
enum make_word_type wtype;
char *cmdleft, *semip, *lb_next;
unsigned int plen = 0;
char *colonp;
const char *end, *beg; /* Helpers for whitespace stripping. */
/* Record the previous rule. */
record_waiting_files ();
tgts_started = fstart->lineno;
/* Search the line for an unquoted ; that is not after an
unquoted #. */
cmdleft = find_char_unquote (line, MAP_SEMI|MAP_COMMENT|MAP_VARIABLE);
if (cmdleft != 0 && *cmdleft == '#')
{
/* We found a comment before a semicolon. */
*cmdleft = '\0';
cmdleft = 0;
}
else if (cmdleft != 0)
/* Found one. Cut the line short there before expanding it. */
*(cmdleft++) = '\0';
semip = cmdleft;
collapse_continuations (line);
/* We can't expand the entire line, since if it's a per-target
variable we don't want to expand it. So, walk from the
beginning, expanding as we go, and looking for "interesting"
chars. The first word is always expandable. */
wtype = get_next_mword (line, NULL, &lb_next, &wlen);
switch (wtype)
{
case w_eol:
if (cmdleft != 0)
O (fatal, fstart, _("missing rule before recipe"));
/* This line contained something but turned out to be nothing
but whitespace (a comment?). */
continue;
case w_colon:
case w_dcolon:
/* We accept and ignore rules without targets for
compatibility with SunOS 4 make. */
no_targets = 1;
continue;
default:
break;
}
p2 = variable_expand_string (NULL, lb_next, wlen);
while (1)
{
lb_next += wlen;
if (cmdleft == 0)
{
/* Look for a semicolon in the expanded line. */
cmdleft = find_char_unquote (p2, MAP_SEMI);
if (cmdleft != 0)
{
unsigned long p2_off = p2 - variable_buffer;
unsigned long cmd_off = cmdleft - variable_buffer;
char *pend = p2 + strlen (p2);
/* Append any remnants of lb, then cut the line short
at the semicolon. */
*cmdleft = '\0';
/* One school of thought says that you shouldn't expand
here, but merely copy, since now you're beyond a ";"
and into a command script. However, the old parser
expanded the whole line, so we continue that for
backwards-compatibility. Also, it wouldn't be
entirely consistent, since we do an unconditional
expand below once we know we don't have a
target-specific variable. */
(void)variable_expand_string (pend, lb_next, (long)-1);
lb_next += strlen (lb_next);
p2 = variable_buffer + p2_off;
cmdleft = variable_buffer + cmd_off + 1;
}
}
colonp = find_char_unquote (p2, MAP_COLON);
#ifdef HAVE_DOS_PATHS
/* The drive spec brain-damage strikes again... */
/* Note that the only separators of targets in this context
are whitespace and a left paren. If others are possible,
they should be added to the string in the call to index. */
while (colonp && (colonp[1] == '/' || colonp[1] == '\\') &&
colonp > p2 && isalpha ((unsigned char)colonp[-1]) &&
(colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0))
colonp = find_char_unquote (colonp + 1, MAP_COLON);
#endif
if (colonp != 0)
break;
wtype = get_next_mword (lb_next, NULL, &lb_next, &wlen);
if (wtype == w_eol)
break;
p2 += strlen (p2);
*(p2++) = ' ';
p2 = variable_expand_string (p2, lb_next, wlen);
/* We don't need to worry about cmdleft here, because if it was
found in the variable_buffer the entire buffer has already
been expanded... we'll never get here. */
}
p2 = next_token (variable_buffer);
/* If the word we're looking at is EOL, see if there's _anything_
on the line. If not, a variable expanded to nothing, so ignore
it. If so, we can't parse this line so punt. */
if (wtype == w_eol)
{
if (*p2 == '\0')
continue;
/* There's no need to be ivory-tower about this: check for
one of the most common bugs found in makefiles... */
if (cmd_prefix == '\t' && strneq (line, " ", 8))
O (fatal, fstart, _("missing separator (did you mean TAB instead of 8 spaces?)"));
else
O (fatal, fstart, _("missing separator"));
}
/* Make the colon the end-of-string so we know where to stop
looking for targets. Start there again once we're done. */
*colonp = '\0';
filenames = PARSE_SIMPLE_SEQ (&p2, struct nameseq);
*colonp = ':';
p2 = colonp;
if (!filenames)
{
/* We accept and ignore rules without targets for
compatibility with SunOS 4 make. */
no_targets = 1;
continue;
}
/* This should never be possible; we handled it above. */
assert (*p2 != '\0');
++p2;
/* Is this a one-colon or two-colon entry? */
two_colon = *p2 == ':';
if (two_colon)
p2++;
/* Test to see if it's a target-specific variable. Copy the rest
of the buffer over, possibly temporarily (we'll expand it later
if it's not a target-specific variable). PLEN saves the length
of the unparsed section of p2, for later. */
if (*lb_next != '\0')
{
unsigned int l = p2 - variable_buffer;
plen = strlen (p2);
variable_buffer_output (p2+plen, lb_next, strlen (lb_next)+1);
p2 = variable_buffer + l;
}
p2 = parse_var_assignment (p2, &vmod);
if (vmod.assign_v)
{
/* If there was a semicolon found, add it back, plus anything
after it. */
if (semip)
{
unsigned int l = p2 - variable_buffer;
*(--semip) = ';';
collapse_continuations (semip);
variable_buffer_output (p2 + strlen (p2),
semip, strlen (semip)+1);
p2 = variable_buffer + l;
}
record_target_var (filenames, p2,
vmod.override_v ? o_override : o_file,
&vmod, fstart);
filenames = 0;
continue;
}
/* This is a normal target, _not_ a target-specific variable.
Unquote any = in the dependency list. */
find_char_unquote (lb_next, MAP_EQUALS);
/* Remember the command prefix for this target. */
prefix = cmd_prefix;
/* We have some targets, so don't ignore the following commands. */
no_targets = 0;
/* Expand the dependencies, etc. */
if (*lb_next != '\0')
{
unsigned int l = p2 - variable_buffer;
(void) variable_expand_string (p2 + plen, lb_next, (long)-1);
p2 = variable_buffer + l;
/* Look for a semicolon in the expanded line. */
if (cmdleft == 0)
{
cmdleft = find_char_unquote (p2, MAP_SEMI);
if (cmdleft != 0)
*(cmdleft++) = '\0';
}
}
/* Is this a static pattern rule: 'target: %targ: %dep; ...'? */
p = strchr (p2, ':');
while (p != 0 && p[-1] == '\\')
{
char *q = &p[-1];
int backslash = 0;
while (*q-- == '\\')
backslash = !backslash;
if (backslash)
p = strchr (p + 1, ':');
else
break;
}
#ifdef _AMIGA
/* Here, the situation is quite complicated. Let's have a look
at a couple of targets:
install: dev:make
dev:make: make
dev:make:: xyz
The rule is that it's only a target, if there are TWO :'s
OR a space around the :.
*/
if (p && !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1])))
p = 0;
#endif
#ifdef HAVE_DOS_PATHS
{
int check_again;
do {
check_again = 0;
/* For DOS-style paths, skip a "C:\..." or a "C:/..." */
if (p != 0 && (p[1] == '\\' || p[1] == '/') &&
isalpha ((unsigned char)p[-1]) &&
(p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) {
p = strchr (p + 1, ':');
check_again = 1;
}
} while (check_again);
}
#endif
if (p != 0)
{
struct nameseq *target;
target = PARSE_FILE_SEQ (&p2, struct nameseq, MAP_COLON, NULL,
PARSEFS_NOGLOB);
++p2;
if (target == 0)
O (fatal, fstart, _("missing target pattern"));
else if (target->next != 0)
O (fatal, fstart, _("multiple target patterns"));
pattern_percent = find_percent_cached (&target->name);
pattern = target->name;
if (pattern_percent == 0)
O (fatal, fstart, _("target pattern contains no '%%'"));
free_ns (target);
}
else
pattern = 0;
/* Strip leading and trailing whitespaces. */
beg = p2;
end = beg + strlen (beg) - 1;
strip_whitespace (&beg, &end);
/* Put all the prerequisites here; they'll be parsed later. */
if (beg <= end && *beg != '\0')
depstr = xstrndup (beg, end - beg + 1);
else
depstr = 0;
commands_idx = 0;
if (cmdleft != 0)
{
/* Semicolon means rest of line is a command. */
unsigned int l = strlen (cmdleft);
cmds_started = fstart->lineno;
/* Add this command line to the buffer. */
if (l + 2 > commands_len)
{
commands_len = (l + 2) * 2;
commands = xrealloc (commands, commands_len);
}
memcpy (commands, cmdleft, l);
commands_idx += l;
commands[commands_idx++] = '\n';
}
/* Determine if this target should be made default. We used to do
this in record_files() but because of the delayed target recording
and because preprocessor directives are legal in target's commands
it is too late. Consider this fragment for example:
foo:
ifeq ($(.DEFAULT_GOAL),foo)
...
endif
Because the target is not recorded until after ifeq directive is
evaluated the .DEFAULT_GOAL does not contain foo yet as one
would expect. Because of this we have to move the logic here. */
if (set_default && default_goal_var->value[0] == '\0')
{
struct dep *d;
struct nameseq *t = filenames;
for (; t != 0; t = t->next)
{
int reject = 0;
const char *name = t->name;
/* We have nothing to do if this is an implicit rule. */
if (strchr (name, '%') != 0)
break;
/* See if this target's name does not start with a '.',
unless it contains a slash. */
if (*name == '.' && strchr (name, '/') == 0
#ifdef HAVE_DOS_PATHS
&& strchr (name, '\\') == 0
#endif
)
continue;
/* If this file is a suffix, don't let it be
the default goal file. */
for (d = suffix_file->deps; d != 0; d = d->next)
{
register struct dep *d2;
if (*dep_name (d) != '.' && streq (name, dep_name (d)))
{
reject = 1;
break;
}
for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
{
unsigned int l = strlen (dep_name (d2));
if (!strneq (name, dep_name (d2), l))
continue;
if (streq (name + l, dep_name (d)))
{
reject = 1;
break;
}
}
if (reject)
break;
}
if (!reject)
{
define_variable_global (".DEFAULT_GOAL", 13, t->name,
o_file, 0, NILF);
break;
}
}
}
continue;
}
/* We get here except in the case that we just read a rule line.
Record now the last rule we read, so following spurious
commands are properly diagnosed. */
record_waiting_files ();
}
#undef word1eq
if (conditionals->if_cmds)
O (fatal, fstart, _("missing 'endif'"));
/* At eof, record the last rule. */
record_waiting_files ();
free (collapsed);
free (commands);
}
/* Remove comments from LINE.
This is done by copying the text at LINE onto itself. */
static void
remove_comments (char *line)
{
char *comment;
comment = find_char_unquote (line, MAP_COMMENT);
if (comment != 0)
/* Cut off the line at the #. */
*comment = '\0';
}
/* Execute a 'undefine' directive.
The undefine line has already been read, and NAME is the name of
the variable to be undefined. */
static void
do_undefine (char *name, enum variable_origin origin, struct ebuffer *ebuf)
{
char *p, *var;
/* Expand the variable name and find the beginning (NAME) and end. */
var = allocated_variable_expand (name);
name = next_token (var);
if (*name == '\0')
O (fatal, &ebuf->floc, _("empty variable name"));
p = name + strlen (name) - 1;
while (p > name && ISBLANK (*p))
--p;
p[1] = '\0';
undefine_variable_global (name, p - name + 1, origin);
free (var);
}
/* 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. */
static struct variable *
do_define (char *name, enum variable_origin origin, struct ebuffer *ebuf)
{
struct variable *v;
struct variable var;
floc defstart;
int nlevels = 1;
unsigned int length = 100;
char *definition = xmalloc (length);
unsigned int idx = 0;
char *p, *n;
defstart = ebuf->floc;
p = parse_variable_definition (name, &var);
if (p == NULL)
/* No assignment token, so assume recursive. */
var.flavor = f_recursive;
else
{
if (var.value[0] != '\0')
O (error, &defstart, _("extraneous text after 'define' directive"));
/* Chop the string before the assignment token to get the name. */
var.name[var.length] = '\0';
}
/* Expand the variable name and find the beginning (NAME) and end. */
n = allocated_variable_expand (name);
name = next_token (n);
if (name[0] == '\0')
O (fatal, &defstart, _("empty variable name"));
p = name + strlen (name) - 1;
while (p > name && ISBLANK (*p))
--p;
p[1] = '\0';
/* Now read the value of the variable. */
while (1)
{
unsigned int len;
char *line;
long nlines = readline (ebuf);
/* If there is nothing left to be eval'd, there's no 'endef'!! */
if (nlines < 0)
O (fatal, &defstart, _("missing 'endef', unterminated 'define'"));
ebuf->floc.lineno += nlines;
line = ebuf->buffer;
collapse_continuations (line);
/* If the line doesn't begin with a tab, test to see if it introduces
another define, or ends one. Stop if we find an 'endef' */
if (line[0] != cmd_prefix)
{
p = next_token (line);
len = strlen (p);
/* If this is another 'define', increment the level count. */
if ((len == 6 || (len > 6 && ISBLANK (p[6])))
&& strneq (p, "define", 6))
++nlevels;
/* If this is an 'endef', decrement the count. If it's now 0,
we've found the last one. */
else if ((len == 5 || (len > 5 && ISBLANK (p[5])))
&& strneq (p, "endef", 5))
{
p += 5;
remove_comments (p);
if (*(next_token (p)) != '\0')
O (error, &ebuf->floc,
_("extraneous text after 'endef' directive"));
if (--nlevels == 0)
break;
}
}
/* Add this line to the variable definition. */
len = strlen (line);
if (idx + len + 1 > length)
{
length = (idx + len) * 2;
definition = xrealloc (definition, length + 1);
}
memcpy (&definition[idx], line, len);
idx += len;
/* Separate lines with a newline. */
definition[idx++] = '\n';
}
/* We've got what we need; define the variable. */
if (idx == 0)
definition[0] = '\0';
else
definition[idx - 1] = '\0';
v = do_variable_definition (&defstart, name,
definition, origin, var.flavor, 0);
free (definition);
free (n);
return (v);
}
/* 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 -2 if the line is not a conditional at all,
-1 if the line is an invalid conditional,
0 if following text should be interpreted,
1 if following text should be ignored. */
static int
conditional_line (char *line, int len, const floc *flocp)
{
const char *cmdname;
enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, c_else, c_endif } cmdtype;
unsigned int i;
unsigned int o;
/* Compare a word, both length and contents. */
#define word1eq(s) (len == CSTRLEN (s) && strneq (s, line, CSTRLEN (s)))
#define chkword(s, t) if (word1eq (s)) { cmdtype = (t); cmdname = (s); }
/* Make sure this line is a conditional. */
chkword ("ifdef", c_ifdef)
else chkword ("ifndef", c_ifndef)
else chkword ("ifeq", c_ifeq)
else chkword ("ifneq", c_ifneq)
else chkword ("else", c_else)
else chkword ("endif", c_endif)
else
return -2;
/* Found one: skip past it and any whitespace after it. */
line += len;
NEXT_TOKEN (line);
#define EXTRATEXT() OS (error, flocp, _("extraneous text after '%s' directive"), cmdname)
#define EXTRACMD() OS (fatal, flocp, _("extraneous '%s'"), cmdname)
/* An 'endif' cannot contain extra text, and reduces the if-depth by 1 */
if (cmdtype == c_endif)
{
if (*line != '\0')
EXTRATEXT ();
if (!conditionals->if_cmds)
EXTRACMD ();
--conditionals->if_cmds;
goto DONE;
}
/* An 'else' statement can either be simple, or it can have another
conditional after it. */
if (cmdtype == c_else)
{
const char *p;
if (!conditionals->if_cmds)
EXTRACMD ();
o = conditionals->if_cmds - 1;
if (conditionals->seen_else[o])
O (fatal, flocp, _("only one 'else' per conditional"));
/* Change the state of ignorance. */
switch (conditionals->ignoring[o])
{
case 0:
/* We've just been interpreting. Never do it again. */
conditionals->ignoring[o] = 2;
break;
case 1:
/* We've never interpreted yet. Maybe this time! */
conditionals->ignoring[o] = 0;
break;
}
/* It's a simple 'else'. */
if (*line == '\0')
{
conditionals->seen_else[o] = 1;
goto DONE;
}
/* The 'else' has extra text. That text must be another conditional
and cannot be an 'else' or 'endif'. */
/* Find the length of the next word. */
for (p = line+1; ! STOP_SET (*p, MAP_SPACE|MAP_NUL); ++p)
;
len = p - line;
/* If it's 'else' or 'endif' or an illegal conditional, fail. */
if (word1eq ("else") || word1eq ("endif")
|| conditional_line (line, len, flocp) < 0)
EXTRATEXT ();
else
{
/* conditional_line() created a new level of conditional.
Raise it back to this level. */
if (conditionals->ignoring[o] < 2)
conditionals->ignoring[o] = conditionals->ignoring[o+1];
--conditionals->if_cmds;
}
goto DONE;
}
if (conditionals->allocated == 0)
{
conditionals->allocated = 5;
conditionals->ignoring = xmalloc (conditionals->allocated);
conditionals->seen_else = xmalloc (conditionals->allocated);
}
o = conditionals->if_cmds++;
if (conditionals->if_cmds > conditionals->allocated)
{
conditionals->allocated += 5;
conditionals->ignoring = xrealloc (conditionals->ignoring,
conditionals->allocated);
conditionals->seen_else = xrealloc (conditionals->seen_else,
conditionals->allocated);
}
/* Record that we have seen an 'if...' but no 'else' so far. */
conditionals->seen_else[o] = 0;
/* Search through the stack to see if we're already ignoring. */
for (i = 0; i < o; ++i)
if (conditionals->ignoring[i])
{
/* We are already ignoring, so just push a level to match the next
"else" or "endif", and keep ignoring. We don't want to expand
variables in the condition. */
conditionals->ignoring[o] = 1;
return 1;
}
if (cmdtype == c_ifdef || cmdtype == c_ifndef)
{
char *var;
struct variable *v;
char *p;
/* Expand the thing we're looking up, so we can use indirect and
constructed variable names. */
var = allocated_variable_expand (line);
/* Make sure there's only one variable name to test. */
p = end_of_token (var);
i = p - var;
NEXT_TOKEN (p);
if (*p != '\0')
return -1;
var[i] = '\0';
v = lookup_variable (var, i);
conditionals->ignoring[o] =
((v != 0 && *v->value != '\0') == (cmdtype == c_ifndef));
free (var);
}
else
{
/* "ifeq" or "ifneq". */
char *s1, *s2;
unsigned int l;
char termin = *line == '(' ? ',' : *line;
if (termin != ',' && termin != '"' && termin != '\'')
return -1;
s1 = ++line;
/* Find the end of the first string. */
if (termin == ',')
{
int count = 0;
for (; *line != '\0'; ++line)
if (*line == '(')
++count;
else if (*line == ')')
--count;
else if (*line == ',' && count <= 0)
break;
}
else
while (*line != '\0' && *line != termin)
++line;
if (*line == '\0')
return -1;
if (termin == ',')
{
/* Strip blanks after the first string. */
char *p = line++;
while (ISBLANK (p[-1]))
--p;
*p = '\0';
}
else
*line++ = '\0';
s2 = variable_expand (s1);
/* We must allocate a new copy of the expanded string because
variable_expand re-uses the same buffer. */
l = strlen (s2);
s1 = alloca (l + 1);
memcpy (s1, s2, l + 1);
if (termin != ',')
/* Find the start of the second string. */
NEXT_TOKEN (line);
termin = termin == ',' ? ')' : *line;
if (termin != ')' && termin != '"' && termin != '\'')
return -1;
/* Find the end of the second string. */
if (termin == ')')
{
int count = 0;
s2 = next_token (line);
for (line = s2; *line != '\0'; ++line)
{
if (*line == '(')
++count;
else if (*line == ')')
{
if (count <= 0)
break;
else
--count;
}
}
}
else
{
++line;
s2 = line;
while (*line != '\0' && *line != termin)
++line;
}
if (*line == '\0')
return -1;
*(line++) = '\0';
NEXT_TOKEN (line);
if (*line != '\0')
EXTRATEXT ();
s2 = variable_expand (s2);
conditionals->ignoring[o] = (streq (s1, s2) == (cmdtype == c_ifneq));
}
DONE:
/* Search through the stack to see if we're ignoring. */
for (i = 0; i < conditionals->if_cmds; ++i)
if (conditionals->ignoring[i])
return 1;
return 0;
}
/* Record target-specific variable values for files FILENAMES.
TWO_COLON is nonzero if a double colon was used.
The links of FILENAMES are freed, and so are any names in it
that are not incorporated into other data structures.
If the target is a pattern, add the variable to the pattern-specific
variable value list. */
static void
record_target_var (struct nameseq *filenames, char *defn,
enum variable_origin origin, struct vmodifiers *vmod,
const floc *flocp)
{
struct nameseq *nextf;
struct variable_set_list *global;
global = current_variable_set_list;
/* If the variable is an append version, store that but treat it as a
normal recursive variable. */
for (; filenames != 0; filenames = nextf)
{
struct variable *v;
const char *name = filenames->name;
const char *percent;
struct pattern_var *p;
nextf = filenames->next;
free_ns (filenames);
/* If it's a pattern target, then add it to the pattern-specific
variable list. */
percent = find_percent_cached (&name);
if (percent)
{
/* Get a reference for this pattern-specific variable struct. */
p = create_pattern_var (name, percent);
p->variable.fileinfo = *flocp;
/* I don't think this can fail since we already determined it was a
variable definition. */
v = assign_variable_definition (&p->variable, defn);
assert (v != 0);
v->origin = origin;
if (v->flavor == f_simple)
v->value = allocated_variable_expand (v->value);
else
v->value = xstrdup (v->value);
}
else
{
struct file *f;
/* Get a file reference for this file, and initialize it.
We don't want to just call enter_file() because that allocates a
new entry if the file is a double-colon, which we don't want in
this situation. */
f = lookup_file (name);
if (!f)
f = enter_file (strcache_add (name));
else if (f->double_colon)
f = f->double_colon;
initialize_file_variables (f, 1);
current_variable_set_list = f->variables;
v = try_variable_definition (flocp, defn, origin, 1);
if (!v)
O (fatal, flocp, _("Malformed target-specific variable definition"));
current_variable_set_list = global;
}
/* Set up the variable to be *-specific. */
v->per_target = 1;
v->private_var = vmod->private_v;
v->export = vmod->export_v ? v_export : v_default;
/* If it's not an override, check to see if there was a command-line
setting. If so, reset the value. */
if (v->origin != o_override)
{
struct variable *gv;
int len = strlen (v->name);
gv = lookup_variable (v->name, len);
if (gv && v != gv
&& (gv->origin == o_env_override || gv->origin == o_command))
{
free (v->value);
v->value = xstrdup (gv->value);
v->origin = gv->origin;
v->recursive = gv->recursive;
v->append = 0;
}
}
}
}
/* Record a description line for files FILENAMES,
with dependencies DEPS, commands to execute described
by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED.
TWO_COLON is nonzero if a double colon was used.
If not nil, PATTERN is the '%' pattern to make this
a static pattern rule, and PATTERN_PERCENT is a pointer
to the '%' within it.
The links of FILENAMES are freed, and so are any names in it
that are not incorporated into other data structures. */
static void
record_files (struct nameseq *filenames, const char *pattern,
const char *pattern_percent, char *depstr,
unsigned int cmds_started, char *commands,
unsigned int commands_idx, int two_colon,
char prefix, const floc *flocp)
{
struct commands *cmds;
struct dep *deps;
const char *implicit_percent;
const char *name;
/* If we've already snapped deps, that means we're in an eval being
resolved after the makefiles have been read in. We can't add more rules
at this time, since they won't get snapped and we'll get core dumps.
See Savannah bug # 12124. */
if (snapped_deps)
O (fatal, flocp, _("prerequisites cannot be defined in recipes"));
/* Determine if this is a pattern rule or not. */
name = filenames->name;
implicit_percent = find_percent_cached (&name);
/* If there's a recipe, set up a struct for it. */
if (commands_idx > 0)
{
cmds = xmalloc (sizeof (struct commands));
cmds->fileinfo.filenm = flocp->filenm;
cmds->fileinfo.lineno = cmds_started;
cmds->fileinfo.offset = 0;
cmds->commands = xstrndup (commands, commands_idx);
cmds->command_lines = 0;
cmds->recipe_prefix = prefix;
}
else
cmds = 0;
/* If there's a prereq string then parse it--unless it's eligible for 2nd
expansion: if so, snap_deps() will do it. */
if (depstr == 0)
deps = 0;
else
{
depstr = unescape_char (depstr, ':');
if (second_expansion && strchr (depstr, '$'))
{
deps = alloc_dep ();
deps->name = depstr;
deps->need_2nd_expansion = 1;
deps->staticpattern = pattern != 0;
}
else
{
deps = split_prereqs (depstr);
free (depstr);
/* We'll enter static pattern prereqs later when we have the stem.
We don't want to enter pattern rules at all so that we don't
think that they ought to exist (make manual "Implicit Rule Search
Algorithm", item 5c). */
if (! pattern && ! implicit_percent)
deps = enter_prereqs (deps, NULL);
}
}
/* For implicit rules, _all_ the targets must have a pattern. That means we
can test the first one to see if we're working with an implicit rule; if
so we handle it specially. */
if (implicit_percent)
{
struct nameseq *nextf;
const char **targets, **target_pats;
unsigned int c;
if (pattern != 0)
O (fatal, flocp, _("mixed implicit and static pattern rules"));
/* Count the targets to create an array of target names.
We already have the first one. */
nextf = filenames->next;
free_ns (filenames);
filenames = nextf;
for (c = 1; nextf; ++c, nextf = nextf->next)
;
targets = xmalloc (c * sizeof (const char *));
target_pats = xmalloc (c * sizeof (const char *));
targets[0] = name;
target_pats[0] = implicit_percent;
c = 1;
while (filenames)
{
name = filenames->name;
implicit_percent = find_percent_cached (&name);
if (implicit_percent == 0)
O (fatal, flocp, _("mixed implicit and normal rules"));
targets[c] = name;
target_pats[c] = implicit_percent;
++c;
nextf = filenames->next;
free_ns (filenames);
filenames = nextf;
}
create_pattern_rule (targets, target_pats, c, two_colon, deps, cmds, 1);
return;
}
/* Walk through each target and create it in the database.
We already set up the first target, above. */
while (1)
{
struct nameseq *nextf = filenames->next;
struct file *f;
struct dep *this = 0;
free_ns (filenames);
/* Check for special targets. Do it here instead of, say, snap_deps()
so that we can immediately use the value. */
if (streq (name, ".POSIX"))
{
posix_pedantic = 1;
define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
/* These default values are based on IEEE Std 1003.1-2008. */
define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
define_variable_cname ("CC", "c99", o_default, 0);
define_variable_cname ("CFLAGS", "-O", o_default, 0);
define_variable_cname ("FC", "fort77", o_default, 0);
define_variable_cname ("FFLAGS", "-O 1", o_default, 0);
define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
}
else if (streq (name, ".SECONDEXPANSION"))
second_expansion = 1;
#if !defined (__MSDOS__) && !defined (__EMX__)
else if (streq (name, ".ONESHELL"))
one_shell = 1;
#endif
/* If this is a static pattern rule:
'targets: target%pattern: prereq%pattern; recipe',
make sure the pattern matches this target name. */
if (pattern && !pattern_matches (pattern, pattern_percent, name))
OS (error, flocp,
_("target '%s' doesn't match the target pattern"), name);
else if (deps)
/* If there are multiple targets, 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 database. */
this = nextf != 0 ? copy_dep_chain (deps) : deps;
/* Find or create an entry in the file database for this target. */
if (!two_colon)
{
/* Single-colon. Combine this rule with the file's existing record,
if any. */
f = enter_file (strcache_add (name));
if (f->double_colon)
OS (fatal, flocp,
_("target file '%s' has both : and :: entries"), f->name);
/* If CMDS == F->CMDS, this target was listed in this rule
more than once. Just give a warning since this is harmless. */
if (cmds != 0 && cmds == f->cmds)
OS (error, flocp,
_("target '%s' given more than once in the same rule"),
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. */
else if (cmds != 0 && f->cmds != 0 && f->is_target)
{
size_t l = strlen (f->name);
error (&cmds->fileinfo, l,
_("warning: overriding recipe for target '%s'"),
f->name);
error (&f->cmds->fileinfo, l,
_("warning: ignoring old recipe for target '%s'"),
f->name);
}
/* Defining .DEFAULT with no deps or cmds clears it. */
if (f == default_file && this == 0 && cmds == 0)
f->cmds = 0;
if (cmds != 0)
f->cmds = cmds;
/* Defining .SUFFIXES with no dependencies clears out the list of
suffixes. */
if (f == suffix_file && this == 0)
{
free_dep_chain (f->deps);
f->deps = 0;
}
}
else
{
/* Double-colon. Make a new record even if there already is one. */
f = lookup_file (name);
/* Check for both : and :: rules. Check is_target so we don't lose
on default suffix rules or makefiles. */
if (f != 0 && f->is_target && !f->double_colon)
OS (fatal, flocp,
_("target file '%s' has both : and :: entries"), f->name);
f = enter_file (strcache_add (name));
/* If there was an existing entry and it was a double-colon entry,
enter_file will have returned a new one, making it the prev
pointer of the old one, and setting its double_colon pointer to
the first one. */
if (f->double_colon == 0)
/* This is the first entry for this name, so we must set its
double_colon pointer to itself. */
f->double_colon = f;
f->cmds = cmds;
}
f->is_target = 1;
/* If this is a static pattern rule, set the stem to the part of its
name that matched the '%' in the pattern, so you can use $* in the
commands. If we didn't do it before, enter the prereqs now. */
if (pattern)
{
static const char *percent = "%";
char *buffer = variable_expand ("");
char *o = patsubst_expand_pat (buffer, name, pattern, percent,
pattern_percent+1, percent+1);
f->stem = strcache_add_len (buffer, o - buffer);
if (this)
{
if (! this->need_2nd_expansion)
this = enter_prereqs (this, f->stem);
else
this->stem = f->stem;
}
}
/* Add the dependencies to this file entry. */
if (this != 0)
{
/* Add the file's old deps and the new ones in THIS together. */
if (f->deps == 0)
f->deps = this;
else if (cmds != 0)
{
struct dep *d = this;
/* If this rule has commands, put these deps first. */
while (d->next != 0)
d = d->next;
d->next = f->deps;
f->deps = this;
}
else
{
struct dep *d = f->deps;
/* A rule without commands: put its prereqs at the end. */
while (d->next != 0)
d = d->next;
d->next = this;
}
}
name = f->name;
/* All done! Set up for the next one. */
if (nextf == 0)
break;
filenames = nextf;
/* Reduce escaped percents. If there are any unescaped it's an error */
name = filenames->name;
if (find_percent_cached (&name))
O (error, flocp,
_("*** mixed implicit and normal rules: deprecated syntax"));
}
}
/* Search STRING for an unquoted STOPCHAR or blank (if BLANK is nonzero).
Backslashes quote STOPCHAR, blanks if BLANK is nonzero, and backslash.
Quoting backslashes are removed from STRING by compacting it into
itself. Returns a pointer to the first unquoted STOPCHAR if there is
one, or nil if there are none. STOPCHARs inside variable references are
ignored if IGNOREVARS is true.
STOPCHAR _cannot_ be '$' if IGNOREVARS is true. */
static char *
find_char_unquote (char *string, int map)
{
unsigned int string_len = 0;
char *p = string;
/* Always stop on NUL. */
map |= MAP_NUL;
while (1)
{
while (! STOP_SET (*p, map))
++p;
if (*p == '\0')
break;
/* If we stopped due to a variable reference, skip over its contents. */
if (STOP_SET (*p, MAP_VARIABLE))
{
char openparen = p[1];
/* Check if '$' is the last character in the string. */
if (openparen == '\0')
break;
p += 2;
/* Skip the contents of a non-quoted, multi-char variable ref. */
if (openparen == '(' || openparen == '{')
{
unsigned int pcount = 1;
char closeparen = (openparen == '(' ? ')' : '}');
while (*p)
{
if (*p == openparen)
++pcount;
else if (*p == closeparen)
if (--pcount == 0)
{
++p;
break;
}
++p;
}
}
/* Skipped the variable reference: look for STOPCHARS again. */
continue;
}
if (p > string && p[-1] == '\\')
{
/* Search for more backslashes. */
int i = -2;
while (&p[i] >= string && p[i] == '\\')
--i;
++i;
/* Only compute the length if really needed. */
if (string_len == 0)
string_len = strlen (string);
/* The number of backslashes is now -I.
Copy P over itself to swallow half of them. */
memmove (&p[i], &p[i/2], (string_len - (p - string)) - (i/2) + 1);
p += i/2;
if (i % 2 == 0)
/* All the backslashes quoted each other; the STOPCHAR was
unquoted. */
return p;
/* The STOPCHAR was quoted by a backslash. Look for another. */
}
else
/* No backslash in sight. */
return p;
}
/* Never hit a STOPCHAR or blank (with BLANK nonzero). */
return 0;
}
/* Unescape a character in a string. The string is compressed onto itself. */
static char *
unescape_char (char *string, int c)
{
char *p = string;
char *s = string;
while (*s != '\0')
{
if (*s == '\\')
{
char *e = s;
int l;
/* We found a backslash. See if it's escaping our character. */
while (*e == '\\')
++e;
l = e - s;
if (*e != c || l%2 == 0)
{
/* It's not; just take it all without unescaping. */
memmove (p, s, l);
p += l;
// If we hit the end of the string, we're done
if (*e == '\0')
break;
}
else if (l > 1)
{
/* It is, and there's >1 backslash. Take half of them. */
l /= 2;
memmove (p, s, l);
p += l;
}
s = e;
}
*(p++) = *(s++);
}
*p = '\0';
return string;
}
/* Search PATTERN for an unquoted % and handle quoting. */
char *
find_percent (char *pattern)
{
return find_char_unquote (pattern, MAP_PERCENT);
}
/* Search STRING for an unquoted % and handle quoting. Returns a pointer to
the % or NULL if no % was found.
This version is used with strings in the string cache: if there's a need to
modify the string a new version will be added to the string cache and
*STRING will be set to that. */
const char *
find_percent_cached (const char **string)
{
const char *p = *string;
char *new = 0;
int slen = 0;
/* If the first char is a % return now. This lets us avoid extra tests
inside the loop. */
if (*p == '%')
return p;
while (1)
{
while (! STOP_SET (*p, MAP_PERCENT|MAP_NUL))
++p;
if (*p == '\0')
break;
/* See if this % is escaped with a backslash; if not we're done. */
if (p[-1] != '\\')
break;
{
/* Search for more backslashes. */
char *pv;
int i = -2;
while (&p[i] >= *string && p[i] == '\\')
--i;
++i;
/* At this point we know we'll need to allocate a new string.
Make a copy if we haven't yet done so. */
if (! new)
{
slen = strlen (*string);
new = alloca (slen + 1);
memcpy (new, *string, slen + 1);
p = new + (p - *string);
*string = new;
}
/* At this point *string, p, and new all point into the same string.
Get a non-const version of p so we can modify new. */
pv = new + (p - *string);
/* The number of backslashes is now -I.
Copy P over itself to swallow half of them. */
memmove (&pv[i], &pv[i/2], (slen - (pv - new)) - (i/2) + 1);
p += i/2;
/* If the backslashes quoted each other; the % was unquoted. */
if (i % 2 == 0)
break;
}
}
/* If we had to change STRING, add it to the strcache. */
if (new)
{
*string = strcache_add (*string);
p = *string + (p - new);
}
/* If we didn't find a %, return NULL. Otherwise return a ptr to it. */
return (*p == '\0') ? NULL : p;
}
/* Find the next line of text in an eval buffer, combining continuation lines
into one line.
Return the number of actual lines read (> 1 if continuation lines).
Returns -1 if there's nothing left in the buffer.
After this function, ebuf->buffer points to the first character of the
line we just found.
*/
/* Read a line of text from a STRING.
Since we aren't really reading from a file, don't bother with linenumbers.
*/
static long
readstring (struct ebuffer *ebuf)
{
char *eol;
/* If there is nothing left in this buffer, return 0. */
if (ebuf->bufnext >= ebuf->bufstart + ebuf->size)
return -1;
/* Set up a new starting point for the buffer, and find the end of the
next logical line (taking into account backslash/newline pairs). */
eol = ebuf->buffer = ebuf->bufnext;
while (1)
{
int backslash = 0;
const char *bol = eol;
const char *p;
/* Find the next newline. At EOS, stop. */
p = eol = strchr (eol , '\n');
if (!eol)
{
ebuf->bufnext = ebuf->bufstart + ebuf->size + 1;
return 0;
}
/* Found a newline; if it's escaped continue; else we're done. */
while (p > bol && *(--p) == '\\')
backslash = !backslash;
if (!backslash)
break;
++eol;
}
/* Overwrite the newline char. */
*eol = '\0';
ebuf->bufnext = eol+1;
return 0;
}
static long
readline (struct ebuffer *ebuf)
{
char *p;
char *end;
char *start;
long nlines = 0;
/* The behaviors between string and stream buffers are different enough to
warrant different functions. Do the Right Thing. */
if (!ebuf->fp)
return readstring (ebuf);
/* When reading from a file, we always start over at the beginning of the
buffer for each new line. */
p = start = ebuf->bufstart;
end = p + ebuf->size;
*p = '\0';
while (fgets (p, end - p, ebuf->fp) != 0)
{
char *p2;
unsigned long len;
int backslash;
len = strlen (p);
if (len == 0)
{
/* This only happens when the first thing on the line is a '\0'.
It is a pretty hopeless case, but (wonder of wonders) Athena
lossage strikes again! (xmkmf puts NULs in its makefiles.)
There is nothing really to be done; we synthesize a newline so
the following line doesn't appear to be part of this line. */
O (error, &ebuf->floc,
_("warning: NUL character seen; rest of line ignored"));
p[0] = '\n';
len = 1;
}
/* Jump past the text we just read. */
p += len;
/* If the last char isn't a newline, the whole line didn't fit into the
buffer. Get some more buffer and try again. */
if (p[-1] != '\n')
goto more_buffer;
/* We got a newline, so add one to the count of lines. */
++nlines;
#if !defined(WINDOWS32) && !defined(__MSDOS__) && !defined(__EMX__)
/* Check to see if the line was really ended with CRLF; if so ignore
the CR. */
if ((p - start) > 1 && p[-2] == '\r')
{
--p;
memmove (p-1, p, strlen (p) + 1);
}
#endif
backslash = 0;
for (p2 = p - 2; p2 >= start; --p2)
{
if (*p2 != '\\')
break;
backslash = !backslash;
}
if (!backslash)
{
p[-1] = '\0';
break;
}
/* It was a backslash/newline combo. If we have more space, read
another line. */
if (end - p >= 80)
continue;
/* We need more space at the end of our buffer, so realloc it.
Make sure to preserve the current offset of p. */
more_buffer:
{
unsigned long off = p - start;
ebuf->size *= 2;
start = ebuf->buffer = ebuf->bufstart = xrealloc (start, ebuf->size);
p = start + off;
end = start + ebuf->size;
*p = '\0';
}
}
if (ferror (ebuf->fp))
pfatal_with_name (ebuf->floc.filenm);
/* If we found some lines, return how many.
If we didn't, but we did find _something_, that indicates we read the last
line of a file with no final newline; return 1.
If we read nothing, we're at EOF; return -1. */
return nlines ? nlines : p == ebuf->bufstart ? -1 : 1;
}
/* Parse the next "makefile word" from the input buffer, and return info
about it.
A "makefile word" is one of:
w_bogus Should never happen
w_eol End of input
w_static A static word; cannot be expanded
w_variable A word containing one or more variables/functions
w_colon A colon
w_dcolon A double-colon
w_semicolon A semicolon
w_varassign A variable assignment operator (=, :=, ::=, +=, ?=, or !=)
Note that this function is only used when reading certain parts of the
makefile. Don't use it where special rules hold sway (RHS of a variable,
in a command list, etc.) */
static enum make_word_type
get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length)
{
enum make_word_type wtype = w_bogus;
char *p = buffer, *beg;
char c;
/* Skip any leading whitespace. */
while (ISBLANK (*p))
++p;
beg = p;
c = *(p++);
switch (c)
{
case '\0':
wtype = w_eol;
break;
case ';':
wtype = w_semicolon;
break;
case '=':
wtype = w_varassign;
break;
case ':':
wtype = w_colon;
switch (*p)
{
case ':':
++p;
if (p[1] != '=')
wtype = w_dcolon;
else
{
wtype = w_varassign;
++p;
}
break;
case '=':
++p;
wtype = w_varassign;
break;
}
break;
case '+':
case '?':
case '!':
if (*p == '=')
{
++p;
wtype = w_varassign;
break;
}
default:
if (delim && strchr (delim, c))
wtype = w_static;
break;
}
/* Did we find something? If so, return now. */
if (wtype != w_bogus)
goto done;
/* This is some non-operator word. A word consists of the longest
string of characters that doesn't contain whitespace, one of [:=#],
or [?+!]=, or one of the chars in the DELIM string. */
/* We start out assuming a static word; if we see a variable we'll
adjust our assumptions then. */
wtype = w_static;
/* We already found the first value of "c", above. */
while (1)
{
char closeparen;
int count;
switch (c)
{
case '\0':
case ' ':
case '\t':
case '=':
goto done_word;
case ':':
#ifdef HAVE_DOS_PATHS
/* A word CAN include a colon in its drive spec. The drive
spec is allowed either at the beginning of a word, or as part
of the archive member name, like in "libfoo.a(d:/foo/bar.o)". */
if (!(p - beg >= 2
&& (*p == '/' || *p == '\\') && isalpha ((unsigned char)p[-2])
&& (p - beg == 2 || p[-3] == '(')))
#endif
goto done_word;
case '$':
c = *(p++);
if (c == '$')
break;
if (c == '\0')
goto done_word;
/* This is a variable reference, so note that it's expandable.
Then read it to the matching close paren. */
wtype = w_variable;
if (c == '(')
closeparen = ')';
else if (c == '{')
closeparen = '}';
else
/* This is a single-letter variable reference. */
break;
for (count=0; *p != '\0'; ++p)
{
if (*p == c)
++count;
else if (*p == closeparen && --count < 0)
{
++p;
break;
}
}
break;
case '?':
case '+':
if (*p == '=')
goto done_word;
break;
case '\\':
switch (*p)
{
case ':':
case ';':
case '=':
case '\\':
++p;
break;
}
break;
default:
if (delim && strchr (delim, c))
goto done_word;
break;
}
c = *(p++);
}
done_word:
--p;
done:
if (startp)
*startp = beg;
if (length)
*length = p - beg;
return wtype;
}
/* Construct the list of include directories
from the arguments and the default list. */
void
construct_include_path (const char **arg_dirs)
{
#ifdef VAXC /* just don't ask ... */
stat_t stbuf;
#else
struct stat stbuf;
#endif
const char **dirs;
const char **cpp;
unsigned int idx;
/* Compute the number of pointers we need in the table. */
idx = sizeof (default_include_directories) / sizeof (const char *);
if (arg_dirs)
for (cpp = arg_dirs; *cpp != 0; ++cpp)
++idx;
#ifdef __MSDOS__
/* Add one for $DJDIR. */
++idx;
#endif
dirs = xmalloc (idx * sizeof (const char *));
idx = 0;
max_incl_len = 0;
/* First consider any dirs specified with -I switches.
Ignore any that don't exist. Remember the maximum string length. */
if (arg_dirs)
while (*arg_dirs != 0)
{
const char *dir = *(arg_dirs++);
char *expanded = 0;
int e;
if (dir[0] == '~')
{
expanded = tilde_expand (dir);
if (expanded != 0)
dir = expanded;
}
EINTRLOOP (e, stat (dir, &stbuf));
if (e == 0 && S_ISDIR (stbuf.st_mode))
{
unsigned int len = strlen (dir);
/* If dir name is written with trailing slashes, discard them. */
while (len > 1 && dir[len - 1] == '/')
--len;
if (len > max_incl_len)
max_incl_len = len;
dirs[idx++] = strcache_add_len (dir, len);
}
free (expanded);
}
/* Now add the standard default dirs at the end. */
#ifdef __MSDOS__
{
/* The environment variable $DJDIR holds the root of the DJGPP directory
tree; add ${DJDIR}/include. */
struct variable *djdir = lookup_variable ("DJDIR", 5);
if (djdir)
{
unsigned int len = strlen (djdir->value) + 8;
char *defdir = alloca (len + 1);
strcat (strcpy (defdir, djdir->value), "/include");
dirs[idx++] = strcache_add (defdir);
if (len > max_incl_len)
max_incl_len = len;
}
}
#endif
for (cpp = default_include_directories; *cpp != 0; ++cpp)
{
int e;
EINTRLOOP (e, stat (*cpp, &stbuf));
if (e == 0 && S_ISDIR (stbuf.st_mode))
{
unsigned int len = strlen (*cpp);
/* If dir name is written with trailing slashes, discard them. */
while (len > 1 && (*cpp)[len - 1] == '/')
--len;
if (len > max_incl_len)
max_incl_len = len;
dirs[idx++] = strcache_add_len (*cpp, len);
}
}
dirs[idx] = 0;
/* Now add each dir to the .INCLUDE_DIRS variable. */
for (cpp = dirs; *cpp != 0; ++cpp)
do_variable_definition (NILF, ".INCLUDE_DIRS", *cpp,
o_default, f_append, 0);
include_directories = dirs;
}
/* Expand ~ or ~USER at the beginning of NAME.
Return a newly malloc'd string or 0. */
char *
tilde_expand (const char *name)
{
#ifndef VMS
if (name[1] == '/' || name[1] == '\0')
{
char *home_dir;
int is_variable;
{
/* Turn off --warn-undefined-variables while we expand HOME. */
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
home_dir = allocated_variable_expand ("$(HOME)");
warn_undefined_variables_flag = save;
}
is_variable = home_dir[0] != '\0';
if (!is_variable)
{
free (home_dir);
home_dir = getenv ("HOME");
}
# if !defined(_AMIGA) && !defined(WINDOWS32)
if (home_dir == 0 || home_dir[0] == '\0')
{
char *logname = getlogin ();
home_dir = 0;
if (logname != 0)
{
struct passwd *p = getpwnam (logname);
if (p != 0)
home_dir = p->pw_dir;
}
}
# endif /* !AMIGA && !WINDOWS32 */
if (home_dir != 0)
{
char *new = xstrdup (concat (2, home_dir, name + 1));
if (is_variable)
free (home_dir);
return new;
}
}
# if !defined(_AMIGA) && !defined(WINDOWS32)
else
{
struct passwd *pwent;
char *userend = strchr (name + 1, '/');
if (userend != 0)
*userend = '\0';
pwent = getpwnam (name + 1);
if (pwent != 0)
{
if (userend == 0)
return xstrdup (pwent->pw_dir);
else
return xstrdup (concat (3, pwent->pw_dir, "/", userend + 1));
}
else if (userend != 0)
*userend = '/';
}
# endif /* !AMIGA && !WINDOWS32 */
#endif /* !VMS */
return 0;
}
/* Parse a string into a sequence of filenames represented as a chain of
struct nameseq's and return that chain. Optionally expand the strings via
glob().
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.
PREFIX, if non-null, is added to the beginning of each filename.
FLAGS allows one or more of the following bitflags to be set:
PARSEFS_NOSTRIP - Do no strip './'s off the beginning
PARSEFS_NOAR - Do not check filenames for archive references
PARSEFS_NOGLOB - Do not expand globbing characters
PARSEFS_EXISTS - Only return globbed files that actually exist
(cannot also set NOGLOB)
PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees)
*/
void *
parse_file_seq (char **stringp, unsigned int size, int stopmap,
const char *prefix, int flags)
{
/* tmp points to tmpbuf after the prefix, if any.
tp is the end of the buffer. */
static char *tmpbuf = NULL;
int cachep = NONE_SET (flags, PARSEFS_NOCACHE);
struct nameseq *new = 0;
struct nameseq **newp = &new;
#define NEWELT(_n) do { \
const char *__n = (_n); \
*newp = xcalloc (size); \
(*newp)->name = (cachep ? strcache_add (__n) : xstrdup (__n)); \
newp = &(*newp)->next; \
} while(0)
char *p;
glob_t gl;
char *tp;
/* Always stop on NUL. */
stopmap |= MAP_NUL;
if (size < sizeof (struct nameseq))
size = sizeof (struct nameseq);
if (NONE_SET (flags, PARSEFS_NOGLOB))
dir_setup_glob (&gl);
/* Get enough temporary space to construct the largest possible target. */
{
static int tmpbuf_len = 0;
int l = strlen (*stringp) + 1;
if (l > tmpbuf_len)
{
tmpbuf = xrealloc (tmpbuf, l);
tmpbuf_len = l;
}
}
tp = tmpbuf;
/* Parse STRING. P will always point to the end of the parsed content. */
p = *stringp;
while (1)
{
const char *name;
const char **nlist = 0;
char *tildep = 0;
int globme = 1;
#ifndef NO_ARCHIVES
char *arname = 0;
char *memname = 0;
#endif
char *s;
int nlen;
int i;
/* Skip whitespace; at the end of the string or STOPCHAR we're done. */
NEXT_TOKEN (p);
if (STOP_SET (*p, stopmap))
break;
/* There are names left, so find the end of the next name.
Throughout this iteration S points to the start. */
s = p;
p = find_char_unquote (p, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#ifdef VMS
/* convert comma separated list to space separated */
if (p && *p == ',')
*p =' ';
#endif
#ifdef _AMIGA
if (p && STOP_SET (*p, stopmap & MAP_COLON)
&& !(ISSPACE (p[1]) || !p[1] || ISSPACE (p[-1])))
p = find_char_unquote (p+1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#endif
#ifdef HAVE_DOS_PATHS
/* For DOS paths, skip a "C:\..." or a "C:/..." until we find the
first colon which isn't followed by a slash or a backslash.
Note that tokens separated by spaces should be treated as separate
tokens since make doesn't allow path names with spaces */
if (stopmap | MAP_COLON)
while (p != 0 && !ISSPACE (*p) &&
(p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]))
p = find_char_unquote (p + 1, stopmap|MAP_VMSCOMMA|MAP_BLANK);
#endif
if (p == 0)
p = s + strlen (s);
/* Strip leading "this directory" references. */
if (NONE_SET (flags, PARSEFS_NOSTRIP))
#ifdef VMS
/* Skip leading '[]'s. should only be one set or bug somwhere else */
if (p - s > 2 && s[0] == '[' && s[1] == ']')
s += 2;
/* Skip leading '<>'s. should only be one set or bug somwhere else */
if (p - s > 2 && s[0] == '<' && s[1] == '>')
s += 2;
#endif
/* Skip leading './'s. */
while (p - s > 2 && s[0] == '.' && s[1] == '/')
{
/* Skip "./" and all following slashes. */
s += 2;
while (*s == '/')
++s;
}
/* Extract the filename just found, and skip it.
Set NAME to the string, and NLEN to its length. */
if (s == p)
{
/* The name was stripped to empty ("./"). */
#if defined(_AMIGA)
/* PDS-- This cannot be right!! */
tp[0] = '\0';
nlen = 0;
#else
tp[0] = '.';
tp[1] = '/';
tp[2] = '\0';
nlen = 2;
#endif
}
else
{
#ifdef VMS
/* VMS filenames can have a ':' in them but they have to be '\'ed but we need
* to remove this '\' before we can use the filename.
* xstrdup called because S may be read-only string constant.
*/
char *n = tp;
while (s < p)
{
if (s[0] == '\\' && s[1] == ':')
++s;
*(n++) = *(s++);
}
n[0] = '\0';
nlen = strlen (tp);
#else
nlen = p - s;
memcpy (tp, s, nlen);
tp[nlen] = '\0';
#endif
}
/* At this point, TP points to the element and NLEN is its length. */
#ifndef NO_ARCHIVES
/* If this is the start of an archive group that isn't complete, set up
to add the archive prefix for future files. A file list like:
"libf.a(x.o y.o z.o)" needs to be expanded as:
"libf.a(x.o) libf.a(y.o) libf.a(z.o)"
TP == TMP means we're not already in an archive group. Ignore
something starting with '(', as that cannot actually be an
archive-member reference (and treating it as such results in an empty
file name, which causes much lossage). Also if it ends in ")" then
it's a complete reference so we don't need to treat it specially.
Finally, note that archive groups must end with ')' as the last
character, so ensure there's some word ending like that before
considering this an archive group. */
if (NONE_SET (flags, PARSEFS_NOAR)
&& tp == tmpbuf && tp[0] != '(' && tp[nlen-1] != ')')
{
char *n = strchr (tp, '(');
if (n)
{
/* This looks like the first element in an open archive group.
A valid group MUST have ')' as the last character. */
const char *e = p;
do
{
const char *o = e;
NEXT_TOKEN (e);
/* Find the end of this word. We don't want to unquote and
we don't care about quoting since we're looking for the
last char in the word. */
while (! STOP_SET (*e, stopmap|MAP_BLANK|MAP_VMSCOMMA))
++e;
/* If we didn't move, we're done now. */
if (e == o)
break;
if (e[-1] == ')')
{
/* Found the end, so this is the first element in an
open archive group. It looks like "lib(mem".
Reset TP past the open paren. */
nlen -= (n + 1) - tp;
tp = n + 1;
/* We can stop looking now. */
break;
}
}
while (*e != '\0');
/* If we have just "lib(", part of something like "lib( a b)",
go to the next item. */
if (! nlen)
continue;
}
}
/* If we are inside an archive group, make sure it has an end. */
if (tp > tmpbuf)
{
if (tp[nlen-1] == ')')
{
/* This is the natural end; reset TP. */
tp = tmpbuf;
/* This is just ")", something like "lib(a b )": skip it. */
if (nlen == 1)
continue;
}
else
{
/* Not the end, so add a "fake" end. */
tp[nlen++] = ')';
tp[nlen] = '\0';
}
}
#endif
/* If we're not globbing we're done: add it to the end of the chain.
Go to the next item in the string. */
if (ANY_SET (flags, PARSEFS_NOGLOB))
{
NEWELT (concat (2, prefix, tmpbuf));
continue;
}
/* If we get here we know we're doing glob expansion.
TP is a string in tmpbuf. NLEN is no longer used.
We may need to do more work: after this NAME will be set. */
name = tmpbuf;
/* Expand tilde if applicable. */
if (tmpbuf[0] == '~')
{
tildep = tilde_expand (tmpbuf);
if (tildep != 0)
name = tildep;
}
#ifndef NO_ARCHIVES
/* If NAME is an archive member reference replace it with the archive
file name, and save the member name in MEMNAME. We will glob on the
archive name and then reattach MEMNAME later. */
if (NONE_SET (flags, PARSEFS_NOAR) && ar_name (name))
{
ar_parse_name (name, &arname, &memname);
name = arname;
}
#endif /* !NO_ARCHIVES */
/* glob() is expensive: don't call it unless we need to. */
if (NONE_SET (flags, PARSEFS_EXISTS) && strpbrk (name, "?*[") == NULL)
{
globme = 0;
i = 1;
nlist = &name;
}
else
switch (glob (name, GLOB_NOSORT|GLOB_ALTDIRFUNC, NULL, &gl))
{
case GLOB_NOSPACE:
OUT_OF_MEM();
case 0:
/* Success. */
i = gl.gl_pathc;
nlist = (const char **)gl.gl_pathv;
break;
case GLOB_NOMATCH:
/* If we want only existing items, skip this one. */
if (ANY_SET (flags, PARSEFS_EXISTS))
{
i = 0;
break;
}
/* FALLTHROUGH */
default:
/* By default keep this name. */
i = 1;
nlist = &name;
break;
}
/* For each matched element, add it to the list. */
while (i-- > 0)
#ifndef NO_ARCHIVES
if (memname != 0)
{
/* Try to glob on MEMNAME within the archive. */
struct nameseq *found = ar_glob (nlist[i], memname, size);
if (! found)
/* No matches. Use MEMNAME as-is. */
NEWELT (concat (5, prefix, nlist[i], "(", memname, ")"));
else
{
/* We got a chain of items. Attach them. */
if (*newp)
(*newp)->next = found;
else
*newp = found;
/* Find and set the new end. Massage names if necessary. */
while (1)
{
if (! cachep)
found->name = xstrdup (concat (2, prefix, name));
else if (prefix)
found->name = strcache_add (concat (2, prefix, name));
if (found->next == 0)
break;
found = found->next;
}
newp = &found->next;
}
}
else
#endif /* !NO_ARCHIVES */
NEWELT (concat (2, prefix, nlist[i]));
if (globme)
globfree (&gl);
#ifndef NO_ARCHIVES
free (arname);
#endif
free (tildep);
}
*stringp = p;
return new;
}
make-4.2.1/load.c 0000644 0001750 0001750 00000015464 12720141610 010443 0000000 0000000 /* Loading dynamic objects for GNU Make.
Copyright (C) 2012-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
#include "makeint.h"
#if MAKE_LOAD
#include
#include
#include
#include
#include
#define SYMBOL_EXTENSION "_gmk_setup"
#include "debug.h"
#include "filedef.h"
#include "variable.h"
/* Tru64 V4.0 does not have this flag */
#ifndef RTLD_GLOBAL
# define RTLD_GLOBAL 0
#endif
struct load_list
{
struct load_list *next;
const char *name;
void *dlp;
};
static struct load_list *loaded_syms = NULL;
static load_func_t
load_object (const floc *flocp, int noerror, const char *ldname,
const char *symname)
{
static void *global_dl = NULL;
load_func_t symp;
if (! global_dl)
{
global_dl = dlopen (NULL, RTLD_NOW|RTLD_GLOBAL);
if (! global_dl)
{
const char *err = dlerror ();
OS (fatal, flocp, _("Failed to open global symbol table: %s"), err);
}
}
symp = (load_func_t) dlsym (global_dl, symname);
if (! symp)
{
struct load_list *new;
void *dlp = NULL;
/* If the path has no "/", try the current directory first. */
if (! strchr (ldname, '/')
#ifdef HAVE_DOS_PATHS
&& ! strchr (ldname, '\\')
#endif
)
dlp = dlopen (concat (2, "./", ldname), RTLD_LAZY|RTLD_GLOBAL);
/* If we haven't opened it yet, try the default search path. */
if (! dlp)
dlp = dlopen (ldname, RTLD_LAZY|RTLD_GLOBAL);
/* Still no? Then fail. */
if (! dlp)
{
const char *err = dlerror ();
if (noerror)
DB (DB_BASIC, ("%s", err));
else
OS (error, flocp, "%s", err);
return NULL;
}
/* Assert that the GPL license symbol is defined. */
symp = (load_func_t) dlsym (dlp, "plugin_is_GPL_compatible");
if (! symp)
OS (fatal, flocp,
_("Loaded object %s is not declared to be GPL compatible"),
ldname);
symp = (load_func_t) dlsym (dlp, symname);
if (! symp)
{
const char *err = dlerror ();
OSSS (fatal, flocp, _("Failed to load symbol %s from %s: %s"),
symname, ldname, err);
}
/* Add this symbol to a trivial lookup table. This is not efficient but
it's highly unlikely we'll be loading lots of objects, and we only
need it to look them up on unload, if we rebuild them. */
new = xmalloc (sizeof (struct load_list));
new->name = xstrdup (ldname);
new->dlp = dlp;
new->next = loaded_syms;
loaded_syms = new;
}
return symp;
}
int
load_file (const floc *flocp, const char **ldname, int noerror)
{
int nmlen = strlen (*ldname);
char *new = alloca (nmlen + CSTRLEN (SYMBOL_EXTENSION) + 1);
char *symname = NULL;
char *loaded;
const char *fp;
int r;
load_func_t symp;
/* Break the input into an object file name and a symbol name. If no symbol
name was provided, compute one from the object file name. */
fp = strchr (*ldname, '(');
if (fp)
{
const char *ep;
/* There's an open paren, so see if there's a close paren: if so use
that as the symbol name. We can't have whitespace: it would have
been chopped up before this function is called. */
ep = strchr (fp+1, ')');
if (ep && ep[1] == '\0')
{
int l = fp - *ldname;;
++fp;
if (fp == ep)
OS (fatal, flocp, _("Empty symbol name for load: %s"), *ldname);
/* Make a copy of the ldname part. */
memcpy (new, *ldname, l);
new[l] = '\0';
*ldname = new;
nmlen = l;
/* Make a copy of the symbol name part. */
symname = new + l + 1;
memcpy (symname, fp, ep - fp);
symname[ep - fp] = '\0';
}
}
/* Add this name to the string cache so it can be reused later. */
*ldname = strcache_add (*ldname);
/* If this object has been loaded, we're done. */
loaded = allocated_variable_expand ("$(.LOADED)");
fp = strstr (loaded, *ldname);
r = fp && (fp==loaded || fp[-1]==' ') && (fp[nmlen]=='\0' || fp[nmlen]==' ');
if (r)
goto exit;
/* If we didn't find a symbol name yet, construct it from the ldname. */
if (! symname)
{
char *p = new;
fp = strrchr (*ldname, '/');
#ifdef HAVE_DOS_PATHS
if (fp)
{
const char *fp2 = strchr (fp, '\\');
if (fp2 > fp)
fp = fp2;
}
else
fp = strrchr (*ldname, '\\');
/* The (improbable) case of d:foo. */
if (fp && *fp && fp[1] == ':')
fp++;
#endif
if (!fp)
fp = *ldname;
else
++fp;
while (isalnum (*fp) || *fp == '_')
*(p++) = *(fp++);
strcpy (p, SYMBOL_EXTENSION);
symname = new;
}
DB (DB_VERBOSE, (_("Loading symbol %s from %s\n"), symname, *ldname));
/* Load it! */
symp = load_object (flocp, noerror, *ldname, symname);
if (! symp)
return 0;
/* Invoke the symbol. */
r = (*symp) (flocp);
/* If it succeeded, add the load file to the loaded variable. */
if (r > 0)
{
size_t loadlen = strlen (loaded);
char *newval = alloca (loadlen + strlen (*ldname) + 2);
/* Don't add a space if it's empty. */
if (loadlen)
{
memcpy (newval, loaded, loadlen);
newval[loadlen++] = ' ';
}
strcpy (&newval[loadlen], *ldname);
do_variable_definition (flocp, ".LOADED", newval, o_default, f_simple, 0);
}
exit:
free (loaded);
return r;
}
void
unload_file (const char *name)
{
struct load_list *d;
for (d = loaded_syms; d != NULL; d = d->next)
if (streq (d->name, name) && d->dlp)
{
if (dlclose (d->dlp))
perror_with_name ("dlclose", d->name);
d->dlp = NULL;
break;
}
}
#else
int
load_file (const floc *flocp, const char **ldname UNUSED, int noerror)
{
if (! noerror)
O (fatal, flocp,
_("The 'load' operation is not supported on this platform."));
return 0;
}
void
unload_file (const char *name UNUSED)
{
O (fatal, NILF, "INTERNAL: Cannot unload when load is not supported!");
}
#endif /* MAKE_LOAD */
make-4.2.1/makeint.h 0000644 0001750 0001750 00000054156 12720141610 011162 0000000 0000000 /* Miscellaneous global declarations and portability cruft for GNU Make.
Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3 of the License, or (at your option) any later
version.
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see . */
/* We use instead of "config.h" so that a compilation
using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h
(which it would do because makeint.h was found in $srcdir). */
#include
#undef HAVE_CONFIG_H
#define HAVE_CONFIG_H 1
/* Specify we want GNU source code. This must be defined before any
system headers are included. */
#define _GNU_SOURCE 1
/* AIX requires this to be the first thing in the file. */
#if HAVE_ALLOCA_H
# include
#else
# ifdef _AIX
#pragma alloca
# else
# if !defined(__GNUC__) && !defined(WINDOWS32)
# ifndef alloca /* predefined by HP cc +Olibcalls */
char *alloca ();
# endif
# endif
# endif
#endif
/* Disable assert() unless we're a maintainer.
Some asserts are compute-intensive. */
#ifndef MAKE_MAINTAINER_MODE
# define NDEBUG 1
#endif
/* Include the externally-visible content.
Be sure to use the local one, and not one installed on the system.
Define GMK_BUILDING_MAKE for proper selection of dllexport/dllimport
declarations for MS-Windows. */
#ifdef WINDOWS32
# define GMK_BUILDING_MAKE
#endif
#include "gnumake.h"
#ifdef CRAY
/* This must happen before #include so
that the declaration therein is changed. */
# define signal bsdsignal
#endif
/* If we're compiling for the dmalloc debugger, turn off string inlining. */
#if defined(HAVE_DMALLOC_H) && defined(__GNUC__)
# define __NO_STRING_INLINES
#endif
#include
#include
#include
#include
#include
#ifdef HAVE_SYS_TIMEB_H
/* SCO 3.2 "devsys 4.2" has a prototype for 'ftime' in that bombs
unless has been included first. */
# include