anjuta r4104 - in trunk: . plugins/build-basic-autotools



Author: sgranjoux
Date: Sun Aug  3 09:26:34 2008
New Revision: 4104
URL: http://svn.gnome.org/viewvc/anjuta?rev=4104&view=rev

Log:
 	* (renamed) plugins/build-basic-autotools/plugin.c,
	(removed) plugins/build-basic-autotools/build-basic-autotools.c,
	(renamed) plugins/build-basic-autotools/plugin.h,
	(removed) plugins/build-basic-autotools/build-basic-autotools.h,
	(added) plugins/build-basic-autotools/program.c,
	(added) plugins/build-basic-autotools/program.h,
	plugins/build-basic-autotools/configuration-list.c,
	plugins/build-basic-autotools/configuration-list.h,
	plugins/build-basic-autotools/build-options.c,
	plugins/build-basic-autotools/executer.h,
	plugins/build-basic-autotools/Makefile.am:
	Rename build-basic-autotools.{ch} to plugin.{ch}
	Fix several memory leak in build plugin
	Keep all command data in one object


Added:
   trunk/plugins/build-basic-autotools/plugin.c
      - copied, changed from r4103, /trunk/plugins/build-basic-autotools/build-basic-autotools.c
   trunk/plugins/build-basic-autotools/plugin.h
      - copied, changed from r4103, /trunk/plugins/build-basic-autotools/build-basic-autotools.h
   trunk/plugins/build-basic-autotools/program.c   (contents, props changed)
   trunk/plugins/build-basic-autotools/program.h   (contents, props changed)
Removed:
   trunk/plugins/build-basic-autotools/build-basic-autotools.c
   trunk/plugins/build-basic-autotools/build-basic-autotools.h
Modified:
   trunk/ChangeLog
   trunk/plugins/build-basic-autotools/Makefile.am
   trunk/plugins/build-basic-autotools/build-options.c
   trunk/plugins/build-basic-autotools/configuration-list.c
   trunk/plugins/build-basic-autotools/configuration-list.h
   trunk/plugins/build-basic-autotools/executer.h

Modified: trunk/plugins/build-basic-autotools/Makefile.am
==============================================================================
--- trunk/plugins/build-basic-autotools/Makefile.am	(original)
+++ trunk/plugins/build-basic-autotools/Makefile.am	Sun Aug  3 09:26:34 2008
@@ -38,14 +38,16 @@
 
 # Plugin sources
 libanjuta_build_basic_autotools_la_SOURCES = \
-	build-basic-autotools.c \
-	build-basic-autotools.h \
+	plugin.c \
+	plugin.h \
 	executer.c \
 	executer.h \
 	build-options.c \
 	build-options.h \
 	configuration-list.c \
-	configuration-list.h
+	configuration-list.h \
+	program.c \
+	program.h
 
 # Plugin dependencies
 libanjuta_build_basic_autotools_la_LIBADD = \

Modified: trunk/plugins/build-basic-autotools/build-options.c
==============================================================================
--- trunk/plugins/build-basic-autotools/build-options.c	(original)
+++ trunk/plugins/build-basic-autotools/build-options.c	Sun Aug  3 09:26:34 2008
@@ -257,8 +257,6 @@
 	else
 	{
 		BuildConfiguration *cfg;
-		GString* args_str;
-		gchar **arg;
 		gchar *uri;
 		
 		gtk_widget_set_sensitive (dlg->ok, TRUE);
@@ -267,21 +265,7 @@
 		
 		if (cfg != NULL)
 		{
-			args_str = g_string_new (NULL);
-			arg = build_configuration_get_args (cfg);
-			if (arg)
-			{
-				for (; *arg != NULL; arg++)
-				{
-					gchar *quoted_arg = g_shell_quote (*arg);
-						
-					g_string_append (args_str, quoted_arg);
-					g_free (quoted_arg);
-					g_string_append_c (args_str, ' ');
-				}
-			}
-			gtk_entry_set_text (GTK_ENTRY (dlg->args), args_str->str);
-			g_string_free (args_str, TRUE);
+			gtk_entry_set_text (GTK_ENTRY (dlg->args), build_configuration_get_args (cfg));
 		
 			uri = build_configuration_list_get_build_uri (dlg->config_list, cfg);
 			build_gtk_file_chooser_create_and_set_current_folder_uri (GTK_FILE_CHOOSER (dlg->build_dir_chooser), uri);

Modified: trunk/plugins/build-basic-autotools/configuration-list.c
==============================================================================
--- trunk/plugins/build-basic-autotools/configuration-list.c	(original)
+++ trunk/plugins/build-basic-autotools/configuration-list.c	Sun Aug  3 09:26:34 2008
@@ -35,7 +35,7 @@
 {
 	gchar *name;
 	gchar *build_uri;
-	gchar **args;
+	gchar *args;
 	gboolean translate;
 	BuildConfiguration *next;
 	BuildConfiguration *prev;
@@ -139,7 +139,7 @@
 	{
 		BuildConfiguration *next = cfg->next;
 		
-		if (cfg->args) g_strfreev (cfg->args);
+		if (cfg->args) g_free (cfg->args);
 		if (cfg->build_uri) g_free (cfg->build_uri);
 		if (cfg->name) g_free (cfg->name);
 		g_free (cfg);
@@ -322,7 +322,7 @@
 		}
 		if ((cfg->args == NULL) && (dcfg->args))
 		{
-				g_shell_parse_argv (dcfg->args, NULL, &cfg->args, NULL);
+				cfg->args = g_strdup (dcfg->args);
 		}
 	}	
 }
@@ -422,14 +422,11 @@
 void
 build_configuration_set_args (BuildConfiguration *cfg, const gchar *args)
 {
-	if (cfg->args) g_strfreev (cfg->args);
-	if (args != NULL)
-	{
-		g_shell_parse_argv (args, NULL, &cfg->args, NULL);
-	}
+	if (cfg->args) g_free (cfg->args);
+	cfg->args = args != NULL ? g_strdup (args) : NULL;
 }
 
-gchar **
+const gchar *
 build_configuration_get_args (BuildConfiguration *cfg)
 {
 	return cfg->args;

Modified: trunk/plugins/build-basic-autotools/configuration-list.h
==============================================================================
--- trunk/plugins/build-basic-autotools/configuration-list.h	(original)
+++ trunk/plugins/build-basic-autotools/configuration-list.h	Sun Aug  3 09:26:34 2008
@@ -47,6 +47,6 @@
 gchar *build_configuration_list_get_build_uri (BuildConfigurationList *list, BuildConfiguration *cfg);
 const gchar *build_configuration_get_relative_build_uri (BuildConfiguration *cfg);
 void build_configuration_set_args (BuildConfiguration *cfg, const gchar *args);
-gchar **build_configuration_get_args (BuildConfiguration *cfg);
+const gchar *build_configuration_get_args (BuildConfiguration *cfg);
 
 #endif /* CONFIGURATION_LIST_H */

Modified: trunk/plugins/build-basic-autotools/executer.h
==============================================================================
--- trunk/plugins/build-basic-autotools/executer.h	(original)
+++ trunk/plugins/build-basic-autotools/executer.h	Sun Aug  3 09:26:34 2008
@@ -19,7 +19,7 @@
 #ifndef _EXECUTE_H_
 #define _EXECUTE_H_
 
-#include "build-basic-autotools.h"
+#include "plugin.h"
 
 void execute_program (BasicAutotoolsPlugin* plugin,
 					  const gchar *pre_select_uri);

Copied: trunk/plugins/build-basic-autotools/plugin.c (from r4103, /trunk/plugins/build-basic-autotools/build-basic-autotools.c)
==============================================================================
--- /trunk/plugins/build-basic-autotools/build-basic-autotools.c	(original)
+++ trunk/plugins/build-basic-autotools/plugin.c	Sun Aug  3 09:26:34 2008
@@ -1,6 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
-    build-basic-autotools.c
+    plugin.c
     Copyright (C) 2000 Naba Kumar
 
     This program is free software; you can redistribute it and/or modify
@@ -41,9 +41,10 @@
 #include <libanjuta/interfaces/ianjuta-indicable.h>
 #include <libanjuta/interfaces/ianjuta-preferences.h>
 
-#include "build-basic-autotools.h"
+#include "plugin.h"
 #include "build-options.h"
 #include "executer.h"
+#include "program.h"
 
 #include <sys/wait.h>
 
@@ -94,14 +95,6 @@
 
 typedef struct
 {
-	gchar *project_dir;
-	gchar *build_dir;
-	gchar **argv;
-	GtkWindow *parent;
-} BuildLinkCommand;
-
-typedef struct
-{
 	gchar *pattern;
 	GRegex *regex;
 	GRegex *local_regex;
@@ -121,10 +114,9 @@
 	
 	AnjutaLauncher *launcher;
 	gboolean used;
-	
-	IAnjutaBuilderCallback callback;
-	gpointer user_data;
 
+	BuildProgram *program;
+	
 	IAnjutaMessageView *message_view;
 	GHashTable *build_dir_stack;
 	
@@ -140,6 +132,7 @@
 
 /* Declarations */
 static void update_project_ui (BasicAutotoolsPlugin *bb_plugin);
+static void update_configuration_menu (BasicAutotoolsPlugin *plugin);
 static gboolean directory_has_file (const gchar *dirname, const gchar *filename);
 
 static GList *patterns_list = NULL;
@@ -165,158 +158,6 @@
 /* Helper functions
  *---------------------------------------------------------------------------*/
 
-static gchar*
-build_shell_expand (const gchar *input)
-{
-	GString* expand;
-	
-	if (input == NULL) return NULL;
-	
-	expand = g_string_sized_new (strlen (input));
-	
-	for (; *input != '\0'; input++)
-	{
-		switch (*input)
-		{
-			case '$':
-			{
-				/* Variable expansion */
-				const gchar *end;
-				gint var_name_len;
-
-				end = input + 1;
-				while (isalnum (*end) || (*end == '_')) end++;
-				var_name_len = end - input - 1;
-				if (var_name_len > 0)
-				{
-					const gchar *value;
-					
-					g_string_append_len (expand, input + 1, var_name_len);
-					value = g_getenv (expand->str + expand->len - var_name_len);
-					g_string_truncate (expand, expand->len - var_name_len);
-					g_string_append (expand, value);
-					input = end - 1;
-					continue;
-				}
-				break;
-			}
-			case '~':
-			{
-				/* User home directory expansion */
-				if (isspace(input[1]) || (input[1] == G_DIR_SEPARATOR) || (input[1] == '\0'))
-				{
-					g_string_append (expand, g_get_home_dir());
-					continue;
-				}
-				break;
-			}
-			default:
-				break;
-		}
-		g_string_append_c (expand, *input);
-	}
-	
-	return g_string_free (expand, FALSE);
-}
-
-static gchar **
-build_argv_command (const gchar *cmd_dir, const gchar *cmd, gchar **argv)
-{
-	gchar **new_cmd;
-	gchar **split_cmd;
-	guint split_len;
-	
-	split_cmd = g_strsplit (cmd, " ", 2);
-	split_len = g_strv_length (split_cmd);
-	
-	if (argv == NULL)
-	{
-		new_cmd = split_cmd;
-	}
-	else
-	{
-		guint argv_len;
-		
-		argv_len = g_strv_length (argv);
-		new_cmd = g_new (gchar *, split_len + argv_len + 1);
-		memcpy (new_cmd, split_cmd, split_len * sizeof (gchar *));
-		g_free (split_cmd);
-		memcpy (new_cmd + split_len, argv, (argv_len + 1) * sizeof (gchar *));
-		g_free (argv);
-	}
-	
-	if (cmd_dir != NULL)
-	{
-		gchar *cmd = new_cmd[0];
-		
-		new_cmd[0] = g_strconcat (cmd_dir, G_DIR_SEPARATOR_S, cmd, NULL);
-		g_free (cmd);
-	}
-	
-	return new_cmd;
-}
-
-static gchar **
-build_add_env_variable (gchar **envp, const gchar *name, const gchar *value)
-{
-	gchar **var;
-	guint len = 0;
-
-	if (envp != NULL)
-	{
-		/* Look for an already existing variable */
-		for (var = envp; *var != NULL; var++)
-		{
-			if (strcmp (*var, name) == 0)
-			{
-				/* Just update variable */
-				if (value == NULL)
-				{
-					*var[strlen(name)] = '\0';
-				}
-				else
-				{
-					g_free (*var);
-					*var = g_strconcat (name, "=", value, NULL);
-				}
-				
-				return envp;
-			}
-		}
-		len = var - envp;
-	}	
-	
-	/* Need to create a new variable */
-	var = g_new (gchar *, len + 2);
-	*var = g_strconcat (name, value == NULL ? NULL : "=", value, NULL);
-	if (envp != NULL)
-	{
-		memcpy (&var[1], envp, len * sizeof (gchar *));
-		g_free (envp);
-	}
-	var[len + 1] = NULL;
-	
-	return var;
-}
-
-static gchar **
-build_add_arg (gchar **argv, const gchar *argument)
-{
-	gchar **new_argv;
-	guint len;
-
-	len = g_strv_length (argv);
-	
-	/* Need to create a new variable */
-	new_argv = g_new (gchar *, len + 2);
-	new_argv[0] = argv[0];
-	new_argv[1] = g_strdup (argument);
-	memcpy (&new_argv[2], &argv[1], len * sizeof (gchar *));
-	g_free (argv);
-	
-	return new_argv;
-}	
-	
 /* Allow installation as root (#321455) */
 static void on_root_check_toggled(GtkWidget* toggle_button, GtkWidget* entry)
 {
@@ -324,23 +165,6 @@
 			gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle_button)));
 }
 
