#include "make.h"
#include "dep.h"
#include "filedef.h"
#include "variable.h"
#include "job.h"
#include "commands.h"
extern int remote_kill PARAMS ((int id, int sig));
#ifndef HAVE_UNISTD_H
extern int getpid ();
#endif
static void
set_file_variables (file)
register struct file *file;
{
register char *p;
char *at, *percent, *star, *less;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
unsigned int len;
p = strchr (file->name, '(');
at = (char *) alloca (p - file->name + 1);
bcopy (file->name, at, p - file->name);
at[p - file->name] = '\0';
len = strlen (p + 1);
percent = (char *) alloca (len);
bcopy (p + 1, percent, len - 1);
percent[len - 1] = '\0';
}
else
#endif
{
at = file->name;
percent = "";
}
if (file->stem == 0)
{
register struct dep *d;
char *name;
unsigned int len;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
name = strchr (file->name, '(') + 1;
len = strlen (name) - 1;
}
else
#endif
{
name = file->name;
len = strlen (name);
}
for (d = enter_file (".SUFFIXES")->deps; d != 0; d = d->next)
{
unsigned int slen = strlen (dep_name (d));
if (len > slen && strneq (dep_name (d), name + (len - slen), slen))
{
file->stem = savestring (name, len - slen);
break;
}
}
if (d == 0)
file->stem = "";
}
star = file->stem;
less = file->deps != 0 ? dep_name (file->deps) : "";
if (file->cmds == default_file->cmds)
less = at;
#define DEFINE_VARIABLE(name, len, value) \
(void) define_variable_for_file (name,len,value,o_automatic,0,file)
DEFINE_VARIABLE ("<", 1, less);
DEFINE_VARIABLE ("*", 1, star);
DEFINE_VARIABLE ("@", 1, at);
DEFINE_VARIABLE ("%", 1, percent);
{
register unsigned int qmark_len, plus_len;
char *caret_value, *plus_value;
register char *cp;
char *qmark_value;
register char *qp;
register struct dep *d;
unsigned int len;
plus_len = 0;
for (d = file->deps; d != 0; d = d->next)
plus_len += strlen (dep_name (d)) + 1;
len = plus_len == 0 ? 1 : plus_len;
cp = plus_value = (char *) alloca (len);
qmark_len = plus_len;
for (d = file->deps; d != 0; d = d->next)
{
char *c = dep_name (d);
#ifndef NO_ARCHIVES
if (ar_name (c))
{
c = strchr (c, '(') + 1;
len = strlen (c) - 1;
}
else
#endif
len = strlen (c);
bcopy (c, cp, len);
cp += len;
#if VMS
*cp++ = ',';
#else
*cp++ = ' ';
#endif
if (! d->changed)
qmark_len -= len + 1;
}
cp[cp > plus_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("+", 1, plus_value);
uniquize_deps (file->deps);
cp = caret_value = plus_value;
len = qmark_len == 0 ? 1 : qmark_len;
qp = qmark_value = (char *) alloca (len);
for (d = file->deps; d != 0; d = d->next)
{
char *c = dep_name (d);
#ifndef NO_ARCHIVES
if (ar_name (c))
{
c = strchr (c, '(') + 1;
len = strlen (c) - 1;
}
else
#endif
len = strlen (c);
bcopy (c, cp, len);
cp += len;
#if VMS
*cp++ = ',';
#else
*cp++ = ' ';
#endif
if (d->changed)
{
bcopy (c, qp, len);
qp += len;
#if VMS
*qp++ = ',';
#else
*qp++ = ' ';
#endif
}
}
cp[cp > caret_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("^", 1, caret_value);
qp[qp > qmark_value ? -1 : 0] = '\0';
DEFINE_VARIABLE ("?", 1, qmark_value);
}
#undef DEFINE_VARIABLE
}
void
chop_commands (cmds)
register struct commands *cmds;
{
register char *p;
unsigned int nlines, idx;
char **lines;
if (!cmds || cmds->command_lines != 0)
return;
nlines = 5;
lines = (char **) xmalloc (5 * sizeof (char *));
idx = 0;
p = cmds->commands;
while (*p != '\0')
{
char *end = p;
find_end:;
end = strchr (end, '\n');
if (end == 0)
end = p + strlen (p);
else if (end > p && end[-1] == '\\')
{
int backslash = 1;
register char *b;
for (b = end - 2; b >= p && *b == '\\'; --b)
backslash = !backslash;
if (backslash)
{
++end;
goto find_end;
}
}
if (idx == nlines)
{
nlines += 2;
lines = (char **) xrealloc ((char *) lines,
nlines * sizeof (char *));
}
lines[idx++] = savestring (p, end - p);
p = end;
if (*p != '\0')
++p;
}
if (idx != nlines)
{
nlines = idx;
lines = (char **) xrealloc ((char *) lines,
nlines * sizeof (char *));
}
cmds->ncommand_lines = nlines;
cmds->command_lines = lines;
cmds->any_recurse = 0;
cmds->lines_flags = (char *) xmalloc (nlines);
for (idx = 0; idx < nlines; ++idx)
{
int flags = 0;
for (p = lines[idx];
isblank (*p) || *p == '-' || *p == '@' || *p == '+';
++p)
switch (*p)
{
case '+':
flags |= COMMANDS_RECURSE;
break;
case '@':
flags |= COMMANDS_SILENT;
break;
case '-':
flags |= COMMANDS_NOERROR;
break;
}
if (!(flags & COMMANDS_RECURSE))
{
unsigned int len = strlen (p);
if (sindex (p, len, "$(MAKE)", 7) != 0
|| sindex (p, len, "${MAKE}", 7) != 0)
flags |= COMMANDS_RECURSE;
}
cmds->lines_flags[idx] = flags;
cmds->any_recurse |= flags & COMMANDS_RECURSE;
}
}
void
execute_file_commands (file)
struct file *file;
{
register char *p;
for (p = file->cmds->commands; *p != '\0'; ++p)
if (!isspace ((unsigned char)*p) && *p != '-' && *p != '@')
break;
if (*p == '\0')
{
set_command_state (file, cs_running);
file->update_status = 0;
notice_finished_file (file);
return;
}
initialize_file_variables (file, 0);
set_file_variables (file);
new_job (file);
}
int handling_fatal_signal = 0;
RETSIGTYPE
fatal_error_signal (sig)
int sig;
{
#ifdef __MSDOS__
extern int dos_status, dos_command_running;
if (dos_command_running)
{
dos_status |= (sig << 8);
return;
}
remove_intermediates (1);
exit (EXIT_FAILURE);
#else
#ifdef _AMIGA
remove_intermediates (1);
if (sig == SIGINT)
fputs (_("*** Break.\n"), stderr);
exit (10);
#else
handling_fatal_signal = 1;
signal (sig, SIG_DFL);
if (sig == SIGTERM)
{
register struct child *c;
for (c = children; c != 0; c = c->next)
if (!c->remote)
(void) kill (c->pid, SIGTERM);
}
if (sig == SIGTERM || sig == SIGINT
#ifdef SIGHUP
|| sig == SIGHUP
#endif
#ifdef SIGQUIT
|| sig == SIGQUIT
#endif
)
{
register struct child *c;
for (c = children; c != 0; c = c->next)
if (c->remote)
(void) remote_kill (c->pid, sig);
for (c = children; c != 0; c = c->next)
delete_child_targets (c);
while (job_slots_used > 0)
reap_children (1, 0);
}
else
while (job_slots_used > 0)
reap_children (1, 1);
remove_intermediates (1);
#ifdef SIGQUIT
if (sig == SIGQUIT)
exit (EXIT_FAILURE);
#endif
if (kill (getpid (), sig) < 0)
pfatal_with_name ("kill");
#endif
#endif
}
static void
delete_target (file, on_behalf_of)
struct file *file;
char *on_behalf_of;
{
struct stat st;
if (file->precious || file->phony)
return;
#ifndef NO_ARCHIVES
if (ar_name (file->name))
{
if (ar_member_date (file->name) != FILE_TIMESTAMP_S (file->last_mtime))
{
if (on_behalf_of)
error (NILF, _("*** [%s] Archive member `%s' may be bogus; not deleted"),
on_behalf_of, file->name);
else
error (NILF, _("*** Archive member `%s' may be bogus; not deleted"),
file->name);
}
return;
}
#endif
if (stat (file->name, &st) == 0
&& S_ISREG (st.st_mode)
&& FILE_TIMESTAMP_STAT_MODTIME (st) != file->last_mtime)
{
if (on_behalf_of)
error (NILF, _("*** [%s] Deleting file `%s'"), on_behalf_of, file->name);
else
error (NILF, _("*** Deleting file `%s'"), file->name);
if (unlink (file->name) < 0
&& errno != ENOENT)
perror_with_name ("unlink: ", file->name);
}
}
void
delete_child_targets (child)
struct child *child;
{
struct dep *d;
if (child->deleted)
return;
delete_target (child->file, (char *) 0);
for (d = child->file->also_make; d != 0; d = d->next)
delete_target (d->file, child->file->name);
child->deleted = 1;
}
void
print_commands (cmds)
register struct commands *cmds;
{
register char *s;
fputs (_("# commands to execute"), stdout);
if (cmds->fileinfo.filenm == 0)
puts (_(" (built-in):"));
else
printf (_(" (from `%s', line %lu):\n"),
cmds->fileinfo.filenm, cmds->fileinfo.lineno);
s = cmds->commands;
while (*s != '\0')
{
char *end;
while (isspace ((unsigned char)*s))
++s;
end = strchr (s, '\n');
if (end == 0)
end = s + strlen (s);
printf ("\t%.*s\n", (int) (end - s), s);
s = end;
}
}