#include <mk/defs.h>
#include <mksh/misc.h>
#include <setjmp.h>
#include <unistd.h>
#include <errno.h>
#include <locale.h>
#define LONGJUMP_VALUE 17
#define XFWRITE(string, length, fd) {if (fwrite(string, 1, length, fd) == 0) \
longjmp(long_jump, LONGJUMP_VALUE);}
#define XPUTC(ch, fd) { \
if (putc((int) ch, fd) == EOF) \
longjmp(long_jump, LONGJUMP_VALUE); \
}
#define XFPUTS(string, fd) fputs(string, fd)
static char * escape_target_name(Name np)
{
if(np->dollar) {
int len = strlen(np->string_mb);
char * buff = (char*)malloc(2 * len);
int pos = 0;
wchar_t wc;
int pp = 0;
while(pos < len) {
int n = mbtowc(&wc, np->string_mb + pos, MB_CUR_MAX);
if(n < 0) {
(void)free(buff);
return strdup(np->string_mb);
}
if(wc == dollar_char) {
buff[pp] = '\\'; pp++;
buff[pp] = '$'; pp++;
} else {
for(int j=0;j<n;j++) {
buff[pp] = np->string_mb[pos+j]; pp++;
}
}
pos += n;
}
buff[pp] = '\0';
return buff;
} else {
return strdup(np->string_mb);
}
}
static void print_auto_depes(Dependency dependency, FILE *fd, Boolean built_this_run, int *line_length, char *target_name, jmp_buf long_jump);
void
write_state_file(int, Boolean exiting)
{
FILE *fd;
int lock_err;
char buffer[MAXPATHLEN];
char make_state_tempfile[MAXPATHLEN];
jmp_buf long_jump;
int attempts = 0;
Name_set::iterator np, e;
Property lines;
int m;
Dependency dependency;
Boolean name_printed;
Boolean built_this_run = false;
char *target_name;
int line_length;
Cmd_line cp;
if (!rewrite_statefile ||
!command_changed ||
!keep_state ||
do_not_exec_rule ||
(report_dependencies_level > 0)) {
return;
}
make_state_lockfile = getmem(strlen(make_state->string_mb) + strlen(".lock") + 1);
(void) sprintf(make_state_lockfile,
"%s.lock",
make_state->string_mb);
if (lock_err = file_lock(make_state->string_mb,
make_state_lockfile,
(int *) &make_state_locked, 0)) {
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
if (exiting) {
(void) sprintf(buffer, "%s/.make.state.%d.XXXXXX", tmpdir, getpid());
report_pwd = true;
warning(gettext("Writing to %s"), buffer);
int fdes = mkstemp(buffer);
if ((fdes < 0) || (fd = fdopen(fdes, "w")) == NULL) {
fprintf(stderr,
gettext("Could not open statefile `%s': %s"),
buffer,
errmsg(errno));
return;
}
} else {
report_pwd = true;
fatal(gettext("Can't lock .make.state"));
}
}
(void) sprintf(make_state_tempfile,
"%s.tmp",
make_state->string_mb);
(void) unlink(make_state_tempfile);
if ((fd = fopen(make_state_tempfile, "w")) == NULL) {
lock_err = errno;
(void) unlink(make_state_lockfile);
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
make_state_locked = false;
fatal(gettext("Could not open temporary statefile `%s': %s"),
make_state_tempfile,
errmsg(lock_err));
}
if (setjmp(long_jump)) {
(void) fclose(fd);
if (attempts++ > 5) {
if ((make_state_lockfile != NULL) &&
make_state_locked) {
(void) unlink(make_state_lockfile);
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
make_state_locked = false;
}
fatal(gettext("Giving up on writing statefile"));
}
sleep(10);
(void) sprintf(buffer, "%s/.make.state.%d.XXXXXX", tmpdir, getpid());
int fdes = mkstemp(buffer);
if ((fdes < 0) || (fd = fdopen(fdes, "w")) == NULL) {
fatal(gettext("Could not open statefile `%s': %s"),
buffer,
errmsg(errno));
}
warning(gettext("Initial write of statefile failed. Trying again on %s"),
buffer);
}
XFWRITE(make_version->string_mb,
strlen(make_version->string_mb),
fd);
XPUTC(colon_char, fd);
XPUTC(tab_char, fd);
XFWRITE(current_make_version->string_mb,
strlen(current_make_version->string_mb),
fd);
XPUTC(newline_char, fd);
for (np = hashtab.begin(), e = hashtab.end(); np != e; np++) {
if ((lines = get_prop(np->prop, line_prop)) == NULL) {
continue;
}
if (np->special_reader != no_special) {
continue;
}
for (m = 0, dependency = lines->body.line.dependencies;
dependency != NULL;
dependency = dependency->next) {
if (m = !dependency->stale
&& (dependency->name != force)
#ifndef PRINT_EXPLICIT_DEPEN
&& dependency->automatic
#endif
) {
break;
}
}
if (m || (lines->body.line.command_used != NULL)) {
name_printed = false;
built_this_run = false;
if (np->has_built) {
built_this_run = true;
XFWRITE(built_last_make_run->string_mb,
strlen(built_last_make_run->string_mb),
fd);
XPUTC(colon_char, fd);
XPUTC(newline_char, fd);
}
target_name = escape_target_name(np);
if (np->has_long_member_name) {
target_name =
get_prop(np->prop, long_member_name_prop)
->body.long_member_name.member_name->
string_mb;
}
if (m) {
XFPUTS(target_name, fd);
XPUTC(colon_char, fd);
XFPUTS("\t", fd);
name_printed = true;
line_length = 0;
for (dependency =
lines->body.line.dependencies;
dependency != NULL;
dependency = dependency->next) {
print_auto_depes(dependency,
fd,
built_this_run,
&line_length,
target_name,
long_jump);
}
XFPUTS("\n", fd);
}
if (lines->body.line.command_used != NULL) {
if (!name_printed) {
XFPUTS(target_name, fd);
XPUTC(colon_char, fd);
XPUTC(newline_char, fd);
}
for (cp = lines->body.line.command_used;
cp != NULL;
cp = cp->next) {
char *csp;
int n;
XPUTC(tab_char, fd);
if (cp->command_line != NULL) {
for (csp = cp->
command_line->
string_mb,
n = strlen(cp->
command_line->
string_mb);
n > 0;
n--, csp++) {
XPUTC(*csp, fd);
if (*csp ==
(int) newline_char) {
XPUTC(tab_char,
fd);
}
}
}
XPUTC(newline_char, fd);
}
}
(void)free(target_name);
}
}
if (fclose(fd) == EOF) {
longjmp(long_jump, LONGJUMP_VALUE);
}
if (attempts == 0) {
if (unlink(make_state->string_mb) != 0 && errno != ENOENT) {
lock_err = errno;
(void) unlink(make_state_tempfile);
(void) unlink(make_state_lockfile);
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
make_state_locked = false;
fatal(gettext("Could not delete old statefile `%s': %s"),
make_state->string_mb,
errmsg(lock_err));
}
if (rename(make_state_tempfile, make_state->string_mb) != 0) {
lock_err = errno;
(void) unlink(make_state_tempfile);
(void) unlink(make_state_lockfile);
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
make_state_locked = false;
fatal(gettext("Could not rename `%s' to `%s': %s"),
make_state_tempfile,
make_state->string_mb,
errmsg(lock_err));
}
}
if ((make_state_lockfile != NULL) && make_state_locked) {
(void) unlink(make_state_lockfile);
retmem_mb(make_state_lockfile);
make_state_lockfile = NULL;
make_state_locked = false;
}
}
static void
print_auto_depes(Dependency dependency, FILE *fd, Boolean built_this_run, int *line_length, char *target_name, jmp_buf long_jump)
{
if (!dependency->automatic ||
dependency->stale ||
(dependency->name == force)) {
return;
}
XFWRITE(dependency->name->string_mb,
strlen(dependency->name->string_mb),
fd);
if ((*line_length += (int) strlen(dependency->name->string_mb) + 1) > 450) {
*line_length = 0;
XPUTC(newline_char, fd);
if (built_this_run) {
XFPUTS(built_last_make_run->string_mb, fd);
XPUTC(colon_char, fd);
XPUTC(newline_char, fd);
}
XFPUTS(target_name, fd);
XPUTC(colon_char, fd);
XPUTC(tab_char, fd);
} else {
XFPUTS(" ", fd);
}
return;
}