-static gchar*
-get_root_install_command(BasicAutotoolsPlugin *bplugin)
-{
-	AnjutaPlugin* plugin = ANJUTA_PLUGIN(bplugin);
-	AnjutaPreferences* prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
-	if (anjuta_preferences_get_int (prefs , PREF_INSTALL_ROOT))
-	{
-		gchar* command = anjuta_preferences_get(prefs, PREF_INSTALL_ROOT_COMMAND);
-		if (command != NULL)
-			return command;
-		else
-			return g_strdup("");
-	}
-	else
-		return g_strdup("");
-}
-
 /* Indicator locations reported by the build */
 
 static BuildIndicatorLocation*
@@ -462,21 +286,23 @@
 	return dir_stack->data;
 }
 
+static void
+build_context_cancel (BuildContext *context)
+{
+	if (context->launcher != NULL)
+	{
+		anjuta_launcher_signal (context->launcher, SIGTERM);
+	}
+}
+
 static gboolean
 build_context_destroy_command (BuildContext *context)
 {
 	if (context->used) return FALSE;
-	if (context->callback)
-	{
-		GError *err;
-			
-		/* Emit command-finished signal abort */
-		err = g_error_new_literal (ianjuta_builder_error_quark (),
-								   IANJUTA_BUILDER_ABORTED,
-								   _("Command aborted"));
-		context->callback (G_OBJECT (context->plugin), context, err, context->user_data);
-		g_error_free (err);
-		context->callback = NULL;
+	if (context->program)
+	{	
+		build_program_free (context->program);
+		context->program = NULL;
 	}
 		
 	if (context->launcher)
@@ -1052,10 +878,9 @@
 					 BuildContext *context)
 {
 	context->used = FALSE;
-	if (context->callback != NULL)
+	if (context->program->callback != NULL)
 	{
 		GError *err = NULL;
-		IAnjutaBuilderCallback callback;
 		
 		if (WIFEXITED (status))
 		{
@@ -1093,9 +918,7 @@
 							   IANJUTA_BUILDER_TERMINATED,
 							   _("Command terminated for an unknown reason"));
 		}
-		callback = context->callback;	
-		context->callback = NULL;
-		callback (G_OBJECT (context->plugin), context, err, context->user_data);	
+		build_program_callback (context->program, G_OBJECT (context->plugin), context, err);
 	}
 	if (context->used)
 		return;	/* Another command is run */
@@ -1271,7 +1094,6 @@
 		context->environment = NULL;
 	}
 	
-	context->callback = NULL;
 	context->launcher = anjuta_launcher_new ();
 	g_signal_connect (G_OBJECT (context->launcher), "child-exited",
 					  G_CALLBACK (on_build_terminated), context);
@@ -1301,124 +1123,95 @@
 }
 
 static gboolean
-build_execute_command_in_context (BuildContext* context, const gchar *dir,
-					gchar *argv[],
-								  gchar *envp[],
-								  IAnjutaBuilderCallback callback, gpointer user_data,
+build_execute_command_in_context (BuildContext* context, BuildProgram *prog,
 								  GError **err)
 {
-	gchar *real_dir;
-	
-	g_return_val_if_fail (argv != NULL, FALSE);
+	AnjutaPreferences* prefs = anjuta_shell_get_preferences (context->plugin->shell, NULL);
 
-	real_dir = g_strdup (dir);
-	
-	context->callback = callback;
-	context->user_data = user_data;
+	if (context->program != NULL)
+		build_program_free (context->program);
+	context->program = prog;
 	context->used = TRUE;
 	
-	/* Add current directory */
-	envp = build_add_env_variable (envp, "PWD", dir);
-	
-  	if (context->environment)
+	/* Send options to make */
+	if (strcmp (build_program_get_basename (prog), "make") == 0)
 	{
-		if (!ianjuta_environment_override (context->environment, &real_dir, &argv, &envp, NULL))
+		if (!anjuta_preferences_get_int (prefs , PREF_TRANSLATE_MESSAGE))
 		{
-			g_object_unref (context->environment);
-			context->environment = NULL;
+			build_program_add_env (prog, "LANGUAGE", "C");
+		}
+		if (anjuta_preferences_get_int (prefs , PREF_PARALLEL_MAKE))
+		{
+			gchar *arg = g_strdup_printf ("-j%d", anjuta_preferences_get_int (prefs , PREF_PARALLEL_MAKE_JOB));
+			build_program_insert_arg (prog, 1, arg);
+			g_free (arg);
+		}
+		if (anjuta_preferences_get_int (prefs , PREF_CONTINUE_ON_ERROR))
+		{
+			build_program_insert_arg (prog, 1, "-k");
 		}
 	}
 	
+	build_program_override (prog, context->environment);
+	
+	/* Add current directory */
+	build_program_add_env (prog, "PWD", prog->work_dir);
+	
 	if (context->message_view)
 	{
 		gchar *command;
 		
-		command = g_strjoinv (" ", argv);
+		command = g_strjoinv (" ", prog->argv);
 		ianjuta_message_view_buffer_append (context->message_view,
 										"Building in directory: ", NULL);
-		ianjuta_message_view_buffer_append (context->message_view, dir, NULL);
+		ianjuta_message_view_buffer_append (context->message_view, prog->work_dir, NULL);
 		ianjuta_message_view_buffer_append (context->message_view, "\n", NULL);
 		ianjuta_message_view_buffer_append (context->message_view, command, NULL);
 		ianjuta_message_view_buffer_append (context->message_view, "\n", NULL);
 		g_free (command);
 	
-		anjuta_launcher_execute_v (context->launcher, argv, envp,
-								 on_build_mesg_arrived, context);
+		anjuta_launcher_execute_v (context->launcher,
+								   prog->argv,
+								   prog->envp,
+								   on_build_mesg_arrived, context);
 	}
 	else
 	{
-		anjuta_launcher_execute_v (context->launcher, argv, envp,
-								 NULL, NULL);
+		anjuta_launcher_execute_v (context->launcher,
+								   prog->argv,
+								   prog->envp,
+								   NULL, NULL);
 	}		
 	
 	return TRUE;
 }	
 
 static gchar *
-target_from_source (BasicAutotoolsPlugin *plugin, const gchar *target)
+build_dir_from_source (BasicAutotoolsPlugin *plugin, const gchar *src_dir)
 {
 	if ((plugin->project_root_dir == NULL) || 
 		(plugin->project_build_dir == NULL) || 
 		(strcmp (plugin->project_root_dir, plugin->project_build_dir) == 0) ||
-		(strncmp (target, plugin->project_root_dir, strlen (plugin->project_root_dir)) != 0))
+		(strncmp (src_dir, plugin->project_root_dir, strlen (plugin->project_root_dir)) != 0))
 	{
-		return g_strdup (target);
+		return g_strdup (src_dir);
 	}
 	else
 	{
-		return g_strconcat (plugin->project_build_dir, target + strlen (plugin->project_root_dir), NULL);
+		return g_strconcat (plugin->project_build_dir, src_dir + strlen (plugin->project_root_dir), NULL);
 	}
 }
 
 static BuildContext*
