1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
2 /* am-project.c
3  *
4  * Copyright (C) 2009  Sébastien Granjoux
5  *
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.
10  *
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.
15  *
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.
20  *
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include "am-project.h"
28 
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"
38 
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>
43 
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>
55 
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"
62 
63 
64 #define UNIMPLEMENTED  G_STMT_START { g_warning (G_STRLOC": unimplemented"); } G_STMT_END
65 
66 /* Constant strings for parsing perl script error output */
67 #define ERROR_PREFIX      "ERROR("
68 #define WARNING_PREFIX    "WARNING("
69 #define MESSAGE_DELIMITER ": "
70 
71 const gchar *valid_am_makefiles[] = {"GNUmakefile.am", "makefile.am", "Makefile.am", NULL};
72 
73 
74 #define STR_REPLACE(target, source) \
75 	{ g_free (target); target = source == NULL ? NULL : g_strdup (source);}
76 
77 
78 typedef struct _AmpConfigFile AmpConfigFile;
79 
80 struct _AmpConfigFile {
81 	GFile *file;
82 	AnjutaToken *token;
83 };
84 
85 /* Node types
86  *---------------------------------------------------------------------------*/
87 
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},
96 
97 	{{ANJUTA_PROJECT_GROUP,
98 	N_("Group"),
99 	"text/plain",
100 	"autotools-project-folder-edit"},
101 	ANJUTA_TOKEN_NONE,
102 	NULL,
103 	NULL},
104 
105 	{{ANJUTA_PROJECT_SOURCE,
106 	N_("Source"),
107 	"text/plain",
108 	NULL},
109 	ANJUTA_TOKEN_NONE,
110 	NULL,
111 	NULL},
112 
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},
122 
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"},
130 
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"},
138 
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"},
146 
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"},
154 
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"},
162 
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"},
170 
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"},
178 
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"},
186 
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"},
194 
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"},
202 
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"},
210 
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"},
218 
219 	{{ANJUTA_PROJECT_MODULE,
220 	N_("Module"),
221 	"",
222 	NULL},
223 	ANJUTA_TOKEN_NONE,
224 	NULL,
225 	NULL},
226 
227 	{{ANJUTA_PROJECT_PACKAGE,
228 	N_("Package"),
229 	"",
230 	NULL},
231 	ANJUTA_TOKEN_NONE,
232 	NULL,
233 	NULL},
234 
235 	{{ANJUTA_PROJECT_UNKNOWN,
236 	NULL,
237 	NULL,
238 	NULL},
239 	ANJUTA_TOKEN_NONE,
240 	NULL,
241 	NULL}
242 };
243 
244 /* Types
245  *---------------------------------------------------------------------------*/
246 
247 static void iproject_iface_init(IAnjutaProjectIface* iface);
248 
249 G_DEFINE_DYNAMIC_TYPE_EXTENDED (AmpProject,
250                                 amp_project,
251                                 AMP_TYPE_ROOT_NODE,
252                                 0,
253                                 G_IMPLEMENT_INTERFACE_DYNAMIC (IANJUTA_TYPE_PROJECT,
254                                                                iproject_iface_init));
255 
256 
257 
258 /* Properties
259  *---------------------------------------------------------------------------*/
260 
261 
262 /* ----- Standard GObject types and variables ----- */
263 
264 enum {
265 	PROP_0,
266 	PROP_PROJECT_DIR
267 };
268 
269 static GObject *parent_class;
270 
271 /* Helper functions
272  *---------------------------------------------------------------------------*/
273 
274 /* Work even if file is not a descendant of parent */
275 gchar*
get_relative_path(GFile * parent,GFile * file)276 get_relative_path (GFile *parent, GFile *file)
277 {
278 	gchar *relative;
279 
280 	if (file == NULL)
281 	{
282 		g_warning("get_relative_path for a NULL file");
283 		return NULL;
284 	}
285 
286 	relative = g_file_get_relative_path (parent, file);
287 	if (relative == NULL)
288 	{
289 		if (g_file_equal (parent, file))
290 		{
291 			relative = g_strdup (".");
292 		}
293 		else
294 		{
295 			GFile *grand_parent = g_file_get_parent (parent);
296 			gint level;
297 			gchar *grand_relative;
298 			gchar *ptr;
299 			gsize len;
300 
301 
302 			for (level = 1;  !g_file_has_prefix (file, grand_parent); level++)
303 			{
304 				GFile *next = g_file_get_parent (grand_parent);
305 
306 				g_object_unref (grand_parent);
307 				grand_parent = next;
308 			}
309 
310 			grand_relative = g_file_get_relative_path (grand_parent, file);
311 			g_object_unref (grand_parent);
312 
313 			len = strlen (grand_relative);
314 			relative = g_new (gchar, len + level * 3 + 1);
315 			ptr = relative;
316 			for (; level; level--)
317 			{
318 				memcpy(ptr, ".." G_DIR_SEPARATOR_S, 3);
319 				ptr += 3;
320 			}
321 			memcpy (ptr, grand_relative, len + 1);
322 			g_free (grand_relative);
323 		}
324 	}
325 
326 	return relative;
327 }
328 
329 GFileType
file_type(GFile * file,const gchar * filename)330 file_type (GFile *file, const gchar *filename)
331 {
332 	GFile *child;
333 	GFileInfo *info;
334 	GFileType type;
335 
336 	child = filename != NULL ? g_file_get_child (file, filename) : g_object_ref (file);
337 
338 	info = g_file_query_info (child,
339 	                          G_FILE_ATTRIBUTE_STANDARD_TYPE,
340 	                          G_FILE_QUERY_INFO_NONE,
341 	                          NULL,
342 	                          NULL);
343 	if (info != NULL)
344 	{
345 		type = g_file_info_get_file_type (info);
346 		g_object_unref (info);
347 	}
348 	else
349 	{
350 		type = G_FILE_TYPE_UNKNOWN;
351 	}
352 
353 	g_object_unref (child);
354 
355 	return type;
356 }
357 
358 /* Automake parsing function
359  *---------------------------------------------------------------------------*/
360 
361 /* Remove invalid character according to automake rules */
362 gchar*
canonicalize_automake_variable(const gchar * name)363 canonicalize_automake_variable (const gchar *name)
364 {
365 	gchar *canon_name = g_strdup (name);
366 	gchar *ptr;
367 
368 	for (ptr = canon_name; *ptr != '\0'; ptr++)
369 	{
370 		if (!g_ascii_isalnum (*ptr) && (*ptr != '@'))
371 		{
372 			*ptr = '_';
373 		}
374 	}
375 
376 	return canon_name;
377 }
378 
379 gboolean
split_automake_variable(gchar * name,gint * flags,gchar ** module,gchar ** primary)380 split_automake_variable (gchar *name, gint *flags, gchar **module, gchar **primary)
381 {
382 	gboolean res = FALSE;
383 	GRegex *regex;
384 	GMatchInfo *match_info;
385 	gint start_pos;
386 	gint end_pos;
387 
388 	regex = g_regex_new ("(nobase_|notrans_)?"
389 	                     "(dist_|nodist_)?"
390 	                     "(noinst_|check_|man_|man[0-9al]_)?"
391 	                     "(.*_)?"
392 	                     "([^_]+)",
393 	                     G_REGEX_ANCHORED,
394 	                     G_REGEX_MATCH_ANCHORED,
395 	                     NULL);
396 
397 	if (!g_regex_match (regex, name, G_REGEX_MATCH_ANCHORED, &match_info))
398 		goto out;
399 
400 	if (flags)
401 	{
402 		*flags = 0;
403 		g_match_info_fetch_pos (match_info, 1, &start_pos, &end_pos);
404 		if (start_pos >= 0)
405 		{
406 			if (*(name + start_pos + 2) == 'b') *flags |= AM_TARGET_NOBASE;
407 			if (*(name + start_pos + 2) == 't') *flags |= AM_TARGET_NOTRANS;
408 		}
409 
410 		g_match_info_fetch_pos (match_info, 2, &start_pos, &end_pos);
411 		if (start_pos >= 0)
412 		{
413 			if (*(name + start_pos) == 'd') *flags |= AM_TARGET_DIST;
414 			if (*(name + start_pos) == 'n') *flags |= AM_TARGET_NODIST;
415 		}
416 
417 		g_match_info_fetch_pos (match_info, 3, &start_pos, &end_pos);
418 		if (start_pos >= 0)
419 		{
420 			if (*(name + start_pos) == 'n') *flags |= AM_TARGET_NOINST;
421 			if (*(name + start_pos) == 'c') *flags |= AM_TARGET_CHECK;
422 			if (*(name + start_pos) == 'm')
423 			{
424 				gchar section = *(name + end_pos - 1);
425 				*flags |= AM_TARGET_MAN;
426 				if (section != 'n') *flags |= (section & 0x1F) << 7;
427 			}
428 		}
429 	}
430 
431 	if (module)
432 	{
433 		g_match_info_fetch_pos (match_info, 4, &start_pos, &end_pos);
434 		if (start_pos >= 0)
435 		{
436 			*module = name + start_pos;
437 			*(name + end_pos - 1) = '\0';
438 		}
439 		else
440 		{
441 			*module = NULL;
442 		}
443 	}
444 
445 	if (primary)
446 	{
447 		g_match_info_fetch_pos (match_info, 5, &start_pos, &end_pos);
448 		if (start_pos >= 0)
449 		{
450 			*primary = name + start_pos;
451 		}
452 		else
453 		{
454 			*primary = NULL;
455 		}
456 	}
457 
458 	res = TRUE;
459 
460 out:
461 	g_match_info_unref (match_info);
462 	g_regex_unref (regex);
463 
464 	return res;
465 }
466 
467 static gchar*
ac_init_default_tarname(const gchar * name)468 ac_init_default_tarname (const gchar *name)
469 {
470 	gchar *tarname;
471 
472 	if (name == NULL) return NULL;
473 
474 	/* Remove GNU prefix */
475 	if (strncmp (name, "GNU ", 4) == 0) name += 4;
476 
477 	tarname = g_ascii_strdown (name, -1);
478 	g_strcanon (tarname, "abcdefghijklmnopqrstuvwxyz0123456789", '-');
479 
480 	return tarname;
481 }
482 
483 /* Config file objects
484  *---------------------------------------------------------------------------*/
485 
486 static AmpConfigFile*
amp_config_file_new(const gchar * pathname,GFile * project_root,AnjutaToken * token)487 amp_config_file_new (const gchar *pathname, GFile *project_root, AnjutaToken *token)
488 {
489 	AmpConfigFile *config;
490 
491 	g_return_val_if_fail ((pathname != NULL) && (project_root != NULL), NULL);
492 
493 	config = g_slice_new0(AmpConfigFile);
494 	config->file = g_file_resolve_relative_path (project_root, pathname);
495 	config->token = token;
496 
497 	return config;
498 }
499 
500 static void
amp_config_file_free(AmpConfigFile * config)501 amp_config_file_free (AmpConfigFile *config)
502 {
503 	if (config)
504 	{
505 		g_object_unref (config->file);
506 		g_slice_free (AmpConfigFile, config);
507 	}
508 }
509 
510 static void
amp_project_clear(AmpProject * project)511 amp_project_clear (AmpProject *project)
512 {
513 	if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
514 	project->configure_file = NULL;
515 	if (project->configure_token) anjuta_token_free (project->configure_token);
516 	project->configure_token = NULL;
517 }
518 
519 static void
on_project_monitor_changed(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event_type,gpointer data)520 on_project_monitor_changed (GFileMonitor *monitor,
521 											GFile *file,
522 											GFile *other_file,
523 											GFileMonitorEvent event_type,
524 											gpointer data)
525 {
526 	AmpProject *project = AMP_PROJECT (data);
527 
528 	switch (event_type) {
529 		case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
530 		case G_FILE_MONITOR_EVENT_CHANGED:
531 		case G_FILE_MONITOR_EVENT_DELETED:
532 			/* project can be NULL, if the node is dummy node because the
533 			 * original one is reloaded. */
534 			g_signal_emit_by_name (G_OBJECT (project), "file-changed", data);
535 			break;
536 		default:
537 			break;
538 	}
539 }
540 
541 AnjutaTokenFile*
amp_project_set_configure(AmpProject * project,GFile * configure)542 amp_project_set_configure (AmpProject *project, GFile *configure)
543 {
544 	if (project->configure != NULL) g_object_unref (project->configure);
545 	if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
546 	if (project->monitor) g_object_unref (project->monitor);
547 	if (configure != NULL)
548 	{
549 		project->configure_file = anjuta_token_file_new (configure);
550 		project->configure = g_object_ref (configure);
551 
552 		project->monitor = g_file_monitor_file (configure,
553 						      									G_FILE_MONITOR_NONE,
554 						       									NULL,
555 						       									NULL);
556 		if (project->monitor != NULL)
557 		{
558 			g_signal_connect (G_OBJECT (project->monitor),
559 					  "changed",
560 					  G_CALLBACK (on_project_monitor_changed),
561 					  project);
562 		}
563 	}
564 	else
565 	{
566 		project->configure_file = NULL;
567 		project->configure = NULL;
568 		project->monitor = NULL;
569 	}
570 
571 	return project->configure_file;
572 }
573 
574 gboolean
amp_project_update_configure(AmpProject * project,AnjutaToken * token)575 amp_project_update_configure (AmpProject *project, AnjutaToken *token)
576 {
577 	return anjuta_token_file_update (project->configure_file, token);
578 }
579 
580 AnjutaToken*
amp_project_get_configure_token(AmpProject * project)581 amp_project_get_configure_token (AmpProject *project)
582 {
583 	return project->configure_token;
584 }
585 
586 AnjutaToken *
amp_project_get_config_token(AmpProject * project,GFile * file)587 amp_project_get_config_token (AmpProject *project, GFile *file)
588 {
589 	AmpConfigFile *config;
590 
591 	config = g_hash_table_lookup (project->configs, file);
592 
593 	return config != NULL ? config->token : NULL;
594 }
595 
596 static void
remove_config_file(gpointer data,GObject * object)597 remove_config_file (gpointer data, GObject *object)
598 {
599 	AmpProject *project = (AmpProject *)data;
600 
601 	g_return_if_fail (project->files != NULL);
602 
603 	project->files = g_list_remove (project->files, object);
604 }
605 
606 void
amp_project_update_root(AmpProject * project,AmpProject * new_project)607 amp_project_update_root (AmpProject *project, AmpProject *new_project)
608 {
609 	GHashTable *hash;
610 	GList *list;
611 	AnjutaTokenStyle *style;
612 
613 	if (project->configure != NULL) g_object_unref (project->configure);
614 	if (project->configure_file != NULL) anjuta_token_file_free (project->configure_file);
615 	if (project->monitor) g_object_unref (project->monitor);
616 
617 	project->configure = new_project->configure;
618 	if (project->configure != NULL)
619 	{
620 		project->monitor = g_file_monitor_file (project->configure,
621 						      						G_FILE_MONITOR_NONE,
622 						       						NULL,
623 						       						NULL);
624 		if (project->monitor != NULL)
625 		{
626 			g_signal_connect (G_OBJECT (project->monitor),
627 					  "changed",
628 					  G_CALLBACK (on_project_monitor_changed),
629 					  project);
630 		}
631 	}
632 	else
633 	{
634 		project->monitor = NULL;
635 	}
636 	new_project->configure = NULL;
637 	project->configure_file = new_project->configure_file;
638 	new_project->configure_file = NULL;
639 	project->configure_token = new_project->configure_token;
640 	new_project->configure_token = NULL;
641 
642 	hash = project->groups;
643 	project->groups = new_project->groups;
644 	new_project->groups = hash;
645 
646 	list = project->files;
647 	project->files = new_project->files;
648 	new_project->files = list;
649 
650 	for (list = project->files; list != NULL; list = g_list_next (list))
651 	{
652 		GObject *tfile = (GObject *)list->data;
653 
654 		g_object_weak_unref (tfile, remove_config_file, new_project);
655 		g_object_weak_ref (tfile, remove_config_file, project);
656 	}
657 	for (list = new_project->files; list != NULL; list = g_list_next (list))
658 	{
659 		GObject *tfile = (GObject *)list->data;
660 
661 		g_object_weak_unref (tfile, remove_config_file, project);
662 		g_object_weak_ref (tfile, remove_config_file, new_project);
663 	}
664 
665 	hash = project->configs;
666 	project->configs = new_project->configs;
667 	new_project->configs = hash;
668 
669 
670 	style = project->ac_space_list;
671 	project->ac_space_list = new_project->ac_space_list;
672 	new_project->ac_space_list = style;
673 
674 	style = project->am_space_list;
675 	project->am_space_list = new_project->am_space_list;
676 	new_project->am_space_list = style;
677 
678 	style = project->arg_list;
679 	project->arg_list = new_project->arg_list;
680 	new_project->arg_list = style;
681 
682 	AMP_NODE_CLASS (parent_class)->update (AMP_NODE (project), AMP_NODE (new_project));
683 }
684 
685 
686 /* Target objects
687  *---------------------------------------------------------------------------*/
688 
689 static gboolean
find_target(AnjutaProjectNode * node,gpointer data)690 find_target (AnjutaProjectNode *node, gpointer data)
691 {
692 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET)
693 	{
694 		if (strcmp (anjuta_project_node_get_name (node), *(gchar **)data) == 0)
695 		{
696 			/* Find target, return node value in pointer */
697 			*(AnjutaProjectNode **)data = node;
698 
699 			return TRUE;
700 		}
701 	}
702 
703 	return FALSE;
704 }
705 
706 static gboolean
find_canonical_target(AnjutaProjectNode * node,gpointer data)707 find_canonical_target (AnjutaProjectNode *node, gpointer data)
708 {
709 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET)
710 	{
711 		gchar *canon_name = canonicalize_automake_variable (anjuta_project_node_get_name (node));
712 		DEBUG_PRINT ("compare canon %s vs %s node %p", canon_name, *(gchar **)data, node);
713 		if (strcmp (canon_name, *(gchar **)data) == 0)
714 		{
715 			/* Find target, return node value in pointer */
716 			*(AnjutaProjectNode **)data = node;
717 			g_free (canon_name);
718 
719 			return TRUE;
720 		}
721 		g_free (canon_name);
722 	}
723 
724 	return FALSE;
725 }
726 
727 /*
728  * ---------------- Data structures managment
729  */
730 
731 void
amp_project_load_properties(AmpProject * project,AnjutaToken * macro,AnjutaToken * args)732 amp_project_load_properties (AmpProject *project, AnjutaToken *macro, AnjutaToken *args)
733 {
734 	GList *item;
735 	gint type = anjuta_token_get_type (macro);
736 
737 	for (item = anjuta_project_node_get_properties_info (ANJUTA_PROJECT_NODE (project)); item != NULL; item = g_list_next (item))
738 	{
739 		AmpPropertyInfo *info = (AmpPropertyInfo *)item->data;
740 
741 		if ((info->token_type == type) && (info->flags & AM_PROPERTY_IN_CONFIGURE))
742 		{
743 			AnjutaProjectProperty *new_prop;
744 
745 			new_prop = anjuta_project_node_get_property (ANJUTA_PROJECT_NODE (project), info->base.id);
746 			if ((new_prop != NULL) && (new_prop->info->default_value != new_prop))
747 			{
748 				anjuta_project_node_remove_property (ANJUTA_PROJECT_NODE (project), new_prop);
749 				amp_property_free (new_prop);
750 			}
751 			new_prop = amp_property_new (NULL, info->token_type, info->position, NULL, args);
752 
753 			if (info->position >= 0)
754 			{
755 				/* Each parameter correspond to a different property */
756 				AnjutaToken *arg;
757 
758 				arg = anjuta_token_nth_word (args, info->position);
759 				g_free (new_prop->value);
760 				new_prop->value = anjuta_token_evaluate_name (arg);
761 			}
762 			else
763 			{
764 				/* Property value is whole argument */
765 				if (args == NULL)
766 				{
767 					new_prop->value = g_strdup(" ");
768 				}
769 				else
770 				{
771 					AnjutaToken *arg;
772 
773 					arg = anjuta_token_nth_word (args, 0);
774 					new_prop->value = anjuta_token_evaluate_name (arg);
775 					if (new_prop->value == NULL) new_prop->value = g_strdup(" ");
776 				}
777 			}
778 			amp_node_property_add (ANJUTA_PROJECT_NODE (project), new_prop);
779 		}
780 	}
781 }
782 
783 void
amp_project_load_module(AmpProject * project,AnjutaToken * module_token)784 amp_project_load_module (AmpProject *project, AnjutaToken *module_token)
785 {
786 	AmpAcScanner *scanner = NULL;
787 
788 	if (module_token != NULL)
789 	{
790 		AnjutaToken *arg;
791 		AnjutaToken *list;
792 		AnjutaToken *item;
793 		gchar *value;
794 		AmpModuleNode *module;
795 		AmpPackageNode *package;
796 		gchar *compare;
797 
798 		/* Module name */
799 		arg = anjuta_token_first_item (module_token);
800 		value = anjuta_token_evaluate (arg);
801 		module = amp_module_node_new (value);
802 		amp_module_node_add_token (module, module_token);
803 		anjuta_project_node_append (ANJUTA_PROJECT_NODE (project), ANJUTA_PROJECT_NODE (module));
804 
805 		/* Package list */
806 		arg = anjuta_token_next_word (arg);
807 		if (arg != NULL)
808 		{
809 			scanner = amp_ac_scanner_new (project);
810 			list = amp_ac_scanner_parse_token (scanner, NULL, arg, AC_SPACE_LIST_STATE, NULL, NULL);
811 			anjuta_token_free_children (arg);
812 			list = anjuta_token_delete_parent (list);
813 			anjuta_token_prepend_items (arg, list);
814 			amp_ac_scanner_free (scanner);
815 		}
816 
817 		package = NULL;
818 		compare = NULL;
819 		for (item = anjuta_token_first_word (arg); item != NULL; item = anjuta_token_next_word (item))
820 		{
821 			value = anjuta_token_evaluate (item);
822 			if (value == NULL) continue;		/* Empty value, a comment of a quote by example */
823 			if (*value == '\0')
824 			{
825 				g_free (value);
826 				continue;
827 			}
828 
829 			if ((package != NULL) && (compare != NULL))
830 			{
831 				amp_package_node_set_version (package, compare, value);
832 				g_free (value);
833 				g_free (compare);
834 				package = NULL;
835 				compare = NULL;
836 			}
837 			else if ((package != NULL) && (anjuta_token_get_type (item) == ANJUTA_TOKEN_OPERATOR))
838 			{
839 				compare = value;
840 			}
841 			else
842 			{
843 				package = amp_package_node_new (value);
844 				amp_package_node_add_token (package, item);
845 				anjuta_project_node_append (ANJUTA_PROJECT_NODE (module), ANJUTA_PROJECT_NODE (package));
846 				anjuta_project_node_set_state (ANJUTA_PROJECT_NODE (package), ANJUTA_PROJECT_INCOMPLETE);
847 				g_free (value);
848 				compare = NULL;
849 			}
850 		}
851 	}
852 }
853 
854 void
amp_project_load_config(AmpProject * project,AnjutaToken * arg_list)855 amp_project_load_config (AmpProject *project, AnjutaToken *arg_list)
856 {
857 	AmpAcScanner *scanner = NULL;
858 
859 	if (arg_list != NULL)
860 	{
861 		AnjutaToken *arg;
862 		AnjutaToken *list;
863 		AnjutaToken *item;
864 
865 		/* File list */
866 		scanner = amp_ac_scanner_new (project);
867 
868 		arg = anjuta_token_first_word (arg_list);
869 		list = amp_ac_scanner_parse_token (scanner, NULL, arg, AC_SPACE_LIST_STATE, NULL, NULL);
870 		anjuta_token_free_children (arg);
871 		list = anjuta_token_delete_parent (list);
872 		amp_ac_scanner_free (scanner);
873 
874 		/* list can be NULL is there is no argument to AC_OUTPUT or AC_CONFIG_FILES */
875 		if (list != NULL)
876 		{
877 			anjuta_token_prepend_items (arg, list);
878 			for (item = anjuta_token_first_word (arg); item != NULL; item = anjuta_token_next_word (item))
879 			{
880 				gchar *value;
881 				AmpConfigFile *cfg;
882 
883 				value = anjuta_token_evaluate (item);
884 				if (value == NULL) continue;
885 
886 				cfg = amp_config_file_new (value, anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)), item);
887 				g_hash_table_replace (project->configs, cfg->file, cfg);
888 				g_free (value);
889 			}
890 		}
891 	}
892 }
893 
894 static AnjutaToken*
project_load_target(AmpProject * project,AnjutaProjectNode * parent,AnjutaToken * variable,GHashTable * orphan_properties)895 project_load_target (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties)
896 {
897 	AnjutaToken *arg;
898 	gchar *install = NULL;
899 	gchar *value;
900 	gint flags = 0;
901 	AmpNodeInfo *info = AmpNodeInformations;
902 
903 	while (info->base.type != 0)
904 	{
905 		if (anjuta_token_get_type (variable) == info->token)
906 		{
907 			break;
908 		}
909 		info++;
910 	}
911 
912 	value = anjuta_token_evaluate (anjuta_token_first_word (variable));
913 	split_automake_variable (value, &flags, &install, NULL);
914 
915 	amp_group_node_add_token (AMP_GROUP_NODE (parent), variable, AM_GROUP_TARGET);
916 
917 	for (arg = anjuta_token_first_word (anjuta_token_last_item (variable)); arg != NULL; arg = anjuta_token_next_word (arg))
918 	{
919 		gchar *value;
920 		gchar *canon_id;
921 		AmpTargetNode *target;
922 		AmpTargetNode *orphan;
923 		gchar *orig_key;
924 		gpointer find;
925 
926 		value = anjuta_token_evaluate (arg);
927 
928 		/* This happens for variable token which are considered as value */
929 		if (value == NULL) continue;
930 		canon_id = canonicalize_automake_variable (value);
931 
932 		/* Check if target already exists */
933 		find = value;
934 		anjuta_project_node_children_traverse (parent, find_target, &find);
935 		if ((gchar *)find != value)
936 		{
937 			/* Find target */
938 			g_free (canon_id);
939 			g_free (value);
940 			continue;
941 		}
942 
943 		/* Create target */
944 		target = amp_target_node_new (value, info->base.type, install, flags);
945 		if (target != NULL)
946 		{
947 			amp_target_node_add_token (target, ANJUTA_TOKEN_ARGUMENT, arg);
948 			anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (target));
949 			DEBUG_PRINT ("create target %p name %s", target, value);
950 
951 			/* Check if there are sources or properties availables */
952 			if (g_hash_table_lookup_extended (orphan_properties, canon_id, (gpointer *)&orig_key, (gpointer *)&orphan))
953 			{
954 				AnjutaTokenType type;
955 				GList *properties;
956 				AnjutaProjectNode *child;
957 
958 				g_hash_table_steal (orphan_properties, canon_id);
959 
960 				/* Copy all token */
961 				for (type = amp_target_node_get_first_token_type (orphan); type != 0; type = amp_target_node_get_next_token_type (orphan, type))
962 				{
963 					GList *tokens;
964 					tokens = amp_target_node_get_token (orphan, type);
965 
966 					for (tokens = g_list_first (tokens); tokens != NULL; tokens = g_list_next (tokens))
967 					{
968 						AnjutaToken *token = (AnjutaToken *)tokens->data;
969 
970 						amp_target_node_add_token (target, type, token);
971 					}
972 				}
973 
974 				/* Copy all properties */
975 				while ((properties = anjuta_project_node_get_properties (ANJUTA_PROJECT_NODE (orphan))) != NULL)
976 				{
977 					AnjutaProjectProperty *prop;
978 
979 					prop = (AnjutaProjectProperty *)anjuta_project_node_remove_property (ANJUTA_PROJECT_NODE (orphan), (AnjutaProjectProperty *)properties->data);
980 					amp_node_property_add ((AnjutaProjectNode *)target, prop);
981 				}
982 
983 				/* Copy all sources */
984 				while ((child = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (orphan))) != NULL)
985 				{
986 					anjuta_project_node_remove (child);
987 					anjuta_project_node_append (ANJUTA_PROJECT_NODE (target), child);
988 					g_object_unref (child);
989 				}
990 				amp_target_changed (target);
991 				g_free (orig_key);
992 				amp_target_node_free (orphan);
993 			}
994 
995 			/* Set target properties */
996 			if (flags & AM_TARGET_NOBASE)
997 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 0, "1", arg);
998 			if (flags & AM_TARGET_NOTRANS)
999 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 1, "1", arg);
1000 			if (flags & AM_TARGET_DIST)
1001 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "1", arg);
1002 			if (flags & AM_TARGET_NODIST)
1003 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "0", arg);
1004 			if (flags & AM_TARGET_NOINST)
1005 			{
1006 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 3, "1", arg);
1007 			}
1008 			else if (install != NULL)
1009 			{
1010 				gchar *instdir = g_strconcat (install, "dir", NULL);
1011 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 6, instdir, arg);
1012 				g_free (instdir);
1013 			}
1014 
1015 			if (flags & AM_TARGET_CHECK)
1016 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 4, "1", arg);
1017 			if (flags & AM_TARGET_MAN)
1018 			{
1019 				gchar section[] = "0";
1020 
1021 				section[0] += (flags >> 7) & 0x1F;
1022 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 4, section, arg);
1023 			}
1024 		}
1025 
1026 		g_free (canon_id);
1027 		g_free (value);
1028 	}
1029 	g_free (value);
1030 
1031 	return NULL;
1032 }
1033 
1034 static AnjutaToken*
project_load_sources(AmpProject * project,AnjutaProjectNode * group,AnjutaToken * variable,GHashTable * orphan_properties)1035 project_load_sources (AmpProject *project, AnjutaProjectNode *group, AnjutaToken *variable, GHashTable *orphan_properties)
1036 {
1037 	AnjutaToken *arg;
1038 	GFile *group_file = g_object_ref (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (group)));
1039 	gchar *target_id = NULL;
1040 
1041 	target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1042 	if (target_id)
1043 	{
1044 		gchar *end = strrchr (target_id, '_');
1045 		if (end)
1046 		{
1047 			*end = '\0';
1048 		}
1049 	}
1050 
1051 	if (target_id)
1052 	{
1053 		gpointer find;
1054 		AnjutaProjectNode *target;
1055 
1056 		find = target_id;
1057 		DEBUG_PRINT ("search for canonical %s", target_id);
1058 		anjuta_project_node_children_traverse (group, find_canonical_target, &find);
1059 		target = (gchar *)find != target_id ? (AnjutaProjectNode *)find : NULL;
1060 
1061 		/* Get orphan buffer if there is no target */
1062 		if (target == NULL)
1063 		{
1064 			gchar *orig_key;
1065 
1066 			if (g_hash_table_lookup_extended (orphan_properties, target_id, (gpointer *)&orig_key, (gpointer *)&target))
1067 			{
1068 				g_hash_table_steal (orphan_properties, target_id);
1069 				g_free (orig_key);
1070 			}
1071 			else
1072 			{
1073 				target = ANJUTA_PROJECT_NODE (amp_target_node_new ("dummy", 0, NULL, 0));
1074 			}
1075 			g_hash_table_insert (orphan_properties, target_id, target);
1076 		}
1077 		else
1078 		{
1079 			g_free (target_id);
1080 		}
1081 		amp_target_node_add_token (AMP_TARGET_NODE (target), AM_TOKEN__SOURCES, variable);
1082 
1083 		for (arg = anjuta_token_first_word (anjuta_token_last_item (variable)); arg != NULL; arg = anjuta_token_next_word (arg))
1084 		{
1085 			gchar *value;
1086 			AnjutaProjectNode *source;
1087 			AnjutaProjectNode *parent = target;
1088 			GFile *src_file;
1089 			GFileInfo* file_info;
1090 
1091 			value = anjuta_token_evaluate (arg);
1092 			if (value == NULL) continue;
1093 
1094 			src_file = g_file_get_child (group_file, value);
1095 			if (project->lang_manager != NULL)
1096 			{
1097 				file_info = g_file_query_info (src_file,
1098 					                                          G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1099 				    	                                      G_FILE_QUERY_INFO_NONE,
1100 		    		    	                                  NULL,
1101 		        		    	                              NULL);
1102 				if (file_info)
1103 				{
1104 					gint id = ianjuta_language_get_from_mime_type (project->lang_manager,
1105 			    		                                           g_file_info_get_content_type (file_info),
1106 			        		                                       NULL);
1107 					if (id > 0)
1108 					{
1109 						const gchar *obj_ext = ianjuta_language_get_make_target (project->lang_manager, id, NULL);
1110 						if (obj_ext != NULL)
1111 						{
1112 							/* Create object node */
1113 							gchar *object_name;
1114 							gchar *basename;
1115 							gchar *ext;
1116 							GFile *obj_file;
1117 							AnjutaProjectNode *object;
1118 
1119 							ext = strrchr (value, '.');
1120 							if ((ext != NULL) && (ext != value)) *ext = '\0';
1121 							object_name = g_strconcat (value, obj_ext, NULL);
1122 							basename = g_path_get_basename (object_name);
1123 							obj_file = g_file_get_child (group_file, basename);
1124 							g_free (basename);
1125 							g_free (object_name);
1126 							object = amp_object_node_new (obj_file, ANJUTA_PROJECT_PROJECT);
1127 							g_object_unref (obj_file);
1128 							anjuta_project_node_append (parent, object);
1129 							parent = object;
1130 						}
1131 					}
1132 					g_object_unref (file_info);
1133 				}
1134 			}
1135 
1136 			/* Create source */
1137 			source = amp_source_node_new (src_file, ANJUTA_PROJECT_PROJECT);
1138 			g_object_unref (src_file);
1139 			if (source != NULL)
1140 			{
1141 				amp_source_node_add_token (AMP_SOURCE_NODE (source), arg);
1142 
1143 				DEBUG_PRINT ("add target child %p", target);
1144 				/* Add as target child */
1145 				anjuta_project_node_append (parent, source);
1146 			}
1147 
1148 			g_free (value);
1149 		}
1150 		amp_target_changed (AMP_TARGET_NODE (target));
1151 	}
1152 
1153 	g_object_unref (group_file);
1154 
1155 	return NULL;
1156 }
1157 
1158 static AnjutaToken*
project_load_data(AmpProject * project,AnjutaProjectNode * parent,AnjutaToken * variable,GHashTable * orphan_properties,gint data_flags)1159 project_load_data (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties, gint data_flags)
1160 {
1161 	gchar *install = NULL;
1162 	AmpTargetNode *target;
1163 	gchar *target_id;
1164 	gpointer find;
1165 	gint flags = 0;
1166 	AmpNodeInfo *info = AmpNodeInformations;
1167 	AnjutaToken *arg;
1168 	AnjutaToken *list;
1169 
1170 	while (info->base.name != NULL)
1171 	{
1172 		if (anjuta_token_get_type (variable) == info->token)
1173 		{
1174 			break;
1175 		}
1176 		info++;
1177 	}
1178 
1179 	target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1180 	split_automake_variable (target_id, &flags, &install, NULL);
1181 
1182 	amp_group_node_add_token (AMP_GROUP_NODE (parent), variable, AM_GROUP_TARGET);
1183 
1184 	/* Check if target already exists */
1185 	find = target_id;
1186 	anjuta_project_node_children_traverse (parent, find_target, &find);
1187 	if ((gchar *)find == target_id)
1188 	{
1189 		/* Create target */
1190 		target = amp_target_node_new (target_id, info->base.type, install, flags);
1191 		if (target != NULL)
1192 		{
1193 			anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (target));
1194 			DEBUG_PRINT ("create target %p name %s", target, target_id);
1195 		}
1196 	}
1197 	else
1198 	{
1199 		target = AMP_TARGET_NODE (find);
1200 	}
1201 
1202 	if (target != NULL)
1203 	{
1204 		GFile *parent_file = g_object_ref (anjuta_project_node_get_file (parent));
1205 
1206 		amp_target_node_add_token (AMP_TARGET_NODE (target), AM_TOKEN__DATA, variable);
1207 
1208 		list = anjuta_token_last_item (variable);
1209 		for (arg = anjuta_token_first_word (list); arg != NULL; arg = anjuta_token_next_word (arg))
1210 		{
1211 			gchar *value;
1212 			AnjutaProjectNode *source;
1213 			GFile *src_file;
1214 
1215 			value = anjuta_token_evaluate (arg);
1216 			if (value == NULL) continue;
1217 
1218 			/* Create source */
1219 			src_file = g_file_get_child (parent_file, value);
1220 			source = amp_source_node_new (src_file, ANJUTA_PROJECT_PROJECT | data_flags);
1221 			g_object_unref (src_file);
1222 			if (source != NULL)
1223 			{
1224 				amp_source_node_add_token (AMP_SOURCE_NODE(source), arg);
1225 
1226 				/* Add as target child */
1227 				DEBUG_PRINT ("add target child %p", target);
1228 				anjuta_project_node_append (ANJUTA_PROJECT_NODE (target), source);
1229 			}
1230 
1231 			g_free (value);
1232 		}
1233 		g_object_unref (parent_file);
1234 
1235 		/* Set target properties */
1236 		if (flags & AM_TARGET_NOBASE)
1237 			amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 0, "1", arg);
1238 		if (flags & AM_TARGET_NOTRANS)
1239 			amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 1, "1", arg);
1240 		if (flags & AM_TARGET_DIST)
1241 			amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "1", arg);
1242 		if (flags & AM_TARGET_NODIST)
1243 			amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 2, "0", arg);
1244 		if (flags & AM_TARGET_NOINST)
1245 		{
1246 			amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 3, "1", arg);
1247 		}
1248 		else if (install != NULL)
1249 		{
1250 				gchar *instdir = g_strconcat (install, "dir", NULL);
1251 				amp_node_property_load (ANJUTA_PROJECT_NODE (target), AM_TOKEN__PROGRAMS, 6, instdir, arg);
1252 				g_free (instdir);
1253 		}
1254 	}
1255 	g_free (target_id);
1256 
1257 	return NULL;
1258 }
1259 
1260 static AnjutaToken*
project_load_target_properties(AmpProject * project,AnjutaProjectNode * parent,AnjutaToken * variable,GHashTable * orphan_properties)1261 project_load_target_properties (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable, GHashTable *orphan_properties)
1262 {
1263 	gchar *target_id = NULL;
1264 
1265 	target_id = anjuta_token_evaluate (anjuta_token_first_word (variable));
1266 	if (target_id)
1267 	{
1268 		gchar *end = strrchr (target_id, '_');
1269 		if (end)
1270 		{
1271 			*end = '\0';
1272 		}
1273 	}
1274 
1275 	if (target_id)
1276 	{
1277 		gpointer find;
1278 		gchar *value;
1279 		AnjutaProjectProperty *prop;
1280 		AnjutaToken *list;
1281 		AnjutaTokenType type;
1282 
1283 		find = target_id;
1284 		DEBUG_PRINT ("search for canonical %s", target_id);
1285 		anjuta_project_node_children_traverse (parent, find_canonical_target, &find);
1286 		parent = (gchar *)find != target_id ? (AnjutaProjectNode *)find : NULL;
1287 
1288 		/* Create property */
1289 		list = anjuta_token_last_item (variable);
1290 		type = anjuta_token_get_type (variable);
1291 		value = anjuta_token_evaluate_name (list);
1292 		prop = amp_property_new (NULL, type, 0, value, list);
1293 
1294 		if (parent == NULL)
1295 		{
1296 			/* Add property to non existing target, create a dummy target */
1297 			gchar *orig_key;
1298 
1299 			if (g_hash_table_lookup_extended (orphan_properties, target_id, (gpointer *)&orig_key, (gpointer *)&parent))
1300 			{
1301 				/* Dummy target already created */
1302 				g_hash_table_steal (orphan_properties, target_id);
1303 				g_free (orig_key);
1304 			}
1305 			else
1306 			{
1307 				/* Create dummy target */
1308 				parent = ANJUTA_PROJECT_NODE (amp_target_node_new ("dummy", 0, NULL, 0));
1309 			}
1310 			g_hash_table_insert (orphan_properties, target_id, parent);
1311 		}
1312 		else
1313 		{
1314 			g_free (target_id);
1315 		}
1316 		g_free (value);
1317 
1318 		/* Add property to target */
1319 		amp_node_property_add (parent, prop);
1320 		amp_target_node_add_token (AMP_TARGET_NODE (parent), type, variable);
1321 		amp_target_changed (AMP_TARGET_NODE (parent));
1322 	}
1323 
1324 	return NULL;
1325 }
1326 
1327 static AnjutaToken*
project_load_group_properties(AmpProject * project,AnjutaProjectNode * parent,AnjutaToken * variable)1328 project_load_group_properties (AmpProject *project, AnjutaProjectNode *parent, AnjutaToken *variable)
1329 {
1330 	gchar *value;
1331 	gchar *name;
1332 	AnjutaProjectProperty *prop;
1333 	AnjutaToken *list;
1334 
1335 	/* Create property */
1336 	list = anjuta_token_last_item (variable);
1337 	name = anjuta_token_evaluate (anjuta_token_first_word (variable));
1338 	value = anjuta_token_evaluate_name (list);
1339 
1340 	prop = amp_property_new (name, anjuta_token_get_type (variable), 0, value, list);
1341 
1342 	amp_node_property_add (parent, prop);
1343 
1344 	g_free (value);
1345 	g_free (name);
1346 
1347 	return NULL;
1348 }
1349 
1350 static gboolean
find_group(AnjutaProjectNode * node,gpointer data)1351 find_group (AnjutaProjectNode *node, gpointer data)
1352 {
1353 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1354 	{
1355 		if (g_file_equal (anjuta_project_node_get_file (node), (GFile *)data))
1356 		{
1357 			/* Find group, return node value in pointer */
1358 			return TRUE;
1359 		}
1360 	}
1361 
1362 	return FALSE;
1363 }
1364 
1365 static void
project_load_subdirs(AmpProject * project,AnjutaToken * list,AnjutaProjectNode * parent,gboolean dist_only)1366 project_load_subdirs (AmpProject *project, AnjutaToken *list, AnjutaProjectNode *parent, gboolean dist_only)
1367 {
1368 	AnjutaToken *arg;
1369 
1370 	for (arg = anjuta_token_first_word (list); arg != NULL; arg = anjuta_token_next_word (arg))
1371 	{
1372 		gchar *value;
1373 
1374 		value = anjuta_token_evaluate (arg);
1375 		if (value == NULL) continue;		/* Empty value, a comment of a quote by example */
1376 
1377 		/* Skip ., it is a special case, used to defined build order */
1378 		if (strcmp (value, ".") != 0)
1379 		{
1380 			GFile *subdir;
1381 			AmpGroupNode *group;
1382 
1383 			subdir = g_file_resolve_relative_path (anjuta_project_node_get_file (parent), value);
1384 
1385 			/* Look for already existing group */
1386 			group = AMP_GROUP_NODE (anjuta_project_node_children_traverse (parent, find_group, subdir));
1387 
1388 			if (group != NULL)
1389 			{
1390 				/* Already existing group, mark for built if needed */
1391 				if (!dist_only) amp_group_node_set_dist_only (group, FALSE);
1392 			}
1393 			else
1394 			{
1395 				/* Create new group */
1396 				group = amp_group_node_new (subdir, value, dist_only);
1397 
1398 				/* Group can be NULL if the name is not valid */
1399 				if (group != NULL)
1400 				{
1401 					g_hash_table_insert (project->groups, g_file_get_uri (subdir), group);
1402 					anjuta_project_node_append (parent, ANJUTA_PROJECT_NODE (group));
1403 
1404 					amp_node_load (AMP_NODE (group), NULL, project, NULL);
1405 				}
1406 			}
1407 			if (group) amp_group_node_add_token (group, arg, dist_only ? AM_GROUP_TOKEN_DIST_SUBDIRS : AM_GROUP_TOKEN_SUBDIRS);
1408 			g_object_unref (subdir);
1409 		}
1410 		g_free (value);
1411 	}
1412 }
1413 
1414 void
amp_project_set_am_variable(AmpProject * project,AmpGroupNode * group,AnjutaToken * variable,GHashTable * orphan_properties)1415 amp_project_set_am_variable (AmpProject* project, AmpGroupNode* group, AnjutaToken *variable, GHashTable *orphan_properties)
1416 {
1417 	AnjutaToken *list;
1418 
1419 	switch (anjuta_token_get_type (variable))
1420 	{
1421 	case AM_TOKEN_SUBDIRS:
1422 		list = anjuta_token_last_item (variable);
1423 		project_load_subdirs (project, list, ANJUTA_PROJECT_NODE (group), FALSE);
1424 		break;
1425 	case AM_TOKEN_DIST_SUBDIRS:
1426 		list = anjuta_token_last_item (variable);
1427 		project_load_subdirs (project, list, ANJUTA_PROJECT_NODE (group), TRUE);
1428 		break;
1429 	case AM_TOKEN__DATA:
1430 	case AM_TOKEN__HEADERS:
1431 	case AM_TOKEN__LISP:
1432 	case AM_TOKEN__MANS:
1433 	case AM_TOKEN__PYTHON:
1434 	case AM_TOKEN__JAVA:
1435 	case AM_TOKEN__TEXINFOS:
1436 		project_load_data (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties, 0);
1437 		break;
1438 	case AM_TOKEN__SCRIPTS:
1439 		project_load_data (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties, ANJUTA_PROJECT_EXECUTABLE);
1440 		break;
1441 	case AM_TOKEN__LIBRARIES:
1442 	case AM_TOKEN__LTLIBRARIES:
1443 	case AM_TOKEN__PROGRAMS:
1444 		project_load_target (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1445 		break;
1446 	case AM_TOKEN__SOURCES:
1447 		project_load_sources (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1448 		break;
1449 	case AM_TOKEN_DIR:
1450 	case AM_TOKEN__LDFLAGS:
1451 	case AM_TOKEN__CPPFLAGS:
1452 	case AM_TOKEN__CFLAGS:
1453 	case AM_TOKEN__CXXFLAGS:
1454 	case AM_TOKEN__JAVACFLAGS:
1455 	case AM_TOKEN__VALAFLAGS:
1456 	case AM_TOKEN__FCFLAGS:
1457 	case AM_TOKEN__OBJCFLAGS:
1458 	case AM_TOKEN__LFLAGS:
1459 	case AM_TOKEN__YFLAGS:
1460 		project_load_group_properties (project, ANJUTA_PROJECT_NODE (group), variable);
1461 		break;
1462 	case AM_TOKEN_TARGET_LDFLAGS:
1463 	case AM_TOKEN_TARGET_CPPFLAGS:
1464 	case AM_TOKEN_TARGET_CFLAGS:
1465 	case AM_TOKEN_TARGET_CXXFLAGS:
1466 	case AM_TOKEN_TARGET_JAVACFLAGS:
1467 	case AM_TOKEN_TARGET_VALAFLAGS:
1468 	case AM_TOKEN_TARGET_FCFLAGS:
1469 	case AM_TOKEN_TARGET_OBJCFLAGS:
1470 	case AM_TOKEN_TARGET_LFLAGS:
1471 	case AM_TOKEN_TARGET_YFLAGS:
1472 	case AM_TOKEN_TARGET_DEPENDENCIES:
1473 	case AM_TOKEN_TARGET_LIBADD:
1474 	case AM_TOKEN_TARGET_LDADD:
1475 		project_load_target_properties (project, ANJUTA_PROJECT_NODE (group), variable, orphan_properties);
1476 		break;
1477 	default:
1478 		break;
1479 	}
1480 
1481 	/* Keep the autotools variable as a normal variable too */
1482     amp_group_node_update_variable (group, variable);
1483 }
1484 
1485 /* Map function
1486  *---------------------------------------------------------------------------*/
1487 
1488 static gint
amp_project_compare_node(AnjutaProjectNode * old_node,AnjutaProjectNode * new_node)1489 amp_project_compare_node (AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1490 {
1491 	const gchar *name1;
1492 	const gchar *name2;
1493 	GFile *file1;
1494 	GFile *file2;
1495 
1496 	name1 = anjuta_project_node_get_name (old_node);
1497 	name2 = anjuta_project_node_get_name (new_node);
1498 	file1 = anjuta_project_node_get_file (old_node);
1499 	file2 = anjuta_project_node_get_file (new_node);
1500 
1501 	return (anjuta_project_node_get_full_type (old_node) == anjuta_project_node_get_full_type (new_node))
1502 		&& ((name1 == NULL) || (name2 == NULL) || (strcmp (name1, name2) == 0))
1503 		&& ((file1 == NULL) || (file2 == NULL) || g_file_equal (file1, file2)) ? 0 : 1;
1504 }
1505 
1506 static void
amp_project_map_children(GHashTable * map,AnjutaProjectNode * old_node,AnjutaProjectNode * new_node)1507 amp_project_map_children (GHashTable *map, AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1508 {
1509 	GList *children = NULL;
1510 
1511 	if (new_node != NULL)
1512 	{
1513 		for (new_node = anjuta_project_node_first_child (new_node); new_node != NULL; new_node = anjuta_project_node_next_sibling (new_node))
1514 		{
1515 			children = g_list_prepend (children, new_node);
1516 		}
1517 		children = g_list_reverse (children);
1518 	}
1519 
1520 	for (old_node = anjuta_project_node_first_child (old_node); old_node != NULL; old_node = anjuta_project_node_next_sibling (old_node))
1521 	{
1522 		GList *same;
1523 
1524 		same = g_list_find_custom (children, old_node, (GCompareFunc)amp_project_compare_node);
1525 
1526 		if (same != NULL)
1527 		{
1528 			/* Add new to old node mapping */
1529 			g_hash_table_insert (map, (AnjutaProjectNode *)same->data, old_node);
1530 
1531 			amp_project_map_children (map, old_node, (AnjutaProjectNode *)same->data);
1532 			children = g_list_delete_link (children, same);
1533 		}
1534 		else
1535 		{
1536 			/* Keep old_node to be deleted in the hash table as a key with a NULL
1537 			 * value */
1538 			g_hash_table_insert (map, old_node, NULL);
1539 		}
1540 	}
1541 
1542 	/* Add remaining node in hash table */
1543 	for (; children != NULL; children = g_list_delete_link (children,  children))
1544 	{
1545 		/* Keep new node without a corresponding old node as a key and a identical
1546 		 * value */
1547 		g_hash_table_insert (map, children->data, children->data);
1548 	}
1549 }
1550 
1551 /* Find the correspondance between the new loaded node (new_node) and the
1552  * original node currently in the tree (old_node) */
1553 static GHashTable *
amp_project_map_node(AnjutaProjectNode * old_node,AnjutaProjectNode * new_node)1554 amp_project_map_node (AnjutaProjectNode *old_node, AnjutaProjectNode *new_node)
1555 {
1556 	GHashTable *map;
1557 
1558 	map = g_hash_table_new (g_direct_hash, NULL);
1559 
1560 	g_hash_table_insert (map, new_node, old_node);
1561 
1562 	amp_project_map_children (map, old_node, new_node);
1563 
1564 	return map;
1565 }
1566 
1567 
1568 static void
amp_project_update_node(AnjutaProjectNode * key,AnjutaProjectNode * value,GHashTable * map)1569 amp_project_update_node (AnjutaProjectNode *key, AnjutaProjectNode *value, GHashTable *map)
1570 {
1571 	AnjutaProjectNode *old_node = NULL;	 /* The node that will be deleted */
1572 
1573 	if (value == NULL)
1574 	{
1575 		/* if value is NULL, delete the old node which is the key */
1576 		old_node = key;
1577 	}
1578 	else
1579 	{
1580 		AnjutaProjectNode *node = value;	/* The node that we keep in the tree */
1581 		AnjutaProjectNode *new_node = key;  /* The node with the new data */
1582 
1583 		if (new_node && new_node != node)
1584 		{
1585 			GList *properties;
1586 
1587 			amp_node_update (AMP_NODE (node), AMP_NODE (new_node));
1588 
1589 			/* Swap custom properties */
1590 			properties = node->properties;
1591 			node->properties = new_node->properties;
1592 			new_node->properties = properties;
1593 
1594 			if (new_node->parent == NULL)
1595 			{
1596 				/* This is the top loaded node, update only the children */
1597 				node->children = new_node->children;
1598 			}
1599 			else
1600 			{
1601 				/* Other node update all pointers */
1602 				node->parent = new_node->parent;
1603 				node->children = new_node->children;
1604 				node->next = new_node->next;
1605 				node->prev = new_node->prev;
1606 			}
1607 
1608 			/* Destroy node with data */
1609 			old_node = new_node;
1610 		}
1611 
1612 		/* Update links, using original node address if they stay in the tree */
1613 		new_node = g_hash_table_lookup (map, node->parent);
1614 		if (new_node != NULL) node->parent = new_node;
1615 		new_node = g_hash_table_lookup (map, node->children);
1616 		if (new_node != NULL) node->children = new_node;
1617 		new_node = g_hash_table_lookup (map, node->next);
1618 		if (new_node != NULL) node->next = new_node;
1619 		new_node = g_hash_table_lookup (map, node->prev);
1620 		if (new_node != NULL) node->prev = new_node;
1621 	}
1622 
1623 
1624 	/* Unlink old node and free it */
1625 	if (old_node != NULL)
1626 	{
1627 		old_node->parent = NULL;
1628 		old_node->children = NULL;
1629 		old_node->next = NULL;
1630 		old_node->prev = NULL;
1631 		g_object_unref (old_node);
1632 	}
1633 }
1634 
1635 /* Public functions
1636  *---------------------------------------------------------------------------*/
1637 
1638 AnjutaProjectNodeInfo *
amp_project_get_type_info(AmpProject * project,AnjutaProjectNodeType type)1639 amp_project_get_type_info (AmpProject *project, AnjutaProjectNodeType type)
1640 {
1641 	AmpNodeInfo *info;
1642 
1643 	for (info = AmpNodeInformations; info->base.type != type; info++)
1644 	{
1645 		if ((info->base.type == type) || (info->base.type == 0)) break;
1646 	}
1647 
1648 	return (AnjutaProjectNodeInfo *)info;
1649 }
1650 
1651 static gboolean
amp_project_load_root(AmpProject * project,GError ** error)1652 amp_project_load_root (AmpProject *project, GError **error)
1653 {
1654 	AmpAcScanner *scanner;
1655 	AnjutaToken *arg;
1656 	GFile *root_file;
1657 	GFile *configure_file;
1658 	AnjutaTokenFile *configure_token_file;
1659 	AnjutaProjectNode *source;
1660 	GError *err = NULL;
1661 
1662 	root_file = anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project));
1663 	DEBUG_PRINT ("reload project %p root file %p", project, root_file);
1664 
1665 	/* Unload current project */
1666 	amp_project_unload (project);
1667 
1668 	/* Initialize list styles */
1669 	project->ac_space_list = anjuta_token_style_new (NULL, " ", "\n", NULL, 0);
1670 	project->am_space_list = anjuta_token_style_new (NULL, " ", " \\\n\t", NULL, 0);
1671 	project->arg_list = anjuta_token_style_new (NULL, ", ", ", ", ")", 0);
1672 
1673 	/* Find configure file */
1674 	if (file_type (root_file, "configure.ac") == G_FILE_TYPE_REGULAR)
1675 	{
1676 		configure_file = g_file_get_child (root_file, "configure.ac");
1677 	}
1678 	else if (file_type (root_file, "configure.in") == G_FILE_TYPE_REGULAR)
1679 	{
1680 		configure_file = g_file_get_child (root_file, "configure.in");
1681 	}
1682 	else
1683 	{
1684 		g_set_error (error, IANJUTA_PROJECT_ERROR,
1685 					IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1686 			_("Project doesn't exist or invalid path"));
1687 
1688 		return FALSE;
1689 	}
1690 
1691 	/* Parse configure */
1692 	configure_token_file = amp_project_set_configure (project, configure_file);
1693 	amp_project_add_file (project, configure_file, configure_token_file);
1694 	source = amp_source_node_new (configure_file, ANJUTA_PROJECT_PROJECT | ANJUTA_PROJECT_FRAME | ANJUTA_PROJECT_READ_ONLY);
1695 	anjuta_project_node_append (ANJUTA_PROJECT_NODE (project), source);
1696 	arg = anjuta_token_file_load (configure_token_file, NULL);
1697 	g_hash_table_remove_all (project->ac_variables);
1698 	scanner = amp_ac_scanner_new (project);
1699 	project->configure_token = amp_ac_scanner_parse_token (scanner, NULL, arg, 0, configure_file, &err);
1700 	amp_ac_scanner_free (scanner);
1701 
1702 	if (project->configure_token == NULL)
1703 	{
1704 		if (err != NULL)
1705 		{
1706 			g_set_error_literal (error, IANJUTA_PROJECT_ERROR,
1707 						IANJUTA_PROJECT_ERROR_PROJECT_MALFORMED,
1708 						err->message);
1709 			g_error_free (err);
1710 		}
1711 		else
1712 		{
1713 			g_set_error (error, IANJUTA_PROJECT_ERROR,
1714 						IANJUTA_PROJECT_ERROR_PROJECT_MALFORMED,
1715 						"%s",
1716 						_("Unable to parse project file"));
1717 		}
1718 
1719 		return FALSE;
1720 	}
1721 
1722 	/* Load all makefiles recursively */
1723 	if (!AMP_NODE_CLASS (parent_class)->load (AMP_NODE (project), NULL, project, NULL))
1724 	{
1725 		g_set_error (error, IANJUTA_PROJECT_ERROR,
1726 					IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1727 			_("Project doesn't exist or has an invalid path"));
1728 
1729 		return FALSE;
1730 	}
1731 
1732 	return TRUE;
1733 }
1734 
1735 void
amp_project_unload(AmpProject * project)1736 amp_project_unload (AmpProject *project)
1737 {
1738 	/* project data */
1739 	amp_project_clear (project);
1740 
1741 	/* shortcut hash tables */
1742 	if (project->groups) g_hash_table_remove_all (project->groups);
1743 	if (project->files != NULL)
1744 	{
1745 		GList *list;
1746 
1747 		for (list = project->files; list != NULL; list = g_list_delete_link (list, list))
1748 		{
1749 			g_object_weak_unref (G_OBJECT (list->data), remove_config_file, project);
1750 		}
1751 		project->files = NULL;
1752 	}
1753 	if (project->configs) g_hash_table_remove_all (project->configs);
1754 
1755 	/* List styles */
1756 	if (project->am_space_list) anjuta_token_style_free (project->am_space_list);
1757 	if (project->ac_space_list) anjuta_token_style_free (project->ac_space_list);
1758 	if (project->arg_list) anjuta_token_style_free (project->arg_list);
1759 }
1760 
1761 gboolean
amp_project_is_loaded(AmpProject * project)1762 amp_project_is_loaded (AmpProject *project)
1763 {
1764 	return project->loading == 0;
1765 }
1766 
1767 gint
amp_project_probe(GFile * file,GError ** error)1768 amp_project_probe (GFile *file,
1769 	    GError     **error)
1770 {
1771 	gint probe;
1772 	gboolean dir;
1773 
1774 	dir = (file_type (file, NULL) == G_FILE_TYPE_DIRECTORY);
1775 	if (!dir)
1776 	{
1777 		g_set_error (error, IANJUTA_PROJECT_ERROR,
1778 		             IANJUTA_PROJECT_ERROR_DOESNT_EXIST,
1779 			   _("Project doesn't exist or invalid path"));
1780 	}
1781 
1782 	probe =  dir;
1783 	if (probe)
1784 	{
1785 		const gchar **makefile;
1786 
1787 		/* Look for makefiles */
1788 		probe = FALSE;
1789 		for (makefile = valid_am_makefiles; *makefile != NULL; makefile++)
1790 		{
1791 			if (file_type (file, *makefile) == G_FILE_TYPE_REGULAR)
1792 			{
1793 				probe = TRUE;
1794 				break;
1795 			}
1796 		}
1797 
1798 		if (probe)
1799 		{
1800 			probe = ((file_type (file, "configure.ac") == G_FILE_TYPE_REGULAR) ||
1801 			 				(file_type (file, "configure.in") == G_FILE_TYPE_REGULAR));
1802 		}
1803 	}
1804 
1805 	return probe ? IANJUTA_PROJECT_PROBE_PROJECT_FILES : 0;
1806 }
1807 
1808 gboolean
amp_project_get_token_location(AmpProject * project,AnjutaTokenFileLocation * location,AnjutaToken * token)1809 amp_project_get_token_location (AmpProject *project, AnjutaTokenFileLocation *location, AnjutaToken *token)
1810 {
1811 	GList *list;
1812 
1813 	for (list = project->files; list != NULL; list = g_list_next (list))
1814 	{
1815 		if (anjuta_token_file_get_token_location ((AnjutaTokenFile *)list->data, location, token))
1816 		{
1817 			return TRUE;
1818 		}
1819 	}
1820 
1821 	return FALSE;
1822 }
1823 
1824 void
amp_project_remove_group(AmpProject * project,AmpGroupNode * group,GError ** error)1825 amp_project_remove_group (AmpProject  *project,
1826 		   AmpGroupNode *group,
1827 		   GError     **error)
1828 {
1829 	GList *token_list;
1830 
1831 	if (anjuta_project_node_get_node_type (ANJUTA_PROJECT_NODE (group)) != ANJUTA_PROJECT_GROUP) return;
1832 
1833 	for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_CONFIGURE); token_list != NULL; token_list = g_list_next (token_list))
1834 	{
1835 		anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1836 	}
1837 	for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_SUBDIRS); token_list != NULL; token_list = g_list_next (token_list))
1838 	{
1839 		anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1840 	}
1841 	for (token_list = amp_group_node_get_token (group, AM_GROUP_TOKEN_DIST_SUBDIRS); token_list != NULL; token_list = g_list_next (token_list))
1842 	{
1843 		anjuta_token_remove_word ((AnjutaToken *)token_list->data);
1844 	}
1845 
1846 	amp_group_node_free (group);
1847 }
1848 
1849 void
amp_project_remove_source(AmpProject * project,AmpSourceNode * source,GError ** error)1850 amp_project_remove_source (AmpProject  *project,
1851 		    AmpSourceNode *source,
1852 		    GError     **error)
1853 {
1854 	if (anjuta_project_node_get_node_type (ANJUTA_PROJECT_NODE (source)) != ANJUTA_PROJECT_SOURCE) return;
1855 
1856 	anjuta_token_remove_word (amp_source_node_get_token (source));
1857 
1858 	amp_source_node_free (source);
1859 }
1860 
1861 const GList *
amp_project_get_node_info(AmpProject * project,GError ** error)1862 amp_project_get_node_info (AmpProject *project, GError **error)
1863 {
1864 	static GList *info_list = NULL;
1865 
1866 	if (info_list == NULL)
1867 	{
1868 		AmpNodeInfo *node;
1869 
1870 		for (node = AmpNodeInformations; node->base.type != 0; node++)
1871 		{
1872 			info_list = g_list_prepend (info_list, node);
1873 		}
1874 
1875 		info_list = g_list_reverse (info_list);
1876 	}
1877 
1878 	return info_list;
1879 }
1880 
1881 /* Public functions
1882  *---------------------------------------------------------------------------*/
1883 
1884 typedef struct _AmpMovePacket {
1885 	AmpProject *project;
1886 	GFile *old_root_file;
1887 	GFile *new_root_file;
1888 } AmpMovePacket;
1889 
1890 static void
foreach_node_move(AnjutaProjectNode * g_node,gpointer data)1891 foreach_node_move (AnjutaProjectNode *g_node, gpointer data)
1892 {
1893 	AmpProject *project = ((AmpMovePacket *)data)->project;
1894 	GFile *old_root_file = ((AmpMovePacket *)data)->old_root_file;
1895 	GFile *new_root_file = ((AmpMovePacket *)data)->new_root_file;
1896 	gchar *relative;
1897 	GFile *new_file;
1898 
1899 	switch (anjuta_project_node_get_node_type (g_node))
1900 	{
1901 	case ANJUTA_PROJECT_GROUP:
1902 		relative = get_relative_path (old_root_file, anjuta_project_node_get_file (g_node));
1903 		new_file = g_file_resolve_relative_path (new_root_file, relative);
1904 		g_free (relative);
1905 		amp_group_node_set_file (AMP_GROUP_NODE (g_node), new_file);
1906 		g_object_unref (new_file);
1907 
1908 		g_hash_table_insert (project->groups, g_file_get_uri (new_file), g_node);
1909 		break;
1910 	case ANJUTA_PROJECT_SOURCE:
1911 		relative = get_relative_path (old_root_file, anjuta_project_node_get_file (g_node));
1912 		new_file = g_file_resolve_relative_path (new_root_file, relative);
1913 		g_free (relative);
1914 		amp_source_node_set_file (AMP_SOURCE_NODE (g_node), new_file);
1915 		g_object_unref (new_file);
1916 		break;
1917 	default:
1918 		break;
1919 	}
1920 }
1921 
1922 gboolean
amp_project_move(AmpProject * project,const gchar * path)1923 amp_project_move (AmpProject *project, const gchar *path)
1924 {
1925 	GFile *new_file;
1926 	gchar *relative;
1927 	GList *list;
1928 	gpointer key;
1929 	AmpConfigFile *cfg;
1930 	GHashTable* old_hash;
1931 	GHashTableIter iter;
1932 	AmpMovePacket packet= {project, NULL};
1933 
1934 	/* Change project root directory */
1935 	packet.old_root_file = g_object_ref (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)));
1936 	packet.new_root_file = g_file_new_for_path (path);
1937 
1938 	/* Change project root directory in groups */
1939 	old_hash = project->groups;
1940 	project->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1941 	anjuta_project_node_foreach (ANJUTA_PROJECT_NODE (project), G_POST_ORDER, foreach_node_move, &packet);
1942 	g_hash_table_destroy (old_hash);
1943 
1944 	/* Change all files */
1945 	for (list = project->files; list != NULL; list = g_list_next (list))
1946 	{
1947 		AnjutaTokenFile *tfile = (AnjutaTokenFile *)list->data;
1948 
1949 		relative = get_relative_path (packet.old_root_file, anjuta_token_file_get_file (tfile));
1950 		new_file = g_file_resolve_relative_path (packet.new_root_file, relative);
1951 		g_free (relative);
1952 		anjuta_token_file_move (tfile, new_file);
1953 	}
1954 
1955 	/* Change all configs */
1956 	old_hash = project->configs;
1957 	project->configs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, (GDestroyNotify)amp_config_file_free);
1958 	g_hash_table_iter_init (&iter, old_hash);
1959 	while (g_hash_table_iter_next (&iter, &key, (gpointer *)&cfg))
1960 	{
1961 		relative = get_relative_path (packet.old_root_file, cfg->file);
1962 		new_file = g_file_resolve_relative_path (packet.new_root_file, relative);
1963 		g_free (relative);
1964 		g_object_unref (cfg->file);
1965 		cfg->file = new_file;
1966 
1967 		g_hash_table_insert (project->configs, new_file, cfg);
1968 	}
1969 	g_hash_table_steal_all (old_hash);
1970 	g_hash_table_destroy (old_hash);
1971 
1972 	g_object_unref (packet.old_root_file);
1973 	g_object_unref (packet.new_root_file);
1974 
1975 	return TRUE;
1976 }
1977 
1978 /* Dump file content of corresponding node */
1979 gboolean
amp_project_dump(AmpProject * project,AnjutaProjectNode * node,AmpFileType type)1980 amp_project_dump (AmpProject *project, AnjutaProjectNode *node, AmpFileType type)
1981 {
1982 	gboolean ok = FALSE;
1983 
1984 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1985 	{
1986 		switch (type)
1987 		{
1988 		case DUMP_MAKEFILE:
1989 			anjuta_token_dump (amp_group_node_get_makefile_token (AMP_GROUP_NODE (node)));
1990 			break;
1991 		case DUMP_CONFIGURE:
1992 			anjuta_token_dump (AMP_PROJECT (node)->configure_token);
1993 			break;
1994 		default:
1995 			break;
1996 		}
1997 	}
1998 
1999 	return ok;
2000 }
2001 
2002 
2003 AmpProject *
amp_project_new(GFile * file,IAnjutaLanguage * language,GError ** error)2004 amp_project_new (GFile *file, IAnjutaLanguage *language, GError **error)
2005 {
2006 	AmpProject *project;
2007 	GFile *new_file;
2008 
2009 	project = AMP_PROJECT (g_object_new (AMP_TYPE_PROJECT, NULL));
2010 	new_file = g_file_dup (file);
2011 	amp_root_node_set_file (AMP_ROOT_NODE (project), new_file);
2012 	g_object_unref (new_file);
2013 
2014 	project->lang_manager = (language != NULL) ? g_object_ref (language) : NULL;
2015 
2016 	return project;
2017 }
2018 
2019 /* Project access functions
2020  *---------------------------------------------------------------------------*/
2021 
2022 AmpProject *
amp_project_get_root(AmpProject * project)2023 amp_project_get_root (AmpProject *project)
2024 {
2025 	return AMP_PROJECT (project);
2026 }
2027 
2028 AmpGroupNode *
amp_project_get_group(AmpProject * project,const gchar * id)2029 amp_project_get_group (AmpProject *project, const gchar *id)
2030 {
2031 	return (AmpGroupNode *)g_hash_table_lookup (project->groups, id);
2032 }
2033 
2034 AmpTargetNode *
amp_project_get_target(AmpProject * project,const gchar * id)2035 amp_project_get_target (AmpProject *project, const gchar *id)
2036 {
2037 	AmpTargetNode **buffer;
2038 	AmpTargetNode *target;
2039 	gsize dummy;
2040 
2041 	buffer = (AmpTargetNode **)g_base64_decode (id, &dummy);
2042 	target = *buffer;
2043 	g_free (buffer);
2044 
2045 	return target;
2046 }
2047 
2048 AmpSourceNode *
amp_project_get_source(AmpProject * project,const gchar * id)2049 amp_project_get_source (AmpProject *project, const gchar *id)
2050 {
2051 	AmpSourceNode **buffer;
2052 	AmpSourceNode *source;
2053 	gsize dummy;
2054 
2055 	buffer = (AmpSourceNode **)g_base64_decode (id, &dummy);
2056 	source = *buffer;
2057 	g_free (buffer);
2058 
2059 	return source;
2060 }
2061 
2062 gchar *
amp_project_get_uri(AmpProject * project)2063 amp_project_get_uri (AmpProject *project)
2064 {
2065 	g_return_val_if_fail (project != NULL, NULL);
2066 
2067 	return g_file_get_uri (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)));
2068 }
2069 
2070 GFile*
amp_project_get_file(AmpProject * project)2071 amp_project_get_file (AmpProject *project)
2072 {
2073 	g_return_val_if_fail (project != NULL, NULL);
2074 
2075 	return anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project));
2076 }
2077 
2078 void
amp_project_add_file(AmpProject * project,GFile * file,AnjutaTokenFile * token)2079 amp_project_add_file (AmpProject *project, GFile *file, AnjutaTokenFile* token)
2080 {
2081 	project->files = g_list_prepend (project->files, token);
2082 	g_object_weak_ref (G_OBJECT (token), remove_config_file, project);
2083 }
2084 
2085 void
amp_project_add_subst_variable(AmpProject * project,const gchar * name,AnjutaToken * value)2086 amp_project_add_subst_variable (AmpProject *project, const gchar *name, AnjutaToken *value)
2087 {
2088 	g_hash_table_insert (project->ac_variables, (gchar *)name, value);
2089 }
2090 
2091 AnjutaToken *
amp_project_get_subst_variable_token(AmpProject * project,const gchar * name)2092 amp_project_get_subst_variable_token (AmpProject *project, const gchar *name)
2093 {
2094 	return g_hash_table_lookup (project->ac_variables, name);
2095 }
2096 
2097 
2098 gboolean
amp_project_is_busy(AmpProject * project)2099 amp_project_is_busy (AmpProject *project)
2100 {
2101 	if (project->queue == NULL) return FALSE;
2102 
2103 	return pm_command_queue_is_busy (project->queue);
2104 }
2105 
2106 /* Worker thread
2107  *---------------------------------------------------------------------------*/
2108 
2109 static gboolean
amp_load_setup(PmJob * job)2110 amp_load_setup (PmJob *job)
2111 {
2112 	//anjuta_project_node_check (job->node);
2113 	pm_job_set_parent (job, anjuta_project_node_parent (job->node));
2114 	job->proxy = ANJUTA_PROJECT_NODE (amp_node_copy (AMP_NODE (job->node)));
2115 
2116 	return TRUE;
2117 }
2118 
2119 static gboolean
amp_load_work(PmJob * job)2120 amp_load_work (PmJob *job)
2121 {
2122 	return amp_node_load (AMP_NODE (job->proxy), AMP_NODE (job->parent), AMP_PROJECT (job->user_data), &job->error);
2123 }
2124 
2125 static gboolean
amp_load_complete(PmJob * job)2126 amp_load_complete (PmJob *job)
2127 {
2128 	GHashTable *map;
2129 	//static GTimer *timer = NULL;
2130 
2131 	g_return_val_if_fail (job->proxy != NULL, FALSE);
2132 
2133 	//anjuta_project_node_check (job->node);
2134 	/*if (timer == NULL)
2135 	{
2136 		timer = g_timer_new ();
2137 	}
2138 	else
2139 	{
2140 		g_timer_continue (timer);
2141 	}*/
2142 	map = amp_project_map_node (job->node, job->proxy);
2143 	g_object_ref (job->proxy);
2144 
2145 	job->proxy->parent = NULL;	// Mark loaded top node
2146 	g_hash_table_foreach (map, (GHFunc)amp_project_update_node, map);
2147 	//anjuta_project_node_check (job->node);
2148 	g_hash_table_destroy (map);
2149 	g_object_unref (job->proxy);
2150 	job->proxy = NULL;
2151 	AMP_PROJECT (job->user_data)->loading--;
2152 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-loaded", job->node,  job->error);
2153 	//g_timer_stop (timer);
2154 	//g_message ("amp_load_complete completed in %g", g_timer_elapsed (timer, NULL));
2155 
2156 	return TRUE;
2157 }
2158 
2159 static PmCommandWork amp_load_job = {amp_load_setup, amp_load_work, amp_load_complete};
2160 
2161 static gboolean
amp_save_setup(PmJob * job)2162 amp_save_setup (PmJob *job)
2163 {
2164 	return TRUE;
2165 }
2166 
2167 static gboolean
amp_save_work(PmJob * job)2168 amp_save_work (PmJob *job)
2169 {
2170 	/* It is difficult to save only a particular node, so the whole project is saved */
2171 	amp_node_save (AMP_NODE (job->user_data), NULL, AMP_PROJECT (job->user_data), &job->error);
2172 
2173 	return TRUE;
2174 }
2175 
2176 static gboolean
amp_save_complete(PmJob * job)2177 amp_save_complete (PmJob *job)
2178 {
2179 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-saved", job->node,  job->error);
2180 
2181 	return TRUE;
2182 }
2183 
2184 static PmCommandWork amp_save_job = {amp_save_setup, amp_save_work, amp_save_complete};
2185 
2186 static gboolean
amp_add_before_setup(PmJob * job)2187 amp_add_before_setup (PmJob *job)
2188 {
2189 	/* If add is called to add the root group, the node is already existing */
2190 	if (job->parent != job->node)
2191 		anjuta_project_node_insert_before (job->parent, job->sibling, job->node);
2192 
2193 	return TRUE;
2194 }
2195 
2196 static gboolean
amp_add_after_setup(PmJob * job)2197 amp_add_after_setup (PmJob *job)
2198 {
2199 	/* If add is called to add the root group, the node is already existing */
2200 	if (job->parent != job->node)
2201 		anjuta_project_node_insert_after (job->parent, job->sibling, job->node);
2202 
2203 	return TRUE;
2204 }
2205 
2206 static gboolean
amp_add_work(PmJob * job)2207 amp_add_work (PmJob *job)
2208 {
2209 	AmpNode *parent = AMP_NODE (job->parent);
2210 	gboolean ok;
2211 
2212 	ok = amp_node_write (AMP_NODE (job->node), parent, AMP_PROJECT (job->user_data), &job->error);
2213 	/* Add new node properties if existing */
2214 	if (ok)
2215 	{
2216 		GList *item;
2217 
2218 		for (item = anjuta_project_node_get_properties (ANJUTA_PROJECT_NODE (job->node)); item != NULL; item = g_list_next (item))
2219 		{
2220 			AnjutaProjectProperty *property = (AnjutaProjectProperty *)item->data;
2221 			gint flags;
2222 
2223 			flags = ((AmpPropertyInfo *)property->info)->flags;
2224 			if (flags & AM_PROPERTY_IN_CONFIGURE)
2225 			{
2226 				ok = ok && amp_project_update_ac_property (AMP_PROJECT (job->user_data), property);
2227 			}
2228 			else if (flags & AM_PROPERTY_IN_MAKEFILE)
2229 			{
2230 				if (((AnjutaProjectPropertyInfo *)property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2231 				{
2232 					ok = ok && amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, property);
2233 				}
2234 			}
2235 		}
2236 	}
2237 
2238 	return ok;
2239 }
2240 
2241 static gboolean
amp_add_complete(PmJob * job)2242 amp_add_complete (PmJob *job)
2243 {
2244 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->parent,  job->error);
2245 
2246 	return TRUE;
2247 }
2248 
2249 static PmCommandWork amp_add_before_job = {amp_add_before_setup, amp_add_work, amp_add_complete};
2250 static PmCommandWork amp_add_after_job = {amp_add_after_setup, amp_add_work, amp_add_complete};
2251 
2252 
2253 static gboolean
amp_remove_setup(PmJob * job)2254 amp_remove_setup (PmJob *job)
2255 {
2256 	AnjutaProjectNode *parent;
2257 
2258 	parent = anjuta_project_node_parent (job->node);
2259 	if (parent == NULL) parent = job->node;
2260 	pm_job_set_parent (job, parent);
2261 	anjuta_project_node_set_state (job->node, ANJUTA_PROJECT_REMOVED);
2262 
2263 	return TRUE;
2264 }
2265 
2266 static gboolean
amp_remove_work(PmJob * job)2267 amp_remove_work (PmJob *job)
2268 {
2269 	AmpNode *parent = AMP_NODE (job->parent);
2270 	gboolean ok;
2271 
2272 	ok = amp_node_erase (AMP_NODE (job->node), parent, AMP_PROJECT (job->user_data), &job->error);
2273 
2274 	return ok;
2275 }
2276 
2277 static gboolean
amp_remove_complete(PmJob * job)2278 amp_remove_complete (PmJob *job)
2279 {
2280 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->parent,  job->error);
2281 
2282 	return TRUE;
2283 }
2284 
2285 static PmCommandWork amp_remove_job = {amp_remove_setup, amp_remove_work, amp_remove_complete};
2286 
2287 static gboolean
amp_set_property_setup(PmJob * job)2288 amp_set_property_setup (PmJob *job)
2289 {
2290 	return TRUE;
2291 }
2292 
2293 static gboolean
amp_set_property_work(PmJob * job)2294 amp_set_property_work (PmJob *job)
2295 {
2296 	gint flags;
2297 
2298 	flags = ((AmpPropertyInfo *)job->property->info)->flags;
2299 
2300 	if (flags & AM_PROPERTY_IN_CONFIGURE)
2301 	{
2302 		amp_project_update_ac_property (AMP_PROJECT (job->user_data), job->property);
2303 	}
2304 	else if (flags & AM_PROPERTY_IN_MAKEFILE)
2305 	{
2306 		if (((AnjutaProjectPropertyInfo *)job->property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2307 		{
2308 			amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, job->property);
2309 		}
2310 	}
2311 
2312 	return TRUE;
2313 }
2314 
2315 static gboolean
amp_set_property_complete(PmJob * job)2316 amp_set_property_complete (PmJob *job)
2317 {
2318 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->node,  job->error);
2319 
2320 	return TRUE;
2321 }
2322 
2323 static PmCommandWork amp_set_property_job = {amp_set_property_setup, amp_set_property_work, amp_set_property_complete};
2324 
2325 static gboolean
amp_remove_property_setup(PmJob * job)2326 amp_remove_property_setup (PmJob *job)
2327 {
2328 	return TRUE;
2329 }
2330 
2331 static gboolean
amp_remove_property_work(PmJob * job)2332 amp_remove_property_work (PmJob *job)
2333 {
2334 	gint flags;
2335 
2336 	flags = ((AmpPropertyInfo *)job->property->info)->flags;
2337 
2338 	if (flags & AM_PROPERTY_IN_CONFIGURE)
2339 	{
2340 		amp_project_update_ac_property (AMP_PROJECT (job->user_data), job->property);
2341 	}
2342 	else if (flags & AM_PROPERTY_IN_MAKEFILE)
2343 	{
2344 		if (((AnjutaProjectPropertyInfo *)job->property->info)->flags & ANJUTA_PROJECT_PROPERTY_READ_WRITE)
2345 		{
2346 			amp_project_update_am_property (AMP_PROJECT (job->user_data), job->node, job->property);
2347 		}
2348 	}
2349 
2350 	return TRUE;
2351 }
2352 
2353 static gboolean
amp_remove_property_complete(PmJob * job)2354 amp_remove_property_complete (PmJob *job)
2355 {
2356 	g_signal_emit_by_name (AMP_PROJECT (job->user_data), "node-changed", job->node,  job->error);
2357 
2358 	return TRUE;
2359 }
2360 
2361 static PmCommandWork amp_remove_property_job = {amp_remove_property_setup, amp_remove_property_work, amp_remove_property_complete};
2362 
2363 /* Implement IAnjutaProject
2364  *---------------------------------------------------------------------------*/
2365 
2366 static gboolean
iproject_load_node(IAnjutaProject * obj,AnjutaProjectNode * node,GError ** error)2367 iproject_load_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **error)
2368 {
2369 	PmJob *load_job;
2370 
2371 	if (node == NULL) node = ANJUTA_PROJECT_NODE (obj);
2372 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2373 
2374 	AMP_PROJECT (obj)->loading++;
2375 	load_job = pm_job_new (&amp_load_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2376 
2377 	pm_command_queue_push (AMP_PROJECT (obj)->queue, load_job);
2378 
2379 	return TRUE;
2380 }
2381 
2382 static gboolean
iproject_save_node(IAnjutaProject * obj,AnjutaProjectNode * node,GError ** error)2383 iproject_save_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **error)
2384 {
2385 	PmJob *save_job;
2386 
2387 	if (node == NULL) node = ANJUTA_PROJECT_NODE (obj);
2388 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2389 
2390 	save_job = pm_job_new (&amp_save_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2391 	pm_command_queue_push (AMP_PROJECT (obj)->queue, save_job);
2392 
2393 	return TRUE;
2394 }
2395 
2396 static AnjutaProjectNode *
iproject_add_node_before(IAnjutaProject * obj,AnjutaProjectNode * parent,AnjutaProjectNode * sibling,AnjutaProjectNodeType type,GFile * file,const gchar * name,GError ** err)2397 iproject_add_node_before (IAnjutaProject *obj, AnjutaProjectNode *parent, AnjutaProjectNode *sibling, AnjutaProjectNodeType type, GFile *file, const gchar *name, GError **err)
2398 {
2399 	AnjutaProjectNode *node;
2400 	PmJob *add_job;
2401 
2402 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2403 
2404 	node = amp_node_new_valid (parent, type, file, name, err);
2405 	if (node != NULL)
2406 	{
2407 		add_job = pm_job_new (&amp_add_before_job, node, parent, sibling, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2408 		pm_command_queue_push (AMP_PROJECT (obj)->queue, add_job);
2409 	}
2410 
2411 	return node;
2412 }
2413 
2414 static AnjutaProjectNode *
iproject_add_node_after(IAnjutaProject * obj,AnjutaProjectNode * parent,AnjutaProjectNode * sibling,AnjutaProjectNodeType type,GFile * file,const gchar * name,GError ** err)2415 iproject_add_node_after (IAnjutaProject *obj, AnjutaProjectNode *parent, AnjutaProjectNode *sibling, AnjutaProjectNodeType type, GFile *file, const gchar *name, GError **err)
2416 {
2417 	AnjutaProjectNode *node;
2418 	PmJob *add_job;
2419 
2420 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2421 
2422 	node = amp_node_new_valid (parent, type, file, name, err);
2423 	if (node != NULL)
2424 	{
2425 		add_job = pm_job_new (&amp_add_after_job, node, parent, sibling, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2426 		pm_command_queue_push (AMP_PROJECT (obj)->queue, add_job);
2427 	}
2428 
2429 	return node;
2430 }
2431 
2432 static gboolean
iproject_remove_node(IAnjutaProject * obj,AnjutaProjectNode * node,GError ** err)2433 iproject_remove_node (IAnjutaProject *obj, AnjutaProjectNode *node, GError **err)
2434 {
2435 	PmJob *remove_job;
2436 
2437 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2438 
2439 	remove_job = pm_job_new (&amp_remove_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2440 	pm_command_queue_push (AMP_PROJECT (obj)->queue, remove_job);
2441 
2442 	return TRUE;
2443 }
2444 
2445 static AnjutaProjectProperty *
iproject_set_property(IAnjutaProject * obj,AnjutaProjectNode * node,const gchar * id,const gchar * name,const gchar * value,GError ** error)2446 iproject_set_property (IAnjutaProject *obj, AnjutaProjectNode *node, const gchar *id, const gchar *name, const gchar *value, GError **error)
2447 {
2448 	AnjutaProjectProperty *new_prop;
2449 	PmJob *set_property_job;
2450 
2451 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2452 
2453 	new_prop = name == NULL ? amp_node_property_set (node, id, value) : amp_node_map_property_set (node, id, name, value);
2454 	set_property_job = pm_job_new (&amp_set_property_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2455 	set_property_job->property = new_prop;
2456 	pm_command_queue_push (AMP_PROJECT (obj)->queue, set_property_job);
2457 
2458 	return new_prop;
2459 }
2460 
2461 static gboolean
iproject_remove_property(IAnjutaProject * obj,AnjutaProjectNode * node,const gchar * id,const gchar * name,GError ** error)2462 iproject_remove_property (IAnjutaProject *obj, AnjutaProjectNode *node, const gchar *id, const gchar *name, GError **error)
2463 {
2464 	AnjutaProjectProperty *new_prop;
2465 	PmJob *remove_property_job;
2466 
2467 	if (AMP_PROJECT (obj)->queue == NULL) AMP_PROJECT (obj)->queue = pm_command_queue_new ();
2468 
2469 
2470 	new_prop = amp_node_map_property_set (node, id, name, NULL);
2471 	remove_property_job = pm_job_new (&amp_set_property_job, node, NULL, NULL, ANJUTA_PROJECT_UNKNOWN, NULL, NULL, obj);
2472 	remove_property_job->property = new_prop;
2473 	pm_command_queue_push (AMP_PROJECT (obj)->queue, remove_property_job);
2474 
2475 	return TRUE;
2476 }
2477 
2478 static AnjutaProjectNode *
iproject_get_root(IAnjutaProject * obj,GError ** err)2479 iproject_get_root (IAnjutaProject *obj, GError **err)
2480 {
2481 	return ANJUTA_PROJECT_NODE (obj);
2482 }
2483 
2484 static const GList*
iproject_get_node_info(IAnjutaProject * obj,GError ** err)2485 iproject_get_node_info (IAnjutaProject *obj, GError **err)
2486 {
2487 	return amp_project_get_node_info (AMP_PROJECT (obj), err);
2488 }
2489 
2490 static gboolean
iproject_is_loaded(IAnjutaProject * obj,GError ** err)2491 iproject_is_loaded (IAnjutaProject *obj, GError **err)
2492 {
2493 	return amp_project_is_loaded (AMP_PROJECT (obj));
2494 }
2495 
2496 static void
iproject_iface_init(IAnjutaProjectIface * iface)2497 iproject_iface_init(IAnjutaProjectIface* iface)
2498 {
2499 	iface->load_node = iproject_load_node;
2500 	iface->save_node = iproject_save_node;
2501 	iface->add_node_before = iproject_add_node_before;
2502 	iface->add_node_after = iproject_add_node_after;
2503 	iface->remove_node = iproject_remove_node;
2504 	iface->set_property = iproject_set_property;
2505 	iface->remove_property = iproject_remove_property;
2506 	iface->get_root = iproject_get_root;
2507 	iface->get_node_info = iproject_get_node_info;
2508 	iface->is_loaded = iproject_is_loaded;
2509 }
2510 
2511 /* AmpNode implementation
2512  *---------------------------------------------------------------------------*/
2513 
2514 static gboolean
amp_project_load(AmpNode * root,AmpNode * parent,AmpProject * project,GError ** error)2515 amp_project_load (AmpNode *root, AmpNode *parent, AmpProject *project, GError **error)
2516 {
2517 	return amp_project_load_root (AMP_PROJECT (root), error);
2518 }
2519 
2520 static gboolean
amp_project_save(AmpNode * root,AmpNode * parent,AmpProject * project,GError ** error)2521 amp_project_save (AmpNode *root, AmpNode *parent, AmpProject *project, GError **error)
2522 {
2523 	AnjutaTokenFile *tfile;
2524 	AnjutaProjectNode *child;
2525 
2526 	/* Save node */
2527 	tfile = AMP_PROJECT (root)->configure_file;
2528 	if (anjuta_token_file_is_dirty (tfile))
2529 	{
2530 		if (!anjuta_token_file_save (tfile, error)) return FALSE;
2531 	}
2532 
2533 	if (!AMP_NODE_CLASS (parent_class)->save (root, parent, project, error))
2534 	{
2535 		return FALSE;
2536 	}
2537 
2538 	/* Save all children */
2539 	for (child = anjuta_project_node_first_child (ANJUTA_PROJECT_NODE (root)); child != NULL; child = anjuta_project_node_next_sibling (child))
2540 	{
2541 		if (!amp_node_save (AMP_NODE (child), root, project, error)) return FALSE;
2542 	}
2543 
2544 	return TRUE;
2545 }
2546 
2547 
2548 static gboolean
amp_project_update(AmpNode * node,AmpNode * new_node)2549 amp_project_update (AmpNode *node, AmpNode *new_node)
2550 {
2551 	amp_project_update_root (AMP_PROJECT (node), AMP_PROJECT (new_node));
2552 
2553 	return TRUE;
2554 }
2555 
2556 static AmpNode *
amp_project_copy(AmpNode * old_node)2557 amp_project_copy (AmpNode *old_node)
2558 {
2559 	AmpNode *new_node;
2560 
2561 	new_node = AMP_NODE_CLASS (amp_project_parent_class)->copy (old_node);
2562 	((AmpProject *)new_node)->lang_manager = (((AmpProject *)old_node)->lang_manager != NULL) ? g_object_ref (((AmpProject *)old_node)->lang_manager) : NULL;
2563 
2564 	return new_node;
2565 }
2566 
2567 
2568 /* GObject implementation
2569  *---------------------------------------------------------------------------*/
2570 
2571 static void
amp_project_dispose(GObject * object)2572 amp_project_dispose (GObject *object)
2573 {
2574 	AmpProject *project;
2575 
2576 	g_return_if_fail (AMP_IS_PROJECT (object));
2577 
2578 	project = AMP_PROJECT (object);
2579 	amp_project_unload (project);
2580 
2581 	amp_project_clear (project);
2582 
2583 	if (project->groups) g_hash_table_destroy (project->groups);
2584 	project->groups = NULL;
2585 	if (project->configs) g_hash_table_destroy (project->configs);
2586 	project->configs = NULL;
2587 	if (project->ac_variables) g_hash_table_destroy (project->ac_variables);
2588 	project->ac_variables = NULL;
2589 
2590 	if (project->queue) pm_command_queue_free (project->queue);
2591 	project->queue = NULL;
2592 
2593 	if (project->monitor) g_object_unref (project->monitor);
2594 	project->monitor = NULL;
2595 
2596 	if (project->lang_manager) g_object_unref (project->lang_manager);
2597 	project->lang_manager = NULL;
2598 
2599 	G_OBJECT_CLASS (parent_class)->dispose (object);
2600 }
2601 
2602 static void
amp_project_init(AmpProject * project)2603 amp_project_init (AmpProject *project)
2604 {
2605 	g_return_if_fail (project != NULL);
2606 	g_return_if_fail (AMP_IS_PROJECT (project));
2607 
2608 	/* project data */
2609 	project->configure_file = NULL;
2610 	project->configure_token = NULL;
2611 
2612 	/* Hash tables */
2613 	project->groups = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
2614 	project->files = NULL;
2615 	project->configs = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, NULL, (GDestroyNotify)amp_config_file_free);
2616 	project->ac_variables = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
2617 
2618 	/* Default style */
2619 	project->am_space_list = NULL;
2620 	project->ac_space_list = NULL;
2621 	project->arg_list = NULL;
2622 
2623 	project->queue = NULL;
2624 	project->loading = 0;
2625 }
2626 
2627 static void
amp_project_class_init(AmpProjectClass * klass)2628 amp_project_class_init (AmpProjectClass *klass)
2629 {
2630 	GObjectClass *object_class;
2631 	AmpNodeClass *node_class;
2632 
2633 	parent_class = g_type_class_peek_parent (klass);
2634 
2635 	object_class = G_OBJECT_CLASS (klass);
2636 	object_class->dispose = amp_project_dispose;
2637 
2638 	node_class = AMP_NODE_CLASS (klass);
2639 	node_class->load = amp_project_load;
2640 	node_class->save = amp_project_save;
2641 	node_class->update = amp_project_update;
2642 	node_class->copy = amp_project_copy;
2643 }
2644 
2645 static void
amp_project_class_finalize(AmpProjectClass * klass)2646 amp_project_class_finalize (AmpProjectClass *klass)
2647 {
2648 }
2649 
2650 void
amp_project_register(GTypeModule * module)2651 amp_project_register (GTypeModule *module)
2652 {
2653 	amp_node_register (module);
2654 	amp_project_register_type (module);
2655 }
2656