Added byline
[anjuta.git] / plugins / am-project / am-project.c
blob47abaf7d3dd09a075013fdbf62fc532231c11c39
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
2 /* am-project.c
4 * Copyright (C) 2009 Sébastien Granjoux
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public
17 * License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
27 #include "am-project.h"
29 #include "am-project-private.h"
30 #include "amp-node.h"
31 #include "amp-module.h"
32 #include "amp-package.h"
33 #include "amp-group.h"
34 #include "amp-target.h"
35 #include "amp-source.h"
36 #include "amp-object.h"
37 #include "command-queue.h"
39 #include <libanjuta/interfaces/ianjuta-project.h>
40 #include <libanjuta/anjuta-debug.h>
41 #include <libanjuta/anjuta-utils.h>
42 #include <libanjuta/anjuta-pkg-config.h>
44 #include <string.h>
45 #include <memory.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <ctype.h>
50 #include <sys/types.h>
51 #include <signal.h>
52 #include <glib/gi18n.h>
53 #include <gio/gio.h>
54 #include <glib.h>
56 #include "ac-scanner.h"
57 #include "ac-writer.h"
58 #include "am-scanner.h"
59 #include "am-writer.h"
60 //#include "am-config.h"
61 #include "am-properties.h"
64 #define UNIMPLEMENTED G_STMT_START { g_warning (G_STRLOC": unimplemented"); } G_STMT_END
66 /* Constant strings for parsing perl script error output */
67 #define ERROR_PREFIX "ERROR("
68 #define WARNING_PREFIX "WARNING("
69 #define MESSAGE_DELIMITER ": "
71 const gchar *valid_am_makefiles[] = {"GNUmakefile.am", "makefile.am", "Makefile.am", NULL};
74 #define STR_REPLACE(target, source) \
75 { g_free (target); target = source == NULL ? NULL : g_strdup (source);}
78 typedef struct _AmpConfigFile AmpConfigFile;
80 struct _AmpConfigFile {
81 GFile *file;
82 AnjutaToken *token;
85 /* Node types
86 *---------------------------------------------------------------------------*/
88 static AmpNodeInfo AmpNodeInformations[] = {
89 {{ANJUTA_PROJECT_GROUP | ANJUTA_PROJECT_ROOT_GROUP,
90 N_("Root"),
91 "text/plain",
92 "autotools-project-root-edit"},
93 ANJUTA_TOKEN_NONE,
94 NULL,
95 NULL},
97 {{ANJUTA_PROJECT_GROUP,
98 N_("Group"),
99 "text/plain",
100 "autotools-project-folder-edit"},
101 ANJUTA_TOKEN_NONE,
102 NULL,
103 NULL},
105 {{ANJUTA_PROJECT_SOURCE,
106 N_("Source"),
107 "text/plain",
108 NULL},
109 ANJUTA_TOKEN_NONE,
110 NULL,
111 NULL},
113 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_UNKNOWN | ANJUTA_PROJECT_READ_ONLY,
114 /* Translator: Unknown here is a target type, if not unknown it can
115 * be a program or a shared library by example */
116 N_("Unknown"),
117 "text/plain",
118 "autotools-project-target-edit"},
119 ANJUTA_TOKEN_NONE,
120 NULL,
121 NULL},
123 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PRIMARY | ANJUTA_PROJECT_SHAREDLIB,
124 N_("Shared Library (Libtool)"),
125 "application/x-sharedlib",
126 "autotools-project-target-edit"},
127 AM_TOKEN__LTLIBRARIES,
128 "LTLIBRARIES",
129 "lib"},
131 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PRIMARY | ANJUTA_PROJECT_LT_MODULE,
132 N_("Module (Libtool)"),
133 "application/x-sharedlib",
134 "autotools-project-target-edit"},
135 AM_TOKEN__LTLIBRARIES,
136 "LTLIBRARIES",
137 "lib"},
139 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PRIMARY | ANJUTA_PROJECT_STATICLIB,
140 N_("Static Library (Libtool)"),
141 "application/x-archive",
142 "autotools-project-target-edit"},
143 AM_TOKEN__LIBRARIES,
144 "LIBRARIES",
145 "lib"},
147 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PRIMARY | ANJUTA_PROJECT_PROGRAM | ANJUTA_PROJECT_EXECUTABLE,
148 N_("Program"),
149 "application/x-executable",
150 "autotools-project-target-edit"},
151 AM_TOKEN__PROGRAMS,
152 "PROGRAMS",
153 "bin"},
155 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_PYTHON,
156 N_("Python Module"),
157 "application/x-python",
158 "autotools-project-target-edit"},
159 AM_TOKEN__PYTHON,
160 "PYTHON",
161 "python"},
163 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_JAVA,
164 N_("Java Module"),
165 "application/x-java",
166 "autotools-project-target-edit"},
167 AM_TOKEN__JAVA,
168 "JAVA",
169 "java"},
171 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_LISP,
172 N_("Lisp Module"),
173 "text/plain",
174 "autotools-project-target-edit"},
175 AM_TOKEN__LISP,
176 "LISP",
177 "lisp"},
179 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_HEADER,
180 N_("Header Files"),
181 "text/x-chdr",
182 "autotools-project-target-edit"},
183 AM_TOKEN__HEADERS,
184 "HEADERS",
185 "include"},
187 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_MAN,
188 N_("Man Documentation"),
189 "text/x-troff-man",
190 "autotools-project-target-edit"},
191 AM_TOKEN__MANS,
192 "MANS",
193 "man"},
195 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_INFO,
196 N_("Info Documentation"),
197 "application/x-tex-info",
198 "autotools-project-target-edit"},
199 AM_TOKEN__TEXINFOS,
200 "TEXINFOS",
201 "info"},
203 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_DATA,
204 N_("Miscellaneous Data"),
205 "application/octet-stream",
206 "autotools-project-target-edit"},
207 AM_TOKEN__DATA,
208 "DATA",
209 "data"},
211 {{ANJUTA_PROJECT_TARGET | ANJUTA_PROJECT_SCRIPT,
212 N_("Script"),
213 "text/x-shellscript",
214 "autotools-project-target-edit"},
215 AM_TOKEN__SCRIPTS,
216 "SCRIPTS",
217 "bin"},
219 {{ANJUTA_PROJECT_MODULE,
220 N_("Module"),
222 NULL},
223 ANJUTA_TOKEN_NONE,
224 NULL,
225 NULL},
227 {{ANJUTA_PROJECT_PACKAGE,
228 N_("Package"),
230 NULL},
231 ANJUTA_TOKEN_NONE,
232 NULL,
233 NULL},
235 {{ANJUTA_PROJECT_UNKNOWN,
236 NULL,
237 NULL,
238 NULL},
239 ANJUTA_TOKEN_NONE,
240 NULL,
241 NULL}
244 /* Types
245 *---------------------------------------------------------------------------*/
247 static void iproject_iface_init(IAnjutaProjectIface* iface);
249 G_DEFINE_DYNAMIC_TYPE_EXTENDED (AmpProject,
250 amp_project,
251 AMP_TYPE_ROOT_NODE,
253 G_IMPLEMENT_INTERFACE_DYNAMIC (IANJUTA_TYPE_PROJECT,
254 iproject_iface_init));
258 /* Properties
259 *---------------------------------------------------------------------------*/
262 /* ----- Standard GObject types and variables ----- */
264 enum {
265 PROP_0,
266 PROP_PROJECT_DIR
269 static GObject *parent_class;
271 /* Helper functions
272 *---------------------------------------------------------------------------*/
274 /* Work even if file is not a descendant of parent */
275 gchar*
276 get_relative_path (GFile *parent, GFile *file)
278 gchar *relative;
280 relative = g_file_get_relative_path (parent, file);
281 if (relative == NULL)
283 if (g_file_equal (parent, file))
285 relative = g_strdup (".");
287 else
289 GFile *grand_parent = g_file_get_parent (parent);
290 gint level;
291 gchar *grand_relative;
292 gchar *ptr;
293 gsize len;
296 for (level = 1; !g_file_has_prefix (file, grand_parent); level++)
298 GFile *next = g_file_get_parent (grand_parent);
300 g_object_unref (grand_parent);
301 grand_parent = next;
304 grand_relative = g_file_get_relative_path (grand_parent, file);
305 g_object_unref (grand_parent);
307 len = strlen (grand_relative);
308 relative = g_new (gchar, len + level * 3 + 1);
309 ptr = relative;
310 for (; level; level--)
312 memcpy(ptr, ".." G_DIR_SEPARATOR_S, 3);
313 ptr += 3;
315 memcpy (ptr, grand_relative, len + 1);
316 g_free (grand_relative);
320 return relative;
323 GFileType
324 file_type (GFile *file, const gchar *filename)
326 GFile *child;
327 GFileInfo *info;
328 GFileType type;
330 child = filename != NULL ? g_file_get_child (file, filename) : g_object_ref (file);
332 info = g_file_query_info (child,
333 G_FILE_ATTRIBUTE_STANDARD_TYPE,
334 G_FILE_QUERY_INFO_NONE,
335 NULL,
336 NULL);
337 if (info != NULL)
339 type = g_file_info_get_file_type (info);
340 g_object_unref (info);
342 else
344 type = G_FILE_TYPE_UNKNOWN;
347 g_object_unref (child);
349 return type;
352 /* Automake parsing function
353 *---------------------------------------------------------------------------*/
355 /* Remove invalid character according to automake rules */
356 gchar*
357 canonicalize_automake_variable (const gchar *name)
359 gchar *canon_name = g_strdup (name);
360 gchar *ptr;
362 for (ptr = canon_name; *ptr != '\0'; ptr++)
364 if (!g_ascii_isalnum (*ptr) && (*ptr != '@'))
366 *ptr = '_';
370 return canon_name;
373 gboolean
374 split_automake_variable (gchar *name, gint *flags, gchar **module, gchar **primary)
376 gboolean res = FALSE;
377 GRegex *regex;
378 GMatchInfo *match_info;
379 gint start_pos;
380 gint end_pos;
382 regex = g_regex_new ("(nobase_|notrans_)?"
383 "(dist_|nodist_)?"
384 "(noinst_|check_|man_|man[0-9al]_)?"
385 "(.*_)?"
386 "([^_]+)",
387 G_REGEX_ANCHORED,
388 G_REGEX_MATCH_ANCHORED,
389 NULL);
391 if (!g_regex_match (regex, name, G_REGEX_MATCH_ANCHORED, &match_info))
392 goto out;
394 if (flags)
396 *flags = 0;
397 g_match_info_fetch_pos (match_info, 1, &start_pos, &end_pos);
398 if (start_pos >= 0)
400 if (*(name + start_pos + 2) == 'b') *flags |= AM_TARGET_NOBASE;
401 if (*(name + start_pos + 2) == 't') *flags |= AM_TARGET_NOTRANS;
404 g_match_info_fetch_pos (match_info, 2, &start_pos, &end_pos);
405 if (start_pos >= 0)
407 if (*(name + start_pos) == 'd') *flags |= AM_TARGET_DIST;
408 if (*(name + start_pos) == 'n') *flags |= AM_TARGET_NODIST;
411 g_match_info_fetch_pos (match_info, 3, &start_pos, &end_pos);
412 if (start_pos >= 0)
414 if (*(name + start_pos) == 'n') *flags |= AM_TARGET_NOINST;
415 if (*(name + start_pos) == 'c') *flags |= AM_TARGET_CHECK;
416 if (*(name + start_pos) == 'm')
418 gchar section = *(name + end_pos - 1);
419 *flags |= AM_TARGET_MAN;
420 if (section != 'n') *flags |= (section & 0x1F) << 7;
425 if (module)
427 g_match_info_fetch_pos (match_info, 4, &start_pos, &end_pos);
428 if (start_pos >= 0)
430 *module = name + start_pos;
431 *(name + end_pos - 1) = '\0';
433 else
435 *module = NULL;
439 if (primary)
441 g_match_info_fetch_pos (match_info, 5, &start_pos, &end_pos);
442 if (start_pos >= 0)
444 *primary = name + start_pos;
446 else
448 *primary = NULL;
452 res = TRUE;
454 out:
455 g_match_info_unref (match_info);
456 g_regex_unref (regex);
458 return res;
461 static gchar*
462 ac_init_default_tarname (const gchar *name)
464 gchar *tarname;
466 if (name == NULL) return NULL;
468 /* Remove GNU prefix */
469 if (strncmp (name, "GNU ", 4) == 0) name += 4;
471 tarname = g_ascii_strdown (name, -1);
472 g_strcanon (tarname, "abcdefghijklmnopqrstuvwxyz0123456789", '-');
474 return tarname;
477 /* Config file objects
478 *---------------------------------------------------------------------------*/
480 static AmpConfigFile*
481 amp_config_file_new (const gchar *pathname, GFile *project_root, AnjutaToken *token)
483 AmpConfigFile *config;
485 g_return_val_if_fail ((pathname != NULL) && (project_root != NULL), NULL);
487 config = g_slice_new0(AmpConfigFile);
488 config->file = g_file_resolve_relative_path (project_root, pathname);
489 config->token = token;
491 return config;
494 static void
495 amp_config_file_free (AmpConfigFile *config)
497 if (config)
499 g_object_unref (config->file);
500 g_slice_free (AmpConfigFile, config);
504 static void
505 amp_project_clear (AmpProject *project)
507 if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
508 project->configure_file = NULL;
509 if (project->configure_token) anjuta_token_free (project->configure_token);
510 project->configure_token = NULL;
513 static void
514 on_project_monitor_changed (GFileMonitor *monitor,
515 GFile *file,
516 GFile *other_file,
517 GFileMonitorEvent event_type,
518 gpointer data)
520 AmpProject *project = AMP_PROJECT (data);
522 switch (event_type) {
523 case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
524 case G_FILE_MONITOR_EVENT_CHANGED:
525 case G_FILE_MONITOR_EVENT_DELETED:
526 /* project can be NULL, if the node is dummy node because the
527 * original one is reloaded. */
528 g_signal_emit_by_name (G_OBJECT (project), "file-changed", data);
529 break;
530 default:
531 break;
535 AnjutaTokenFile*
536 amp_project_set_configure (AmpProject *project, GFile *configure)
538 if (project->configure != NULL) g_object_unref (project->configure);
539 if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
540 if (project->monitor) g_object_unref (project->monitor);
541 if (configure != NULL)
543 project->configure_file = anjuta_token_file_new (configure);
544 project->configure = g_object_ref (configure);
546 project->monitor = g_file_monitor_file (configure,
547 G_FILE_MONITOR_NONE,
548 NULL,
549 NULL);
550 if (project->monitor != NULL)
552 g_signal_connect (G_OBJECT (project->monitor),
553 "changed",
554 G_CALLBACK (on_project_monitor_changed),
555 project);
558 else
560 project->configure_file = NULL;
561 project->configure = NULL;
562 project->monitor = NULL;
565 return project->configure_file;
568 gboolean
569 amp_project_update_configure (AmpProject *project, AnjutaToken *token)
571 return anjuta_token_file_update (project->configure_file, token);
574 AnjutaToken*
575 amp_project_get_configure_token (AmpProject *project)
577 return project->configure_token;
580 AnjutaToken *
581 amp_project_get_config_token (AmpProject *project, GFile *file)
583 AmpConfigFile *config;
585 config = g_hash_table_lookup (project->configs, file);
587 return config != NULL ? config->token : NULL;
590 static void
591 remove_config_file (gpointer data, GObject *object)
593 AmpProject *project = (AmpProject *)data;
595 g_return_if_fail (project->files != NULL);
597 project->files = g_list_remove (project->files, object);
600 void
601 amp_project_update_root (AmpProject *project, AmpProject *new_project)
603 GHashTable *hash;
604 GList *list;
605 AnjutaTokenStyle *style;
607 if (project->configure != NULL) g_object_unref (project->configure);
608 if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
609 if (project->monitor) g_object_unref (project->monitor);
611 project->configure = new_project->configure;
612 if (project->configure != NULL)
614 project->monitor = g_file_monitor_file (project->configure,
615 G_FILE_MONITOR_NONE,
616 NULL,
617 NULL);
618 if (project->monitor != NULL)
620 g_signal_connect (G_OBJECT (project->monitor),
621 "changed",
622 G_CALLBACK (on_project_monitor_changed),
623 project);
626 else
628 project->monitor = NULL;
630 new_project->configure = NULL;
631 project->configure_file = new_project->configure_file;
632 new_project->configure_file = NULL;
633 project->configure_token = new_project->configure_token;
634 new_project->configure_token = NULL;
636 hash = project->groups;
637 project->groups = new_project->groups;
638 new_project->groups = hash;
640 list = project->files;
641 project->files = new_project->files;
642 new_project->files = list;
644 for (list = project->files; list != NULL; list = g_list_next (list))
646 GObject *tfile = (GObject *)list->data;
648 g_object_weak_unref (tfile, remove_config_file, new_project);
649 g_object_weak_ref (tfile, remove_config_file, project);
651 for (list = new_project->files; list != NULL; list = g_list_next (list))
653 GObject *tfile = (GObject *)list->data;
655 g_object_weak_unref (tfile, remove_config_file, project);
656 g_object_weak_ref (tfile, remove_config_file, new_project);
659 hash = project->configs;
660 project->configs = new_project->configs;
661 new_project->configs = hash;
664 style = project->ac_space_list;
665 project->ac_space_list = new_project->ac_space_list;
666 new_project->ac_space_list = style;
668 style = project->am_space_list;
669 project->am_space_list = new_project->am_space_list;
670 new_project->am_space_list = style;
672 style = project->arg_list;
673 project->arg_list = new_project->arg_list;
674 new_project->arg_list = style;
676 AMP_NODE_CLASS (parent_class)->update (AMP_NODE (project), AMP_NODE (new_project));
680 /* Target objects
681 *---------------------------------------------------------------------------*/
683 static gboolean
684 find_target (AnjutaProjectNode *node, gpointer data)
686 if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET)
688 if (strcmp (anjuta_project_node_get_name (node), *(gchar **)data) == 0)
690 /* Find target, return node value in pointer */
691 *(AnjutaProjectNode **)data = node;
693 return TRUE;
697 return FALSE;
700 static gboolean
701 find_canonical_target (AnjutaProjectNode *node, gpointer data)
703 if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET)
705 gchar *canon_name = canonicalize_automake_variable (anjuta_project_node_get_name (node));
706 DEBUG_PRINT ("compare canon %s vs %s node %p", canon_name, *(gchar **)data, node);
707 if (strcmp (canon_name, *(gchar **)data) == 0)
709 /* Find target, return node value in pointer */
710 *(AnjutaProjectNode **)data = node;
711 g_free (canon_name);
713 return TRUE;
715 g_free (canon_name);
718 return FALSE;
722 * ---------------- Data structures managment
725 void
726 amp_project_load_properties (AmpProject *project, AnjutaToken *macro, AnjutaToken *args)
728 GList *item;
729 gint type = anjuta_token_get_type (macro);
731 for (item = anjuta_project_node_get_properties_info (ANJUTA_PROJECT_NODE (project)); item != NULL; item = g_list_next (item))
733 AmpPropertyInfo *info = (AmpPropertyInfo *)item->data;
735 if ((info->token_type == type) && (info->flags & AM_PROPERTY_IN_CONFIGURE))
737 AnjutaProjectProperty *new_prop;
739 new_prop = anjuta_project_node_get_property (ANJUTA_PROJECT_NODE (project), info->base.id);
740 if ((new_prop != NULL) && (new_prop->info->default_value != new_prop))
742 anjuta_project_node_remove_property (ANJUTA_PROJECT_NODE (project), new_prop);
743 amp_property_free (new_prop);
745 new_prop = amp_property_new (NULL, info->token_type, info->position, NULL, args);
747 if (info->position >= 0)
749 /* Each parameter correspond to a different property */
750 AnjutaToken *arg;
752 arg = anjuta_token_nth_word (args, info->position);
753 g_free (new_prop->value);
754 new_prop->value = anjuta_token_evaluate_name (arg);
756 else
758 /* Property value is whole argument */
759 if (args == NULL)
761 new_prop->value = g_strdup(" ");
763 else
765 AnjutaToken *arg;
767 arg = anjuta_token_nth_word (args, 0);
768 new_prop->value = anjuta_token_evaluate_name (arg);
769 if (new_prop->value == NULL) new_prop->value = g_strdup(" ");
772 amp_node_property_add (ANJUTA_PROJECT_NODE (project), new_prop);
777 void
778 amp_project_load_module (AmpProject *project, AnjutaToken *module_token)
780 AmpAcScanner *scanner = NULL;
782 if (module_token != NULL)
784 AnjutaToken *arg;
785 AnjutaToken *list;
786 AnjutaToken *item;
787 gchar *value;
788 AmpModuleNode *module;
789 AmpPackageNode *package;
790 gchar *compare;
792 /* Module name */
793 arg = anjuta_token_first_item (module_token);
794 value = anjuta_token_evaluate (arg);
795 module = amp_module_node_new (value);
796 amp_module_node_add_token (module, module_token);
797 anjuta_project_node_append (ANJUTA_PROJECT_NODE (project), ANJUTA_PROJECT_NODE (module));
799 /* Package list */
800 arg = anjuta_token_next_word (arg);
801 if (arg != NULL)
803 scanner = amp_ac_scanner_new (project);
804 list = amp_ac_scanner_parse_token (scanner, NULL, arg, AC_SPACE_LIST_STATE, NULL, NULL);
805 anjuta_token_free_children (arg);
806 list = anjuta_token_delete_parent (list);
807 anjuta_token_prepend_items (arg, list);
808 amp_ac_scanner_free (scanner);
811 package = NULL;
812 compare = NULL;
813 for (item = anjuta_token_first_word (arg); item != NULL; item = anjuta_token_next_word (item))
815 value = anjuta_token_evaluate (item);
816 if (value == NULL) continue; /* Empty value, a comment of a quote by example */
817 if (*value == '\0')
819 g_free (value);
820 continue;
823 if ((package != NULL) && (compare != NULL))
825 amp_package_node_set_version (package, compare, value);
826 g_free (value);
827 g_free (compare);
828 package = NULL;
829 compare = NULL;
831 else if ((package != NULL) && (anjuta_token_get_type (item) == ANJUTA_TOKEN_OPERATOR))
833 compare = value;
835 else
837 package = amp_package_node_new (value);
838 amp_package_node_add_token (package, item);
839 anjuta_project_node_append (ANJUTA_PROJECT_NODE (module), ANJUTA_PROJECT_NODE (package));
840 anjuta_project_node_set_state (ANJUTA_PROJECT_NODE (package), ANJUTA_PROJECT_INCOMPLETE);
841 g_free (value);
842 compare = NULL;
848 void
849 amp_project_load_config (AmpProject *project, AnjutaToken *arg_list)
851 AmpAcScanner *scanner = NULL;
853 if (arg_list != NULL)
855 AnjutaToken *arg;
856 AnjutaToken *list;
857 AnjutaToken *item;
859 /* File list */
860 scanner = amp_ac_scanner_new (project);
862 arg = anjuta_token_first_word (arg_list);
863 list = amp_ac_scanner_parse_token (scanner, NULL, arg, AC_SPACE_LIST_STATE, NULL, NULL);
864 anjuta_token_free_children (arg);
865 list = anjuta_token_delete_parent (list);
866 amp_ac_scanner_free (scanner);
868 /* list can be NULL is there is no argument to AC_OUTPUT or AC_CONFIG_FILES */
869 if (list != NULL)
871 anjuta_token_prepend_items (arg, list);
872 for (item = anjuta_token_first_word (arg); item != NULL; item = anjuta_token_next_word (item))
874 gchar *value;
875 AmpConfigFile *cfg;
877 value = anjuta_token_evaluate (item);
878 if (value == NULL) continue;
880 cfg = amp_config_file_new (value, anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)), item);
881 g_hash_table_replace (project->configs, cfg->file, cfg);
882 g_free (value);
888 static AnjutaToken*
889 project_load_target (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties)
891 AnjutaToken *arg;
892 gchar *install = NULL;
893 gchar *value;
894 gint flags = 0;
895 AmpNodeInfo *info = AmpNodeInformations;
897 while (info->base.type != 0)
899 if (anjuta_token_get_type (variable) == info->token)
901 break;
903 info++;
906 value = anjuta_token_evaluate (anjuta_token_first_word (variable));
907 split_automake_variable (value, &flags, &install, NULL);
909 amp_group_node_add_token (AMP_GROUP_NODE (parent), variable, AM_GROUP_TARGET);
911 for (arg = anjuta_token_first_word (anjuta_token_last_item (variable)); arg != NULL; arg = anjuta_token_next_word (arg))
913 gchar *value;
914 gchar *canon_id;
915 AmpTargetNode *target;
916 AmpTargetNode *orphan;
917 gchar *orig_key;
918 gpointer find;
920 value = anjuta_token_evaluate (arg);
922 /* This happens for variable token which are considered as value */
923 if (value == NULL) continue;
924 canon_id = canonicalize_automake_variable (value);
926 /* Check if target already exists */
927 find = value;
928 anjuta_project_node_children_traverse (parent, find_target, &find);
929 if ((gchar *)find != value)
931 /* Find target */
932 g_free (canon_id);
933 g_free (value);
934 continue;
937 /* Create target */
938 target = amp_target_node_new (value, info->base.type, install, flags);
939 if (target != NULL)
941 amp_target_node_add_token (target, ANJUTA_TOKEN_ARGUMENT, arg);
942 anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (target));
943 DEBUG_PRINT ("create target %p name %s", target, value);
945 /* Check if there are sources or properties availables */
946 if (g_hash_table_lookup_extended (orphan_properties, canon_id, (gpointer *)&orig_key, (gpointer *)&orphan))
948 AnjutaTokenType type;
949 GList *properties;
950 AnjutaProjectNode *child;
952 g_hash_table_steal (orphan_properties, canon_id);
954 /* Copy all token */
955 for (type = amp_target_node_get_first_token_type (orphan); type != 0; type = amp_target_node_get_next_token_type (orphan, type))
957 GList *tokens;
958 tokens = amp_target_node_get_token (orphan, type);
960 for (tokens = g_list_first (tokens); tokens != NULL; tokens = g_list_next (tokens))
962 AnjutaToken *token = (AnjutaToken *)tokens->data;
964 amp_target_node_add_token (target, type, token);
968 /* Copy all properties */
969 while ((properties = anjuta_project_node_get_properties (ANJUTA_PROJECT_NODE (orphan))) != NULL)
971 AnjutaProjectProperty *prop;
973 prop = (AnjutaProjectProperty *)anjuta_project_node_remove_property (ANJUTA_PROJECT_NODE (orphan), (AnjutaProjectProperty *)properties->data);
974 amp_node_property_add ((AnjutaProjectNode *)target, prop);
977 /* Copy all sources */
978 while ((child = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (orphan))) != NULL)
980 anjuta_project_node_remove (child);
981 anjuta_project_node_append (ANJUTA_PROJECT_NODE (target), child);
982 g_object_unref (child);
984 amp_target_changed (target);
985 g_free (orig_key);
986 amp_target_node_free (orphan);
989 /* Set target properties */
990 if (flags & AM_TARGET_NOBASE)
991 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 0, "1", arg);
992 if (flags & AM_TARGET_NOTRANS)
993 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 1, "1", arg);
994 if (flags & AM_TARGET_DIST)
995 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "1", arg);
996 if (flags & AM_TARGET_NODIST)
997 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "0", arg);
998 if (flags & AM_TARGET_NOINST)
1000 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 3, "1", arg);
1002 else if (install != NULL)
1004 gchar *instdir = g_strconcat (install, "dir", NULL);
1005 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 6, instdir, arg);
1006 g_free (instdir);
1009 if (flags & AM_TARGET_CHECK)
1010 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 4, "1", arg);
1011 if (flags & AM_TARGET_MAN)
1013 gchar section[] = "0";
1015 section[0] += (flags >> 7) & 0x1F;
1016 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 4, section, arg);
1020 g_free (canon_id);
1021 g_free (value);
1023 g_free (value);
1025 return NULL;
1028 static AnjutaToken*
1029 project_load_sources (AmpProject *project, AnjutaProjectNode *group, AnjutaToken *variable, GHashTable *orphan_properties)
1031 AnjutaToken *arg;
1032 GFile *group_file = g_object_ref (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (group)));
1033 gchar *target_id = NULL;
1035 target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1036 if (target_id)
1038 gchar *end = strrchr (target_id, '_');
1039 if (end)
1041 *end = '\0';
1045 if (target_id)
1047 gpointer find;
1048 AnjutaProjectNode *target;
1050 find = target_id;
1051 DEBUG_PRINT ("search for canonical %s", target_id);
1052 anjuta_project_node_children_traverse (group, find_canonical_target, &find);
1053 target = (gchar *)find != target_id ? (AnjutaProjectNode *)find : NULL;
1055 /* Get orphan buffer if there is no target */
1056 if (target == NULL)
1058 gchar *orig_key;
1060 if (g_hash_table_lookup_extended (orphan_properties, target_id, (gpointer *)&orig_key, (gpointer *)&target))
1062 g_hash_table_steal (orphan_properties, target_id);
1063 g_free (orig_key);
1065 else
1067 target = ANJUTA_PROJECT_NODE (amp_target_node_new ("dummy", 0, NULL, 0));
1069 g_hash_table_insert (orphan_properties, target_id, target);
1071 else
1073 g_free (target_id);
1075 amp_target_node_add_token (AMP_TARGET_NODE (target), AM_TOKEN__SOURCES, variable);
1077 for (arg = anjuta_token_first_word (anjuta_token_last_item (variable)); arg != NULL; arg = anjuta_token_next_word (arg))
1079 gchar *value;
1080 AnjutaProjectNode *source;
1081 AnjutaProjectNode *parent = target;
1082 GFile *src_file;
1083 GFileInfo* file_info;
1085 value = anjuta_token_evaluate (arg);
1086 if (value == NULL) continue;
1088 src_file = g_file_get_child (group_file, value);
1089 if (project->lang_manager != NULL)
1091 file_info = g_file_query_info (src_file,
1092 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1093 G_FILE_QUERY_INFO_NONE,
1094 NULL,
1095 NULL);
1096 if (file_info)
1098 gint id = ianjuta_language_get_from_mime_type (project->lang_manager,
1099 g_file_info_get_content_type (file_info),
1100 NULL);
1101 if (id > 0)
1103 const gchar *obj_ext = ianjuta_language_get_make_target (project->lang_manager, id, NULL);
1104 if (obj_ext != NULL)
1106 /* Create object node */
1107 gchar *object_name;
1108 gchar *basename;
1109 gchar *ext;
1110 GFile *obj_file;
1111 AnjutaProjectNode *object;
1113 ext = strrchr (value, '.');
1114 if ((ext != NULL) && (ext != value)) *ext = '\0';
1115 object_name = g_strconcat (value, obj_ext, NULL);
1116 basename = g_path_get_basename (object_name);
1117 obj_file = g_file_get_child (group_file, basename);
1118 g_free (basename);
1119 g_free (object_name);
1120 object = amp_object_node_new (obj_file, ANJUTA_PROJECT_PROJECT);
1121 g_object_unref (obj_file);
1122 anjuta_project_node_append (parent, object);
1123 parent = object;
1126 g_object_unref (file_info);
1130 /* Create source */
1131 source = amp_source_node_new (src_file, ANJUTA_PROJECT_PROJECT);
1132 g_object_unref (src_file);
1133 if (source != NULL)
1135 amp_source_node_add_token (AMP_SOURCE_NODE (source), arg);
1137 DEBUG_PRINT ("add target child %p", target);
1138 /* Add as target child */
1139 anjuta_project_node_append (parent, source);
1142 g_free (value);
1144 amp_target_changed (AMP_TARGET_NODE (target));
1147 g_object_unref (group_file);
1149 return NULL;
1152 static AnjutaToken*
1153 project_load_data (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties, gint data_flags)
1155 gchar *install = NULL;
1156 AmpTargetNode *target;
1157 gchar *target_id;
1158 gpointer find;
1159 gint flags = 0;
1160 AmpNodeInfo *info = AmpNodeInformations;
1161 AnjutaToken *arg;
1162 AnjutaToken *list;
1164 while (info->base.name != NULL)
1166 if (anjuta_token_get_type (variable) == info->token)
1168 break;
1170 info++;
1173 target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1174 split_automake_variable (target_id, &flags, &install, NULL);
1176 amp_group_node_add_token (AMP_GROUP_NODE (parent), variable, AM_GROUP_TARGET);
1178 /* Check if target already exists */
1179 find = target_id;
1180 anjuta_project_node_children_traverse (parent, find_target, &find);
1181 if ((gchar *)find == target_id)
1183 /* Create target */
1184 target = amp_target_node_new (target_id, info->base.type, install, flags);
1185 if (target != NULL)
1187 anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (target));
1188 DEBUG_PRINT ("create target %p name %s", target, target_id);
1191 else
1193 target = AMP_TARGET_NODE (find);
1196 if (target != NULL)
1198 GFile *parent_file = g_object_ref (anjuta_project_node_get_file (parent));
1200 amp_target_node_add_token (AMP_TARGET_NODE (target), AM_TOKEN__DATA, variable);
1202 list = anjuta_token_last_item (variable);
1203 for (arg = anjuta_token_first_word (list); arg != NULL; arg = anjuta_token_next_word (arg))
1205 gchar *value;
1206 AnjutaProjectNode *source;
1207 GFile *src_file;
1209 value = anjuta_token_evaluate (arg);
1210 if (value == NULL) continue;
1212 /* Create source */
1213 src_file = g_file_get_child (parent_file, value);
1214 source = amp_source_node_new (src_file, ANJUTA_PROJECT_PROJECT | data_flags);
1215 g_object_unref (src_file);
1216 if (source != NULL)
1218 amp_source_node_add_token (AMP_SOURCE_NODE(source), arg);
1220 /* Add as target child */
1221 DEBUG_PRINT ("add target child %p", target);
1222 anjuta_project_node_append (ANJUTA_PROJECT_NODE (target), source);
1225 g_free (value);
1227 g_object_unref (parent_file);
1229 /* Set target properties */
1230 if (flags & AM_TARGET_NOBASE)
1231 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 0, "1", arg);
1232 if (flags & AM_TARGET_NOTRANS)
1233 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 1, "1", arg);
1234 if (flags & AM_TARGET_DIST)
1235 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "1", arg);
1236 if (flags & AM_TARGET_NODIST)
1237 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "0", arg);
1238 if (flags & AM_TARGET_NOINST)
1240 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 3, "1", arg);
1242 else if (install != NULL)
1244 gchar *instdir = g_strconcat (install, "dir", NULL);
1245 amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 6, instdir, arg);
1246 g_free (instdir);
1249 g_free (target_id);
1251 return NULL;
1254 static AnjutaToken*
1255 project_load_target_properties (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties)
1257 gchar *target_id = NULL;
1259 target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1260 if (target_id)
1262 gchar *end = strrchr (target_id, '_');
1263 if (end)
1265 *end = '\0';
1269 if (target_id)
1271 gpointer find;
1272 gchar *value;
1273 AnjutaProjectProperty *prop;
1274 AnjutaToken *list;
1275 AnjutaTokenType type;
1277 find = target_id;
1278 DEBUG_PRINT ("search for canonical %s", target_id);
1279 anjuta_project_node_children_traverse (parent, find_canonical_target, &find);
1280 parent = (gchar *)find != target_id ? (AnjutaProjectNode *)find : NULL;
1282 /* Create property */
1283 list = anjuta_token_last_item (variable);
1284 type = anjuta_token_get_type (variable);
1285 value = anjuta_token_evaluate_name (list);
1286 prop = amp_property_new (NULL, type, 0, value, list);
1288 if (parent == NULL)
1290 /* Add property to non existing target, create a dummy target */
1291 gchar *orig_key;
1293 if (g_hash_table_lookup_extended (orphan_properties, target_id, (gpointer *)&orig_key, (gpointer *)&parent))
1295 /* Dummy target already created */
1296 g_hash_table_steal (orphan_properties, target_id);
1297 g_free (orig_key);
1299 else
1301 /* Create dummy target */
1302 parent = ANJUTA_PROJECT_NODE (amp_target_node_new ("dummy", 0, NULL, 0));
1304 g_hash_table_insert (orphan_properties, target_id, parent);
1306 else
1308 g_free (target_id);
1310 g_free (value);
1312 /* Add property to target */
1313 amp_node_property_add (parent, prop);
1314 amp_target_node_add_token (AMP_TARGET_NODE (parent), type, variable);
1315 amp_target_changed (AMP_TARGET_NODE (parent));
1318 return NULL;
1321 static AnjutaToken*
1322 project_load_group_properties (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable)
1324 gchar *value;
1325 gchar *name;
1326 AnjutaProjectProperty *prop;
1327 AnjutaToken *list;
1329 /* Create property */
1330 list = anjuta_token_last_item (variable);
1331 name = anjuta_token_evaluate (anjuta_token_first_word (variable));
1332 value = anjuta_token_evaluate_name (list);
1334 prop = amp_property_new (name, anjuta_token_get_type (variable), 0, value, list);
1336 amp_node_property_add (parent, prop);
1338 g_free (value);
1339 g_free (name);
1341 return NULL;
1344 static gboolean
1345 find_group (AnjutaProjectNode *node, gpointer data)
1347 if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1349 if (g_file_equal (anjuta_project_node_get_file (node), (GFile *)data))
1351 /* Find group, return node value in pointer */
1352 return TRUE;
1356 return FALSE;
1359 static void
1360 project_load_subdirs (AmpProject *project, AnjutaToken *list, AnjutaProjectNode *parent, gboolean dist_only)
1362 AnjutaToken *arg;
1364 for (arg = anjuta_token_first_word (list); arg != NULL; arg = anjuta_token_next_word (arg))
1366 gchar *value;
1368 value = anjuta_token_evaluate (arg);
1369 if (value == NULL) continue; /* Empty value, a comment of a quote by example */
1371 /* Skip ., it is a special case, used to defined build order */
1372 if (strcmp (value, ".") != 0)
1374 GFile *subdir;
1375 AmpGroupNode *group;
1377 subdir = g_file_resolve_relative_path (anjuta_project_node_get_file (parent), value);
1379 /* Look for already existing group */
1380 group = AMP_GROUP_NODE (anjuta_project_node_children_traverse (parent, find_group, subdir));
1382 if (group != NULL)
1384 /* Already existing group, mark for built if needed */
1385 if (!dist_only) amp_group_node_set_dist_only (group, FALSE);
1387 else
1389 /* Create new group */
1390 group = amp_group_node_new (subdir, value, dist_only);
1392 /* Group can be NULL if the name is not valid */
1393 if (group != NULL)
1395 g_hash_table_insert (project->groups, g_file_get_uri (subdir), group);
1396 anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (group));
1398 amp_node_load (AMP_NODE (group), NULL, project, NULL);
1401 if (group) amp_group_node_add_token (group, arg, dist_only ? AM_GROUP_TOKEN_DIST_SUBDIRS : AM_GROUP_TOKEN_SUBDIRS);
1402 g_object_unref (subdir);
1404 g_free (value);
1408 void
1409 amp_project_set_am_variable (AmpProject* project, AmpGroupNode* group, AnjutaToken *variable, GHashTable *orphan_properties)
1411 AnjutaToken *list;
1413 switch (anjuta_token_get_type (variable))
1415 case AM_TOKEN_SUBDIRS:
1416 list = anjuta_token_last_item (variable);
1417 project_load_subdirs (project, list, ANJUTA_PROJECT_NODE (group), FALSE);
1418 break;
1419 case AM_TOKEN_DIST_SUBDIRS:
1420 list = anjuta_token_last_item (variable);
1421 project_load_subdirs (project, list, ANJUTA_PROJECT_NODE (group), TRUE);
1422 break;
1423 case AM_TOKEN__DATA:
1424 case AM_TOKEN__HEADERS:
1425 case AM_TOKEN__LISP:
1426 case AM_TOKEN__MANS:
1427 case AM_TOKEN__PYTHON:
1428 case AM_TOKEN__JAVA:
1429 case AM_TOKEN__TEXINFOS:
1430 project_load_data (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties, 0);
1431 break;
1432 case AM_TOKEN__SCRIPTS:
1433 project_load_data (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties, ANJUTA_PROJECT_EXECUTABLE);
1434 break;
1435 case AM_TOKEN__LIBRARIES:
1436 case AM_TOKEN__LTLIBRARIES:
1437 case AM_TOKEN__PROGRAMS:
1438 project_load_target (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1439 break;
1440 case AM_TOKEN__SOURCES:
1441 project_load_sources (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1442 break;
1443 case AM_TOKEN_DIR:
1444 case AM_TOKEN__LDFLAGS:
1445 case AM_TOKEN__CPPFLAGS:
1446 case AM_TOKEN__CFLAGS:
1447 case AM_TOKEN__CXXFLAGS:
1448 case AM_TOKEN__JAVACFLAGS:
1449 case AM_TOKEN__VALAFLAGS:
1450 case AM_TOKEN__FCFLAGS:
1451 case AM_TOKEN__OBJCFLAGS:
1452 case AM_TOKEN__LFLAGS:
1453 case AM_TOKEN__YFLAGS:
1454 project_load_group_properties (project, ANJUTA_PROJECT_NODE (group), variable);
1455 break;
1456 case AM_TOKEN_TARGET_LDFLAGS:
1457 case AM_TOKEN_TARGET_CPPFLAGS:
1458 case AM_TOKEN_TARGET_CFLAGS:
1459 case AM_TOKEN_TARGET_CXXFLAGS:
1460 case AM_TOKEN_TARGET_JAVACFLAGS:
1461 case AM_TOKEN_TARGET_VALAFLAGS:
1462 case AM_TOKEN_TARGET_FCFLAGS:
1463 case AM_TOKEN_TARGET_OBJCFLAGS:
1464 case AM_TOKEN_TARGET_LFLAGS:
1465 case AM_TOKEN_TARGET_YFLAGS:
1466 case AM_TOKEN_TARGET_DEPENDENCIES:
1467 case AM_TOKEN_TARGET_LIBADD:
1468 case AM_TOKEN_TARGET_LDADD:
1469 project_load_target_properties (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1470 break;
1471 default:
1472 break;
1475 /* Keep the autotools variable as a normal variable too */
1476 amp_group_node_update_variable (group, variable);
1479 /* Map function
1480 *---------------------------------------------------------------------------*/
1482 static gint
1483 amp_project_compare_node (AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1485 const gchar *name1;
1486 const gchar *name2;
1487 GFile *file1;
1488 GFile *file2;
1490 name1 = anjuta_project_node_get_name (old_node);
1491 name2 = anjuta_project_node_get_name (new_node);
1492 file1 = anjuta_project_node_get_file (old_node);
1493 file2 = anjuta_project_node_get_file (new_node);
1495 return (anjuta_project_node_get_full_type (old_node) == anjuta_project_node_get_full_type (new_node))
1496 && ((name1 == NULL) || (name2 == NULL) || (strcmp (name1, name2) == 0))
1497 && ((file1 == NULL) || (file2 == NULL) || g_file_equal (file1, file2)) ? 0 : 1;
1500 static void
1501 amp_project_map_children (GHashTable *map, AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1503 GList *children = NULL;
1505 if (new_node != NULL)
1507 for (new_node = anjuta_project_node_first_child (new_node); new_node != NULL; new_node = anjuta_project_node_next_sibling (new_node))
1509 children = g_list_prepend (children, new_node);
1511 children = g_list_reverse (children);
1514 for (old_node = anjuta_project_node_first_child (old_node); old_node != NULL; old_node = anjuta_project_node_next_sibling (old_node))
1516 GList *same;
1518 same = g_list_find_custom (children, old_node, (GCompareFunc)amp_project_compare_node);
1520 if (same != NULL)
1522 /* Add new to old node mapping */
1523 g_hash_table_insert (map, (AnjutaProjectNode *)same->data, old_node);
1525 amp_project_map_children (map, old_node, (AnjutaProjectNode *)same->data);
1526 children = g_list_delete_link (children, same);
1528 else
1530 /* Keep old_node to be deleted in the hash table as a key with a NULL
1531 * value */
1532 g_hash_table_insert (map, old_node, NULL);
1536 /* Add remaining node in hash table */
1537 for (; children != NULL; children = g_list_delete_link (children, children))
1539 /* Keep new node without a corresponding old node as a key and a identical
1540 * value */
1541 g_hash_table_insert (map, children->data, children->data);
1545 /* Find the correspondance between the new loaded node (new_node) and the
1546 * original node currently in the tree (old_node) */
1547 static GHashTable *
1548 amp_project_map_node (AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1550 GHashTable *map;
1552 map = g_hash_table_new (g_direct_hash, NULL);
1554 g_hash_table_insert (map, new_node, old_node);
1556 amp_project_map_children (map, old_node, new_node);
1558 return map;
1562 static void
1563 amp_project_update_node (AnjutaProjectNode *key, AnjutaProjectNode *value, GHashTable *map)
1565 AnjutaProjectNode *old_node = NULL; /* The node that will be deleted */
1567 if (value == NULL)
1569 /* if value is NULL, delete the old node which is the key */
1570 old_node = key;
1572 else
1574 AnjutaProjectNode *node = value; /* The node that we keep in the tree */
1575 AnjutaProjectNode *new_node = key; /* The node with the new data */
1577 if (new_node && new_node != node)
1579 GList *properties;
1581 amp_node_update (AMP_NODE (node), AMP_NODE (new_node));
1583 /* Swap custom properties */
1584 properties = node->properties;
1585 node->properties = new_node->properties;
1586 new_node->properties = properties;
1588 if (new_node->parent == NULL)
1590 /* This is the top loaded node, update only the children */
1591 node->children = new_node->children;
1593 else
1595 /* Other node update all pointers */
1596 node->parent = new_node->parent;
1597 node->children = new_node->children;
1598 node->next = new_node->next;
1599 node->prev = new_node->prev;
1602 /* Destroy node with data */
1603 old_node = new_node;
1606 /* Update links, using original node address if they stay in the tree */
1607 new_node = g_hash_table_lookup (map, node->parent);
1608 if (new_node != NULL) node->parent = new_node;
1609 new_node = g_hash_table_lookup (map, node->children);
1610 if (new_node != NULL) node->children = new_node;
1611 new_node = g_hash_table_lookup (map, node->next);
1612 if (new_node != NULL) node->next = new_node;
1613 new_node = g_hash_table_lookup (map, node->prev);
1614 if (new_node != NULL) node->prev = new_node;
1618 /* Unlink old node and free it */
1619 if (old_node != NULL)
1621 old_node->parent = NULL;
1622 old_node->children = NULL;
1623 old_node->next = NULL;
1624 old_node->prev = NULL;
1625 g_object_unref (old_node);
1629 /* Public functions
1630 *---------------------------------------------------------------------------*/
1632 AnjutaProjectNodeInfo *
1633 amp_project_get_type_info (AmpProject *project, AnjutaProjectNodeType type)
1635 AmpNodeInfo *info;
1637 for (info = AmpNodeInformations; info->base.type != type; info++)
1639 if ((info->base.type == type) || (info->base.type == 0)) break;
1642 return (AnjutaProjectNodeInfo *)info;
1645 static gboolean
1646 amp_project_load_root (AmpProject *project, GError **error)
1648 AmpAcScanner *scanner;
1649 AnjutaToken *arg;
1650 GFile *root_file;
1651 GFile *configure_file;
1652 AnjutaTokenFile *configure_token_file;
1653 AnjutaProjectNode *source;
1654 GError *err = NULL;
1656 root_file = anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project));
1657 DEBUG_PRINT ("reload project %p root file %p", project, root_file);
1659 /* Unload current project */
1660 amp_project_unload (project);
1662 /* Initialize list styles */
1663 project->ac_space_list = anjuta_token_style_new (NULL, " ", "\n", NULL, 0);
1664 project->am_space_list = anjuta_token_style_new (NULL, " ", " \\\n\t", NULL, 0);
1665 project->arg_list = anjuta_token_style_new (NULL, ", ", ", ", ")", 0);
1667 /* Find configure file */
1668 if (file_type (root_file, "configure.ac") == G_FILE_TYPE_REGULAR)
1670 configure_file = g_file_get_child (root_file, "configure.ac");
1672 else if (file_type (root_file, "configure.in") == G_FILE_TYPE_REGULAR)
1674 configure_file = g_file_get_child (root_file, "configure.in");
1676 else
1678 g_set_error (error, IANJUTA_PROJECT_ERROR,
1679 IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1680 _("Project doesn't exist or invalid path"));
1682 return FALSE;
1685 /* Parse configure */
1686 configure_token_file = amp_project_set_configure (project, configure_file);
1687 amp_project_add_file (project, configure_file, configure_token_file);
1688 source = amp_source_node_new (configure_file, ANJUTA_PROJECT_PROJECT | ANJUTA_PROJECT_FRAME | ANJUTA_PROJECT_READ_ONLY);
1689 anjuta_project_node_append (ANJUTA_PROJECT_NODE (project), source);
1690 arg = anjuta_token_file_load (configure_token_file, NULL);
1691 g_hash_table_remove_all (project->ac_variables);
1692 scanner = amp_ac_scanner_new (project);
1693 project->configure_token = amp_ac_scanner_parse_token (scanner, NULL, arg, 0, configure_file, &err);
1694 amp_ac_scanner_free (scanner);
1696 if (project->configure_token == NULL)
1698 if (err != NULL)
1700 g_set_error_literal (error, IANJUTA_PROJECT_ERROR,
1701 IANJUTA_PROJECT_ERROR_PROJECT_MALFORMED,
1702 err->message);
1703 g_error_free (err);
1705 else
1707 g_set_error (error, IANJUTA_PROJECT_ERROR,
1708 IANJUTA_PROJECT_ERROR_PROJECT_MALFORMED,
1709 "%s",
1710 _("Unable to parse project file"));
1713 return FALSE;
1716 /* Load all makefiles recursively */
1717 if (!AMP_NODE_CLASS (parent_class)->load (AMP_NODE (project), NULL, project, NULL))
1719 g_set_error (error, IANJUTA_PROJECT_ERROR,
1720 IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1721 _("Project doesn't exist or has an invalid path"));
1723 return FALSE;
1726 return TRUE;
1729 void
1730 amp_project_unload (AmpProject *project)
1732 /* project data */
1733 amp_project_clear (project);
1735 /* shortcut hash tables */
1736 if (project->groups) g_hash_table_remove_all (project->groups);
1737 if (project->files != NULL)
1739 GList *list;
1741 for (list = project->files; list != NULL; list = g_list_delete_link (list, list))
1743 g_object_weak_unref (G_OBJECT (list->data), remove_config_file, project);
1745 project->files = NULL;
1747 if (project->configs) g_hash_table_remove_all (project->configs);
1749 /* List styles */
1750 if (project->am_space_list) anjuta_token_style_free (project->am_space_list);
1751 if (project->ac_space_list) anjuta_token_style_free (project->ac_space_list);
1752 if (project->arg_list) anjuta_token_style_free (project->arg_list);
1755 gboolean
1756 amp_project_is_loaded (AmpProject *project)
1758 return project->loading == 0;
1761 gint
1762 amp_project_probe (GFile *file,
1763 GError **error)
1765 gint probe;
1766 gboolean dir;
1768 dir = (file_type (file, NULL) == G_FILE_TYPE_DIRECTORY);
1769 if (!dir)
1771 g_set_error (error, IANJUTA_PROJECT_ERROR,
1772 IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1773 _("Project doesn't exist or invalid path"));
1776 probe = dir;
1777 if (probe)
1779 const gchar **makefile;
1781 /* Look for makefiles */
1782 probe = FALSE;
1783 for (makefile = valid_am_makefiles; *makefile != NULL; makefile++)
1785 if (file_type (file, *makefile) == G_FILE_TYPE_REGULAR)
1787 probe = TRUE;
1788 break;
1792 if (probe)
1794 probe = ((file_type (file, "configure.ac") == G_FILE_TYPE_REGULAR) ||
1795 (file_type (file, "configure.in") == G_FILE_TYPE_REGULAR));
1799 return probe ? IANJUTA_PROJECT_PROBE_PROJECT_FILES : 0;
1802 gboolean
1803 amp_project_get_token_location (AmpProject *project, AnjutaTokenFileLocation *location, AnjutaToken *token)
1805 GList *list;
1807 for (list = project->files; list != NULL; list = g_list_next (list))
1809 if (anjuta_token_file_get_token_location ((AnjutaTokenFile *)list->data, location, token))
1811 return TRUE;
1815 return FALSE;
1818 void
1819 amp_project_remove_group (AmpProject *project,
1820 AmpGroupNode *group,
1821 GError **error)
1823 GList *token_list;
1825 if (anjuta_project_node_get_node_type (ANJUTA_PROJECT_NODE (group)) != ANJUTA_PROJECT_GROUP) return;
1827 for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_CONFIGURE); token_list != NULL; token_list = g_list_next (token_list))
1829 anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1831 for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_SUBDIRS); token_list != NULL; token_list = g_list_next (token_list))
1833 anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1835 for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_DIST_SUBDIRS); token_list != NULL; token_list = g_list_next (token_list))
1837 anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1840 amp_group_node_free (group);
1843 void
1844 amp_project_remove_source (AmpProject *project,
1845 AmpSourceNode *source,
1846 GError **error)
1848 if (anjuta_project_node_get_node_type (ANJUTA_PROJECT_NODE (source)) != ANJUTA_PROJECT_SOURCE) return;
1850 anjuta_token_remove_word (amp_source_node_get_token (source));
1852 amp_source_node_free (source);
1855 const GList *
1856 amp_project_get_node_info (AmpProject *project, GError **error)
1858 static GList *info_list = NULL;
1860 if (info_list == NULL)
1862 AmpNodeInfo *node;
1864 for (node = AmpNodeInformations; node->base.type != 0; node++)
1866 info_list = g_list_prepend (info_list, node);
1869 info_list = g_list_reverse (info_list);
1872 return info_list;
1875 /* Public functions
1876 *---------------------------------------------------------------------------*/
1878 typedef struct _AmpMovePacket {
1879 AmpProject *project;
1880 GFile *old_root_file;
1881 GFile *new_root_file;
1882 } AmpMovePacket;
1884 static void
1885 foreach_node_move (AnjutaProjectNode *g_node, gpointer data)
1887 AmpProject *project = ((AmpMovePacket *)data)->project;
1888 GFile *old_root_file = ((AmpMovePacket *)data)->old_root_file;
1889 GFile *new_root_file = ((AmpMovePacket *)data)->new_root_file;
1890 gchar *relative;
1891 GFile *new_file;
1893 switch (anjuta_project_node_get_node_type (g_node))
1895 case ANJUTA_PROJECT_GROUP:
1896 relative = get_relative_path (old_root_file, anjuta_project_node_get_file (g_node));
1897 new_file = g_file_resolve_relative_path (new_root_file, relative);
1898 g_free (relative);
1899 amp_group_node_set_file (AMP_GROUP_NODE (g_node), new_file);
1900 g_object_unref (new_file);
1902 g_hash_table_insert (project->groups, g_file_get_uri (new_file), g_node);
1903 break;
1904 case ANJUTA_PROJECT_SOURCE:
1905 relative = get_relative_path (old_root_file, anjuta_project_node_get_file (g_node));
1906 new_file = g_file_resolve_relative_path (new_root_file, relative);
1907 g_free (relative);
1908 amp_source_node_set_file (AMP_SOURCE_NODE (g_node), new_file);
1909 g_object_unref (new_file);
1910 break;
1911 default:
1912 break;
1916 gboolean
1917 amp_project_move (AmpProject *project, const gchar *path)
1919 GFile *new_file;
1920 gchar *relative;
1921 GList *list;
1922 gpointer key;
1923 AmpConfigFile *cfg;
1924 GHashTable* old_hash;
1925 GHashTableIter iter;
1926 AmpMovePacket packet= {project, NULL};
1928 /* Change project root directory */
1929 packet.old_root_file = g_object_ref (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)));
1930 packet.new_root_file = g_file_new_for_path (path);
1932 /* Change project root directory in groups */
1933 old_hash = project->groups;
1934 project->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1935 anjuta_project_node_foreach (ANJUTA_PROJECT_NODE (project), G_POST_ORDER, foreach_node_move, &packet);
1936 g_hash_table_destroy (old_hash);
1938 /* Change all files */
1939 for (list = project->files; list != NULL; list = g_list_next (list))
1941 AnjutaTokenFile *tfile = (AnjutaTokenFile *)list->data;
1943 relative = get_relative_path (packet.old_root_file, anjuta_token_file_get_file (tfile));
1944 new_file = g_file_resolve_relative_path (packet.new_root_file, relative);
1945 g_free (relative);
1946 anjuta_token_file_move (tfile, new_file);
1949 /* Change all configs */
1950 old_hash = project->configs;
1951 project->configs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, (GDestroyNotify)amp_config_file_free);
1952 g_hash_table_iter_init (&iter, old_hash);
1953 while (g_hash_table_iter_next (&iter, &key, (gpointer *)&cfg))
1955 relative = get_relative_path (packet.old_root_file, cfg->file);
1956 new_file = g_file_resolve_relative_path (packet.new_root_file, relative);
1957 g_free (relative);
1958 g_object_unref (cfg->file);
1959 cfg->file = new_file;
1961 g_hash_table_insert (project->configs, new_file, cfg);
1963 g_hash_table_steal_all (old_hash);
1964 g_hash_table_destroy (old_hash);
1966 g_object_unref (packet.old_root_file);
1967 g_object_unref (packet.new_root_file);
1969 return TRUE;
1972 /* Dump file content of corresponding node */
1973 gboolean
1974 amp_project_dump (AmpProject *project, AnjutaProjectNode *node, AmpFileType type)
1976 gboolean ok = FALSE;
1978 if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1980 switch (type)
1982 case DUMP_MAKEFILE:
1983 anjuta_token_dump (amp_group_node_get_makefile_token (AMP_GROUP_NODE (node)));
1984 break;
1985 case DUMP_CONFIGURE:
1986 anjuta_token_dump (AMP_PROJECT (node)->configure_token);
1987 break;
1988 default:
1989 break;
1993 return ok;
1997 AmpProject *
1998 amp_project_new (GFile *file, IAnjutaLanguage *language, GError **error)
2000 AmpProject *project;
2001 GFile *new_file;
2003 project = AMP_PROJECT (g_object_new (AMP_TYPE_PROJECT, NULL));
2004 new_file = g_file_dup (file);
2005 amp_root_node_set_file (AMP_ROOT_NODE (project), new_file);
2006 g_object_unref (new_file);
2008 project->lang_manager = (language != NULL) ? g_object_ref (language) : NULL;
2010 return project;
2013 /* Project access functions
2014 *---------------------------------------------------------------------------*/
2016 AmpProject *
2017 amp_project_get_root (AmpProject *project)
2019 return AMP_PROJECT (project);
2022 AmpGroupNode *
2023 amp_project_get_group (AmpProject *project, const gchar *id)
2025 return (AmpGroupNode *)g_hash_table_lookup (project->groups, id);
2028 AmpTargetNode *
2029 amp_project_get_target (AmpProject *project, const gchar *id)
2031 AmpTargetNode **buffer;
2032 AmpTargetNode *target;
2033 gsize dummy;
2035 buffer = (AmpTargetNode **)g_base64_decode (id, &dummy);
2036 target = *buffer;
2037 g_free (buffer);
2039 return target;
2042 AmpSourceNode *
2043 amp_project_get_source (AmpProject *project, const gchar *id)
2045 AmpSourceNode **buffer;
2046 AmpSourceNode *source;
2047 gsize dummy;
2049 buffer = (AmpSourceNode **)g_base64_decode (id, &dummy);
2050 source = *buffer;
2051 g_free (buffer);
2053 return source;
2056 gchar *
2057 amp_project_get_uri (AmpProject *project)
2059 g_return_val_if_fail (project != NULL, NULL);
2061 return g_file_get_uri (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)));
2064 GFile*
2065 amp_project_get_file (AmpProject *project)
2067 g_return_val_if_fail (project != NULL, NULL);
2069 return anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project));
2072 void
2073 amp_project_add_file (AmpProject *project, GFile *file, AnjutaTokenFile* token)
2075 project->files = g_list_prepend (project->files, token);
2076 g_object_weak_ref (G_OBJECT (token), remove_config_file, project);
2079 void
2080 amp_project_add_subst_variable (AmpProject *project, const gchar *name, AnjutaToken *value)
2082 g_hash_table_insert (project->ac_variables, (gchar *)name, value);
2085 AnjutaToken *
2086 amp_project_get_subst_variable_token (AmpProject *project, const gchar *name)
2088 return g_hash_table_lookup (project->ac_variables, name);
2092 gboolean
2093 amp_project_is_busy (AmpProject *project)
2095 if (project->queue == NULL) return FALSE;
2097 return pm_command_queue_is_busy (project->queue);
2100 /* Worker thread
2101 *---------------------------------------------------------------------------*/
2103 static gboolean
2104 amp_load_setup (PmJob *job)
2106 //anjuta_project_node_check (job->node);
2107 pm_job_set_parent (job, anjuta_project_node_parent (job->node));
2108 job->proxy = ANJUTA_PROJECT_NODE (amp_node_copy (AMP_NODE (job->node)));
2110 return TRUE;
2113 static gboolean
2114 amp_load_work (PmJob *job)
2116 return amp_node_load (AMP_NODE (job->proxy), AMP_NODE (job->parent), AMP_PROJECT (job->user_data), &job->error);
2119 static gboolean
2120 amp_load_complete (PmJob *job)
2122 GHashTable *map;
2123 //static GTimer *timer = NULL;
2125 g_return_val_if_fail (job->proxy != NULL, FALSE);
2127 //anjuta_project_node_check (job->node);
2128 /*if (timer == NULL)
2130 timer = g_timer_new ();
2132 else
2134 g_timer_continue (timer);
2136 map = amp_project_map_node (job->node, job->proxy);
2137 g_object_ref (job->proxy);
2139 job->proxy->parent = NULL; // Mark loaded top node
2140 g_hash_table_foreach (map, (GHFunc)amp_project_update_node, map);
2141 //anjuta_project_node_check (job->node);
2142 g_hash_table_destroy (map);
2143 g_object_unref (job->proxy);
2144 job->proxy = NULL;
2145 AMP_PROJECT (job->user_data)->loading--;
2146 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-loaded", job->node, job->error);
2147 //g_timer_stop (timer);
2148 //g_message ("amp_load_complete completed in %g", g_timer_elapsed (timer, NULL));
2150 return TRUE;
2153 static PmCommandWork amp_load_job = {amp_load_setup, amp_load_work, amp_load_complete};
2155 static gboolean
2156 amp_save_setup (PmJob *job)
2158 return TRUE;
2161 static gboolean
2162 amp_save_work (PmJob *job)
2164 /* It is difficult to save only a particular node, so the whole project is saved */
2165 amp_node_save (AMP_NODE (job->user_data), NULL, AMP_PROJECT (job->user_data), &job->error);
2167 return TRUE;
2170 static gboolean
2171 amp_save_complete (PmJob *job)
2173 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-saved", job->node, job->error);
2175 return TRUE;
2178 static PmCommandWork amp_save_job = {amp_save_setup, amp_save_work, amp_save_complete};
2180 static gboolean
2181 amp_add_before_setup (PmJob *job)
2183 /* If add is called to add the root group, the node is already existing */
2184 if (job->parent != job->node)
2185 anjuta_project_node_insert_before (job->parent, job->sibling, job->node);
2187 return TRUE;
2190 static gboolean
2191 amp_add_after_setup (PmJob *job)
2193 /* If add is called to add the root group, the node is already existing */
2194 if (job->parent != job->node)
2195 anjuta_project_node_insert_after (job->parent, job->sibling, job->node);
2197 return TRUE;
2200 static gboolean
2201 amp_add_work (PmJob *job)
2203 AmpNode *parent = AMP_NODE (job->parent);
2204 gboolean ok;
2206 ok = amp_node_write (AMP_NODE (job->node), parent, AMP_PROJECT (job->user_data), &job->error);
2207 /* Add new node properties if existing */
2208 if (ok)
2210 GList *item;
2212 for (item = anjuta_project_node_get_properties (ANJUTA_PROJECT_NODE (job->node)); item != NULL; item = g_list_next (item))
2214 AnjutaProjectProperty *property = (AnjutaProjectProperty *)item->data;
2215 gint flags;
2217 flags = ((AmpPropertyInfo *)property->info)->flags;
2218 if (flags & AM_PROPERTY_IN_CONFIGURE)
2220 ok = ok && amp_project_update_ac_property (AMP_PROJECT (job->user_data), property);
2222 else if (flags & AM_PROPERTY_IN_MAKEFILE)
2224 if (((AnjutaProjectPropertyInfo *)property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2226 ok = ok && amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, property);
2232 return ok;
2235 static gboolean
2236 amp_add_complete (PmJob *job)
2238 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->parent, job->error);
2240 return TRUE;
2243 static PmCommandWork amp_add_before_job = {amp_add_before_setup, amp_add_work, amp_add_complete};
2244 static PmCommandWork amp_add_after_job = {amp_add_after_setup, amp_add_work, amp_add_complete};
2247 static gboolean
2248 amp_remove_setup (PmJob *job)
2250 AnjutaProjectNode *parent;
2252 parent = anjuta_project_node_parent (job->node);
2253 if (parent == NULL) parent = job->node;
2254 pm_job_set_parent (job, parent);
2255 anjuta_project_node_set_state (job->node, ANJUTA_PROJECT_REMOVED);
2257 return TRUE;
2260 static gboolean
2261 amp_remove_work (PmJob *job)
2263 AmpNode *parent = AMP_NODE (job->parent);
2264 gboolean ok;
2266 ok = amp_node_erase (AMP_NODE (job->node), parent, AMP_PROJECT (job->user_data), &job->error);
2268 return ok;
2271 static gboolean
2272 amp_remove_complete (PmJob *job)
2274 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->parent, job->error);
2276 return TRUE;
2279 static PmCommandWork amp_remove_job = {amp_remove_setup, amp_remove_work, amp_remove_complete};
2281 static gboolean
2282 amp_set_property_setup (PmJob *job)
2284 return TRUE;
2287 static gboolean
2288 amp_set_property_work (PmJob *job)
2290 gint flags;
2292 flags = ((AmpPropertyInfo *)job->property->info)->flags;
2294 if (flags & AM_PROPERTY_IN_CONFIGURE)
2296 amp_project_update_ac_property (AMP_PROJECT (job->user_data), job->property);
2298 else if (flags & AM_PROPERTY_IN_MAKEFILE)
2300 if (((AnjutaProjectPropertyInfo *)job->property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2302 amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, job->property);
2306 return TRUE;
2309 static gboolean
2310 amp_set_property_complete (PmJob *job)
2312 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->node, job->error);
2314 return TRUE;
2317 static PmCommandWork amp_set_property_job = {amp_set_property_setup, amp_set_property_work, amp_set_property_complete};
2319 static gboolean
2320 amp_remove_property_setup (PmJob *job)
2322 return TRUE;
2325 static gboolean
2326 amp_remove_property_work (PmJob *job)
2328 gint flags;
2330 flags = ((AmpPropertyInfo *)job->property->info)->flags;
2332 if (flags & AM_PROPERTY_IN_CONFIGURE)
2334 amp_project_update_ac_property (AMP_PROJECT (job->user_data), job->property);
2336 else if (flags & AM_PROPERTY_IN_MAKEFILE)
2338 if (((AnjutaProjectPropertyInfo *)job->property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2340 amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, job->property);
2344 return TRUE;
2347 static gboolean
2348 amp_remove_property_complete (PmJob *job)
2350 g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->node, job->error);
2352 return TRUE;
2355 static PmCommandWork amp_remove_property_job = {amp_remove_property_setup, amp_remove_property_work, amp_remove_property_complete};
2357 /* Implement IAnjutaProject
2358 *---------------------------------------------------------------------------*/
2360 static gboolean
2361 iproject_load_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **error)
2363 PmJob *load_job;
2365 if (node == NULL) node = ANJUTA_PROJECT_NODE (obj);
2366 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2368 AMP_PROJECT (obj)->loading++;
2369 load_job = pm_job_new (&amp_load_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2371 pm_command_queue_push (AMP_PROJECT (obj)->queue, load_job);
2373 return TRUE;
2376 static gboolean
2377 iproject_save_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **error)
2379 PmJob *save_job;
2381 if (node == NULL) node = ANJUTA_PROJECT_NODE (obj);
2382 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2384 save_job = pm_job_new (&amp_save_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2385 pm_command_queue_push (AMP_PROJECT (obj)->queue, save_job);
2387 return TRUE;
2390 static AnjutaProjectNode *
2391 iproject_add_node_before (IAnjutaProject *obj, AnjutaProjectNode *parent, AnjutaProjectNode *sibling, AnjutaProjectNodeType type, GFile *file, const gchar *name, GError **err)
2393 AnjutaProjectNode *node;
2394 PmJob *add_job;
2396 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2398 node = amp_node_new_valid (parent, type, file, name, err);
2399 if (node != NULL)
2401 add_job = pm_job_new (&amp_add_before_job, node, parent, sibling, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2402 pm_command_queue_push (AMP_PROJECT (obj)->queue, add_job);
2405 return node;
2408 static AnjutaProjectNode *
2409 iproject_add_node_after (IAnjutaProject *obj, AnjutaProjectNode *parent, AnjutaProjectNode *sibling, AnjutaProjectNodeType type, GFile *file, const gchar *name, GError **err)
2411 AnjutaProjectNode *node;
2412 PmJob *add_job;
2414 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2416 node = amp_node_new_valid (parent, type, file, name, err);
2417 if (node != NULL)
2419 add_job = pm_job_new (&amp_add_after_job, node, parent, sibling, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2420 pm_command_queue_push (AMP_PROJECT (obj)->queue, add_job);
2423 return node;
2426 static gboolean
2427 iproject_remove_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **err)
2429 PmJob *remove_job;
2431 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2433 remove_job = pm_job_new (&amp_remove_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2434 pm_command_queue_push (AMP_PROJECT (obj)->queue, remove_job);
2436 return TRUE;
2439 static AnjutaProjectProperty *
2440 iproject_set_property (IAnjutaProject *obj, AnjutaProjectNode *node, const gchar *id, const gchar *name, const gchar *value, GError **error)
2442 AnjutaProjectProperty *new_prop;
2443 PmJob *set_property_job;
2445 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2447 new_prop = name == NULL ? amp_node_property_set (node, id, value) : amp_node_map_property_set (node, id, name, value);
2448 set_property_job = pm_job_new (&amp_set_property_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2449 set_property_job->property = new_prop;
2450 pm_command_queue_push (AMP_PROJECT (obj)->queue, set_property_job);
2452 return new_prop;
2455 static gboolean
2456 iproject_remove_property (IAnjutaProject *obj, AnjutaProjectNode *node, const gchar *id, const gchar *name, GError **error)
2458 AnjutaProjectProperty *new_prop;
2459 PmJob *remove_property_job;
2461 if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2464 new_prop = amp_node_map_property_set (node, id, name, NULL);
2465 remove_property_job = pm_job_new (&amp_set_property_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2466 remove_property_job->property = new_prop;
2467 pm_command_queue_push (AMP_PROJECT (obj)->queue, remove_property_job);
2469 return TRUE;
2472 static AnjutaProjectNode *
2473 iproject_get_root (IAnjutaProject *obj, GError **err)
2475 return ANJUTA_PROJECT_NODE (obj);
2478 static const GList*
2479 iproject_get_node_info (IAnjutaProject *obj, GError **err)
2481 return amp_project_get_node_info (AMP_PROJECT (obj), err);
2484 static gboolean
2485 iproject_is_loaded (IAnjutaProject *obj, GError **err)
2487 return amp_project_is_loaded (AMP_PROJECT (obj));
2490 static void
2491 iproject_iface_init(IAnjutaProjectIface* iface)
2493 iface->load_node = iproject_load_node;
2494 iface->save_node = iproject_save_node;
2495 iface->add_node_before = iproject_add_node_before;
2496 iface->add_node_after = iproject_add_node_after;
2497 iface->remove_node = iproject_remove_node;
2498 iface->set_property = iproject_set_property;
2499 iface->remove_property = iproject_remove_property;
2500 iface->get_root = iproject_get_root;
2501 iface->get_node_info = iproject_get_node_info;
2502 iface->is_loaded = iproject_is_loaded;
2505 /* AmpNode implementation
2506 *---------------------------------------------------------------------------*/
2508 static gboolean
2509 amp_project_load (AmpNode *root, AmpNode *parent, AmpProject *project, GError **error)
2511 return amp_project_load_root (AMP_PROJECT (root), error);
2514 static gboolean
2515 amp_project_save (AmpNode *root, AmpNode *parent, AmpProject *project, GError **error)
2517 AnjutaTokenFile *tfile;
2518 AnjutaProjectNode *child;
2520 /* Save node */
2521 tfile = AMP_PROJECT (root)->configure_file;
2522 if (anjuta_token_file_is_dirty (tfile))
2524 if (!anjuta_token_file_save (tfile, error)) return FALSE;
2527 if (!AMP_NODE_CLASS (parent_class)->save (root, parent, project, error))
2529 return FALSE;
2532 /* Save all children */
2533 for (child = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (root)); child != NULL; child = anjuta_project_node_next_sibling (child))
2535 if (!amp_node_save (AMP_NODE (child), root, project, error)) return FALSE;
2538 return TRUE;
2542 static gboolean
2543 amp_project_update (AmpNode *node, AmpNode *new_node)
2545 amp_project_update_root (AMP_PROJECT (node), AMP_PROJECT (new_node));
2547 return TRUE;
2550 static AmpNode *
2551 amp_project_copy (AmpNode *old_node)
2553 AmpNode *new_node;
2555 new_node = AMP_NODE_CLASS (amp_project_parent_class)->copy (old_node);
2556 ((AmpProject *)new_node)->lang_manager = (((AmpProject *)old_node)->lang_manager != NULL) ? g_object_ref (((AmpProject *)old_node)->lang_manager) : NULL;
2558 return new_node;
2562 /* GObject implementation
2563 *---------------------------------------------------------------------------*/
2565 static void
2566 amp_project_dispose (GObject *object)
2568 AmpProject *project;
2570 g_return_if_fail (AMP_IS_PROJECT (object));
2572 project = AMP_PROJECT (object);
2573 amp_project_unload (project);
2575 amp_project_clear (project);
2577 if (project->groups) g_hash_table_destroy (project->groups);
2578 project->groups = NULL;
2579 if (project->configs) g_hash_table_destroy (project->configs);
2580 project->configs = NULL;
2581 if (project->ac_variables) g_hash_table_destroy (project->ac_variables);
2582 project->ac_variables = NULL;
2584 if (project->queue) pm_command_queue_free (project->queue);
2585 project->queue = NULL;
2587 if (project->monitor) g_object_unref (project->monitor);
2588 project->monitor = NULL;
2590 if (project->lang_manager) g_object_unref (project->lang_manager);
2591 project->lang_manager = NULL;
2593 G_OBJECT_CLASS (parent_class)->dispose (object);
2596 static void
2597 amp_project_init (AmpProject *project)
2599 g_return_if_fail (project != NULL);
2600 g_return_if_fail (AMP_IS_PROJECT (project));
2602 /* project data */
2603 project->configure_file = NULL;
2604 project->configure_token = NULL;
2606 /* Hash tables */
2607 project->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2608 project->files = NULL;
2609 project->configs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, (GDestroyNotify)amp_config_file_free);
2610 project->ac_variables = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
2612 /* Default style */
2613 project->am_space_list = NULL;
2614 project->ac_space_list = NULL;
2615 project->arg_list = NULL;
2617 project->queue = NULL;
2618 project->loading = 0;
2621 static void
2622 amp_project_class_init (AmpProjectClass *klass)
2624 GObjectClass *object_class;
2625 AmpNodeClass *node_class;
2627 parent_class = g_type_class_peek_parent (klass);
2629 object_class = G_OBJECT_CLASS (klass);
2630 object_class->dispose = amp_project_dispose;
2632 node_class = AMP_NODE_CLASS (klass);
2633 node_class->load = amp_project_load;
2634 node_class->save = amp_project_save;
2635 node_class->update = amp_project_update;
2636 node_class->copy = amp_project_copy;
2639 static void
2640 amp_project_class_finalize (AmpProjectClass *klass)
2644 void
2645 amp_project_register (GTypeModule *module)
2647 amp_node_register (module);
2648 amp_project_register_type (module);