-build_execute_command_full (BasicAutotoolsPlugin* bplugin, const gchar *dir,
-			gchar *argv[],
-			gboolean save_file, gboolean with_view, gchar *envp[],
-			IAnjutaBuilderCallback callback, gpointer user_data,
-			GError **err)
+build_execute_command (BasicAutotoolsPlugin* bplugin, BuildProgram *prog,
+					   gboolean with_view, GError **err)
 {
-	AnjutaPlugin* plugin = ANJUTA_PLUGIN(bplugin);
 	BuildContext *context;
-	AnjutaPreferences* prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
 	gboolean ok;
-	gchar **arg;
 	
-	if (save_file) 
-		save_all_files (ANJUTA_PLUGIN (plugin));
+	context = build_get_context (bplugin, prog->work_dir, with_view);
 
-	context = build_get_context (bplugin, dir, with_view);
-
-	/* Send options to make */
-	if (strcmp (argv[0], "make") == 0)
-	{
-		if (!anjuta_preferences_get_int (prefs , PREF_TRANSLATE_MESSAGE))
-		{
-			envp = build_add_env_variable (envp, "LANGUAGE", "C");
-		}
-		if (anjuta_preferences_get_int (prefs , PREF_PARALLEL_MAKE))
-		{
-			gchar *arg = g_strdup_printf ("-j%d", anjuta_preferences_get_int (prefs , PREF_PARALLEL_MAKE_JOB));
-			argv = build_add_arg (argv, arg);
-			g_free (arg);
-		}
-		if (anjuta_preferences_get_int (prefs , PREF_CONTINUE_ON_ERROR))
-		{
-			argv = build_add_arg (argv, "-k");
-		}
-	}
-	
-	/* Expand shell variable */
-	for (arg = argv; *arg != NULL; arg++)
-	{
-		gchar *old_arg;
-		
-		old_arg = *arg;
-		*arg = build_shell_expand (old_arg);
-		g_free (old_arg);
-	}
-	
-	ok = build_execute_command_in_context (context, dir, argv, envp, callback, user_data, NULL);
-	g_strfreev (argv);
+	ok = build_execute_command_in_context (context, prog, err);
 	
 	if (ok)
 	{
@@ -1432,21 +1225,30 @@
 	}
 }
 
-
-static gboolean
-build_execute_command (BasicAutotoolsPlugin* bplugin, const gchar *dir,
-		   const gchar *command, gboolean save_file, GError **err)
+static BuildContext*
+build_save_and_execute_command (BasicAutotoolsPlugin* bplugin, BuildProgram *prog,
+								gboolean with_view, GError **err)
 {
-	gchar **argv;
+	AnjutaPlugin* plugin = ANJUTA_PLUGIN(bplugin);
+	BuildContext *context;
 	gboolean ok;
-
-	/* Store args and environment variables as string array */
-	if (!g_shell_parse_argv (command, NULL, &argv, NULL))
-		return FALSE;
 	
-	ok = build_execute_command_full (bplugin, dir, argv, save_file, TRUE, NULL, NULL, NULL, NULL) != NULL;
+	context = build_get_context (bplugin, prog->work_dir, with_view);
 
-	return ok;
+	save_all_files (ANJUTA_PLUGIN (plugin));
+	
+	ok = build_execute_command_in_context (context, prog, err);
+	
+	if (ok)
+	{
+		return context;
+	}
+	else
+	{
+		build_context_destroy (context);
+		
+		return NULL;
+	}
 }
 
 static void
@@ -1461,11 +1263,8 @@
 	{
 		if (node->data == context)
 		{	
-			if (context->launcher != NULL)
-			{
-				anjuta_launcher_signal (context->launcher, SIGTERM);
-				return;
-			}
+			build_context_cancel (context);
+			return;
 		}	
 	}	
 
@@ -1473,191 +1272,281 @@
 	g_return_if_reached ();	
 }
 
-static gboolean
-build_compile_file_real (BasicAutotoolsPlugin *plugin, const gchar *file)
+/* Build commands
+ *---------------------------------------------------------------------------*/
+
+static BuildContext*
+build_build_file_or_dir (BasicAutotoolsPlugin *plugin, const gchar *name,
+						 IAnjutaBuilderCallback callback, gpointer user_data,
+						 GError **err)
 {
+	BuildContext *context;
+	BuildProgram *prog;
+	gchar *build_dir;
 	gchar *target;
-	gchar *target_basename;
-	gchar *target_dirname;
-	gchar *ext_ptr;
-	gboolean ret;
 	
-	/* FIXME: This should be configuration somewhere, eg. preferences */
-	static GHashTable *target_ext = NULL;
-	if (!target_ext)
+	if (g_file_test (name, G_FILE_TEST_IS_DIR))
 	{
-		target_ext = g_hash_table_new (g_str_hash, g_str_equal);
-		g_hash_table_insert (target_ext, ".c", ".o");
-		g_hash_table_insert (target_ext, ".cpp", ".o");
-		g_hash_table_insert (target_ext, ".cxx", ".o");
-		g_hash_table_insert (target_ext, ".c++", ".o");
-		g_hash_table_insert (target_ext, ".cc", ".o");
-		g_hash_table_insert (target_ext, ".in", "");
-		g_hash_table_insert (target_ext, ".in.in", ".in");
-		g_hash_table_insert (target_ext, ".la", ".la");
-		g_hash_table_insert (target_ext, ".a", ".a");
-		g_hash_table_insert (target_ext, ".so", ".so");
-		g_hash_table_insert (target_ext, ".java", ".class");
+		build_dir = build_dir_from_source (plugin, name);
+		target = NULL;
 	}
-	
-	g_return_val_if_fail (file != NULL, FALSE);
-	ret = FALSE;
-
-	target = target_from_source (plugin, file);
-	target_basename = g_path_get_basename (target);
-	target_dirname = g_path_get_dirname (target);
-	ext_ptr = strrchr (target_basename, '.');
-	if (ext_ptr)
+	else
 	{
-		const gchar *new_ext;
-		new_ext = g_hash_table_lookup (target_ext, ext_ptr);
-		if (new_ext)
-		{
-			gchar *command;
-			
-			*ext_ptr = '\0';
-			command = g_strconcat (CHOOSE_COMMAND (plugin, COMPILE), " ",
-								   target_basename, new_ext, NULL);
-			build_execute_command (plugin, target_dirname, command, TRUE, NULL);
-			g_free (command);
-			ret = TRUE;
-		}
-	} else {
-		/* If file has no extension, take it as target itself */
-		gchar *command;
-		command = g_strconcat (CHOOSE_COMMAND(plugin, COMPILE), " ",
-							   target_basename, NULL);
-		build_execute_command (plugin, target_dirname, command, TRUE, NULL);
-		g_free (command);
-		ret = TRUE;
+		gchar *src_dir;
+		
+		src_dir = g_path_get_dirname (name);
+		build_dir = build_dir_from_source (plugin, src_dir);
+		g_free (src_dir);
+		
+		target = g_path_get_basename (name);
 	}
-	g_free (target_basename);
-	g_free (target_dirname);
+		
+	prog = build_program_new_with_command (build_dir,
+										   "%s %s",
+										   CHOOSE_COMMAND (plugin, BUILD),
+										   target ? target : "");
+	if (callback) build_program_set_callback (prog, callback, user_data);
+	
+	context = build_save_and_execute_command (plugin, prog, TRUE, err);
 	g_free (target);
-	if (ret == FALSE)
-	{
-		/* FIXME: Prompt the user to create a Makefile with a wizard
-		   (if there is no Makefile in the directory) or to add a target
-		   rule in the above hash table, eg. editing the preferences, if
-		   there is target extension defined for that file extension.
-		*/
-		GtkWindow *window;
-		window = GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell);
-		anjuta_util_dialog_error (window, _("Can not compile \"%s\": No compile rule defined for this file type."), file);
-	}
-	return ret;
+	g_free (build_dir);
+	
+	return context;
 }
 
