/*
* 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
*/
#define DEFINE_GLOBALS
#include <stdarg.h>
#include "maketool.h"
#include "ui.h"
#include "log.h"
#include "util.h"
#include <ctype.h>
#include "maketool_task.h"
#if HAVE_SIGNAL_H
#include <signal.h>
#endif
#include <errno.h>
#include "mqueue.h"
#include "progress.h"
CVSID("$Id: main.c,v 1.110 2003/10/30 14:19:44 gnb Exp $");
/*
* How amazingly confusing that make and X11 selections
* both use the terminology `target' for completely
* different concepts. Sigh.
*/
typedef enum
{
SEL_TARGET_STRING,
SEL_TARGET_TEXT,
SEL_TARGET_COMPOUND_TEXT
} SelectionTargets;
char **cmd_targets; /* targets on commandline */
int cmd_num_targets;
#define TARGET_HISTORY_MAX 16
static GList *target_history = 0; /* last target built is head of list */
GList *available_targets = 0; /* all possible targets, for menu */
GtkWidget *build_menu;
GtkWidget *toolbar_hb, *messagebox;
GtkWidget *messageent;
GtkWidget *progressbar;
GtkWidget *warning_count;
GtkWidget *error_count;
gboolean interrupted = FALSE;
gboolean first_error = TRUE;
#define ANIM_MAX 15
GdkPixmap *anim_pixmaps[ANIM_MAX+1];
GdkBitmap *anim_masks[ANIM_MAX+1];
GtkWidget *anim;
GtkWidget *toolbar;
GtkWidget *again_menu_item, *again_tool_item;
GtkWidget *target_history_menu;
const char * const again_menu_label[2] = { N_("_Again"), N_("_Again (%s)") };
const char * const again_tool_tooltip[2] = { N_("Build last target again"), N_("Build `%s' again") };
#if HAVE_BSD_JOB_CONTROL
GtkWidget *pause_menu_item, *pause_tool_item;
const char * const pause_menu_label[2] = {
N_("_Pause"), N_("_Resume") };
const char * const pause_tool_tooltip[2] = {
N_("Pause current build"),
N_("Resume current build")
};
#endif
gint about_make_position;
GtkWidget *about_make_menu_item;
GtkWidget *about_make_menu;
GdkAtom clipboard_atom = GDK_NONE;
char *clipboard_text = 0;
GtkWidget *clipboard_widget;
GtkWidget *dir_previous_menu;
gboolean has_configure_in;
gboolean has_configure;
const MakeSystem *makesys;
const MakeProgram *makeprog;
#define PASTE3(x,y,z) x##y##z
static void build_cb(GtkWidget *w, gpointer data);
static void set_main_title(void);
static void construct_build_menu_basic_items(void);
static void dir_previous_cb(GtkWidget *w, gpointer data);
static const char *last_target(void);
static void add_target_history(const char *);
static void clear_target_history(void);
static void build_start(const char *target);
/*
* Number of non-standard targets to be present before
* the build menu should be split up into multiple submenus.
*/
#define BUILD_MENU_LENGTH_THRESHOLD 20
/*
* How many characters across the names of targets in the
* build menu may be before they are abbreviated to fit.
*/
#define BUILD_MENU_WIDTH_THRESHOLD 28
#define HOMEPAGE "http://www.alphalink.com.au/~gnb/maketool/"
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
void
message(const char *fmt, ...)
{
va_list args;
char *msg;
va_start(args, fmt);
msg = g_strdup_vprintf(fmt, args);
va_end(args);
gtk_entry_set_text(GTK_ENTRY(messageent), msg);
g_free(msg);
}
/*
* Force the last changed message to appear
* immediately instead of delaying until the
* next dip into the main loop. Useful when
* a long-blocking action is about to be done.
*/
void
message_flush(void)
{
while (g_main_pending())
g_main_iteration(/*may_block*/FALSE);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
main_progress_start(Progress *p)
{
#if DEBUG
fprintf(stderr, "main_progress_start()\n");
#endif
gtk_progress_bar_update(GTK_PROGRESS_BAR(progressbar), 0.0);
gtk_widget_show(progressbar);
message_flush();
}
static void
main_progress_end(Progress *p)
{
#if DEBUG
fprintf(stderr, "main_progress_end()\n");
#endif
gtk_widget_hide(progressbar);
}
static void
main_progress_changed(Progress *p, int pc)
{
#if DEBUG
fprintf(stderr, "main_progress_changed(%d)\n", pc);
#endif
gtk_progress_bar_update(GTK_PROGRESS_BAR(progressbar), (gfloat)pc/100.0);
message_flush();
}
static Progress *
main_progress(void)
{
static const ProgressOps ops =
{
main_progress_start,
main_progress_changed,
main_progress_end
};
static Progress prog = { &ops };
return &prog;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
void
grey_menu_items(void)
{
gboolean running = task_is_running();
gboolean empty = log_is_empty();
LogRec *sel = log_selected();
gboolean selected = (sel != 0);
gboolean editable = (sel != 0 && sel->res.file != 0);
gboolean again = (last_target() != 0 && !running);
gboolean all = (!running && g_list_find_str(available_targets, "all") != 0);
gboolean clean = (!running && g_list_find_str(available_targets, "clean") != 0);
ui_group_set_sensitive(GR_NOTRUNNING, !running);
ui_group_set_sensitive(GR_CLEAR_LOG, !running && !empty);
ui_group_set_sensitive(GR_RUNNING, running);
ui_group_set_sensitive(GR_NOTEMPTY, !empty);
ui_group_set_sensitive(GR_SELECTED, selected);
ui_group_set_sensitive(GR_EDITABLE, editable);
ui_group_set_sensitive(GR_AGAIN, again);
ui_group_set_sensitive(GR_ALL, all);
ui_group_set_sensitive(GR_CLEAN, clean);
ui_group_set_sensitive(GR_FIND_AGAIN, !empty && find_can_find_again());
ui_group_set_sensitive(GR_NEVER, FALSE);
}
char *
expand_prog(
const char *prog,
const char *file,
int line,
const char *target)
{
char *out;
const char *expands[256];
estring fflag;
estring jflag;
estring kflag;
estring nflag;
estring pflag;
estring vflag;
char linebuf[32];
memset(expands, 0, sizeof(expands));
expands['f'] = file;
if (line > 0)
{
sprintf(linebuf, "%d", line);
expands['l'] = linebuf;
}
estring_init(&fflag);
(*makeprog->makefile_flags)(&fflag);
expands['m'] = fflag.data;
estring_init(&jflag);
(*makeprog->parallel_flags)(&jflag);
expands['p'] = jflag.data;
estring_init(&pflag);
(*makeprog->list_targets_flags)(&pflag);
expands['q'] = pflag.data;
estring_init(&kflag);
(*makeprog->keep_going_flags)(&kflag);
expands['k'] = kflag.data;
expands['v'] = prefs.var_make_flags;
estring_init(&vflag);
(*makeprog->version_flags)(&vflag);
expands['V'] = vflag.data;
expands['t'] = target;
estring_init(&nflag);
(*makeprog->dryrun_flags)(&nflag);
expands['n'] = nflag.data;
expands['D'] = PKGDATADIR;
expands['M'] = makeprog->executable;
expands['S'] = makesys->name;
out = expand_string(prog, expands);
estring_free(&fflag);
estring_free(&jflag);
estring_free(&kflag);
estring_free(&nflag);
estring_free(&vflag);
estring_free(&pflag);
return out;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static int
abbreviate_aux(estring *e, const char *str, int limit)
{
int len = strlen(str);
static const char ellipsis[] = "...";
if (len > limit)
{
len = limit;
if (len > (int)sizeof(ellipsis)-1)
{
estring_append_chars(e, str, len-(sizeof(ellipsis)-1));
estring_append_string(e, ellipsis);
return len;
}
}
estring_append_chars(e, str, len);
return len;
}
static char *
abbreviate_target(const char *t, int maxlen)
{
estring e;
estring_init(&e);
abbreviate_aux(&e, t, maxlen);
return e.data;
}
static char *
abbreviate_targets(const char *t1, const char *t2, int maxlen)
{
int l1 = strlen(t1);
int l2 = strlen(t2);
static const char dash[] = " - ";
estring e;
estring_init(&e);
if (l1 + (int)sizeof(dash) + l2 > maxlen)
l1 = (l1 < 4 ? l1 : (maxlen - (int)sizeof(dash)) * l1 / (l1 + l2));
l1 = abbreviate_aux(&e, t1, l1);
estring_append_string(&e, dash);
abbreviate_aux(&e, t2, (maxlen - (int)sizeof(dash)) - l1);
return e.data;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
target_history_cb(GtkWidget *w, gpointer data)
{
const char *target = (const char *)data;
if (!task_is_running())
build_start(target);
}
static void
update_target_history_menu(void)
{
GtkLabel *label;
char *menulabel;
char *tooltip;
char *targ;
int idx;
GList *iter;
/* Note: this assumes that the accelerator remains constant, i.e. Ctrl+A,
* even though the position of the underscore in the label
* may change.
*/
/* Update the menu item in the Build menu */
targ = (last_target() == 0 ? 0 :
abbreviate_target(last_target(),
BUILD_MENU_WIDTH_THRESHOLD-5/*heuristic*/));
idx = !!targ;
menulabel = g_strdup_printf(_(again_menu_label[idx]), targ);
if (targ != 0)
g_free(targ);
label = GTK_LABEL(GTK_BIN(again_menu_item)->child);
gtk_label_set_text(label, menulabel);
gtk_label_parse_uline(label, menulabel);
g_free(menulabel);
/* Update the tooltip on the Again tool */
tooltip = g_strdup_printf(_(again_tool_tooltip[idx]), last_target());
gtk_tooltips_set_tip(GTK_TOOLBAR(toolbar)->tooltips, again_tool_item,
tooltip, 0);
g_free(tooltip);
/* Rebuild the menu on the Again tool */
ui_delete_menu_items(target_history_menu);
for (iter = target_history ; iter != 0 ; iter = iter->next)
{
targ = (char *)iter->data;
ui_add_button_2(target_history_menu, targ, /*douline*/FALSE,
/*accel*/0, target_history_cb, targ, GR_AGAIN, /* position*/-1);
}
}
static void
add_target_history(const char *target)
{
GList *iter;
/*
* `target' is assumed to be non-NULL and to point
* to a saved string in the available_targets list.
*/
/* check to see if already in history */
for (iter = target_history ; iter != 0 ; iter = iter->next)
{
if (target == (const char *)iter->data)
{
target_history = g_list_remove_link(target_history, iter);
break;
}
}
/* add new target to head of history */
target_history = g_list_prepend(target_history, (gpointer)target);
/* trim tail to enforce history length */
while (g_list_length(target_history) > TARGET_HISTORY_MAX)
{
GList *last = g_list_last(target_history);
target_history = g_list_remove_link(target_history, last);
}
/* update gui */
update_target_history_menu();
}
static void
clear_target_history(void)
{
/* remove entire history list */
while (target_history != 0)
target_history = g_list_remove_link(target_history, target_history);
/* update gui */
update_target_history_menu();
}
static const char *
last_target(void)
{
return (target_history == 0 ? 0 : (const char *)target_history->data);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static int anim_current = 0;
static gint anim_timer = -1;
static gint
anim_advance(gpointer data)
{
if (anim_current++ == ANIM_MAX)
anim_current = 1;
gtk_pixmap_set(GTK_PIXMAP(anim),
anim_pixmaps[anim_current], anim_masks[anim_current]);
return TRUE; /* keep going */
}
static void
anim_stop(void)
{
if (anim_timer >= 0)
{
gtk_timeout_remove(anim_timer);
anim_timer = -1;
}
gtk_pixmap_set(GTK_PIXMAP(anim),
anim_pixmaps[0], anim_masks[0]);
}
static void
anim_start(void)
{
if (anim_timer < 0)
anim_timer = gtk_timeout_add(200/* millisec */, anim_advance, 0);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* Called when the number of errors or warnings in the log changes.
*/
static void
count_changed(int nerrors, int nwarnings)
{
char buf[32];
if (nerrors > 0)
{
snprintf(buf, sizeof(buf), "%d", nerrors);
gtk_label_set_text(GTK_LABEL(error_count), buf);
gtk_widget_show(error_count->parent);
}
else
{
gtk_widget_hide(error_count->parent);
}
if (nwarnings > 0)
{
snprintf(buf, sizeof(buf), "%d", nwarnings);
gtk_label_set_text(GTK_LABEL(warning_count), buf);
gtk_widget_show(warning_count->parent);
}
else
{
gtk_widget_hide(warning_count->parent);
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* These 2 fns are called when the task queue
* is started or emptied.
*/
static void
work_started(void)
{
anim_start();
grey_menu_items();
}
static void
work_ended(void)
{
anim_stop();
grey_menu_items();
count_changed(0, 0);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
logged_task_start(Task *task)
{
log_start_build(task->command);
}
static void
logged_task_reap(Task *task)
{
log_end_build(task->command);
}
static TaskOps logged_task_ops =
{
logged_task_start, /* start */
handle_line, /* input */
logged_task_reap, /* reap */
0 /* destroy */
};
Task *
logged_task(char *command)
{
int flags = TASK_LINEMODE;
#if HAVE_BSD_JOB_CONTROL
flags |= TASK_GROUPLEADER;
#endif
return task_create(
(Task *)g_new(Task, 1),
command,
prefs.var_environment,
&logged_task_ops,
flags);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
make_makefile(void)
{
#if DEBUG
fprintf(stderr, "make_makefile: makesys=%s\n", makesys->name);
#endif
task_enqueue(
logged_task(
expand_prog(prefs.prog_make_makefile, 0, 0, makesys->makefile)
)
);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static const char *
get_target_accelerator(const char *targ)
{
if (!strcmp(targ, "all"))
return "<Alt>A";
if (!strcmp(targ, "clean"))
return "<Alt>C";
return 0;
}
static void
append_build_menu_items(GList *list)
{
GtkWidget *menu = 0;
char *targ;
int n;
gboolean multiple_mode = (g_list_length(list) > BUILD_MENU_LENGTH_THRESHOLD);
char *label;
for (n = 0 ; list != 0 ; list = list->next)
{
targ = (char *)list->data;
if (multiple_mode)
{
if (n == 0)
{
GList *last;
last = g_list_nth(list, BUILD_MENU_LENGTH_THRESHOLD-1);
if (last == 0)
last = g_list_last(list);
if (last != list)
{
label = abbreviate_targets(targ, (const char *)last->data,
BUILD_MENU_WIDTH_THRESHOLD);
#if DEBUG
fprintf(stderr, "creating Build submenu \"%s\"\n", label);
#endif
menu = ui_add_submenu(build_menu, /*douline*/FALSE, label);
g_free(label);
}
else
menu = build_menu;
}
if (++n == BUILD_MENU_LENGTH_THRESHOLD)
n = 0;
}
else
menu = build_menu;
if (!strcmp(targ, "-"))
ui_add_separator(menu);
else
{
const char *accel = get_target_accelerator(targ);
label = abbreviate_target(targ, BUILD_MENU_WIDTH_THRESHOLD);
ui_add_button_2(menu, label, FALSE, accel, build_cb, targ,
GR_NOTRUNNING, -1);
g_free(label);
}
}
}
gboolean
filter_target(const char *targ)
{
int len;
if (targ[0] == '.')
return FALSE;
if (strstr(targ, "/.") != 0)
return FALSE;
if (targ[0] == '/')
return FALSE;
if (!strncmp(targ, "../", 3))
return FALSE;
if (targ[0] == '_')
return FALSE;
len = strlen(targ);
if (!strcmp(targ+len-2, ".o"))
return FALSE;
if (len >= 7 && !strcmp(targ+len-7, "DESCEND"))
return FALSE;
if (len >= 8 && !strcmp(targ+len-8, "SETUPDIR"))
return FALSE;
return TRUE;
}
static int
compare_strings(const void *a, const void *b)
{
return strcmp((const char *)a, (const char *)b);
}
/*
* Set the complete collection of all available targets.
* Takes ownership of the targs[] array and the
* strings pointed to by it; these should all be malloc()ed.
*/
void
set_targets(unsigned int ntargs, char **targs)
{
unsigned int i;
char *t;
GList *std = 0;
GHashTable *unique;
/*
* First, remove list of available targets from previous run
*/
while (available_targets != 0)
{
g_free((char *)available_targets->data);
available_targets = g_list_remove_link(available_targets, available_targets);
}
ui_delete_menu_items(build_menu);
construct_build_menu_basic_items();
if (ntargs == 0)
{
GtkWidget *errorw;
errorw = ui_add_button_2(build_menu, _("No targets found"), FALSE, 0, 0,
0, GR_NEVER, -1);
grey_menu_items();
if (targs != 0)
g_free(targs);
return;
}
/*
* Iterate over all the targets. Build two lists, std (all
* the found targets which are also in `standard_targets')
* and available_targets (all others).
*/
unique = g_hash_table_new(g_str_hash, g_str_equal);
for (i = 0 ; i < ntargs ; i++)
{
t = targs[i];
if (g_hash_table_lookup(unique, t) != 0)
{
g_free(t);
continue;
}
g_hash_table_insert(unique, t, t);
if (ms_is_standard_target(makesys, t))
{
#if DEBUG
fprintf(stderr, "set_targets: adding standard target \"%s\"\n", t);
#endif
std = g_list_prepend(std, t);
}
else
{
#if DEBUG
fprintf(stderr, "reap_list adding target \"%s\"\n", t);
#endif
available_targets = g_list_prepend(available_targets, t);
}
}
if (targs != 0)
g_free(targs);
g_hash_table_destroy(unique);
std = g_list_sort(std, compare_strings);
available_targets = g_list_sort(available_targets, compare_strings);
/*
* Build two parts of the menu from the two lists. This
* technique ensures the GNU standard targets like `all'
* and `install' will appear early in the menu and
* will always be visible regardless of its size.
*/
append_build_menu_items(std);
if (std != 0 && available_targets != 0)
ui_add_separator(build_menu);
append_build_menu_items(available_targets);
/*
* Now prepend `std' to `available_targets', which is now a
* list of all the found targets, standard or not.
*/
available_targets = g_list_concat(std, available_targets);
grey_menu_items();
}
/*
* Oh dear, something went wrong. We have no targets.
* TODO: pop up a dialog.
*/
void
list_targets_error(const char *errmsg)
{
set_targets(0, 0);
/*
* Give the user some clue as to what just happened.
*/
message(_("Error listing targets: %s"), errmsg);
#if 1
fprintf(stderr, "Error listing targets:%s\n", errmsg);
#endif
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
list_targets(void)
{
char *command;
Task *task;
if (prefs.enable_make_makefile && ms_makefile_needs_update(makesys))
make_makefile();
clear_target_history();
if (mp_which_makefile(makeprog) == 0)
{
set_targets(0, 0);
return;
}
command = expand_prog(prefs.prog_list_targets, 0, 0, "_no_such_target_");
task = (*makeprog->list_targets_task)(command);
task_enqueue(task);
task_start();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static TaskOps editor_ops =
{
0, /* start */
0, /* input */
0, /* reap */
0 /* destroy */
};
static Task *
editor_task(const char *file, int line)
{
return task_create(
(Task *)g_new(Task, 1),
expand_prog(prefs.prog_edit_source, file, line, 0),
0/*env*/,
&editor_ops,
0);
}
static void
start_edit(LogRec *lr)
{
int i, nfiles;
char **files, **ff;
if (lr->res.file == 0 || lr->res.file[0] == '\0')
return;
files = log_get_filenames(lr);
nfiles = 0;
if (files != 0)
{
for (ff = files ; *ff ; ff++)
nfiles++;
}
if (nfiles > 1)
message(_("%d files match %s"), nfiles, lr->res.file);
else if (nfiles == 1)
message(_("Editing %s (line %d)"), files[0], lr->res.line);
else
message(_("No files match %s"), lr->res.file);
for (i = 0 ; i < nfiles ; i++)
task_spawn(editor_task(files[i], lr->res.line));
if (files)
g_strfreev(files);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static long
handle_message(const char *message)
{
if (!strcmp(message, "configure"))
return show_configure_window(/*from_client*/TRUE);
return 1;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/* Use this as the input function for linemode tasks */
void
handle_line(Task *task, int len, const char *line)
{
LogRec *lr;
#if DEBUG > 38
fprintf(stderr, "handle_line(): \"%s\"\n", line);
#endif
lr = log_add_line(line);
if (lr != 0 && prefs.scroll_on_output)
log_ensure_visible(lr);
if (lr != 0 && prefs.edit_first_error && first_error)
{
if ((lr->res.code == FR_WARNING && prefs.edit_warnings) ||
lr->res.code == FR_ERROR)
{
first_error = FALSE;
log_set_selected(lr);
start_edit(lr);
}
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static TaskOps finish_prog_ops =
{
0, /* start */
0, /* input */
0, /* reap */
0 /* destroy */
};
static Task *
finish_prog_task(const char *target)
{
Task *fpt = g_new(Task, 1);
return task_create(
fpt,
expand_prog(prefs.prog_finish, 0, 0, target),
prefs.var_environment,
&finish_prog_ops,
0);
}
static void
finish_prog_start(const char *target)
{
task_enqueue(finish_prog_task(target));
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
finished_dialog(const char *target)
{
GtkWidget *msg;
estring s;
/* Build the string to display in the box */
estring_init(&s);
estring_append_printf(&s, _("Finished building `%s'\n"), target);
if (log_num_errors() > 0)
estring_append_printf(&s, _("%d errors\n"), log_num_errors());
if (log_num_warnings() > 0)
estring_append_printf(&s, _("%d warnings\n"), log_num_warnings());
msg = ui_message_dialog(toplevel, _("Maketool: Finished"), s.data);
estring_free(&s);
gtk_widget_show(msg);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
typedef struct
{
Task task;
const char *target;
} MakeTask;
static void
make_start(Task *task)
{
MakeTask *mt = (MakeTask *)task;
message(_("Making %s"), mt->target);
switch (prefs.start_action)
{
case START_NOTHING:
break;
case START_CLEAR:
log_clear();
break;
case START_COLLAPSE:
log_collapse_all();
break;
}
add_target_history(mt->target);
interrupted = FALSE;
log_start_build(task->command);
}
static void
make_reap(Task *task)
{
MakeTask *mt = (MakeTask *)task;
char *err_str = 0, *warn_str = 0, *int_str = 0;
if (log_num_errors() > 0)
err_str = g_strdup_printf(_(", %d errors"), log_num_errors());
if (log_num_warnings() > 0)
warn_str = g_strdup_printf(_(", %d warnings"), log_num_warnings());
if (interrupted)
int_str = _(" (interrupted)");
message(_("Finished making %s%s%s%s"),
mt->target,
safe_str(err_str),
safe_str(warn_str),
safe_str(int_str));
if (err_str != 0)
g_free(err_str);
if (warn_str != 0)
g_free(warn_str);
log_end_build(mt->target);
if (!interrupted)
{
switch (prefs.finish_action)
{
case FINISH_BEEP:
gdk_beep();
break;
case FINISH_COMMAND:
finish_prog_start(mt->target);
break;
case FINISH_DIALOG:
finished_dialog(mt->target);
break;
case FINISH_NOTHING:
break;
}
}
}
static TaskOps make_ops =
{
make_start, /* start */
handle_line, /* input */
make_reap, /* reap */
0 /* destroy */
};
static Task *
make_task(const char *target)
{
MakeTask *mt = g_new(MakeTask, 1);
int flags = TASK_LINEMODE;
#if HAVE_BSD_JOB_CONTROL
flags |= TASK_GROUPLEADER;
#endif
mt->target = target;
return task_create(
(Task *)mt,
expand_prog(prefs.prog_make, 0, 0, target),
prefs.var_environment,
&make_ops,
flags);
}
static void
build_start(const char *target)
{
first_error = TRUE;
if (prefs.enable_make_makefile && ms_makefile_needs_update(makesys))
make_makefile();
task_enqueue(make_task(target));
task_start();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
toplevel_resize_cb(GtkWidget *w, GdkEvent *ev, gpointer data)
{
static int curr_width = -1, curr_height = -1;
int width, height;
width = ev->configure.width;
height = ev->configure.height;
/*
* This weeds out the ConfigureNotify events we get
* from the X server when the window is moved.
*/
if (curr_width >= 0 &&
(curr_width != width || curr_height != height))
{
#if DEBUG
fprintf(stderr, "toplevel_resize_cb: Saving new size\n");
#endif
preferences_resize(w->allocation.width, w->allocation.height);
}
curr_width = width;
curr_height = height;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static gboolean
toplevel_property_notify_cb(GtkWidget *w, GdkEvent *event)
{
Message *msg;
long code;
#if DEBUG
fprintf(stderr, "toplevel_property_notify_cb\n");
#endif
if (!mq_message_event(event))
{
/* prevent default signal handler possibly getting confused */
gtk_signal_emit_stop_by_name(GTK_OBJECT(w), "property_notify_event");
return TRUE;
}
while ((msg = mq_receive()) != 0)
{
/* interpret value */
#if DEBUG
fprintf(stderr, "toplevel_property_notify_cb: body=\"%s\"\n",
msg->body.data);
#endif
code = handle_message(msg->body.data);
mq_reply(msg, code);
mq_msg_delete(msg);
}
return TRUE;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
file_exit_cb(GtkWidget *w, gpointer data)
{
gtk_main_quit();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
file_open_file_func(const char *filename)
{
message("Opening log file %s", filename);
message_flush();
log_open(filename, main_progress());
count_changed(0, 0);
}
static void
file_open_cb(GtkWidget *w, gpointer data)
{
static GtkWidget *filesel = 0;
if (filesel == 0)
{
filesel = ui_create_file_sel(
toplevel,
_("Maketool: Open Log File"),
file_open_file_func,
"make.log");
ui_set_help_tag(filesel, "open-log-file-window");
}
gtk_widget_show(filesel);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
file_save_file_func(const char *filename)
{
message("Saving log file %s", filename);
message_flush();
log_save(filename, main_progress());
}
static void
file_save_cb(GtkWidget *w, gpointer data)
{
static GtkWidget *filesel = 0;
if (filesel == 0)
{
filesel = ui_create_file_sel(
toplevel,
_("Maketool: Save Log File"),
file_save_file_func,
"make.log");
ui_set_help_tag(filesel, "save-log-file-window");
}
gtk_widget_show(filesel);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
void
set_makeprog(const char *name)
{
if ((makeprog = mp_find(name)) == 0)
makeprog = makeprograms[0];
if (about_make_menu_item != 0)
{
char *label;
label = g_strdup_printf(_("About %s..."), makeprog->label);
gtk_widget_destroy(about_make_menu_item);
about_make_menu_item = ui_add_button_2(about_make_menu, label,
/*douline*/TRUE, /*accel*/0, help_about_make_cb, 0,
GR_NONE, about_make_position);
g_free(label);
}
}
#if 0
static void
dump_dir_history(const char *str)
{
GList *list;
fprintf(stderr, "%s dir_history = {\n", str);
for (list = prefs.dir_history ; list != 0 ; list = list->next)
fprintf(stderr, " %s\n", (char*)list->data);
fprintf(stderr, "}\n");
}
#endif
static void
construct_dir_previous_menu(void)
{
GList *list;
int i;
char accelbuf[32];
/* first delete previously existing items */
ui_delete_menu_items(dir_previous_menu);
/* now construct a new menu */
for (list = prefs.dir_history, i = 0 ; list != 0 ; list = list->next, i++)
{
char *dir = (char *)list->data;
char *dendir = file_denormalise(dir, DEN_HOME);
if (i < 9)
g_snprintf(accelbuf, sizeof(accelbuf), "<Ctrl>%c", (i+'1'));
ui_add_button_2(dir_previous_menu, dendir, FALSE, (i<9 ? accelbuf : 0),
dir_previous_cb, dir, GR_NOTRUNNING, -1);
g_free(dendir);
}
if (prefs.dir_history == 0)
ui_add_button(dir_previous_menu, _("No previous directories"), 0, 0, 0, GR_NEVER);
}
static gboolean
change_directory(const char *dir)
{
char *olddir;
#if DEBUG > 5
fprintf(stderr, "Changing dir to: %s\n", dir);
#endif
olddir = g_strdup(file_current());
if (file_change_current(dir) < 0)
{
if (messageent != 0)
message("%s: %s", dir, strerror(errno));
g_free(olddir);
return FALSE;
}
/*
* Update directory history
*/
if (g_list_find_str(prefs.dir_history, olddir) != 0)
{
/* already in list */
g_free(olddir);
}
else
{
/* not already in history list, prepend it */
prefs.dir_history = g_list_prepend(prefs.dir_history, olddir);
/* trim list to fit */
while (g_list_length(prefs.dir_history) > MAX_DIR_HISTORY)
{
GList *last = g_list_last(prefs.dir_history);
g_free((char *)last->data);
prefs.dir_history = g_list_remove_link(prefs.dir_history, last);
}
/* save dir history, and everything else */
preferences_save();
/* update Previous Directory menu */
if (dir_previous_menu != 0)
construct_dir_previous_menu();
}
/* Check for presence of autoconf-related files */
set_makeprog(prefs.makeprog);
makesys = ms_probe();
/* update UI for new dir */
if (toplevel != 0)
set_main_title();
if (messageent != 0)
message("Directory %s", file_current());
if (build_menu != 0)
list_targets();
return TRUE;
}
static void
dir_previous_cb(GtkWidget *w, gpointer data)
{
change_directory((char*)data);
}
static void
file_change_dir_func(const char *filename)
{
change_directory(filename);
}
static void
file_change_dir_cb(GtkWidget *w, gpointer data)
{
static GtkWidget *filesel = 0;
char *fakefile;
if (filesel == 0)
{
filesel = ui_create_file_sel(
toplevel,
_("Maketool: Change Directory"),
file_change_dir_func,
".");
ui_set_help_tag(filesel, "change-directory-window");
}
/*
* Tel the filesel window the current directory.
* Filesel window needs the trailing / so it doesn't
* try to interpret the dirname as a filename.
*/
fakefile = g_strdup_printf("%s/", file_current());
gtk_file_selection_set_filename(GTK_FILE_SELECTION(filesel), fakefile);
g_free(fakefile);
gtk_widget_show(filesel);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
file_edit_makefile_cb(GtkWidget *w, gpointer data)
{
const char *makefile = 0;
/*
* Have to do a little dance to figure out what
* filename gmake will use for the makefile.
* First check explicit -f option set in preferences.
*/
if (prefs.makefile != 0)
makefile = prefs.makefile;
else
{
/*
* Now we have to do it the hard way, attempting to
* reproduce the filename search behaviour of the make program.
*/
const char **fn;
makefile = mp_which_makefile(makeprog);
if (makefile == 0 || !strcmp(makefile, "Makefile"))
{
/* attempt to deal with autoconf, automake, and imake */
/* TODO: iterate over makesystems[] */
static const char *meta_makefiles[] = {
"Makefile.am", "Makefile.in", "Imakefile", 0
};
for (fn = meta_makefiles ; *fn != 0 ; fn++)
{
if (file_exists(*fn))
{
makefile = *fn;
break;
}
}
}
}
if (makefile == 0)
{
message(_("No makefile appears to be present in this directory"));
return;
}
message(_("Editing %s"), makefile, 1);
task_spawn(editor_task(makefile, 1));
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_again_cb(GtkWidget *w, gpointer data)
{
if (last_target() != 0 && !task_is_running())
build_start(last_target());
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_stop_cb(GtkWidget *w, gpointer data)
{
if (task_is_running())
{
interrupted = TRUE;
task_kill_current();
}
}
#if HAVE_BSD_JOB_CONTROL
static void
build_pause_cb(GtkWidget *w, gpointer data)
{
gboolean paused;
GtkLabel *label;
if (!task_is_running())
return;
if (task_is_paused())
{
message(_("Resuming..."));
task_resume_current();
paused = FALSE;
}
else
{
task_pause_current();
message(_("Paused"));
paused = TRUE;
}
/* Update the tooltip on the Pause tool */
gtk_tooltips_set_tip(GTK_TOOLBAR(toolbar)->tooltips, pause_tool_item,
_(pause_tool_tooltip[paused]), 0);
/* Update the label on the Pause menu item */
label = GTK_LABEL(GTK_BIN(pause_menu_item)->child);
gtk_label_set_text(label, _(pause_menu_label[paused]));
gtk_label_parse_uline(label, _(pause_menu_label[paused]));
}
#endif /*HAVE_BSD_JOB_CONTROL*/
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_dryrun_cb(GtkWidget *w, gpointer data)
{
preferences_set_dryrun(GTK_CHECK_MENU_ITEM(w)->active);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_makefile_cb(GtkWidget *w, gpointer data)
{
assert(makesys != 0);
assert(makesys->makefile != 0);
first_error = TRUE;
make_makefile();
task_start();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_makesys_command_cb(GtkWidget *w, gpointer data)
{
const MakeCommand *cmd = (const MakeCommand *)data;
assert(cmd != 0);
if (cmd->handler != 0)
(*cmd->handler)(w, (gpointer)cmd->command);
else
{
task_enqueue(logged_task(g_strdup(cmd->command)));
task_start();
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
build_cb(GtkWidget *w, gpointer data)
{
build_start((char *)data);
}
/*
* Same as build_cb() but uses an idle function to
* work around a problem with toolbar highlighting.
*/
static gboolean
tool_build_idle_fn(gpointer data)
{
build_start((char *)data);
return FALSE; /* stop calling me already */
}
static void
delayed_build_cb(GtkWidget *w, gpointer data)
{
gtk_idle_add(tool_build_idle_fn, data);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
view_widget_cb(GtkWidget *w, gpointer data)
{
GtkWidget **wp = (GtkWidget **)data;
if (GTK_CHECK_MENU_ITEM(w)->active)
gtk_widget_show(*wp);
else
gtk_widget_hide(*wp);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
view_flags_cb(GtkWidget *w, gpointer data)
{
gboolean flags = GPOINTER_TO_INT(data);
if (GTK_CHECK_MENU_ITEM(w)->active)
log_set_flags(log_get_flags() | flags);
else
log_set_flags(log_get_flags() & ~flags);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
view_clear_cb(GtkWidget *w, gpointer data)
{
log_clear();
}
static void
view_collapse_all_cb(GtkWidget *w, gpointer data)
{
log_collapse_all();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
edit_error_cb(GtkWidget *w, gpointer data)
{
LogRec *lr = log_selected();
if (lr != 0)
start_edit(lr);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
edit_next_error_cb(GtkWidget *w, gpointer data)
{
gboolean next = GPOINTER_TO_INT(data);
LogRec *lr = log_selected();
do
{
lr = (next ? log_next_error(lr) : log_prev_error(lr));
} while (lr != 0 && !(prefs.edit_warnings || lr->res.code == FR_ERROR));
if (lr != 0)
{
log_set_selected(lr);
start_edit(lr);
}
else
{
message(_("No more errors in log"));
}
}
#define safe_strcmp(a, b) \
strcmp((a) == 0 ? "" : (a), (b) == 0 ? "" : (b))
static void
edit_file_next_error_cb(GtkWidget *w, gpointer data)
{
LogRec *lr = log_selected();
const char *filename = (lr == 0 ? 0 : lr->res.file);
for (;;)
{
lr = log_next_error(lr);
if (lr == 0)
break;
if (!safe_strcmp(filename, lr->res.file))
continue;
if (lr->res.code == FR_WARNING && !prefs.edit_warnings)
continue;
break;
}
if (lr != 0)
{
log_set_selected(lr);
start_edit(lr);
}
else
{
message(_("No more errors in log"));
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
edit_copy_cb(GtkWidget *w, gpointer data)
{
LogRec *lr = log_selected();
assert(lr != 0);
if (clipboard_text != 0)
g_free(clipboard_text);
clipboard_text = g_strdup_printf("%s\n", log_get_text(lr));
#if DEBUG
fprintf(stderr, "Copying `%s'\n", clipboard_text);
#endif
gtk_selection_owner_set(GTK_WIDGET(clipboard_widget), clipboard_atom,
GDK_CURRENT_TIME);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
log_expand_cb(GtkCTree *tree, GtkCTreeNode *tree_node, gpointer data)
{
LogRec *lr = (LogRec *)gtk_ctree_node_get_row_data(tree, tree_node);
lr->expanded = TRUE;
}
static void
log_collapse_cb(GtkCTree *tree, GtkCTreeNode *tree_node, gpointer data)
{
LogRec *lr = (LogRec *)gtk_ctree_node_get_row_data(tree, tree_node);
lr->expanded = FALSE;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* Called when a ctree row is selected or unselected
*/
static void
log_click_cb(GtkCTree *tree, GtkCTreeNode *tree_node, gint column, gpointer data)
{
#if DEBUG
LogRec *lr = (LogRec *)gtk_ctree_node_get_row_data(tree, tree_node);
fprintf(stderr, "log_click_cb: code=%d file=\"%s\" line=%d\n",
lr->res.code, lr->res.file, lr->res.line);
#endif
grey_menu_items();
}
static void
log_doubleclick_cb(GtkWidget *w, GdkEvent *event, gpointer data)
{
if (event->type == GDK_2BUTTON_PRESS)
{
LogRec *lr = log_selected();
if (lr != 0)
{
#if 0
fprintf(stderr, "log_doubleclick_cb: code=%d file=\"%s\" line=%d\n",
lr->res.code, lr->res.file, lr->res.line);
#endif
start_edit(lr);
}
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#if 0
static void
unimplemented(GtkWidget *w, gpointer data)
{
fprintf(stderr, "Unimplemented\n");
}
#endif
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
construct_build_menu_basic_items(void)
{
int i;
const MakeSystem *ms;
gboolean need_sep = FALSE;
again_menu_item = ui_add_button(build_menu, _(again_menu_label[0]), "<Ctrl>A", build_again_cb, 0, GR_AGAIN);
ui_add_button(build_menu, _("_Stop"), 0, build_stop_cb, 0, GR_RUNNING);
#if HAVE_BSD_JOB_CONTROL
pause_menu_item = ui_add_button(build_menu, _(pause_menu_label[0]),
"<Ctrl>Z", build_pause_cb, 0, GR_RUNNING);
#endif
ui_add_toggle(build_menu, _("_Dryrun Only"), "<Ctrl>D", build_dryrun_cb, 0,
0, prefs.dryrun);
if (makesys->makefile != 0)
{
/* add a separator only if we'll be adding any menu items */
ui_add_separator(build_menu);
need_sep = FALSE;
/* TODO: proper groups */
ui_add_button(build_menu, makesys->makefile, 0, build_makefile_cb, 0, GR_NOTRUNNING);
}
for (ms = makesys ; ms != 0 ; ms = ms->parent)
{
if (ms->commands == 0)
continue;
if (need_sep)
{
/* add a separator only if we'll be adding any menu items */
ui_add_separator(build_menu);
need_sep = FALSE;
}
/* TODO: proper groups */
for (i = 0 ; ms->commands[i].label != 0 ; i++)
ui_add_button(build_menu, _(ms->commands[i].label), 0,
build_makesys_command_cb,
(gpointer)&ms->commands[i],
GR_NOTRUNNING);
}
ui_add_separator(build_menu);
}
static void
ui_create_menus(GtkWidget *menubar)
{
GtkWidget *menu;
GtkAccelGroup *ag;
char *label;
ag = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(toplevel), ag);
ui_set_accel_group(ag);
menu = ui_add_menu(menubar, _("_File"));
ui_add_tearoff(menu);
ui_add_button(menu, _("_Open Log..."), "<Ctrl>O", file_open_cb, 0, GR_NONE);
ui_add_button(menu, _("_Save Log..."), "<Ctrl>S", file_save_cb, 0, GR_NOTEMPTY);
ui_add_separator(menu);
ui_add_button(menu, _("_Change Directory..."), 0, file_change_dir_cb, 0, GR_NOTRUNNING);
dir_previous_menu = ui_add_submenu(menu, TRUE, _("_Previous Directories"));
ui_add_tearoff(dir_previous_menu);
construct_dir_previous_menu();
ui_add_separator(menu);
ui_add_button(menu, _("_Edit Makefile..."), 0, file_edit_makefile_cb, 0, GR_NOTRUNNING);
ui_add_separator(menu);
ui_add_button(menu, _("_Print..."), "<Ctrl>P", file_print_cb, 0, GR_NOTEMPTY);
ui_add_separator(menu);
ui_add_button(menu, _("E_xit"), "<Ctrl>X", file_exit_cb, 0, GR_NONE);
menu = ui_add_menu(menubar, _("_Edit"));
ui_add_tearoff(menu);
ui_add_button(menu, _("Edit _Error"), 0, edit_error_cb, 0, GR_EDITABLE);
ui_add_button(menu, _("Edit _Next Error"), "<Ctrl>E", edit_next_error_cb, GINT_TO_POINTER(TRUE), GR_NOTEMPTY);
ui_add_button(menu, _("Edit _Prev Error"), 0, edit_next_error_cb, GINT_TO_POINTER(FALSE), GR_NOTEMPTY);
ui_add_button(menu, _("Edit Next _File Error"), "<Shift><Ctrl>E", edit_file_next_error_cb, GINT_TO_POINTER(TRUE), GR_NOTEMPTY);
ui_add_separator(menu);
ui_add_button(menu, _("_Copy"), "<Ctrl>C", edit_copy_cb, 0, GR_SELECTED);
ui_add_separator(menu);
ui_add_button(menu, _("_Find..."), "<Ctrl>F", edit_find_cb, 0, GR_NOTEMPTY);
ui_add_button(menu, _("Find _Again"), "<Ctrl>G", edit_find_again_cb, 0, GR_FIND_AGAIN);
ui_add_separator(menu);
ui_add_button(menu, _("Pre_ferences..."), 0, edit_preferences_cb, 0, GR_NONE);
build_menu = ui_add_menu(menubar, _("_Build"));
ui_add_tearoff(build_menu);
construct_build_menu_basic_items();
menu = ui_add_menu(menubar, _("_View"));
ui_add_tearoff(menu);
ui_add_button(menu, _("_Clear Log"), 0, view_clear_cb, 0, GR_CLEAR_LOG);
ui_add_button(menu, _("C_ollapse All"), 0, view_collapse_all_cb, 0, GR_NOTEMPTY);
ui_add_separator(menu);
ui_add_toggle(menu, _("_Toolbar"), 0, view_widget_cb, (gpointer)&toolbar_hb, 0, TRUE);
ui_add_toggle(menu, _("_Statusbar"), 0, view_widget_cb, (gpointer)&messagebox, 0, TRUE);
ui_add_separator(menu);
ui_add_toggle(menu, _("_Errors"), 0, view_flags_cb, GINT_TO_POINTER(LF_SHOW_ERRORS),
0, log_get_flags() & LF_SHOW_ERRORS);
ui_add_toggle(menu, _("_Warnings"), 0, view_flags_cb, GINT_TO_POINTER(LF_SHOW_WARNINGS),
0, log_get_flags() & LF_SHOW_WARNINGS);
ui_add_toggle(menu, _("_Information"), 0, view_flags_cb, GINT_TO_POINTER(LF_SHOW_INFO),
0, log_get_flags() & LF_SHOW_INFO);
ui_add_toggle(menu, _("_Summary"), 0, view_flags_cb, GINT_TO_POINTER(LF_SUMMARISE),
0, log_get_flags() & LF_SUMMARISE);
ui_add_toggle(menu, _("_Indent Directories"), 0, view_flags_cb, GINT_TO_POINTER(LF_INDENT_DIRS),
0, log_get_flags() & LF_INDENT_DIRS);
menu = ui_add_menu_right(menubar, _("_Help"));
ui_add_tearoff(menu);
ui_add_button(menu, _("_About Maketool..."), 0, help_about_cb, 0, GR_NONE);
about_make_menu = menu;
about_make_position = ui_container_num_visible_children(GTK_CONTAINER(menu));
label = g_strdup_printf(_("About %s..."), makeprog->label);
about_make_menu_item = ui_add_button(menu, label, 0,
help_about_make_cb, 0, GR_NONE);
g_free(label);
ui_add_separator(menu);
ui_add_button(menu, _("_Help on..."), "F1", help_on_cb, 0, GR_NONE);
ui_add_separator(menu);
ui_add_button(menu, _("Table of _Contents..."), 0, help_goto_tag_cb, "maketool", GR_NONE);
ui_add_button(menu, _("Web Page..."), 0, help_goto_url_cb, HOMEPAGE, GR_NONE);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "all.xpm"
#include "again.xpm"
#include "stop.xpm"
#include "pause.xpm"
#include "clean.xpm"
#include "clear.xpm"
#include "next.xpm"
#include "file_next.xpm"
#include "print.xpm"
static void
ui_create_tools(GtkWidget *toolbar)
{
GtkWidget *w;
char *tooltip;
again_tool_item = ui_tool_create(toolbar, _("Again"), _(again_tool_tooltip[0]),
again_xpm, build_again_cb, 0, GR_AGAIN, "again-tool");
w = ui_tool_drop_menu_create(toolbar, again_tool_item, GR_AGAIN, "again-tool");
target_history_menu = ui_tool_drop_menu_get_menu(w);
ui_tool_create(toolbar, _("Stop"), _("Stop current build"),
stop_xpm, build_stop_cb, 0, GR_RUNNING, "stop-tool");
#if HAVE_BSD_JOB_CONTROL
pause_tool_item = ui_tool_create(toolbar, _("Pause"),
_(pause_tool_tooltip[task_is_paused()]), pause_xpm,
build_pause_cb, 0, GR_RUNNING, "pause-tool");
#endif
ui_tool_add_space(toolbar);
tooltip = g_strdup_printf(_("Build `%s'"), "all");
ui_tool_create(toolbar, "all", tooltip,
all_xpm, delayed_build_cb, "all", GR_ALL, "all-tool");
g_free(tooltip);
tooltip = g_strdup_printf(_("Build `%s'"), "clean");
ui_tool_create(toolbar, "clean", tooltip,
clean_xpm, delayed_build_cb, "clean", GR_CLEAN, "clean-tool");
g_free(tooltip);
ui_tool_add_space(toolbar);
ui_tool_create(toolbar, _("Clear"), _("Clear log"),
clear_xpm, view_clear_cb, 0, GR_CLEAR_LOG, "clear-tool");
ui_tool_create(toolbar, _("Next"), _("Edit next error or warning"),
next_xpm, edit_next_error_cb, GINT_TO_POINTER(TRUE), GR_NOTEMPTY,
"edit-next-tool");
ui_tool_create(toolbar, _("File Next"), _("Edit first error or warning in next file"),
file_next_xpm, edit_file_next_error_cb, GINT_TO_POINTER(TRUE), GR_NOTEMPTY,
"edit-file-next-tool");
ui_tool_add_space(toolbar);
ui_tool_create(toolbar, _("Print"), _("Print log"),
print_xpm, file_print_cb, 0, GR_NOTEMPTY, "print-tool");
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "anim0.xpm"
#include "anim0a.xpm"
#include "anim1.xpm"
#include "anim1a.xpm"
#include "anim1b.xpm"
#include "anim2.xpm"
#include "anim2a.xpm"
#include "anim3.xpm"
#include "anim3a.xpm"
#include "anim3b.xpm"
#include "anim4.xpm"
#include "anim4a.xpm"
#include "anim5.xpm"
#include "anim6.xpm"
#include "anim7.xpm"
#include "anim8.xpm"
#define ANIM_INIT(nm) \
anim_pixmaps[n] = gdk_pixmap_create_from_xpm_d(toplevel->window, \
&anim_masks[n], 0, PASTE3(anim,nm,_xpm)); n++
static void
ui_init_anim_pixmaps(void)
{
int n = 0;
ANIM_INIT(0);
ANIM_INIT(0a);
ANIM_INIT(1);
ANIM_INIT(1a);
ANIM_INIT(1b);
ANIM_INIT(2);
ANIM_INIT(2a);
ANIM_INIT(3);
ANIM_INIT(3a);
ANIM_INIT(3b);
ANIM_INIT(4);
ANIM_INIT(4a);
ANIM_INIT(5);
ANIM_INIT(6);
ANIM_INIT(7);
ANIM_INIT(8);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
clipboard_get(GtkWidget *w, GtkSelectionData *seldata, guint info, guint time)
{
#if DEBUG
fprintf(stderr, "clipboard_get(info=%d)\n", info);
#endif
switch (info)
{
case SEL_TARGET_STRING:
gtk_selection_data_set(seldata,
GDK_SELECTION_TYPE_STRING, 8,
(guchar*)clipboard_text, strlen(clipboard_text));
break;
case SEL_TARGET_TEXT:
case SEL_TARGET_COMPOUND_TEXT:
{
guchar *ctext;
GdkAtom encoding;
gint format;
gint new_length;
gdk_string_to_compound_text((char*)clipboard_text, &encoding, &format, &ctext, &new_length);
gtk_selection_data_set(seldata, encoding, format, ctext, new_length);
gdk_free_compound_text(ctext);
}
break;
default:
fprintf(stderr, "clipboard_get: unknown info %d\n", info);
return;
}
}
static void
clipboard_init(GtkWidget *w)
{
static const GtkTargetEntry targets[] = {
{ "STRING", 0, SEL_TARGET_STRING },
{ "TEXT", 0, SEL_TARGET_TEXT },
{ "COMPOUND_TEXT", 0, SEL_TARGET_COMPOUND_TEXT }
};
clipboard_widget = w;
clipboard_atom = gdk_atom_intern("CLIPBOARD", FALSE);
gtk_selection_add_targets(GTK_WIDGET(w), clipboard_atom,
targets, ARRAYLEN(targets));
gtk_signal_connect(GTK_OBJECT(w), "selection_get",
GTK_SIGNAL_FUNC(clipboard_get), NULL);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*
* Set the title of the main window to
* reflect maketool's current directory.
*/
static void
set_main_title(void)
{
char *denpwd = file_denormalise(file_current(), DEN_HOME);
char *title;
const char *title_prefix = _("Maketool");
title = g_strdup_printf("%s %s: %s", title_prefix, VERSION, denpwd);
gtk_window_set_title(GTK_WINDOW(toplevel), title);
g_free(title);
g_free(denpwd);
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#include "maketool.xpm"
static GtkWidget *
create_log_count(GtkWidget *parentbox, LogSeverity level)
{
GtkWidget *box, *icon, *label;
GdkPixmap *pm = 0;
GdkBitmap *mask = 0;
box = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(parentbox), box, FALSE, TRUE, 0);
/* box hidden by default */
log_get_icon(level, &pm, &mask, 0, 0);
icon = gtk_pixmap_new(pm, mask);
gtk_box_pack_start(GTK_BOX(box), icon, FALSE, TRUE, 0);
gtk_widget_show(icon);
label = gtk_label_new("");
gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0);
gtk_widget_show(label);
return label;
}
static void
ui_create(void)
{
GtkWidget *table;
GtkWidget *menubar, *logwin;
GtkWidget *handlebox;
GtkWidget *sw;
GdkPixmap *iconpm;
GdkBitmap *iconmask = 0;
static char *titles[1] = { "Log" };
toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
set_main_title();
gtk_window_set_default_size(GTK_WINDOW(toplevel),
prefs.win_width, prefs.win_height);
gtk_signal_connect(GTK_OBJECT(toplevel), "destroy",
GTK_SIGNAL_FUNC(file_exit_cb), NULL);
gtk_signal_connect(GTK_OBJECT(toplevel), "configure_event",
GTK_SIGNAL_FUNC(toplevel_resize_cb), NULL);
gtk_signal_connect(GTK_OBJECT(toplevel), "property_notify_event",
GTK_SIGNAL_FUNC(toplevel_property_notify_cb), NULL);
gtk_container_border_width(GTK_CONTAINER(toplevel), 0);
ui_set_help_tag(toplevel, "main-window");
gtk_widget_show(GTK_WIDGET(toplevel));
/* gtk_widget_realize(toplevel); */
iconpm = gdk_pixmap_create_from_xpm_d(toplevel->window, &iconmask,
0, maketool_xpm);
gdk_window_set_icon(toplevel->window, 0, iconpm, iconmask);
gdk_window_set_icon_name(toplevel->window, "Maketool");
gtk_tooltips_new();
table = gtk_table_new(4, 1, FALSE);
gtk_container_add(GTK_CONTAINER(toplevel), table);
gtk_container_border_width(GTK_CONTAINER(table), 0);
gtk_table_set_row_spacings(GTK_TABLE(table), 0);
handlebox = gtk_handle_box_new();
gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(handlebox), GTK_SHADOW_NONE);
gtk_table_attach(GTK_TABLE(table), handlebox, 0, 1, 0, 1,
GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0,
0, 0);
gtk_widget_show(handlebox);
menubar = gtk_menu_bar_new();
gtk_container_add(GTK_CONTAINER(handlebox), menubar);
gtk_widget_show(menubar);
ui_create_menus(menubar);
handlebox = gtk_handle_box_new();
gtk_handle_box_set_shadow_type(GTK_HANDLE_BOX(handlebox), GTK_SHADOW_NONE);
/* gtk_container_border_width(GTK_CONTAINER(handlebox), SPACING); */
gtk_table_attach(GTK_TABLE(table), handlebox, 0, 1, 1, 2,
GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0,
0, 0);
gtk_widget_show(handlebox);
toolbar_hb = handlebox;
#if GTK2
toolbar = gtk_toolbar_new();
/* gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL); */
#else
toolbar = gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH);
gtk_toolbar_set_button_relief(GTK_TOOLBAR(toolbar), GTK_RELIEF_NONE);
gtk_toolbar_set_space_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_SPACE_LINE);
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
#endif
gtk_container_add(GTK_CONTAINER(handlebox), toolbar);
gtk_widget_show(toolbar);
ui_create_tools(toolbar);
sw = gtk_scrolled_window_new(0, 0);
gtk_container_border_width(GTK_CONTAINER(sw), 0);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_table_attach(GTK_TABLE(table), sw, 0, 1, 2, 3,
GTK_FILL|GTK_EXPAND|GTK_SHRINK, GTK_FILL|GTK_EXPAND|GTK_SHRINK,
SPACING, 0);
gtk_widget_show(GTK_WIDGET(sw));
logwin = gtk_ctree_new_with_titles(1, 0, titles);
gtk_ctree_set_line_style(GTK_CTREE(logwin), GTK_CTREE_LINES_NONE);
gtk_ctree_set_expander_style(GTK_CTREE(logwin), GTK_CTREE_EXPANDER_TRIANGLE);
gtk_clist_column_titles_hide(GTK_CLIST(logwin));
gtk_ctree_set_indent(GTK_CTREE(logwin), 16);
gtk_ctree_set_show_stub(GTK_CTREE(logwin), FALSE);
gtk_clist_set_column_width(GTK_CLIST(logwin), 0, 400);
gtk_clist_set_column_auto_resize(GTK_CLIST(logwin), 0, TRUE);
gtk_signal_connect(GTK_OBJECT(logwin), "tree-select-row",
GTK_SIGNAL_FUNC(log_click_cb), 0);
gtk_signal_connect(GTK_OBJECT(logwin), "tree-unselect-row",
GTK_SIGNAL_FUNC(log_click_cb), 0);
gtk_signal_connect(GTK_OBJECT(logwin), "button_press_event",
GTK_SIGNAL_FUNC(log_doubleclick_cb), 0);
gtk_signal_connect(GTK_OBJECT(logwin), "tree_collapse",
GTK_SIGNAL_FUNC(log_collapse_cb), 0);
gtk_signal_connect(GTK_OBJECT(logwin), "tree_expand",
GTK_SIGNAL_FUNC(log_expand_cb), 0);
gtk_container_add(GTK_CONTAINER(sw), logwin);
gtk_scrolled_window_set_hadjustment(GTK_SCROLLED_WINDOW(sw),
GTK_CLIST(logwin)->hadjustment);
gtk_scrolled_window_set_vadjustment(GTK_SCROLLED_WINDOW(sw),
GTK_CLIST(logwin)->vadjustment);
clipboard_init(logwin);
gtk_widget_show(logwin);
log_init(logwin);
log_set_count_callback(count_changed);
messagebox = gtk_hbox_new(FALSE, SPACING);
gtk_table_attach(GTK_TABLE(table), messagebox, 0, 1, 3, 4,
GTK_FILL|GTK_EXPAND|GTK_SHRINK, 0,
SPACING, 0);
gtk_container_border_width(GTK_CONTAINER(messagebox), 0);
gtk_widget_show(GTK_WIDGET(messagebox));
messageent = gtk_entry_new();
gtk_entry_set_editable(GTK_ENTRY(messageent), FALSE);
gtk_entry_set_text(GTK_ENTRY(messageent), _("Welcome to Maketool"));
gtk_box_pack_start(GTK_BOX(messagebox), messageent, TRUE, TRUE, 0);
gtk_widget_show(messageent);
progressbar = gtk_progress_bar_new();
gtk_progress_bar_set_orientation(GTK_PROGRESS_BAR(progressbar),
GTK_PROGRESS_LEFT_TO_RIGHT);
gtk_progress_bar_set_bar_style(GTK_PROGRESS_BAR(progressbar),
GTK_PROGRESS_CONTINUOUS);
gtk_box_pack_start(GTK_BOX(messagebox), progressbar, FALSE, TRUE, 0);
/* hidden by default */
error_count = create_log_count(messagebox, L_ERROR);
warning_count = create_log_count(messagebox, L_WARNING);
ui_init_anim_pixmaps();
anim = gtk_pixmap_new(anim_pixmaps[0], anim_masks[0]);
gtk_box_pack_start(GTK_BOX(messagebox), anim, FALSE, FALSE, 0);
gtk_widget_show(anim);
/*
* Setup the environment variable which tells descendant
* maketool_client processes which window to talk to.
*
* TODO: isolate dep on gdkx.h
*/
#if HAVE_PUTENV
putenv(g_strdup_printf("MAKETOOL_WINDOWID=0x%lx", ui_windowid(toplevel)));
#endif
/*
* Ensure we get PropertyNotify events on our own window,
* so maketool_client can send us stuff.
*/
gdk_window_set_events(toplevel->window,
gdk_window_get_events(toplevel->window)|GDK_PROPERTY_CHANGE_MASK);
#if DEBUG
fprintf(stderr, "toplevel GDK event mask: 0x%08x\n",
gdk_window_get_events(toplevel->window));
#endif
mq_init(toplevel->window);
list_targets();
gtk_widget_show(GTK_WIDGET(table));
if (prefs.upgraded && prefs.found_old)
{
GtkWidget *msg;
msg = ui_message_dialog_f(toplevel, _("Maketool: Upgraded Preferences"),
"Maketool has detected that your preferences file\n"
"$HOME/.maketoolrc is older than version %s and\n"
"has upgraded it.",
VERSION);
ui_message_wait(msg);
}
if (prefs.makefile != 0 &&
prefs.makefile[0] != '\0' &&
!file_exists(prefs.makefile))
{
GtkWidget *msg;
msg = ui_message_dialog_f(toplevel, _("Maketool: Makefile Doesn't Exist"),
"The specified makefile\n"
"%s\n"
"doesn't exist",
prefs.makefile);
ui_message_wait(msg);
}
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static const char usage_string[] = "\
Usage: maketool [options] [target] [var=value] ...\n\
Options:\n\
-C DIRECTORY, --directory=DIRECTORY\n\
Change to DIRECTORY before doing anything.\n\
-f FILE, --file=FILE, --makefile=FILE\n\
Read FILE as a makefile.\n\
-h, --help Print this message and exit.\n\
-j [N], --jobs[=N] Allow N jobs at once; infinite jobs with no arg.\n\
-k, --keep-going Keep going when some targets can't be made.\n\
-l [N], --load-average[=N], --max-load[=N]\n\
Don't start multiple jobs unless load is below N.\n\
-S, --no-keep-going, --stop\n\
Turns off -k.\n\
-v, --version Print the version number of maketool and exit.\n\
";
static const char version_string[] = "\
Maketool " VERSION "\n\
(c) 1999-2000 Greg Banks <gnb@alphalink.com.au>\n\
Maketool comes with ABSOLUTELY NO WARRANTY.\n\
You may redistribute copies of this software\n\
under the terms of the GNU General Public\n\
Licence; see the file COPYING.\n\
";
static void
usage(int code)
{
fputs(usage_string, stderr);
exit(code);
}
static void
set_makefile(const char *mf)
{
if (prefs.makefile != 0)
g_free(prefs.makefile);
prefs.makefile = g_strdup(mf);
}
static void
set_directory(const char *dir)
{
if (!change_directory(dir))
{
perror(dir);
exit(1);
}
}
#ifdef ARGSTEST
char *original_dir = 0;
static char *
relative_dir(void)
{
char *curr_dir = g_get_current_dir();
int i, j = 0;
estring rd;
for (i=0 ;
curr_dir[i] && original_dir[i] && curr_dir[i] == original_dir[i] ;
i++)
if (curr_dir[i] == '/')
j = i;
if (!original_dir[i])
j = i;
estring_init(&rd);
if (j > 0)
estring_append_string(&rd, "...");
estring_append_string(&rd, curr_dir+j);
return rd.data;
}
#endif
static void
parse_args(int argc, char **argv)
{
int i;
#ifdef ARGSTEST
original_dir = g_get_current_dir();
#endif
/* Check for presence of autoconf-related etc files */
set_makeprog(prefs.makeprog);
makesys = ms_probe();
argv0 = argv[0];
cmd_targets = g_new(char*, argc);
cmd_targets[cmd_num_targets = 0] = 0;
for (i=1 ; i<argc ; i++)
{
if (argv[i][0] == '-')
{
if (!strcmp(argv[i], "-C"))
{
if (i == argc-1)
usage(1);
set_directory(argv[++i]);
}
else if (!strncmp(argv[i], "--directory=", 12))
{
set_directory(argv[i]+12);
}
else if (!strcmp(argv[i], "-f"))
{
if (i == argc-1)
usage(1);
set_makefile(argv[++i]);
}
else if (!strncmp(argv[i], "--file=", 7))
{
set_makefile(argv[i]+7);
}
else if (!strncmp(argv[i], "--makefile=", 11))
{
set_makefile(argv[i]+11);
}
else if (!strcmp(argv[i], "-h") ||
!strcmp(argv[i], "--help"))
{
usage(0);
}
else if (!strcmp(argv[i], "-j"))
{
prefs.run_how = RUN_PARALLEL_PROC;
prefs.run_processes = (i < argc-1 && isdigit(argv[i+1][0]) ? atoi(argv[++i]) : 0);
}
else if (!strncmp(argv[i], "--jobs", 6))
{
prefs.run_how = RUN_PARALLEL_PROC;
prefs.run_processes = (argv[i][6] == '=' ? atoi(argv[i]+7) : 0);
}
else if (!strcmp(argv[i], "-k") ||
!strcmp(argv[i], "--keep-going"))
{
prefs.keep_going = TRUE;
}
else if (!strcmp(argv[i], "-l"))
{
prefs.run_how = RUN_PARALLEL_LOAD;
prefs.run_load = (i < argc-1 && isdigit(argv[i+1][0]) ? (int)(atof(argv[++i])*10.0) : 0);
}
else if (!strncmp(argv[i], "--load-average", 14))
{
prefs.run_how = RUN_PARALLEL_LOAD;
prefs.run_load = (argv[i][14] == '=' ? (int)(atof(argv[i]+15)*10.0) : 0);
}
else if (!strncmp(argv[i], "--max-load", 6))
{
prefs.run_how = RUN_PARALLEL_LOAD;
prefs.run_load = (argv[i][10] == '=' ? (int)(atof(argv[i]+11)*10.0) : 0);
}
else if (!strcmp(argv[i], "-S") ||
!strcmp(argv[i], "--no-keep-going") ||
!strcmp(argv[i], "--stop"))
{
prefs.keep_going = FALSE;
}
else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version"))
{
fputs(version_string, stdout);
exit(0);
}
/* TODO: add -n --dryrun flag */
else
{
usage(1);
}
}
else
{
if (strchr(argv[i], '=') != 0)
{
/* variable override */
char *buf = g_strdup(argv[i]);
char *value = strchr(buf, '=');
*value++ = '\0';
preferences_add_variable(buf, value, VAR_MAKE);
g_free(buf);
}
else
{
/* target */
cmd_targets[cmd_num_targets++] = argv[i];
}
}
}
#ifdef ARGSTEST
{
static const char *run_how_strings[] = {
"RUN_SERIES", "RUN_PARALLEL_PROC", "RUN_PARALLEL_LOAD"};
static const char *bool_strings[] = {
"FALSE", "TRUE"};
int i;
printf("makefile = %s\n", prefs.makefile);
printf("directory = %s\n", relative_dir());
printf("targets = {");
for (i=0 ; i<cmd_num_targets ; i++)
printf(" %s", cmd_targets[i]);
printf(" }\n");
printf("keep_going = %s\n", bool_strings[prefs.keep_going]);
printf("run_how = %s\n", run_how_strings[prefs.run_how]);
printf("run_processes = %d\n", prefs.run_processes);
printf("run_load = %d\n", prefs.run_load);
exit(0);
}
#endif
}
static void
enqueue_cmd_targets(void)
{
int i;
if (cmd_num_targets == 0)
return;
/* Don't enqueue make_makefiles_task() 'cos it's just
* been done when we called list_targets()
*/
for (i=0 ; i<cmd_num_targets ; i++)
task_enqueue(make_task(cmd_targets[i]));
task_start();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
#if !HAVE_UNSETENV
/* tsk, IRIX, how primitive */
extern char **environ;
static void
unsetenv(const char *sym)
{
int i;
int len = strlen(sym);
for (i = 0 ; environ[i] != 0 ; i++)
{
if (!strncmp(environ[i], sym, len) && environ[i][len] == '=')
break;
}
for ( ; environ[i] != 0 ; i++)
environ[i] = environ[i+1];
}
#endif
static void
setup_environment(void)
{
const char *oldpath;
const char *lang;
char *newvar;
/*
* Ensure $PATH contains the directory which
* holds extract_targets & make_makefile.
*/
oldpath = getenv("PATH");
if (oldpath == 0)
oldpath = ""; /* should never happen anyway */
newvar = g_strdup_printf("PATH=" PKGLIBEXECDIR ":%s", oldpath);
#if 0
fprintf(stderr, "putenv(\"%s\")\n", newvar);
#endif
putenv(newvar);
/*
* Do some sanity checking on i18n variables. Thanks
* to SATO Satoru of the Japan GNOME Users Group.
*/
if (getenv("LANG") == 0)
putenv("LANG=C");
lang = getenv("LANG");
if (!strcmp(lang, "C") || !strcmp(lang, ""))
unsetenv("XMODIFIERS");
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
static void
setup_i18n(void)
{
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
gtk_set_locale();
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
int
main(int argc, char **argv)
{
setup_environment();
setup_i18n();
gtk_init(&argc, &argv);
preferences_load();
parse_args(argc, argv);
task_init(work_started, work_ended);
ui_create();
enqueue_cmd_targets();
gtk_main();
return 0;
}
/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
/*END*/
syntax highlighted by Code2HTML, v. 0.9.1