#include <assert.h>
#include "make.h"
#include "job.h"
#include "debug.h"
#include "filedef.h"
#include "commands.h"
#include "variable.h"
#include "debug.h"
#include <string.h>
#ifdef WINDOWS32
char *default_shell = "sh.exe";
int no_default_sh_exe = 1;
int batch_mode_shell = 1;
#else
# ifdef _AMIGA
char default_shell[] = "";
extern int MyExecute (char **);
# else
# ifdef __MSDOS__
char *default_shell = "command.com";
# else
# ifdef VMS
# include <descrip.h>
char default_shell[] = "";
# else
char default_shell[] = "/bin/sh";
# endif
# endif
int batch_mode_shell = 0;
# endif
#endif
#ifdef __MSDOS__
# include <process.h>
static int execute_by_shell;
static int dos_pid = 123;
int dos_status;
int dos_command_running;
#endif
#ifdef _AMIGA
# include <proto/dos.h>
static int amiga_pid = 123;
static int amiga_status;
static char amiga_bname[32];
static int amiga_batch_file;
#endif
#ifdef VMS
# include <time.h>
# ifndef __GNUC__
# include <processes.h>
# endif
# include <starlet.h>
# include <lib$routines.h>
#endif
#ifdef WINDOWS32
# include <windows.h>
# include <io.h>
# include <process.h>
# include "sub_proc.h"
# include "w32err.h"
# include "pathstuff.h"
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
#if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT)
# include <sys/wait.h>
#endif
#ifdef HAVE_WAITPID
# define WAIT_NOHANG(status) waitpid (-1, (status), WNOHANG)
#else
# ifdef HAVE_WAIT3
# ifndef wait3
extern int wait3 ();
# endif
# define WAIT_NOHANG(status) wait3 ((status), WNOHANG, (struct rusage *) 0)
# endif
#endif
#if !defined (wait) && !defined (POSIX)
extern 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
# 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
#if !defined F_SETFD
# define CLOSE_ON_EXEC(_d)
#else
# ifndef FD_CLOEXEC
# define FD_CLOEXEC 1
# endif
# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC)
#endif
#ifdef VMS
static int vms_jobsefnmask = 0;
#endif
#ifndef HAVE_UNISTD_H
extern int dup2 ();
extern int execve ();
extern void _exit ();
# ifndef VMS
extern int geteuid ();
extern int getegid ();
extern int setgid ();
extern int getgid ();
# endif
#endif
extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file));
extern int getloadavg PARAMS ((double loadavg[], int nelem));
extern int start_remote_job PARAMS ((char **argv, char **envp, int stdin_fd,
int *is_remote, int *id_ptr, int *used_stdin));
extern int start_remote_job_p PARAMS ((int));
extern int remote_status PARAMS ((int *exit_code_ptr, int *signal_ptr,
int *coredump_ptr, int block));
RETSIGTYPE child_handler PARAMS ((int));
static void free_child PARAMS ((struct child *));
static void start_job_command PARAMS ((struct child *child));
static int load_too_high PARAMS ((void));
static int job_next_command PARAMS ((struct child *));
static int start_waiting_job PARAMS ((struct child *));
#ifdef VMS
static void vmsWaitForChildren PARAMS ((int *));
#endif
struct child *children = 0;
unsigned int job_slots_used = 0;
static int good_stdin_used = 0;
static struct child *waiting_jobs = 0;
int unixy_shell = 1;
#ifdef WINDOWS32
int w32_kill(int pid, int sig)
{
return ((process_kill(pid, sig) == TRUE) ? 0 : -1);
}
#endif
static void
child_error (target_name, exit_code, exit_sig, coredump, ignored)
char *target_name;
int exit_code, exit_sig, coredump;
int ignored;
{
if (ignored && silent_flag)
return;
#ifdef VMS
if (!(exit_code & 1))
error (NILF,
(ignored ? _("*** [%s] Error 0x%x (ignored)")
: _("*** [%s] Error 0x%x")),
target_name, exit_code);
#else
if (exit_sig == 0)
error (NILF, ignored ? _("[%s] Error %d (ignored)") :
_("*** [%s] Error %d"),
target_name, exit_code);
else
error (NILF, "*** [%s] %s%s",
target_name, strsignal (exit_sig),
coredump ? _(" (core dumped)") : "");
#endif
}
#ifdef VMS
static void
vmsWaitForChildren(int *status)
{
while (1)
{
if (!vms_jobsefnmask)
{
*status = 0;
return;
}
*status = sys$wflor (32, vms_jobsefnmask);
}
return;
}
char *
vms_redirect (desc, fname, ibuf)
struct dsc$descriptor_s *desc;
char *fname;
char *ibuf;
{
char *fptr;
extern char *vmsify ();
ibuf++;
while (isspace (*ibuf))
ibuf++;
fptr = ibuf;
while (*ibuf && !isspace (*ibuf))
ibuf++;
*ibuf = 0;
if (strcmp (fptr, "/dev/null") != 0)
{
strcpy (fname, vmsify (fptr, 0));
if (strchr (fname, '.') == 0)
strcat (fname, ".");
}
desc->dsc$w_length = strlen(fname);
desc->dsc$a_pointer = fname;
desc->dsc$b_dtype = DSC$K_DTYPE_T;
desc->dsc$b_class = DSC$K_CLASS_S;
if (*fname == 0)
printf (_("Warning: Empty redirection\n"));
return ibuf;
}
static char *
handle_apos (char *p)
{
int alast;
int inside;
#define SEPCHARS ",/()= "
inside = 0;
while (*p != 0)
{
if (*p == '"')
{
if (inside)
{
while ((alast > 0)
&& (*p == '"'))
{
p++;
alast--;
}
if (alast == 0)
inside = 0;
else
{
fprintf (stderr, _("Syntax error, still inside '\"'\n"));
exit (3);
}
}
else
{
p++;
if (strchr (SEPCHARS, *p))
break;
inside = 1;
alast = 1;
while (*p == '"')
{
alast++;
p++;
}
}
}
else
p++;
}
return p;
}
#endif
static unsigned int dead_children = 0;
RETSIGTYPE
child_handler (sig)
int sig;
{
++dead_children;
if (job_rfd >= 0)
{
close (job_rfd);
job_rfd = -1;
}
DB (DB_JOBS, (_("Got a SIGCHLD; %u unreaped children.\n"), dead_children));
}
extern int shell_function_pid, shell_function_completed;
void
reap_children (block, err)
int block, err;
{
WAIT_T status;
int reap_more = 1;
#ifdef WAIT_NOHANG
# define REAP_MORE reap_more
#else
# define REAP_MORE dead_children
#endif
while ((children != 0 || shell_function_pid != 0) &&
(block || REAP_MORE))
{
int remote = 0;
register int pid;
int exit_code, exit_sig, coredump;
register struct child *lastc, *c;
int child_failed;
int any_remote, any_local;
if (err && block)
{
fflush (stdout);
error (NILF, _("*** Waiting for unfinished jobs...."));
}
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 0x%08lx (%s) PID %ld %s\n"),
(unsigned long int) c, c->file->name,
(long) c->pid, c->remote ? _(" (remote)") : ""));
#ifdef VMS
break;
#endif
}
if (any_remote)
pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
else
pid = 0;
if (pid > 0)
remote = 1;
else if (pid < 0)
{
remote_status_lose:
if (EINTR_SET)
continue;
pfatal_with_name ("remote_status");
}
else
{
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
if (any_local)
{
local_wait:
#ifdef VMS
vmsWaitForChildren (&status);
pid = c->pid;
#else
#ifdef WAIT_NOHANG
if (!block)
pid = WAIT_NOHANG (&status);
else
#endif
pid = wait (&status);
#endif
}
else
pid = 0;
if (pid < 0)
{
if (EINTR_SET)
goto local_wait;
pfatal_with_name ("wait");
}
else if (pid > 0)
{
exit_code = WEXITSTATUS (status);
exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
coredump = WCOREDUMP (status);
}
else
{
reap_more = 0;
if (!block || !any_remote)
break;
pid = remote_status (&exit_code, &exit_sig, &coredump, 1);
if (pid < 0)
goto remote_status_lose;
else if (pid == 0)
break;
remote = 1;
}
#endif
#ifdef __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
#ifdef _AMIGA
pid = amiga_pid - 1;
status = amiga_status;
exit_code = amiga_status;
exit_sig = 0;
coredump = 0;
#endif
#ifdef WINDOWS32
{
HANDLE hPID;
int err;
if (hPID = process_wait_for_any()) {
err = process_last_err(hPID);
exit_code = process_exit_code(hPID);
if (err)
fprintf(stderr, "make (e=%d): %s",
exit_code, map_windows32_error_to_string(exit_code));
exit_sig = process_signal(hPID);
process_cleanup(hPID);
coredump = 0;
}
pid = (int) hPID;
}
#endif
}
if (!remote && pid == shell_function_pid)
{
if (exit_sig == 0 && exit_code == 127)
shell_function_completed = -1;
else
shell_function_completed = 1;
break;
}
child_failed = exit_sig != 0 || exit_code != 0;
lastc = 0;
for (c = children; c != 0; lastc = c, c = c->next)
if (c->remote == remote && c->pid == pid)
break;
if (c == 0)
continue;
DB (DB_JOBS, (child_failed
? _("Reaping losing child 0x%08lx PID %ld %s\n")
: _("Reaping winning child 0x%08lx PID %ld %s\n"),
(unsigned long int) c, (long) c->pid,
c->remote ? _(" (remote)") : ""));
if (c->sh_batch_file) {
DB (DB_JOBS, (_("Cleaning up temp batch file %s\n"),
c->sh_batch_file));
remove (c->sh_batch_file);
free (c->sh_batch_file);
c->sh_batch_file = NULL;
}
if (c->good_stdin)
good_stdin_used = 0;
if (child_failed && !c->noerror && !ignore_errors_flag)
{
static int delete_on_error = -1;
child_error (c->file->name, exit_code, exit_sig, coredump, 0);
c->file->update_status = 2;
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)
{
child_error (c->file->name,
exit_code, exit_sig, coredump, 1);
child_failed = 0;
}
if (job_next_command (c))
{
if (handling_fatal_signal)
{
c->file->update_status = 2;
}
else
{
c->remote = start_remote_job_p (0);
start_job_command (c);
unblock_sigs ();
if (c->file->command_state == cs_running)
continue;
}
if (c->file->update_status != 0)
delete_child_targets (c);
}
else
c->file->update_status = 0;
}
if (! handling_fatal_signal)
notice_finished_file (c->file);
DB (DB_JOBS, (_("Removing child 0x%08lx PID %ld %s from chain.\n"),
(unsigned long int) c, (long) c->pid,
c->remote ? _(" (remote)") : ""));
block_sigs ();
if (job_slots_used > 0)
--job_slots_used;
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
unblock_sigs ();
if (!err && child_failed && !keep_going_flag &&
!handling_fatal_signal)
die (2);
block = 0;
}
return;
}
static void
free_child (child)
register struct child *child;
{
if (job_fds[1] >= 0 && children)
{
char token = '+';
while (write (job_fds[1], &token, 1) != 1)
if (!EINTR_SET)
pfatal_with_name (_("write jobserver"));
DB (DB_JOBS, (_("Released token for child 0x%08lx (%s).\n"),
(unsigned long int) child, child->file->name));
}
if (handling_fatal_signal)
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 ((char *) child->command_lines);
}
if (child->environment != 0)
{
register char **ep = child->environment;
while (*ep != 0)
free (*ep++);
free ((char *) child->environment);
}
free ((char *) child);
}
#ifdef POSIX
extern sigset_t fatal_signal_set;
#endif
void
block_sigs ()
{
#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 ()
{
sigset_t empty;
sigemptyset (&empty);
sigprocmask (SIG_SETMASK, &empty, (sigset_t *) 0);
}
#endif
static void
start_job_command (child)
register struct child *child;
{
#ifndef _AMIGA
static int bad_stdin = -1;
#endif
register char *p;
int flags;
#ifdef VMS
char *argv;
#else
char **argv;
#endif
if (!child->command_ptr)
goto next_command;
flags = (child->file->command_flags
| child->file->cmds->lines_flags[child->command_line - 1]);
p = child->command_ptr;
child->noerror = flags & COMMANDS_NOERROR;
while (*p != '\0')
{
if (*p == '@')
flags |= COMMANDS_SILENT;
else if (*p == '+')
flags |= COMMANDS_RECURSE;
else if (*p == '-')
child->noerror = 1;
else if (!isblank (*p))
break;
++p;
}
child->file->cmds->lines_flags[child->command_line - 1] |= flags;
if (question_flag && !(flags & COMMANDS_RECURSE))
{
child->file->update_status = 1;
notice_finished_file (child->file);
return;
}
p = next_token (p);
{
char *end = 0;
#ifdef VMS
argv = p;
#else
argv = construct_command_argv (p, &end, child->file, &child->sh_batch_file);
#endif
if (end == NULL)
child->command_ptr = NULL;
else
{
*end++ = '\0';
child->command_ptr = end;
}
}
if (touch_flag && !(flags & COMMANDS_RECURSE))
{
#ifndef VMS
free (argv[0]);
free ((char *) argv);
#endif
argv = 0;
}
if (argv == 0)
{
next_command:
#ifdef __MSDOS__
execute_by_shell = 0;
#endif
if (job_next_command (child))
start_job_command (child);
else
{
set_command_state (child->file, cs_running);
child->file->update_status = 0;
notice_finished_file (child->file);
}
return;
}
message (0, (just_print_flag || (!(flags & COMMANDS_SILENT) && !silent_flag))
? "%s" : (char *) 0, p);
#if !defined(VMS) && !defined(_AMIGA)
if (
#ifdef __MSDOS__
unixy_shell
#else
(argv[0] && !strcmp (argv[0], "/bin/sh"))
#endif
#if defined(__APPLE__) || defined(NeXT) || defined(NeXT_PDO)
&& ((argv[1]
&& argv[1][0] == '-' && argv[1][1] == 'c' && argv[1][2] == '\0') ||
(argv[1]
&& argv[1][0] == '-' && argv[1][1] == 'e' && argv[1][2] == 'c' && argv[1][3] == '\0'))
#else
&& (argv[1]
&& argv[1][0] == '-' && argv[1][1] == 'c' && argv[1][2] == '\0')
#endif __APPLE__ || NeXT || NeXT_PDO
&& (argv[2] && argv[2][0] == ':' && argv[2][1] == '\0')
&& argv[3] == NULL)
{
free (argv[0]);
free ((char *) argv);
goto next_command;
}
#endif
++commands_started;
if (just_print_flag && !(flags & COMMANDS_RECURSE))
{
#ifndef VMS
free (argv[0]);
free ((char *) argv);
#endif
goto next_command;
}
fflush (stdout);
fflush (stderr);
#ifndef VMS
#if !defined(WINDOWS32) && !defined(_AMIGA) && !defined(__MSDOS__)
if (bad_stdin == -1)
{
int pd[2];
if (pipe (pd) == 0)
{
(void) close (pd[1]);
bad_stdin = pd[0];
CLOSE_ON_EXEC (bad_stdin);
}
}
#endif
child->good_stdin = !good_stdin_used;
if (child->good_stdin)
good_stdin_used = 1;
#endif
child->deleted = 0;
#ifndef _AMIGA
if (child->environment == 0)
child->environment = target_environment (child->file);
#endif
#if !defined(__MSDOS__) && !defined(_AMIGA) && !defined(WINDOWS32)
#ifndef VMS
if (child->remote)
{
int is_remote, id, used_stdin;
if (start_remote_job (argv, child->environment,
child->good_stdin ? 0 : bad_stdin,
&is_remote, &id, &used_stdin))
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
{
char **parent_environ;
run_local:
block_sigs ();
child->remote = 0;
#ifdef VMS
if (!child_execute_job (argv, child)) {
perror_with_name ("vfork", "");
goto error;
}
#else
parent_environ = environ;
child->pid = vfork ();
environ = parent_environ;
if (child->pid == 0)
{
unblock_sigs ();
if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0)
{
close (job_fds[0]);
close (job_fds[1]);
}
if (job_rfd >= 0)
close (job_rfd);
child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
argv, child->environment);
}
else if (child->pid < 0)
{
unblock_sigs ();
perror_with_name ("vfork", "");
goto error;
}
#endif
}
#else
#ifdef __MSDOS__
{
int proc_return;
block_sigs ();
dos_status = 0;
if (execute_by_shell)
{
char *cmdline = argv[0];
char **parent_environ = environ;
environ = child->environment;
if (unixy_shell)
{
cmdline = argv[2];
}
dos_command_running = 1;
proc_return = system (cmdline);
environ = parent_environ;
execute_by_shell = 0;
}
else
{
dos_command_running = 1;
proc_return = spawnvpe (P_WAIT, argv[0], argv, child->environment);
}
unblock_sigs ();
dos_command_running = 0;
if (proc_return == -1)
dos_status |= 0xff;
else
dos_status |= (proc_return & 0xff);
++dead_children;
child->pid = dos_pid++;
}
#endif
#ifdef _AMIGA
amiga_status = MyExecute (argv);
++dead_children;
child->pid = amiga_pid++;
if (amiga_batch_file)
{
amiga_batch_file = 0;
DeleteFile (amiga_bname);
}
#endif
#ifdef WINDOWS32
{
HANDLE hPID;
char* arg0;
arg0 = argv[0];
if (arg0 && arg0[0] == '/' && arg0[1] == '/')
for ( ; arg0 && *arg0; arg0++)
if (*arg0 == '/')
*arg0 = '\\';
sync_Path_environment();
hPID = process_easy(argv, child->environment);
if (hPID != INVALID_HANDLE_VALUE)
child->pid = (int) hPID;
else {
int i;
unblock_sigs();
fprintf(stderr,
_("process_easy() failed failed to launch process (e=%d)\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);
}
}
#endif
#endif
set_command_state (child->file, cs_running);
#ifndef VMS
free (argv[0]);
free ((char *) argv);
#endif
return;
error:
child->file->update_status = 2;
notice_finished_file (child->file);
return;
}
static int
start_waiting_job (c)
struct child *c;
{
struct file *f = c->file;
c->remote = start_remote_job_p (1);
if (!c->remote && job_slots_used > 0 && load_too_high ())
{
set_command_state (f, cs_running);
c->next = waiting_jobs;
waiting_jobs = c;
return 0;
}
start_job_command (c);
switch (f->command_state)
{
case cs_running:
c->next = children;
DB (DB_JOBS, (_("Putting child 0x%08lx (%s) PID %ld%s on the chain.\n"),
(unsigned long int) c, c->file->name,
(long) c->pid, c->remote ? _(" (remote)") : ""));
children = c;
++job_slots_used;
unblock_sigs ();
break;
case cs_not_started:
f->update_status = 0;
case cs_finished:
notice_finished_file (f);
free_child (c);
break;
default:
assert (f->command_state == cs_finished);
break;
}
return 1;
}
void
new_job (file)
register struct file *file;
{
register struct commands *cmds = file->cmds;
register struct child *c;
char **lines;
register unsigned int i;
start_waiting_jobs ();
reap_children (0, 0);
chop_commands (cmds);
lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
for (i = 0; i < cmds->ncommand_lines; ++i)
{
char *in, *out, *ref;
in = out = cmds->command_lines[i];
while ((ref = strchr (in, '$')) != 0)
{
++ref;
if (out != in)
bcopy (in, out, ref - in);
out += ref - in;
in = ref;
if (*ref == '(' || *ref == '{')
{
char openparen = *ref;
char closeparen = openparen == '(' ? ')' : '}';
int count;
char *p;
*out++ = *in++;
count = 0;
while (*in != '\0')
{
if (*in == closeparen && --count < 0)
break;
else if (*in == '\\' && in[1] == '\n')
{
int quoted = 0;
for (p = in - 1; p > ref && *p == '\\'; --p)
quoted = !quoted;
if (quoted)
*out++ = *in++;
else
{
in = next_token (in + 2);
while (out > ref && isblank (out[-1]))
--out;
*out++ = ' ';
}
}
else
{
if (*in == openparen)
++count;
*out++ = *in++;
}
}
}
}
if (out != in)
strcpy (out, in);
lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
file);
}
#if defined(__APPLE__) || defined(NeXT) || defined(NeXT_PDO)
if (next_flag & NEXT_VPATH_FLAG) {
for (i = 0; i < cmds->ncommand_lines; ++i) {
char *line;
if (lines[i] != 0) {
line = allocated_vpath_expand_for_file (lines[i], file);
free (lines[i]);
lines[i] = line;
}
}
}
#endif
c = (struct child *) xmalloc (sizeof (struct child));
bzero ((char *)c, sizeof (struct child));
c->file = file;
c->command_lines = lines;
c->sh_batch_file = NULL;
job_next_command (c);
if (job_slots != 0)
while (job_slots_used == job_slots)
reap_children (1, 0);
#ifdef MAKE_JOBSERVER
else if (job_fds[0] >= 0)
while (1)
{
char token;
if (!children)
break;
if (read (job_rfd, &token, 1) == 1)
{
DB (DB_JOBS, (_("Obtained token for child 0x%08lx (%s).\n"),
(unsigned long int) c, c->file->name));
break;
}
if (errno != EINTR && errno != EBADF)
pfatal_with_name (_("read jobs pipe"));
if (job_rfd < 0)
job_rfd = dup (job_fds[0]);
reap_children (0, 0);
}
#endif
(void) start_waiting_job (c);
if (job_slots == 1 || not_parallel)
while (file->command_state == cs_running)
reap_children (1, 0);
return;
}
static int
job_next_command (child)
struct child *child;
{
while (child->command_ptr == 0 || *child->command_ptr == '\0')
{
if (child->command_line == child->file->cmds->ncommand_lines)
{
child->command_ptr = 0;
return 0;
}
else
child->command_ptr = child->command_lines[child->command_line++];
}
return 1;
}
static int
load_too_high ()
{
#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA)
return 1;
#else
double load;
if (max_load_average < 0)
return 0;
make_access ();
if (getloadavg (&load, 1) != 1)
{
static int lossage = -1;
if (lossage == -1 || errno != lossage)
{
if (errno == 0)
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 ();
return load >= max_load_average;
#endif
}
void
start_waiting_jobs ()
{
struct child *job;
if (waiting_jobs == 0)
return;
do
{
reap_children (0, 0);
job = waiting_jobs;
waiting_jobs = job->next;
}
while (start_waiting_job (job) && waiting_jobs != 0);
return;
}
#ifndef WINDOWS32
#ifdef VMS
#include <descrip.h>
#include <clidef.h>
int vmsHandleChildTerm(struct child *child)
{
int status;
register struct child *lastc, *c;
int child_failed;
vms_jobsefnmask &= ~(1 << (child->efn - 32));
lib$free_ef(&child->efn);
(void) sigblock (fatal_signal_mask);
child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0));
lastc = 0;
#if defined(RECURSIVEJOBS)
for (c = children; c != 0 && c != child; lastc = c, c = c->next);
#else
c = child;
#endif
if (child_failed && !c->noerror && !ignore_errors_flag)
{
child_error (c->file->name, c->cstatus, 0, 0, 0);
c->file->update_status = 1;
delete_child_targets (c);
}
else
{
if (child_failed)
{
child_error (c->file->name, c->cstatus, 0, 0, 1);
child_failed = 0;
}
#if defined(RECURSIVEJOBS)
start_job (c);
switch (c->file->command_state)
{
case cs_running:
break;
case cs_finished:
if (c->file->update_status != 0) {
delete_child_targets (c);
}
break;
default:
error (NILF, _("internal error: `%s' command_state"),
c->file->name);
abort ();
break;
}
#endif
}
c->file->command_state = cs_finished;
notice_finished_file (c->file);
#if defined(RECURSIVEJOBS)
if (lastc == 0)
children = c->next;
else
lastc->next = c->next;
free_child (c);
#endif
if (job_slots_used > 0)
--job_slots_used;
if (child_failed && !keep_going_flag)
die (EXIT_FAILURE);
(void) sigsetmask (sigblock (0) & ~(fatal_signal_mask));
return 1;
}
#define MAXCMDLEN 200
#include <iodef.h>
#include <libclidef.h>
#include <ssdef.h>
static int ctrlMask= LIB$M_CLI_CTRLY;
static int oldCtrlMask;
static int setupYAstTried= 0;
static int pidToAbort= 0;
static int chan= 0;
static void reEnableAst(void) {
lib$enable_ctrl (&oldCtrlMask,0);
}
static astHandler (void) {
if (pidToAbort) {
sys$forcex (&pidToAbort, 0, SS$_ABORT);
pidToAbort= 0;
}
kill (getpid(),SIGQUIT);
}
static void tryToSetupYAst(void) {
$DESCRIPTOR(inputDsc,"SYS$COMMAND");
int status;
struct {
short int status, count;
int dvi;
} iosb;
setupYAstTried++;
if (!chan) {
status= sys$assign(&inputDsc,&chan,0,0);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
}
status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0,
astHandler,0,0,0,0,0);
if (status==SS$_ILLIOFUNC) {
sys$dassgn(chan);
#ifdef CTRLY_ENABLED_ANYWAY
fprintf (stderr,
_("-warning, CTRL-Y will leave sub-process(es) around.\n"));
#else
return;
#endif
}
if (status==SS$_NORMAL)
status= iosb.status;
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
if (setupYAstTried>1)
return;
if (atexit(reEnableAst))
fprintf (stderr,
_("-warning, you may have to re-enable CTRL-Y handling from DCL.\n"));
status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask);
if (!(status&SS$_NORMAL)) {
lib$signal(status);
return;
}
}
int
child_execute_job (argv, child)
char *argv;
struct child *child;
{
int i;
static struct dsc$descriptor_s cmddsc;
static struct dsc$descriptor_s pnamedsc;
static struct dsc$descriptor_s ifiledsc;
static struct dsc$descriptor_s ofiledsc;
static struct dsc$descriptor_s efiledsc;
int have_redirection = 0;
int have_newline = 0;
int spflags = CLI$M_NOWAIT;
int status;
char *cmd = alloca (strlen (argv) + 512), *p, *q;
char ifile[256], ofile[256], efile[256];
char *comname = 0;
char procname[100];
ifile[0] = 0;
ofile[0] = 0;
efile[0] = 0;
DB (DB_JOBS, ("child_execute_job (%s)\n", argv));
while (isspace (*argv))
argv++;
if (*argv == 0)
return 0;
sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff);
pnamedsc.dsc$w_length = strlen(procname);
pnamedsc.dsc$a_pointer = procname;
pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T;
pnamedsc.dsc$b_class = DSC$K_CLASS_S;
for (p = argv, q = cmd; *p; p++, q++)
{
switch (*p)
{
case '#':
*p-- = 0;
*q-- = 0;
break;
case '\\':
p++;
if (*p == '\n')
p++;
if (isspace (*p))
{
do { p++; } while (isspace (*p));
p--;
}
*q = *p;
break;
case '<':
p = vms_redirect (&ifiledsc, ifile, p);
*q = ' ';
have_redirection = 1;
break;
case '>':
have_redirection = 1;
if (*(p-1) == '2')
{
q--;
if (strncmp (p, ">&1", 3) == 0)
{
p += 3;
strcpy (efile, "sys$output");
efiledsc.dsc$w_length = strlen(efile);
efiledsc.dsc$a_pointer = efile;
efiledsc.dsc$b_dtype = DSC$K_DTYPE_T;
efiledsc.dsc$b_class = DSC$K_CLASS_S;
}
else
{
p = vms_redirect (&efiledsc, efile, p);
}
}
else
{
p = vms_redirect (&ofiledsc, ofile, p);
}
*q = ' ';
break;
case '\n':
have_newline = 1;
default:
*q = *p;
break;
}
}
*q = *p;
if (strncmp (cmd, "builtin_", 8) == 0)
{
child->pid = 270163;
child->efn = 0;
child->cstatus = 1;
DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8));
p = cmd + 8;
if ((*(p) == 'c')
&& (*(p+1) == 'd')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
DB (DB_JOBS, (_("BUILTIN CD %s\n"), p));
if (chdir (p))
return 0;
else
return 1;
}
else if ((*(p) == 'r')
&& (*(p+1) == 'm')
&& ((*(p+2) == ' ') || (*(p+2) == '\t')))
{
int in_arg;
p += 3;
while ((*p == ' ') || (*p == '\t'))
p++;
in_arg = 1;
DB (DB_JOBS, (_("BUILTIN RM %s\n"), p));
while (*p)
{
switch (*p)
{
case ' ':
case '\t':
if (in_arg)
{
*p++ = ';';
in_arg = 0;
}
break;
default:
break;
}
p++;
}
}
else
{
printf(_("Unknown builtin command '%s'\n"), cmd);
fflush(stdout);
return 0;
}
}
if (strlen (cmd) > MAXCMDLEN
|| (have_redirection != 0)
|| (have_newline != 0))
{
FILE *outfile;
char c;
char *sep;
int alevel = 0;
if (strlen (cmd) == 0)
{
printf (_("Error, empty command\n"));
fflush (stdout);
return 0;
}
outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM");
if (outfile == 0)
pfatal_with_name (_("fopen (temporary file)"));
if (ifile[0])
{
fprintf (outfile, "$ assign/user %s sys$input\n", ifile);
DB (DB_JOBS, (_("Redirected input from %s\n"), ifile));
ifiledsc.dsc$w_length = 0;
}
if (efile[0])
{
fprintf (outfile, "$ define sys$error %s\n", efile);
DB (DB_JOBS, (_("Redirected error to %s\n"), efile));
efiledsc.dsc$w_length = 0;
}
if (ofile[0])
{
fprintf (outfile, "$ define sys$output %s\n", ofile);
DB (DB_JOBS, (_("Redirected output to %s\n"), ofile));
ofiledsc.dsc$w_length = 0;
}
p = sep = q = cmd;
for (c = '\n'; c; c = *q++)
{
switch (c)
{
case '\n':
while (isspace (*p))
p++;
if (*p == '$')
p++;
while (isspace (*p))
p++;
fwrite (p, 1, q - p, outfile);
fputc ('$', outfile);
fputc (' ', outfile);
p = sep = q;
break;
case '"':
q = handle_apos (q + 1);
sep = q;
break;
case ',':
case ' ':
sep = q;
break;
case '/':
case '\0':
sep = q - 1;
break;
default:
break;
}
if (sep - p > 78)
{
fwrite (p, 1, sep - p, outfile);
p = sep;
if (*sep)
{
fputc ('-', outfile);
}
fputc ('\n', outfile);
}
}
fwrite (p, 1, q - p, outfile);
fputc ('\n', outfile);
fclose (outfile);
sprintf (cmd, "$ @%s", comname);
DB (DB_JOBS, (_("Executing %s instead\n"), cmd));
}
cmddsc.dsc$w_length = strlen(cmd);
cmddsc.dsc$a_pointer = cmd;
cmddsc.dsc$b_dtype = DSC$K_DTYPE_T;
cmddsc.dsc$b_class = DSC$K_CLASS_S;
child->efn = 0;
while (child->efn < 32 || child->efn > 63)
{
status = lib$get_ef ((unsigned long *)&child->efn);
if (!(status & 1))
return 0;
}
sys$clref (child->efn);
vms_jobsefnmask |= (1 << (child->efn - 32));
#ifndef DONTWAITFORCHILD
if (!setupYAstTried)
tryToSetupYAst();
status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
0, 0,
0, 0, 0);
pidToAbort= child->pid;
status= sys$waitfr (child->efn);
pidToAbort= 0;
vmsHandleChildTerm(child);
#else
status = lib$spawn (&cmddsc,
(ifiledsc.dsc$w_length == 0)?0:&ifiledsc,
(ofiledsc.dsc$w_length == 0)?0:&ofiledsc,
&spflags,
&pnamedsc,
&child->pid, &child->cstatus, &child->efn,
vmsHandleChildTerm, child,
0, 0, 0);
#endif
if (!(status & 1))
{
printf (_("Error spawning, %d\n") ,status);
fflush (stdout);
}
if (comname && !ISDB (DB_JOBS))
unlink (comname);
return (status & 1);
}
#else
#if !defined (_AMIGA) && !defined (__MSDOS__)
void
child_execute_job (stdin_fd, stdout_fd, argv, envp)
int stdin_fd, stdout_fd;
char **argv, **envp;
{
if (stdin_fd != 0)
(void) dup2 (stdin_fd, 0);
if (stdout_fd != 1)
(void) dup2 (stdout_fd, 1);
if (stdin_fd != 0)
(void) close (stdin_fd);
if (stdout_fd != 1)
(void) close (stdout_fd);
exec_command (argv, envp);
}
#endif
#endif
#endif
#ifndef _AMIGA
void
exec_command (argv, envp)
char **argv, **envp;
{
#ifdef VMS
#ifdef SIGCHLD
signal (SIGCHLD,SIG_IGN);
#endif
execve (argv[0], argv, envp);
perror_with_name ("execve: ", argv[0]);
_exit (EXIT_FAILURE);
#else
#ifdef WINDOWS32
HANDLE hPID;
HANDLE hWaitPID;
int err = 0;
int exit_code = EXIT_FAILURE;
sync_Path_environment();
hPID = process_easy(argv, envp);
if (hPID == INVALID_HANDLE_VALUE)
{
int i;
fprintf(stderr,
_("process_easy() failed failed to launch process (e=%d)\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);
}
while (hWaitPID = process_wait_for_any())
{
err = process_last_err(hWaitPID);
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));
process_cleanup(hWaitPID);
if (hWaitPID == hPID)
break;
else
fprintf(stderr,
_("make reaped child pid %d, still waiting for pid %d\n"),
hWaitPID, hPID);
}
exit(exit_code);
#else
child_access ();
environ = envp;
execvp (argv[0], argv);
switch (errno)
{
case ENOENT:
error (NILF, _("%s: Command not found"), argv[0]);
break;
case ENOEXEC:
{
extern char *getenv ();
char *shell;
char **new_argv;
int argc;
shell = getenv ("SHELL");
if (shell == 0)
shell = default_shell;
argc = 1;
while (argv[argc] != 0)
++argc;
new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *));
new_argv[0] = shell;
new_argv[1] = argv[0];
while (argc > 0)
{
new_argv[1 + argc] = argv[argc];
--argc;
}
execvp (shell, new_argv);
if (errno == ENOENT)
error (NILF, _("%s: Shell program not found"), shell);
else
perror_with_name ("execvp: ", shell);
break;
}
default:
perror_with_name ("execvp: ", argv[0]);
break;
}
_exit (127);
#endif
#endif
}
#else
void exec_command (argv)
char **argv;
{
MyExecute (argv);
}
void clean_tmp (void)
{
DeleteFile (amiga_bname);
}
#endif
#ifndef VMS
static char **
construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr)
char *line, **restp;
char *shell, *ifs;
char **batch_filename_ptr;
{
#ifdef __MSDOS__
static char sh_chars_dos[] = "*?[];|<>%^&()";
static 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 char sh_chars_sh[] = "#;\"*?[]&|<>(){}$`^";
static 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",
0 };
char *sh_chars;
char **sh_cmds;
#else
#ifdef _AMIGA
static char sh_chars[] = "#;\"|<>()?*$`";
static char *sh_cmds[] = { "cd", "eval", "if", "delete", "echo", "copy",
"rename", "set", "setenv", "date", "makedir",
"skip", "else", "endif", "path", "prompt",
"unset", "unsetenv", "version",
0 };
#else
#ifdef WINDOWS32
static char sh_chars_dos[] = "\"|&<>";
static char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls",
"copy", "ctty", "date", "del", "dir", "echo",
"erase", "exit", "for", "goto", "if", "if", "md",
"mkdir", "path", "pause", "prompt", "rem", "ren",
"rename", "set", "shift", "time", "type",
"ver", "verify", "vol", ":", 0 };
static char sh_chars_sh[] = "#;\"*?[]&|<>(){}$`^";
static 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 };
char* sh_chars;
char** sh_cmds;
#else
static char sh_chars[] = "#;\"*?[]&|<>(){}$`^";
static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
"logout", "set", "umask", "wait", "while", "for",
"case", "if", ":", ".", "break", "continue",
"export", "read", "readonly", "shift", "times",
"trap", "switch", 0 };
#endif
#endif
#endif
register int i;
register char *p;
register char *ap;
char *end;
int instring, word_has_equals, seen_nonequals, last_argument_was_empty;
char **new_argv = 0;
#ifdef WINDOWS32
int slow_flag = 0;
if (no_default_sh_exe) {
sh_cmds = sh_cmds_dos;
sh_chars = sh_chars_dos;
} else {
sh_cmds = sh_cmds_sh;
sh_chars = sh_chars_sh;
}
#endif
if (restp != NULL)
*restp = NULL;
while (isblank (*line))
++line;
if (*line == '\0')
return 0;
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 : ""));
if (s1)
free (s1);
if (s2)
free (s2);
}
if (slow_flag)
goto slow;
#else
#ifdef __MSDOS__
else if (stricmp (shell, default_shell))
{
extern int _is_unixy_shell (const char *_path);
message (1, _("$SHELL changed (was `%s', now `%s')"), default_shell, shell);
unixy_shell = _is_unixy_shell (shell);
default_shell = 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;
}
#else
else if (strcmp (shell, default_shell))
goto slow;
#endif
#endif
if (ifs != 0)
for (ap = ifs; *ap != '\0'; ++ap)
if (*ap != ' ' && *ap != '\t' && *ap != '\n')
goto slow;
i = strlen (line) + 1;
new_argv = (char **) xmalloc (i * sizeof (char *));
ap = new_argv[0] = (char *) xmalloc (i);
end = ap + i;
i = 0;
instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0;
for (p = line; *p != '\0'; ++p)
{
if (ap > end)
abort ();
if (instring)
{
string_char:
if (*p == instring)
{
instring = 0;
if (ap == new_argv[0] || *(ap-1) == '\0')
last_argument_was_empty = 1;
}
else if (*p == '\\' && p[1] == '\n')
goto swallow_escaped_newline;
else if (*p == '\n' && restp != NULL)
{
*restp = p;
goto end_of_line;
}
else if (instring == '"' && strchr ("\\$`", *p) != 0 && unixy_shell)
goto slow;
else
*ap++ = *p;
}
else if (strchr (sh_chars, *p) != 0)
goto slow;
#ifdef __MSDOS__
else if (*p == '.' && p[1] == '.' && p[2] == '.' && p[3] != '.')
goto slow;
#endif
else
switch (*p)
{
case '=':
if (! seen_nonequals && unixy_shell)
goto slow;
word_has_equals = 1;
*ap++ = '=';
break;
case '\\':
if (p[1] == '\n')
{
swallow_escaped_newline:
p += 2;
if (*p == '\t')
bcopy (p + 1, p, strlen (p));
if (instring)
goto string_char;
else
{
if (ap != new_argv[i])
goto end_of_arg;
else
p = next_token (p) - 1;
}
}
else if (p[1] != '\0')
{
#if defined(__MSDOS__) || defined(WINDOWS32)
#ifdef __MSDOS__
if (strneq (p + 1, ".\\.\\.", 5))
{
*ap++ = '.';
*ap++ = '.';
p += 4;
}
else
#endif
if (p[1] != '\\' && p[1] != '\''
&& !isspace ((unsigned char)p[1])
&& (strchr (sh_chars_sh, p[1]) == 0))
--p;
#endif
*ap++ = *++p;
}
break;
case '\'':
case '"':
instring = *p;
break;
case '\n':
if (restp != NULL)
{
*restp = p;
goto end_of_line;
}
else
*ap++ = '\n';
break;
case ' ':
case '\t':
end_of_arg:
*ap++ = '\0';
new_argv[++i] = ap;
last_argument_was_empty = 0;
seen_nonequals |= ! word_has_equals;
if (word_has_equals && ! seen_nonequals)
goto slow;
word_has_equals = 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;
}
p = next_token (p);
--p;
break;
default:
*ap++ = *p;
break;
}
}
end_of_line:
if (instring)
goto slow;
*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)
return 0;
else
return new_argv;
slow:;
if (new_argv != 0)
{
free (new_argv[0]);
free ((void *)new_argv);
}
#ifdef __MSDOS__
execute_by_shell = 1;
#endif
#ifdef _AMIGA
{
char *ptr;
char *buffer;
char *dptr;
buffer = (char *)xmalloc (strlen (line)+1);
ptr = line;
for (dptr=buffer; *ptr; )
{
if (*ptr == '\\' && ptr[1] == '\n')
ptr += 2;
else if (*ptr == '@')
{
ptr += 2;
*dptr++ = '\n';
}
else
*dptr++ = *ptr++;
}
*dptr = 0;
new_argv = (char **) xmalloc (2 * sizeof (char *));
new_argv[0] = buffer;
new_argv[1] = 0;
}
#else
#ifdef WINDOWS32
while (isspace ((unsigned char)*line))
++line;
if (*line == '\0')
return 0;
#endif
{
unsigned int shell_len = strlen (shell);
unsigned int line_len = strlen (line);
char *new_line;
char *command_ptr = NULL;
#if defined(__APPLE__) || defined(NeXT) || defined(NeXT_PDO)
char *minus_c;
int minus_c_len;
if (next_flag & NEXT_ERREXIT_FLAG) {
minus_c = " -ec ";
minus_c_len = 5;
} else {
minus_c = " -c ";
minus_c_len = 4;
}
#else
#ifndef VMS
static char minus_c[] = " -c ";
int minus_c_len = 4;
#else
static char minus_c[] = "";
int minus_c_len = 0;
#endif
#endif
new_line = (char *) alloca (shell_len + minus_c_len
+ (line_len * 2) + 1);
ap = new_line;
bcopy (shell, ap, shell_len);
ap += shell_len;
bcopy (minus_c, ap, minus_c_len);
ap += minus_c_len;
command_ptr = ap;
for (p = line; *p != '\0'; ++p)
{
if (restp != NULL && *p == '\n')
{
*restp = p;
break;
}
else if (*p == '\\' && p[1] == '\n')
{
p += 2;
if (*p == '\t')
bcopy (p + 1, p, strlen (p));
p = next_token (p);
--p;
if (unixy_shell && !batch_mode_shell)
*ap++ = '\\';
*ap++ = ' ';
continue;
}
if (unixy_shell && !batch_mode_shell &&
(*p == '\\' || *p == '\'' || *p == '"'
|| isspace ((unsigned char)*p)
|| strchr (sh_chars, *p) != 0))
*ap++ = '\\';
#ifdef __MSDOS__
else if (unixy_shell && strneq (p, "...", 3))
{
strcpy (ap, "\\.\\.\\");
ap += 5;
p += 2;
}
#endif
*ap++ = *p;
}
if (ap == new_line + shell_len + minus_c_len)
return 0;
*ap = '\0';
#ifdef WINDOWS32
if ((no_default_sh_exe || batch_mode_shell) && batch_filename_ptr) {
FILE* batch = NULL;
int id = GetCurrentProcessId();
PATH_VAR(fbuf);
char* fname = NULL;
sprintf(fbuf, "make%d", id);
fname = tempnam(".", fbuf);
*batch_filename_ptr = xmalloc(strlen(fname) + 5);
strcpy(*batch_filename_ptr, fname);
if (!unixy_shell) {
fname = *batch_filename_ptr;
for (i = 0; fname[i] != '\0'; ++i)
if (fname[i] == '/')
fname[i] = '\\';
strcat(*batch_filename_ptr, ".bat");
} else {
strcat(*batch_filename_ptr, ".sh");
}
DB (DB_JOBS, (_("Creating temporary batch file %s\n"),
*batch_filename_ptr));
batch = fopen (*batch_filename_ptr, "w");
if (!unixy_shell)
fputs ("@echo off\n", batch);
fputs (command_ptr, batch);
fputc ('\n', batch);
fclose (batch);
new_argv = (char **) xmalloc(3 * sizeof (char *));
if (unixy_shell) {
new_argv[0] = xstrdup (shell);
new_argv[1] = *batch_filename_ptr;
} else {
new_argv[0] = xstrdup (*batch_filename_ptr);
new_argv[1] = NULL;
}
new_argv[2] = NULL;
} else
#endif
if (unixy_shell)
new_argv = construct_command_argv_internal (new_line, (char **) NULL,
(char *) 0, (char *) 0,
(char **) 0);
#ifdef __MSDOS__
else
{
new_argv = (char **) xmalloc (sizeof (char *));
line_len = strlen (new_line) - shell_len - minus_c_len;
new_argv[0] = xmalloc (line_len + 1);
strncpy (new_argv[0],
new_line + shell_len + minus_c_len, line_len);
new_argv[0][line_len] = '\0';
}
#else
else
fatal (NILF, _("%s (line %d) Bad shell context (!unixy && !batch_mode_shell)\n"),
__FILE__, __LINE__);
#endif
}
#endif
return new_argv;
}
#endif
char **
construct_command_argv (line, restp, file, batch_filename_ptr)
char *line, **restp;
struct file *file;
char** batch_filename_ptr;
{
char *shell, *ifs;
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 = (char **)malloc (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
{
int save = warn_undefined_variables_flag;
warn_undefined_variables_flag = 0;
shell = allocated_variable_expand_for_file ("$(SHELL)", file);
#ifdef WINDOWS32
if (shell) {
char *p = w32ify(shell, 0);
strcpy(shell, p);
}
#endif
ifs = allocated_variable_expand_for_file ("$(IFS)", file);
warn_undefined_variables_flag = save;
}
argv = construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr);
free (shell);
free (ifs);
#endif
return argv;
}
#if !defined(HAVE_DUP2) && !defined(_AMIGA)
int
dup2 (old, new)
int old, new;
{
int fd;
(void) close (new);
fd = dup (old);
if (fd != new)
{
(void) close (fd);
errno = EMFILE;
return -1;
}
return fd;
}
#endif