-/* UI actions */
-static void
-build_build_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+
+
+static BuildContext*
+build_is_file_built (BasicAutotoolsPlugin *plugin, const gchar *filename,
+					 IAnjutaBuilderCallback callback, gpointer user_data,
+					 GError **err)
 {
-	build_execute_command (plugin, plugin->project_build_dir,
-						   CHOOSE_COMMAND (plugin, BUILD), TRUE, NULL);
+	BuildContext *context;
+	gchar *build_dir;
+	gchar *src_dir;
+	gchar *target;
+	BuildProgram *prog;
+	
+		
+	src_dir = g_path_get_dirname (filename);
+	build_dir = build_dir_from_source (plugin, src_dir);
+	g_free (src_dir);
+	target = g_path_get_basename (filename);
+
+	prog = build_program_new_with_command (build_dir,
+										   "%s %s",
+										   CHOOSE_COMMAND (plugin, IS_BUILT),
+										   target);
+	
+	build_program_set_callback (prog, callback, user_data);
+	
+	context = build_save_and_execute_command (plugin, prog, FALSE, err);
+	
+	g_free (target);
+	g_free (build_dir);
+	
+	return context;
 }
 
-static void
-build_install_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+
+
+static gchar*
+get_root_install_command(BasicAutotoolsPlugin *bplugin)
 {
+	AnjutaPlugin* plugin = ANJUTA_PLUGIN(bplugin);
+	AnjutaPreferences* prefs = anjuta_shell_get_preferences (plugin->shell, NULL);
+	if (anjuta_preferences_get_int (prefs , PREF_INSTALL_ROOT))
+	{
+		gchar* command = anjuta_preferences_get(prefs, PREF_INSTALL_ROOT_COMMAND);
+		if (command != NULL)
+			return command;
+		else
+			return g_strdup("");
+	}
+	else
+		return g_strdup("");
+}
+
+static BuildContext*
+build_install_dir (BasicAutotoolsPlugin *plugin, const gchar *dirname,
+				   GError **err)
+{
+	BuildContext *context;
 	gchar* root = get_root_install_command(plugin);
-	gchar* command = g_strdup_printf("%s %s", root,
-									 CHOOSE_COMMAND (plugin, INSTALL));
+	gchar *build_dir = build_dir_from_source (plugin, dirname);
+
+	context = build_save_and_execute_command (plugin,
+									 build_program_new_with_command (build_dir,
+																	 "%s %s",
+																	 root,
+																	 CHOOSE_COMMAND (plugin, INSTALL)),
+									 TRUE, err);
+	g_free (build_dir);
 	g_free(root);
-	build_execute_command (plugin, plugin->project_build_dir,
-						   command, TRUE, NULL);
-	g_free(command);
+	
+	return context;
 }
 
-static void
-build_clean_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+
+
+static BuildContext*
+build_clean_dir (BasicAutotoolsPlugin *plugin, const gchar *dirname,
+				 GError **err)
 {
-	build_execute_command (plugin, plugin->project_build_dir,
-						   CHOOSE_COMMAND (plugin, CLEAN), FALSE, NULL);
+	BuildContext *context;
+	gchar *build_dir = build_dir_from_source (plugin, dirname);
+	
+	context = build_execute_command (plugin,
+									 build_program_new_with_command (build_dir,
+																	 "%s",
+																	 CHOOSE_COMMAND (plugin, CLEAN)),
+									 TRUE, err);
+	
+	g_free (build_dir);
+	
+	return context;
 }
 
+
+
 static void
 build_remove_build_dir (GObject *sender,
 						IAnjutaBuilderHandle context,
 						GError *error,
 						gpointer user_data)
 {
-	
+	/* FIXME: Should we remove build dir on distclean ? */	
 }
 
-static void
-build_distclean_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+static BuildContext*
+build_distclean (BasicAutotoolsPlugin *plugin)
 {
-	gchar **argv;
+	BuildContext *context;
+	BuildProgram *prog;
+	
+	prog = build_program_new_with_command (plugin->project_build_dir,
+										   "%s",
+										   CHOOSE_COMMAND (plugin, DISTCLEAN));
+	build_program_set_callback (prog, build_remove_build_dir, plugin);
 
-	if (!g_shell_parse_argv (CHOOSE_COMMAND (plugin, DISTCLEAN), NULL, &argv, NULL))
-		return;
+	context = build_execute_command (plugin, prog, TRUE, NULL);
 	
-	build_execute_command_full (plugin, plugin->project_build_dir, argv, TRUE, TRUE, NULL, build_remove_build_dir, plugin, NULL);
+	return context;
 }
 
-static void
-on_select_configuration (GtkRadioMenuItem *item, gpointer user_data)
-{
-	if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
-	{
-		BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (user_data);
-		gchar *name;
-		GValue *value;
-		gchar *uri;	
 
-		name = g_object_get_data (G_OBJECT (item), "untranslated_name");
 
-		build_configuration_list_select (plugin->configurations, name);
+static BuildContext*
+build_tarball (BasicAutotoolsPlugin *plugin)
+{
+	BuildContext *context;
 
-		value = g_new0 (GValue, 1);
-		g_value_init (value, G_TYPE_STRING);
-	
-		uri = build_configuration_list_get_build_uri (plugin->configurations, build_configuration_list_get_selected (plugin->configurations));
-		g_value_set_string (value, uri);
-		g_free (uri);
+	context = build_save_and_execute_command (plugin,
+									 build_program_new_with_command (plugin->project_build_dir,
+																	 "%s",
+																	 CHOOSE_COMMAND (plugin, BUILD_TARBALL)),
+									 TRUE, NULL);
 	
-		anjuta_shell_add_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_BUILDER_ROOT_URI, value, NULL);	
-	}
+	return context;
 }
 
-static void
-build_update_configuration_menu (BasicAutotoolsPlugin *plugin)
+
+
+static BuildContext*
+build_compile_file (BasicAutotoolsPlugin *plugin, const gchar *filename)
 {
-	GtkWidget *submenu = NULL;
-	BuildConfiguration *cfg;
-	BuildConfiguration *selected;
-	GSList *group = NULL;
+	BuildContext *context = NULL;
+	gchar *build_dir;
+	gchar *src_dir;
+	gchar *target;
+	gchar *ext_ptr;
+	gboolean ret;
 	
-	submenu = gtk_menu_new ();
-	selected = build_configuration_list_get_selected (plugin->configurations);
-	for (cfg = build_configuration_list_get_first (plugin->configurations); cfg != NULL; cfg = build_configuration_next (cfg))
+	/* FIXME: This should be configuration somewhere, eg. preferences */
+	static GHashTable *target_ext = NULL;
+	if (!target_ext)
 	{
-		GtkWidget *item;
-		
-		item = gtk_radio_menu_item_new_with_mnemonic (group, build_configuration_get_translated_name (cfg));
-		group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
-		if (cfg == selected)
+		target_ext = g_hash_table_new (g_str_hash, g_str_equal);
+		g_hash_table_insert (target_ext, ".c", ".o");
+		g_hash_table_insert (target_ext, ".cpp", ".o");
+		g_hash_table_insert (target_ext, ".cxx", ".o");
+		g_hash_table_insert (target_ext, ".c++", ".o");
+		g_hash_table_insert (target_ext, ".cc", ".o");
+		g_hash_table_insert (target_ext, ".in", "");
+		g_hash_table_insert (target_ext, ".in.in", ".in");
+		g_hash_table_insert (target_ext, ".la", ".la");
+		g_hash_table_insert (target_ext, ".a", ".a");
+		g_hash_table_insert (target_ext, ".so", ".so");
+		g_hash_table_insert (target_ext, ".java", ".class");
+	}
+	
+	g_return_val_if_fail (filename != NULL, FALSE);
+	ret = FALSE;
+
+	src_dir = g_path_get_dirname (filename);
+	build_dir = build_dir_from_source (plugin, src_dir);
+	g_free (src_dir);
+	target = g_path_get_basename (filename);
+	ext_ptr = strrchr (target, '.');
+	if (ext_ptr)
+	{
+		const gchar *new_ext;
+		new_ext = g_hash_table_lookup (target_ext, ext_ptr);
+		if (new_ext)
 		{
-			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+			BuildProgram *prog;
+			
+			*ext_ptr = '\0';
+			prog = build_program_new_with_command (build_dir, "%s %s%s",
+											   CHOOSE_COMMAND (plugin, COMPILE),
+											   target, new_ext);
+			context = build_save_and_execute_command (plugin, prog, TRUE, NULL);
+			ret = TRUE;
 		}
-		g_object_set_data_full (G_OBJECT (item), "untranslated_name", g_strdup (build_configuration_get_name (cfg)), g_free);
-		g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (on_select_configuration), plugin);
-		gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+	} else {
+		/* If file has no extension, take it as target itself */
+		BuildProgram *prog;
+		
+		prog = build_program_new_with_command (build_dir, "%s %s",
+										   CHOOSE_COMMAND(plugin, COMPILE),
+							   			   target);
+		context = build_save_and_execute_command (plugin, prog, TRUE, NULL);
+		ret = TRUE;
 	}
-	gtk_menu_item_set_submenu (GTK_MENU_ITEM (plugin->configuration_menu), submenu);
-	gtk_widget_show_all (submenu);
+	g_free (target);
+	g_free (build_dir);
+	
+	if (ret == FALSE)
+	{
+		/* FIXME: Prompt the user to create a Makefile with a wizard
+		   (if there is no Makefile in the directory) or to add a target
+		   rule in the above hash table, eg. editing the preferences, if
+		   there is target extension defined for that file extension.
+		*/
+		GtkWindow *window;
+		window = GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell);
+		anjuta_util_dialog_error (window, _("Can not compile \"%s\": No compile rule defined for this file type."), filename);
+	}
+	
+	return context;
 }
 
+
+
 static void
 build_project_configured (GObject *sender,
-							IAnjutaBuilderHandle context,
+							IAnjutaBuilderHandle handle,
 							GError *error,
 							gpointer user_data)
 {
-	BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)sender;
+	if (error != NULL) return;
+
+	BuildContext *context = (BuildContext *)handle;
+	BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)(context == NULL ? (void *)sender : (void *)context->plugin);
 	GValue *value;
 	gchar *uri;
 	
