/*
* Maketool - GTK-based front end for gmake
* Copyright (c) 1999-2003 Greg Banks
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "maketool.h"
#include "util.h"
#if HAVE_REGCOMP
#include <regex.h> /* POSIX regular expression fns */
#else
#error Why are you even bothering to compile with POSIX regular expressions?
#endif
CVSID("$Id: pmake.c,v 1.5 2003/09/01 13:23:34 gnb Exp $");
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
pmake_makefile_flags(estring *e)
{
if (prefs.makefile != 0)
{
estring_append_string(e, "-f ");
estring_append_string(e, prefs.makefile);
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
pmake_parallel_flags(estring *e)
{
if (prefs.run_how == RUN_PARALLEL_PROC && prefs.run_processes > 0)
estring_append_printf(e, "-J%d", prefs.run_processes);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
pmake_keep_going_flags(estring *e)
{
if (prefs.keep_going)
estring_append_string(e, "-k");
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
pmake_dryrun_flags(estring *e)
{
if (prefs.dryrun)
estring_append_string(e, "-n");
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* pmake is impossibly modest...there is no way to emit even
* a version string, let alone a copyright/authorship message.
* So we do the best we can.
*/
static const char pmake_version_hack[] =
"-n _no_such_target_ > /dev/null 2>&1 ;"
"echo \"BSD Pmake\" ;"
"echo \"by the NetBSD Project\" ;"
"echo \"http://www.netbsd.org/\" ;"
;
static void
pmake_version_flags(estring *e)
{
estring_append_string(e, pmake_version_hack);
}
#if HAVE_IRIX_SMAKE
/*
* Same hack as pmake...different string.
* TODO: showprods to get version
*/
static const char smake_version_hack[] =
"-n _no_such_target_ > /dev/null 2>&1 ;"
"echo \"IRIX smake\" ;"
"echo \"(c) Silicon Graphics Inc\" ;"
"echo \"http://www.sgi.com/\" ;"
"echo \"derived from BSD 4.4. pmake\" ;"
"echo \"by the NetBSD Project\" ;"
"echo \"http://www.netbsd.org/\" ;"
;
static void
smake_version_flags(estring *e)
{
estring_append_string(e, smake_version_hack);
}
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
pmake_list_targets_flags(estring *e)
{
estring_append_string(e, "-q -d g1");
}
#if HAVE_IRIX_SMAKE
static void
irix_smake_list_targets_flags(estring *e)
{
estring_append_string(e, "-q -p 1");
}
#endif
typedef struct
{
Task task;
GPtrArray *targets;
#define NUM_ERROR_LINES 16
int nlines;
estring error_buf; /* first NUM_ERROR_LINES of output */
gboolean is_target;
gboolean is_file;
regex_t target_re;
} PmakeListTargetsTask;
static void
pmake_list_targets_reap(Task *task)
{
PmakeListTargetsTask *ltt = (PmakeListTargetsTask *)task;
/*
* On my Linux box, pmake gets confused, emits spurious
* errors and exits with a failure code despite having
* correctly generated the target list. So don't report
* an error unless no targets were parsed.
*/
if (!task_is_successful(task) && ltt->targets->len == 0)
{
/* Report error to user */
list_targets_error(ltt->error_buf.data);
}
else
{
/* Set all the targets */
set_targets(ltt->targets->len, (char **)ltt->targets->pdata);
/* set_targets() has taken over the array and strings, so forget them */
g_ptr_array_free(ltt->targets, /*free_seg*/FALSE);
ltt->targets = 0;
}
}
/*
* Task has TASK_LINEMODE flag, so the input function gets
* called once per line. Unlike several UNIX awk implementations
* we have no line length limit.
*/
#define is_const_prefix(s, p) (!strncmp(buf, p, sizeof(p)-1))
static void
pmake_list_targets_input(Task *task, int len, const char *buf)
{
PmakeListTargetsTask *ltt = (PmakeListTargetsTask *)task;
regmatch_t match[2];
/*
* Save the first few lines of the output to a buffer
* in case they represent an error message.
*/
if (++ltt->nlines <= NUM_ERROR_LINES)
{
estring_append_chars(<t->error_buf, buf, len);
estring_append_char(<t->error_buf, '\n');
}
/*
* Drive a simple state machine which figures out which
* part of the "gmake -p" output is target listings.
*/
if (is_const_prefix(buf, "#*** Input graph:"))
{
ltt->is_file = TRUE;
return;
}
if (is_const_prefix(buf, "#*** Global Variables:"))
{
ltt->is_file = FALSE;
return;
}
/* Match line against the target regular expression. */
if (regexec(<t->target_re, buf, /*nmatches*/2, match, 0) == 0)
{
if (ltt->is_file && ltt->is_target)
{
/* extract target name from line...steal the buffer temporarily */
char *targ, oldc;
int len;
targ = (char *)buf+match[1].rm_so;
len = match[1].rm_eo - match[1].rm_so;
oldc = targ[len];
targ[len] = '\0';
if (filter_target(targ))
g_ptr_array_add(ltt->targets, g_strdup(targ));
targ[len] = oldc;
}
ltt->is_target = TRUE;
}
}
#undef is_const_prefix
static void
pmake_list_targets_destroy(Task *task)
{
PmakeListTargetsTask *ltt = (PmakeListTargetsTask *)task;
if (ltt->targets != 0)
{
unsigned int i;
for (i = 0 ; i < ltt->targets->len ; i++)
g_free(ltt->targets->pdata[i]);
g_ptr_array_free(ltt->targets, /*free_seg*/TRUE);
}
regfree(<t->target_re);
estring_free(<t->error_buf);
}
static TaskOps pmake_list_targets_ops =
{
0, /* start */
pmake_list_targets_input, /* input */
pmake_list_targets_reap, /* reap */
pmake_list_targets_destroy /* destroy */
};
static Task *
pmake_list_targets_task(char *cmd)
{
PmakeListTargetsTask *ltt = g_new(PmakeListTargetsTask, 1);
int err;
ltt->is_target = TRUE;
ltt->is_file = FALSE;
ltt->targets = g_ptr_array_new();
err = regcomp(<t->target_re, "^([^#:! \t]+)[ \t]*[:!]", REG_EXTENDED);
assert(err == 0);
ltt->nlines = 0;
estring_init(<t->error_buf);
return task_create(
(Task *)ltt,
cmd,
prefs.var_environment,
&pmake_list_targets_ops,
TASK_LINEMODE);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static const char * const pmake_makefiles[] =
{
"Makefile",
"makefile",
0
};
#include "BSD-daemon.xpm"
MakeProgram makeprog_pmake =
{
"pmake",
"pmake",
N_("BSD 4.4 pmake"),
BSD_daemon_xpm,
pmake_makefiles,
pmake_makefile_flags,
pmake_parallel_flags,
pmake_keep_going_flags,
pmake_dryrun_flags,
pmake_version_flags,
pmake_list_targets_flags,
pmake_list_targets_task
};
#if HAVE_IRIX_SMAKE
MakeProgram makeprog_irix_smake =
{
"irix-smake",
"smake",
N_("IRIX smake"),
/*logo_xpm*/0,
pmake_makefiles,
pmake_makefile_flags,
pmake_parallel_flags,
pmake_keep_going_flags,
pmake_dryrun_flags,
smake_version_flags,
irix_smake_list_targets_flags,
pmake_list_targets_task
};
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*END*/
syntax highlighted by Code2HTML, v. 0.9.1