+	/* FIXME: check if build directory correspond, configuration could have changed */
 	value = g_new0 (GValue, 1);
 	g_value_init (value, G_TYPE_STRING);
 	
@@ -1667,174 +1556,261 @@
 	
 	anjuta_shell_add_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_BUILDER_ROOT_URI, value, NULL);
 	
-	build_update_configuration_menu (plugin);
+	update_configuration_menu (plugin);
 }
 
-static void
-build_configure_project_after_autogen (GObject *sender,
-									   IAnjutaBuilderHandle context,
-									   GError *error,
-									   gpointer user_data)
+static BuildContext*
+build_configure_dir (BasicAutotoolsPlugin *plugin, const gchar *dirname, const gchar *args)
 {
-	BuildLinkCommand *link = (BuildLinkCommand *)user_data;
-	BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)sender;
+	BuildContext *context;
+	BuildProgram *prog;
+	
+	prog = build_program_new_with_command (dirname,
+										   "%s%s%s %s",
+										   plugin->project_root_dir,
+										   G_DIR_SEPARATOR_S,
+										   CHOOSE_COMMAND (plugin, CONFIGURE),
+										   args);
+	build_program_set_callback (prog, build_project_configured, NULL);
+	
+	context = build_save_and_execute_command (plugin, prog, TRUE, NULL);
 	
+	return context;
+}
+
+
+
+static void
+build_configure_after_autogen (GObject *sender,
+							   IAnjutaBuilderHandle handle,
+							   GError *error,
+							   gpointer user_data)
+{
 	if (error == NULL)
 	{
+		BuildContext *context = (BuildContext *)handle;
+		BasicAutotoolsPlugin *plugin = (BasicAutotoolsPlugin *)context->plugin;
 		struct stat conf_stat, log_stat;
 		gchar *filename;
 		
-		filename = g_build_filename (link->project_dir, "configure", NULL);
+		filename = g_build_filename (plugin->project_root_dir, "configure", NULL);
 		if (stat (filename, &conf_stat) != 0)
 		{
-			anjuta_util_dialog_error (link->parent, _("Can not configure project: Missing configure script in %s."), link->project_dir);
+			anjuta_util_dialog_error (GTK_WINDOW (ANJUTA_PLUGIN (plugin)->shell), _("Can not configure project: Missing configure script in %s."), plugin->project_root_dir);
 		}
 		else
 		{
 			g_free (filename);
-			filename = g_build_filename (link->build_dir, "config.log", NULL);
-			if ((stat (filename, &log_stat) != 0) ||
-				(log_stat.st_mtime < conf_stat.st_mtime))
+			filename = g_build_filename (context->program->work_dir, "config.log", NULL);
+			if ((stat (filename, &log_stat) != 0) || (log_stat.st_mtime < conf_stat.st_mtime))
 			{
-				link->argv = build_argv_command (link->project_dir,
-												 CHOOSE_COMMAND (plugin, CONFIGURE),
-												 link->argv);
-				build_execute_command_in_context ((BuildContext *)context, link->build_dir, link->argv, 
-												  NULL, build_project_configured, NULL, NULL);
+				/* configure has not be run, run it */
+				BuildProgram *prog;
+
+				prog = build_program_new_with_command (context->program->work_dir,
+													   "%s%s%s %s",
+													   plugin->project_root_dir,
+													   G_DIR_SEPARATOR_S,
+													   CHOOSE_COMMAND (plugin, CONFIGURE),
+													   (gchar *)user_data);
+				build_program_set_callback (prog, build_project_configured, NULL);
+		
+				build_execute_command_in_context ((BuildContext *)context, prog, NULL);
 			}
 		}
 		g_free (filename);
 	}
+	g_free (user_data);
+}
+
+static BuildContext*
+build_generate_dir (BasicAutotoolsPlugin *plugin, const gchar *dirname, const gchar *args)
+{
+	BuildContext *context;
+	BuildProgram *prog;
+	
+	if (directory_has_file (plugin->project_root_dir, "autogen.sh"))
+	{
+		prog = build_program_new_with_command (dirname,
+											   "%s%s%s %s",
+											   plugin->project_root_dir,
+											   G_DIR_SEPARATOR_S,
+											   CHOOSE_COMMAND (plugin, GENERATE),
+											   args);
+	}
+	else
+	{
+		prog = build_program_new_with_command (dirname,
+											   "%s %s",
+											   CHOOSE_COMMAND (plugin, AUTORECONF),
+											   args);
+	}
+	build_program_set_callback (prog, build_configure_after_autogen, g_strdup (args));
+	
+	context = build_save_and_execute_command (plugin, prog, TRUE, NULL);
 	
-	g_free (link->project_dir);
-	g_free (link->build_dir);
-	g_strfreev (link->argv);
-	g_free (link);
+	return context;
+}
+
+
+
+/* User actions
+ *---------------------------------------------------------------------------*/
+
+/* Main menu */
+static void
+on_build_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+{
+	if (plugin->project_root_dir)
+	{
+		build_build_file_or_dir (plugin, plugin->project_root_dir, NULL, NULL, NULL);
+	}
+}
+
+static void
+on_install_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+{
+	if (plugin->project_root_dir)
+	{
+		build_install_dir (plugin, plugin->project_root_dir, NULL);
+	}
+}
+
+static void
+on_clean_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+{
+	if (plugin->project_root_dir)
+	{
+		build_clean_dir (plugin, plugin->project_root_dir, NULL);
+	}
 }
 
 static void
-build_configure_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_configure_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	GtkWindow *parent;
 	gboolean run_autogen = FALSE;
 	const gchar *project_root;
 	GValue value = {0,};
-
+	
 	run_autogen = !directory_has_file (plugin->project_root_dir, "configure");
 	
 	anjuta_shell_get_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_PROJECT_MANAGER_PROJECT_ROOT_URI, &value, NULL);
 	project_root = g_value_get_string (&value);
 	parent = GTK_WINDOW (ANJUTA_PLUGIN(plugin)->shell);
+	
 	if (build_dialog_configure (parent, project_root, plugin->configurations, &run_autogen))
 	{
 		BuildConfiguration *config;
-		gchar **argv;
-		GFile *build_file;
-		gchar *build_dir;
+		GFile *file;
 		gchar *uri;
-
+		gchar *build_dir;
+		const gchar *args;
+	
 		config = build_configuration_list_get_selected (plugin->configurations);
 		uri = build_configuration_list_get_build_uri (plugin->configurations, config);
-		build_file = g_file_new_for_uri (uri);
+		file = g_file_new_for_uri (uri);
 		g_free (uri);
-		build_dir = g_file_get_path (build_file);
-		g_object_unref (build_file);
+	
+		build_dir = g_file_get_path (file);
+		g_object_unref (file);
+	
+		args = build_configuration_get_args (config);
 		
-		IAnjutaBuilderCallback callback = NULL;
-		BuildLinkCommand* user_data = NULL;
-
 		if (run_autogen)
 		{
-			gboolean has_autogen = directory_has_file (plugin->project_root_dir,
-													   "autogen.sh");
-			
-			gchar **args = g_strdupv (build_configuration_get_args (config));
-			argv = build_argv_command (plugin->project_root_dir,
-									   has_autogen ? CHOOSE_COMMAND (plugin, GENERATE) : CHOOSE_COMMAND (plugin, AUTORECONF),
-									   args);
-									   
-			
-			/* Plan to run configure afterward */
-			user_data = g_new (BuildLinkCommand, 1);
-			user_data->project_dir = g_strdup (plugin->project_root_dir);
-			user_data->build_dir = g_strdup (build_dir);
-		    /* Remove command name from argument array */
-			user_data->argv = g_strdupv (&argv[1]); 
-			user_data->parent = parent;
-		
-			callback = build_configure_project_after_autogen;
+			build_generate_dir (plugin, build_dir, args);
 		}
 		else
 		{
-			/* Run configure only */
-			gchar **args = g_strdupv (build_configuration_get_args (config));
-			
-			argv = build_argv_command (plugin->project_root_dir,
-									   CHOOSE_COMMAND (plugin, CONFIGURE),
-									   args);
-			callback = build_project_configured;
-		}
-		build_execute_command_full (plugin, build_dir, 
-					   argv, TRUE, TRUE, NULL,
-					   callback, user_data, NULL);
+			build_configure_dir (plugin, build_dir, args);
+		}
 		g_free (build_dir);
 	}
 }
 
 static void
-build_distribution_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_build_tarball (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
-	build_execute_command (plugin, plugin->project_build_dir,
-			   CHOOSE_COMMAND (plugin, BUILD_TARBALL),
-			   FALSE, NULL);
+	build_tarball (plugin);
 }
 
 static void
-build_build_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_build_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
-	gchar *dirname = g_dirname (plugin->current_editor_filename);
-	gchar *target = target_from_source (plugin, dirname);
-
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, BUILD),
-			   TRUE, NULL);
-	g_free (target);
-	g_free (dirname);
+	if (plugin->current_editor_filename)
+	{
+		gchar *dirname = g_dirname (plugin->current_editor_filename);
+		
+		build_build_file_or_dir (plugin, dirname, NULL, NULL, NULL);
+		
+		g_free (dirname);
+	}
 }
 
 static void
-build_install_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_install_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
-	gchar *dirname = g_dirname (plugin->current_editor_filename);
-	gchar* root = get_root_install_command(plugin);
-	gchar *target = target_from_source (plugin, dirname);
-	gchar* command = g_strdup_printf ("%s %s", root,
-									  CHOOSE_COMMAND (plugin, INSTALL));
-	g_free(root);
-	build_execute_command (plugin, target, command, TRUE, NULL);
-	g_free(command);
-	g_free (target);
-	g_free (dirname);
+	if (plugin->current_editor_filename)
+	{
+		gchar *dirname = g_dirname (plugin->current_editor_filename);
+		
+		build_install_dir (plugin, dirname, NULL);
+		
+		g_free (dirname);
+	}
 }
 
 static void
-build_clean_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_clean_module (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
-	gchar *dirname = g_dirname (plugin->current_editor_filename);
-	gchar *target = target_from_source (plugin, dirname);
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, CLEAN),
-			   FALSE, NULL);
-	g_free (target);
-	g_free (dirname);
+	if (plugin->current_editor_filename)
+	{
+		gchar *dirname = g_dirname (plugin->current_editor_filename);
+		
+		build_clean_dir (plugin, dirname, NULL);
+		
+		g_free (dirname);
+	}
 }
 
 static void
-build_compile_file (GtkAction *action, BasicAutotoolsPlugin *plugin)
+on_compile_file (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	if (plugin->current_editor_filename)
 	{
-		build_compile_file_real (plugin, plugin->current_editor_filename);
+		build_compile_file (plugin, plugin->current_editor_filename);
+	}
+}
+
+static void
+on_distclean_project (GtkAction *action, BasicAutotoolsPlugin *plugin)
+{
+	build_distclean (plugin);
+}
+
+static void
+on_select_configuration (GtkRadioMenuItem *item, gpointer user_data)
+{
+	if (gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (item)))
+	{
+		BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (user_data);
+		gchar *name;
+		GValue *value;
+		gchar *uri;	
+
+		name = g_object_get_data (G_OBJECT (item), "untranslated_name");
+
+		build_configuration_list_select (plugin->configurations, name);
+
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_STRING);
+	
+		uri = build_configuration_list_get_build_uri (plugin->configurations, build_configuration_list_get_selected (plugin->configurations));
+		g_value_set_string (value, uri);
+		g_free (uri);
+	
+		anjuta_shell_add_value (ANJUTA_PLUGIN (plugin)->shell, IANJUTA_BUILDER_ROOT_URI, value, NULL);	
 	}
 }
 
@@ -1842,9 +1818,11 @@
 static void
 fm_compile (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
+	g_return_if_fail (plugin->fm_current_filename != NULL);
+
 	if (plugin->fm_current_filename)
 	{
-		build_compile_file_real (plugin, plugin->fm_current_filename);
+		build_compile_file (plugin, plugin->fm_current_filename);
 	}
 }
 
@@ -1852,7 +1830,6 @@
 fm_build (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar *target;
 	
 	g_return_if_fail (plugin->fm_current_filename != NULL);
 	
@@ -1860,11 +1837,9 @@
 		dir = g_strdup (plugin->fm_current_filename);
 	else
 		dir = g_path_get_dirname (plugin->fm_current_filename);
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, BUILD),
-			   TRUE, NULL);
-	g_free (target);
+	
+	build_build_file_or_dir (plugin, dir, NULL, NULL, NULL);
+	
 	g_free (dir);
 }
 
@@ -1872,31 +1847,23 @@
 fm_install (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar* root; 
-	gchar* command; 
-	gchar *target;
 	
 	g_return_if_fail (plugin->fm_current_filename != NULL);
 	
-	
 	if (g_file_test (plugin->fm_current_filename, G_FILE_TEST_IS_DIR))
 		dir = g_strdup (plugin->fm_current_filename);
 	else
 		dir = g_path_get_dirname (plugin->fm_current_filename);
-	root = get_root_install_command(plugin);
-	command = g_strdup_printf ("%s %s", root,
-							   CHOOSE_COMMAND (plugin, INSTALL));
-	g_free(root);
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, dir, command, TRUE, NULL);
-	g_free (target);
+	
+	build_install_dir (plugin, dir, NULL);
+	
+	g_free (dir);
 }
 
 static void
 fm_clean (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar *target;
 	
 	g_return_if_fail (plugin->fm_current_filename != NULL);
 	
@@ -1905,20 +1872,20 @@
 	else
 		dir = g_path_get_dirname (plugin->fm_current_filename);
 	
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, CLEAN),
-			   FALSE, NULL);
-	g_free (target);
+	build_clean_dir (plugin, dir, NULL);
+	
+	g_free (dir);
 }
 
 /* Project manager context menu */
 static void
 pm_compile (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
+	g_return_if_fail (plugin->pm_current_filename != NULL);
+
 	if (plugin->pm_current_filename)
 	{
-		build_compile_file_real (plugin, plugin->pm_current_filename);
+		build_compile_file (plugin, plugin->pm_current_filename);
 	}
 }
 
@@ -1926,7 +1893,6 @@
 pm_build (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar *target;
 	
 	g_return_if_fail (plugin->pm_current_filename != NULL);
 	
@@ -1934,11 +1900,9 @@
 		dir = g_strdup (plugin->pm_current_filename);
 	else
 		dir = g_path_get_dirname (plugin->pm_current_filename);
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, BUILD),
-			   TRUE, NULL);
-	g_free (target);
+
+	build_build_file_or_dir (plugin, dir, NULL, NULL, NULL);
+
 	g_free (dir);
 }
 
@@ -1946,25 +1910,16 @@
 pm_install (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar *target;
-	gchar* root; 
-	gchar* command; 
 	
 	g_return_if_fail (plugin->pm_current_filename != NULL);
 	
-	root = get_root_install_command(plugin);
-	command = g_strdup_printf ("%s %s", root,
-							   CHOOSE_COMMAND (plugin, INSTALL));
-	g_free(root);
-	
 	if (g_file_test (plugin->pm_current_filename, G_FILE_TEST_IS_DIR))
 		dir = g_strdup (plugin->pm_current_filename);
 	else
 		dir = g_path_get_dirname (plugin->pm_current_filename);
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, target, command, TRUE, NULL);
-	g_free(command);
-	g_free (target);
+	
+	build_install_dir (plugin, dir, NULL);
+	
 	g_free (dir);
 }
 
@@ -1972,7 +1927,6 @@
 pm_clean (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
 	gchar *dir;
-	gchar *target;
 	
 	g_return_if_fail (plugin->pm_current_filename != NULL);
 	
@@ -1980,14 +1934,13 @@
 		dir = g_strdup (plugin->pm_current_filename);
 	else
 		dir = g_path_get_dirname (plugin->pm_current_filename);
-	target = target_from_source (plugin, dir);
-	build_execute_command (plugin, target,
-			   CHOOSE_COMMAND (plugin, CLEAN),
-			   FALSE, NULL);
+	
+	build_clean_dir (plugin, dir, NULL);
+	
 	g_free (dir);
-	g_free (target);
 }
 
+/* Message view context menu */
 static void
 mv_cancel (GtkAction *action, BasicAutotoolsPlugin *plugin)
 {
@@ -2013,14 +1966,11 @@
 				context = (BuildContext *)node->data;
 				if (context->message_view == view)
 				{
-					if (context->launcher != NULL)
-					{
-						anjuta_launcher_signal (context->launcher, SIGTERM);
-					}
+					build_context_cancel (context);
 					return;
 				}
 			}
-		}	
+		}
 	}	
 }
 
@@ -2034,55 +1984,55 @@
 		"ActionBuildBuildProject", NULL,
 		N_("_Build Project"), "<shift>F11",
 		N_("Build whole project"),
-		G_CALLBACK (build_build_project)
+		G_CALLBACK (on_build_project)
 	},
 	{
 		"ActionBuildInstallProject", NULL,
 		N_("_Install Project"), NULL,
 		N_("Install whole project"),
-		G_CALLBACK (build_install_project)
+		G_CALLBACK (on_install_project)
 	},
 	{
 		"ActionBuildCleanProject", NULL,
 		N_("_Clean Project"), NULL,
 		N_("Clean whole project"),
-		G_CALLBACK (build_clean_project)
+		G_CALLBACK (on_clean_project)
 	},
 	{
 		"ActionBuildConfigure", NULL,
 		N_("C_onfigure Project..."), NULL,
 		N_("Configure project"),
-		G_CALLBACK (build_configure_project)
+		G_CALLBACK (on_configure_project)
 	},
 	{
 		"ActionBuildDistribution", NULL,
 		N_("Build _Tarball"), NULL,
 		N_("Build project tarball distribution"),
-		G_CALLBACK (build_distribution_project)
+		G_CALLBACK (on_build_tarball)
 	},
 	{
 		"ActionBuildBuildModule", GTK_STOCK_EXECUTE,
 		N_("_Build Module"), "F11",
 		N_("Build module associated with current file"),
-		G_CALLBACK (build_build_module)
+		G_CALLBACK (on_build_module)
 	},
 	{
 		"ActionBuildInstallModule", NULL,
 		N_("_Install Module"), NULL,
 		N_("Install module associated with current file"),
-		G_CALLBACK (build_install_module)
+		G_CALLBACK (on_install_module)
 	},
 	{
 		"ActionBuildCleanModule", NULL,
 		N_("_Clean Module"), NULL,
 		N_("Clean module associated with current file"),
-		G_CALLBACK (build_clean_module)
+		G_CALLBACK (on_clean_module)
 	},
 	{
 		"ActionBuildCompileFile", GTK_STOCK_CONVERT,
 		N_("Co_mpile File"), "F9",
 		N_("Compile current editor file"),
-		G_CALLBACK (build_compile_file)
+		G_CALLBACK (on_compile_file)
 	},
 	{
 		"ActionBuildSelectConfiguration", NULL,
@@ -2094,7 +2044,7 @@
 		"ActionBuildRemoveConfiguration", NULL,
 		N_("Remove Configuration"), NULL,
 		N_("Clean project (distclean) and remove configuration directory if possible"),
-		G_CALLBACK (build_distclean_project)
+		G_CALLBACK (on_distclean_project)
 	}
 };
 
@@ -2257,7 +2207,7 @@
 		gchar *build_dirname;
 
 		dirname = g_dirname (bb_plugin->current_editor_filename);
-		build_dirname = target_from_source (bb_plugin, dirname);
+		build_dirname = build_dir_from_source (bb_plugin, dirname);
 		
 		module = escape_label (g_basename (dirname));
 		filename = escape_label (g_basename (bb_plugin->current_editor_filename));
@@ -2339,6 +2289,34 @@
 }
 
 static void
+update_configuration_menu (BasicAutotoolsPlugin *plugin)
+{
+	GtkWidget *submenu = NULL;
+	BuildConfiguration *cfg;
+	BuildConfiguration *selected;
+	GSList *group = NULL;
+	
+	submenu = gtk_menu_new ();
+	selected = build_configuration_list_get_selected (plugin->configurations);
+	for (cfg = build_configuration_list_get_first (plugin->configurations); cfg != NULL; cfg = build_configuration_next (cfg))
+	{
+		GtkWidget *item;
+		
+		item = gtk_radio_menu_item_new_with_mnemonic (group, build_configuration_get_translated_name (cfg));
+		group = gtk_radio_menu_item_get_group (GTK_RADIO_MENU_ITEM (item));
+		if (cfg == selected)
+		{
+			gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), TRUE);
+		}
+		g_object_set_data_full (G_OBJECT (item), "untranslated_name", g_strdup (build_configuration_get_name (cfg)), g_free);
+		g_signal_connect (G_OBJECT (item), "toggled", G_CALLBACK (on_select_configuration), plugin);
+		gtk_menu_shell_append (GTK_MENU_SHELL (submenu), item);
+	}
+	gtk_menu_item_set_submenu (GTK_MENU_ITEM (plugin->configuration_menu), submenu);
+	gtk_widget_show_all (submenu);
+}
+
+static void
 on_session_save (AnjutaShell *shell, AnjutaSessionPhase phase,
 				 AnjutaSession *session, BasicAutotoolsPlugin *plugin)
 {
@@ -2909,15 +2887,9 @@
 	klass->finalize = finalize;
 }
 
-#if 0
-static void
-ibuildable_compile (IAnjutaBuildable *manager, const gchar * filename,
-					GError **err)
-{
-	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	build_compile_file_real (plugin, filename);
-}
-#endif
+
+/* IAnjutaBuildable implementation
+ *---------------------------------------------------------------------------*/
 
 static void
 ibuildable_set_command (IAnjutaBuildable *manager,
@@ -2957,9 +2929,8 @@
 				  GError **err)
 {
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	build_execute_command (plugin, directory,
-			   CHOOSE_COMMAND (plugin, BUILD),
-			   TRUE, NULL);
+	
+	build_build_file_or_dir (plugin, directory, NULL, NULL, err);
 }
 
 static void
@@ -2967,9 +2938,8 @@
 				  GError **err)
 {
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	build_execute_command (plugin, directory,
-			   CHOOSE_COMMAND (plugin, CLEAN),
-			   FALSE, NULL);
+	
+	build_clean_dir (plugin, directory, err);
 }
 
 static void
@@ -2977,12 +2947,8 @@
 					GError **err)
 {
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	gchar* root = get_root_install_command(plugin);
-	gchar* command = g_strdup_printf ("%s %s", root,
-									  CHOOSE_COMMAND (plugin, INSTALL));
-	g_free(root);
-	build_execute_command (plugin, directory, command, TRUE, NULL);
-	g_free(command);
+	
+	build_install_dir (plugin, directory, err);
 }
 
 static void
@@ -2990,9 +2956,8 @@
 					  GError **err)
 {
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	build_execute_command (plugin, directory,
-			   CHOOSE_COMMAND (plugin, CONFIGURE),
-			   TRUE, NULL);
+	
+	build_configure_dir (plugin, directory, NULL);
 }
 
 static void
@@ -3000,19 +2965,8 @@
 					 GError **err)
 {
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (manager);
-	if (directory_has_file (plugin->project_root_dir, "autogen.sh"))
-	{
-		build_execute_command (plugin, directory,
-				   CHOOSE_COMMAND (plugin, GENERATE),
-				   FALSE, NULL);
-	}
-	else
-	{
-		/* FIXME: get override command for this too */
-		build_execute_command (plugin, directory,
-				   "autoreconf -i --force", 
-				   FALSE, NULL);
-	}
+
+	build_generate_dir (plugin, directory, NULL);
 }
 
 static void
@@ -3041,6 +2995,10 @@
 	iface->execute = ibuildable_execute;
 }
 
+
+/* IAnjutaFile implementation
+ *---------------------------------------------------------------------------*/
+
 static void
 ifile_open (IAnjutaFile *manager, GFile* file,
 			GError **err)
@@ -3076,23 +3034,16 @@
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (builder);
 	BuildContext *context;
 	gchar *filename;
-	gchar *dirname;
-	gchar **argv;
-	gchar **args = g_new0 (gchar *, 2);
-	GFile* file = g_file_new_for_uri (uri);
-	
+	GFile* file;
+
+	file = g_file_new_for_uri (uri);
 	filename = g_file_get_path (file);
 	g_object_unref (file);
 	if (filename == NULL) return NULL;
-	args[0] = g_path_get_basename (filename);
-	dirname = g_path_get_dirname (filename);
-	g_free (filename);	
-	argv = build_argv_command (NULL, CHOOSE_COMMAND (plugin, IS_BUILT), args);
-	
-	context = build_execute_command_full (plugin, dirname, argv,
-			       			TRUE, FALSE, NULL,
-			       			callback, user_data, err);
-	g_free (dirname);
+	
+	context = build_is_file_built (plugin, filename, callback, user_data, err);
+	
+	g_free (filename);
 	
 	return (IAnjutaBuilderHandle)context;
 }
@@ -3105,23 +3056,16 @@
 	BasicAutotoolsPlugin *plugin = ANJUTA_PLUGIN_BASIC_AUTOTOOLS (builder);
 	BuildContext *context;
 	gchar *filename;
-	gchar *dirname;
-	gchar **argv;
-	gchar **args = g_new0 (gchar *, 2);
-	GFile* file = g_file_new_for_uri (uri);
-
+	GFile* file;
+	
+	file = g_file_new_for_uri (uri);
 	filename = g_file_get_path (file);
 	g_object_unref (file);
 	if (filename == NULL) return NULL;
-	args[0] = g_path_get_basename (filename);
-	dirname = g_path_get_dirname (filename);
-	g_free (filename);	
-	argv = build_argv_command (NULL, CHOOSE_COMMAND (plugin, BUILD), args);
-
-	context = build_execute_command_full (plugin, dirname, argv,
-		       				TRUE, TRUE, NULL,
-						callback, user_data, err);
-	g_free (dirname);
+	
+	context = build_build_file_or_dir (plugin, filename, callback, user_data, err);
+	
+	g_free (filename);
 	
 	return (IAnjutaBuilderHandle)context;
 }

Copied: trunk/plugins/build-basic-autotools/plugin.h (from r4103, /trunk/plugins/build-basic-autotools/build-basic-autotools.h)
==============================================================================
--- /trunk/plugins/build-basic-autotools/build-basic-autotools.h	(original)
+++ trunk/plugins/build-basic-autotools/plugin.h	Sun Aug  3 09:26:34 2008
@@ -1,6 +1,6 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
 /*
-    build-basic-autotools.h
+    plugin.h
     Copyright (C) 2000 Naba Kumar
 
     This program is free software; you can redistribute it and/or modify
@@ -18,8 +18,8 @@
     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
-#ifndef __BUILD_BASIC_AUTOTOOLS_H__
-#define __BUILD_BASIC_AUTOTOOLS_H__
+#ifndef __PLUGIN_H__
+#define __PLUGIN_H__
 
 #include <libanjuta/anjuta-plugin.h>
 #include <libanjuta/interfaces/ianjuta-buildable.h>

Added: trunk/plugins/build-basic-autotools/program.c
==============================================================================
--- (empty file)
+++ trunk/plugins/build-basic-autotools/program.c	Sun Aug  3 09:26:34 2008
@@ -0,0 +1,387 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+    program.c
+    Copyright (C) 2008 SÃbastien Granjoux
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+/*
+ * This objects is used to keep all data useful to run a program:
+ *	- working directory
+ *  - program name
+ *  - program arguments
+ *  - program environment variables
+ *  - a callback when program end
+ *
+ * It is just a container, so it is not able to run the program by itself, but
+ * all data are available.
+ * It includes some functions to modify the program data, take care of
+ * memory allocation.
+ *---------------------------------------------------------------------------*/
+
+
+#include "program.h"
+
+#include <glib/gi18n.h>
+
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+
+/* Helper functions
+ *---------------------------------------------------------------------------*/
+
+static gchar*
+build_shell_expand (const gchar *input)
+{
+	GString* expand;
+	
+	if (input == NULL) return NULL;
+	
+	expand = g_string_sized_new (strlen (input));
+	
+	for (; *input != '\0'; input++)
+	{
+		switch (*input)
+		{
+			case '$':
+			{
+				/* Variable expansion */
+				const gchar *end;
+				gint var_name_len;
+
+				end = input + 1;
+				while (isalnum (*end) || (*end == '_')) end++;
+				var_name_len = end - input - 1;
+				if (var_name_len > 0)
+				{
+					const gchar *value;
+					
+					g_string_append_len (expand, input + 1, var_name_len);
+					value = g_getenv (expand->str + expand->len - var_name_len);
+					g_string_truncate (expand, expand->len - var_name_len);
+					g_string_append (expand, value);
+					input = end - 1;
+					continue;
+				}
+				break;
+			}
+			case '~':
+			{
+				/* User home directory expansion */
+				if (isspace(input[1]) || (input[1] == G_DIR_SEPARATOR) || (input[1] == '\0'))
+				{
+					g_string_append (expand, g_get_home_dir());
+					continue;
+				}
+				break;
+			}
+			default:
+				break;
+		}
+		g_string_append_c (expand, *input);
+	}
+	
+	return g_string_free (expand, FALSE);
+}
+
+static gchar **
+build_strv_insert_before (gchar ***pstrv, gint pos)
+{
+	gsize count;
+	gchar **strv = *pstrv;
+	
+	g_return_val_if_fail (pos >= 0, FALSE);
+	
+	if (strv == NULL)
+	{
+		/* First argument, allocate memory */
+		strv = g_new0 (gchar *, 2);
+		pos = 0;
+		count = 1;
+	}
+	else
+	{
+		gchar **new_strv;
+		
+		/* Increase array */
+		count = g_strv_length (strv);
+
+		new_strv = g_new (gchar *, count + 2);
+		if (pos < count)
+			memcpy (&new_strv[pos + 1], &strv[pos], sizeof (gchar *) * (count - pos));
+		else
+			pos = count;
+		if (pos > 0) memcpy(new_strv, strv, (sizeof (gchar *)) * pos);
+		g_free (strv);
+		strv = new_strv;
+		count++;
+	}
+	
+	strv[count] = NULL;
+	*pstrv = strv;
+	
+	return &strv[pos];
+}
+
+static gboolean
+build_strv_remove (gchar **strv, gint pos)
+{
+	gsize count = g_strv_length (strv);
+	
+	g_return_val_if_fail (pos >= 0, FALSE);
+
+	if (pos >= count)
+	{
+		/* Argument does not exist */
+		
+		return FALSE;
+	}
+	else
+	{
+		g_free (strv[pos]);
+		memcpy (&strv[pos], &strv[pos + 1], sizeof(gchar *) * (count - pos));
+		
+		return TRUE;
+	}
+}
+
+/* Private functions
+ *---------------------------------------------------------------------------*/
+
+static gint
+build_program_find_env (BuildProgram *prog, const gchar *name)
+{
+	if (prog->envp != NULL)
+	{
+		gint i;
+		gchar **envp = prog->envp;
+		gsize len = strlen (name);
+		
+		/* Look for an already existing variable */
+		for (i = 0; envp[i] != NULL; i++)
+		{
+			if ((envp[i][len] == '=') && (strncmp (envp[i], name, len) == 0))
+			{
+				return i;
+			}
+		}
+	}
+	
+	return -1;
+}
+
+/* Public functions
+ *---------------------------------------------------------------------------*/
+
+gboolean
+build_program_set_command (BuildProgram *prog, const gchar *command)
+{
+	gboolean ok;
+	gchar **arg;
+	
+	g_return_val_if_fail (prog != NULL, FALSE);
+
+	if (prog->argv) g_strfreev (prog->argv);
+	
+	/* Store args and environment variables as string array */
+	ok = g_shell_parse_argv (command, NULL, &prog->argv, NULL) ? TRUE : FALSE;
+	for (arg = prog->argv; *arg != NULL; arg++)
+	{
+		gchar *new_arg;
+		
+		new_arg = build_shell_expand (*arg);
+		g_free (*arg);
+		*arg = new_arg;
+	}
+	
+	return TRUE;
+}
+
+const gchar *
+build_program_get_basename (BuildProgram *prog)
+{
+	const gchar *base;
+	
+	if ((prog->argv == NULL) || (prog->argv[0] == NULL)) return NULL;
+
+	base = strrchr (prog->argv[0], G_DIR_SEPARATOR);
+	
+	return base == NULL ? prog->argv[0] : base;
+}
+
+
+void
+build_program_set_working_directory (BuildProgram *prog, const gchar *directory)
+{
+	g_free (prog->work_dir);
+	
+	prog->work_dir = g_strdup (directory);
+}
+
+
+gboolean
+build_program_insert_arg (BuildProgram *prog, gint pos, const gchar *arg)
+{
+	gchar **parg;
+	
+	parg = build_strv_insert_before (&prog->argv, pos);
+	*parg = build_shell_expand (arg);
+	
+	return TRUE;
+}
+
+gboolean
+build_program_replace_arg (BuildProgram *prog, gint pos, const gchar *arg)
+{
+	if (pos >= g_strv_length (prog->argv))
+	{
+		return build_program_insert_arg (prog, pos, arg);
+	}
+	else
+	{
+		g_free (prog->argv[pos]);
+		prog->argv[pos] = build_shell_expand (arg);
+	}
+	
+	return TRUE;
+}
+
+gboolean
+build_program_remove_arg (BuildProgram *prog, gint pos)
+{
+	return build_strv_remove (prog->argv, pos);
+}
+
+
+
+gboolean
+build_program_add_env (BuildProgram *prog, const gchar *name, const gchar *value)
+{
+	gint found = build_program_find_env (prog, name);
+	gchar *name_and_value = g_strconcat (name, "=", value, NULL);
+	
+	if (found == -1)
+	{
+		/* Append variable */
+		*build_strv_insert_before (&prog->envp, G_MAXSSIZE) = name_and_value;
+	}
+	else
+	{
+		g_free (prog->envp[found]);
+		prog->envp[found] = name_and_value;
+	}		
+	return TRUE;
+}
+
+gboolean
+build_program_remove_env (BuildProgram *prog, const gchar *name)
+{
+	gint found = build_program_find_env (prog, name);
+	if (found == -1)
+	{
+		/* Variable not found */
+		return FALSE;
+	}
+	else
+	{
+		return build_strv_remove (prog->envp, found);
+	}
+}
+
+void
+build_program_override (BuildProgram *prog, IAnjutaEnvironment *env)
+{
+	gboolean ok;
+	
+	if (env == NULL) return;
+	
+	ok = ianjuta_environment_override (env, &prog->work_dir, &prog->argv, &prog->envp, NULL);
+}	
+
+void
+build_program_set_callback (BuildProgram *prog, IAnjutaBuilderCallback callback, gpointer user_data)
+{
+	prog->callback = callback;
+	prog->user_data = user_data;
+}
+
+void build_program_callback (BuildProgram *prog, GObject *sender, IAnjutaBuilderHandle handle, GError *err)
+{
+	if (prog->callback != NULL)
+	{
+		prog->callback (sender, handle, err, prog->user_data);
+		prog->callback = NULL;
+	}
+}
+
+
+/* Constructor & Destructor
+ *---------------------------------------------------------------------------*/
+
+BuildProgram* 
+build_program_new (void)
+{
+	BuildProgram *prog ;
+	
+	prog = g_new0 (BuildProgram, 1);
+	
+	return prog;
+}
+
+BuildProgram* 
+build_program_new_with_command (const gchar *directory, const gchar *command,...)
+{
+	BuildProgram *prog;
+	gchar *full_command;
+	va_list args;
+
+	prog = build_program_new ();
+	if (prog == NULL) return NULL;
+
+	build_program_set_working_directory (prog, directory);
+	
+	va_start (args, command);
+	full_command = g_strdup_vprintf (command, args);
+	va_end (args);
+	build_program_set_command (prog, full_command);	
+	g_free (full_command);
+	
+	return prog;
+}
+
+void
+build_program_free (BuildProgram *prog)
+{
+	if (prog->callback != NULL)
+	{
+		GError *err;
+		
+		/* Emit command-finished signal abort */
+		err = g_error_new_literal (ianjuta_builder_error_quark (),
+								   IANJUTA_BUILDER_ABORTED,
+								   _("Command aborted"));
+		prog->callback (NULL, NULL, err, prog->user_data);
+		g_error_free (err);		
+	}
+	g_free (prog->work_dir);
+	if (prog->argv) g_strfreev (prog->argv);
+	if (prog->envp) g_strfreev (prog->envp);
+	g_free (prog);
+}
+
+

Added: trunk/plugins/build-basic-autotools/program.h
==============================================================================
--- (empty file)
+++ trunk/plugins/build-basic-autotools/program.h	Sun Aug  3 09:26:34 2008
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+/*
+    program.h
+    Copyright (C) 2008 SÃbastien Granjoux
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+ 
+#ifndef PROGRAM_H
+#define PROGRAM_H
+
+#include <glib.h>
+#include <libanjuta/interfaces/ianjuta-environment.h>
+#include <libanjuta/interfaces/ianjuta-builder.h>
+
+typedef struct _BuildProgram BuildProgram;
+
+struct _BuildProgram
+{
+	gchar *work_dir;
+	gchar **argv;
+	gchar **envp;
+	
+	IAnjutaBuilderCallback callback;
+	gpointer user_data;
+};
+
+BuildProgram* build_program_new (void);
+BuildProgram* build_program_new_with_command (const gchar *directory, const gchar *command,...);
+void build_program_free (BuildProgram *proc);
+
+gboolean build_program_set_command (BuildProgram *proc, const gchar *command);
+const gchar *build_program_get_basename (BuildProgram *proc);
+
+void build_program_set_working_directory (BuildProgram *proc, const gchar *directory);
+
+gboolean build_program_insert_arg (BuildProgram *proc, gint pos, const gchar *arg);
+gboolean build_program_replace_arg (BuildProgram *proc, gint pos, const gchar *arg);
+gboolean build_program_remove_arg (BuildProgram *proc, gint pos);
+
+gboolean build_program_add_env (BuildProgram *proc, const gchar *name, const gchar *value);
+gboolean build_program_remove_env (BuildProgram *proc, const gchar *name);
+
+void build_program_override (BuildProgram *proc, IAnjutaEnvironment *env);
+
+void build_program_set_callback (BuildProgram *proc, IAnjutaBuilderCallback callback, gpointer user_data);
+void build_program_callback (BuildProgram *proc, GObject *sender, IAnjutaBuilderHandle handle, GError *err); 
+
+#endif /* PROGRAM_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]