1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4; coding: utf-8 -*- */
2 /* am-writer.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-writer.h"
28 #include "ac-scanner.h"
29 #include "ac-parser.h"
30 
31 #include "am-project-private.h"
32 #include "amp-node.h"
33 #include "amp-group.h"
34 #include "amp-target.h"
35 #include "amp-source.h"
36 #include "am-properties.h"
37 #include "am-scanner.h"
38 
39 #include <libanjuta/anjuta-debug.h>
40 #include <libanjuta/anjuta-utils.h>
41 
42 #include <string.h>
43 #include <ctype.h>
44 
45 /* Types & Constants
46   *---------------------------------------------------------------------------*/
47 
48 const static gchar* AmpStandardDirectory[] = {"bindir", "sbindir", "libdir", "pkglibdir", "libexecdir", "pkglibexecdir", "datadir", "pkgdatadir", "mandir", "infodir", "docdir", NULL};
49 
50 /* Helper functions
51  *---------------------------------------------------------------------------*/
52 
53 /* Private functions
54  *---------------------------------------------------------------------------*/
55 
56 static AnjutaToken *
anjuta_token_find_target_property_position(AmpTargetNode * target,AnjutaTokenType type)57 anjuta_token_find_target_property_position (AmpTargetNode *target,
58                                             AnjutaTokenType type)
59 {
60 	AnjutaToken *pos = NULL;
61 	gboolean after = FALSE;
62 	GList *list;
63 	AmpGroupNode *group;
64 	AnjutaToken *makefile;
65 
66 	group = AMP_GROUP_NODE (anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (target), ANJUTA_PROJECT_GROUP));
67 
68 	/* Try to find a better position */
69 
70 	/* 1. With the other properties of the target */
71 	list = amp_target_node_get_all_token (target);
72 	if (list != NULL)
73 	{
74 		GList *link;
75 		AnjutaTokenType best = 0;
76 
77 		for (link = list; link != NULL; link = g_list_next (link))
78 		{
79 			AnjutaToken *token = (AnjutaToken *)link->data;
80 			AnjutaTokenType existing = anjuta_token_get_type (token);
81 
82 			if ((existing < AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) || (existing > AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
83 			{
84 				token = anjuta_token_list (token);
85 				if (token != NULL) existing = anjuta_token_get_type (token);
86 			}
87 
88 			if ((existing >= AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) && (existing <= AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
89 			{
90 				if (existing > type)
91 				{
92 					if ((best == 0) || ((existing - type) < best))
93 					{
94 						best = existing - type;
95 						pos = token;
96 						after = FALSE;
97 					}
98 				}
99 				else
100 				{
101 					if ((best == 0) || ((type -existing) < best))
102 					{
103 						best = type - existing;
104 						pos = token;
105 						after = TRUE;
106 					}
107 				}
108 			}
109 		}
110 		g_list_free (list);
111 	}
112 
113 
114 	/* 2. With properties of sibling targets */
115 	if (pos == NULL)
116 	{
117 		AnjutaProjectNode *prev = ANJUTA_PROJECT_NODE (target);
118 		AnjutaProjectNode *next = ANJUTA_PROJECT_NODE (target);
119 		AmpTargetNode *sibling;
120 		AnjutaTokenFile *makefile;
121 		AnjutaToken *target_list = NULL;
122 		GList *link;
123 
124 		link = amp_target_node_get_token (target, ANJUTA_TOKEN_ARGUMENT);
125 		if ((link != NULL) && (link->data != NULL))
126 		{
127 			target_list = anjuta_token_list ((AnjutaToken *)link->data);
128 		}
129 
130 		makefile = amp_group_node_get_make_token_file (group);
131 
132 		if (makefile != NULL)
133 		{
134 			after = TRUE;
135 			while ((prev != NULL) || (next != NULL))
136 			{
137 				/* Find sibling */
138 				if (after)
139 				{
140 					while (prev != NULL)
141 					{
142 						prev = anjuta_project_node_prev_sibling (prev);
143 						if (anjuta_project_node_get_node_type (prev) == ANJUTA_PROJECT_TARGET) break;
144 					}
145 					sibling = AMP_TARGET_NODE (prev);
146 				}
147 				else
148 				{
149 					while (next != NULL)
150 					{
151 						next = anjuta_project_node_next_sibling (next);
152 						if (anjuta_project_node_get_node_type (next) == ANJUTA_PROJECT_TARGET) break;
153 					}
154 					sibling = AMP_TARGET_NODE (next);
155 				}
156 				list = sibling == NULL ? NULL : amp_target_node_get_all_token (sibling);
157 
158 				/* Check that the target is in the same list */
159 				if ((list != NULL) && (target_list != NULL))
160 				{
161 					AnjutaToken *token;
162 
163 					link = amp_target_node_get_token (sibling, ANJUTA_TOKEN_ARGUMENT);
164 					if ((link != NULL) && (link->data != NULL))
165 					{
166 						token = anjuta_token_list ((AnjutaToken *)link->data);
167 					}
168 
169 					if ((token != NULL) && (target_list != token))
170 					{
171 						/* Target is in another list, do not use it, nor following ones */
172 						list = NULL;
173 						if (after)
174 						{
175 							prev = NULL;
176 						}
177 						else
178 						{
179 							next = NULL;
180 						}
181 					}
182 				}
183 
184 				if (list != NULL)
185 				{
186 					gsize best = 0;
187 
188 					for (link = list; link != NULL; link = g_list_next (link))
189 					{
190 						AnjutaToken *token = (AnjutaToken *)link->data;
191 						AnjutaTokenType existing = anjuta_token_get_type (token);
192 
193 						if ((existing < AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) || (existing > AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
194 						{
195 							token = anjuta_token_list (token);
196 							if (token != NULL) existing = anjuta_token_get_type (token);
197 						}
198 
199 						if ((existing >= AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) && (existing <= AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
200 						{
201 							gsize tpos;
202 
203 							tpos = anjuta_token_file_get_token_position (makefile, token);
204 
205 							if ((best == 0) ||
206 							    (after && (tpos > best)) ||
207 							    (!after && (tpos < best)))
208 							{
209 								pos = token;
210 								best = tpos;
211 							}
212 						}
213 					}
214 					g_list_free (list);
215 					list = NULL;
216 
217 					if (best != 0) break;
218 				}
219 
220 				after = after ? FALSE : TRUE;
221 			}
222 		}
223 	}
224 
225 
226 	/* 3. After target declaration */
227 	if (pos == NULL)
228 	{
229 		list = amp_target_node_get_token (AMP_TARGET_NODE (target), ANJUTA_TOKEN_ARGUMENT);
230 		if (list != NULL)
231 		{
232 			pos = (AnjutaToken *)list->data;
233 			if (pos != NULL)
234 			{
235 				pos = anjuta_token_list (pos);
236 				if (pos != NULL)
237 				{
238 					pos = anjuta_token_list (pos);
239 				}
240 			}
241 		}
242 		after = TRUE;
243 	}
244 
245 	/* 4. At the end of the file */
246 	if (pos == NULL)
247 	{
248 		makefile = amp_group_node_get_makefile_token (group);
249 
250 		for (pos = anjuta_token_first_item (makefile); (pos != NULL) && (anjuta_token_next_item (pos) != NULL); pos = anjuta_token_next_item (pos));
251 
252 		after = TRUE;
253 	}
254 
255 	/* 5. Create new file */
256 	if (pos == NULL)
257 	{
258 		/* Empty file */
259 		pos = anjuta_token_new_string (ANJUTA_TOKEN_COMMENT | ANJUTA_TOKEN_ADDED, "## Process this file with automake to produce Makefile.in\n");
260 		anjuta_token_append_child (makefile, pos);
261 		amp_group_node_update_makefile (group, pos);
262 	}
263 
264 
265 	/* Find end of line */
266 	if (after)
267 	{
268 		while (pos != NULL)
269 		{
270 			if (anjuta_token_get_type (pos) == ANJUTA_TOKEN_EOL) break;
271 			if (anjuta_token_next (pos) == NULL)
272 			{
273 				pos = anjuta_token_insert_token_list (after, pos,
274 					ANJUTA_TOKEN_EOL, "\n",
275 					NULL);
276 
277 				break;
278 			}
279 			pos = anjuta_token_next (pos);
280 		}
281 	}
282 
283 	pos = anjuta_token_insert_token_list (after, pos,
284 		    ANJUTA_TOKEN_EOL, "\n",
285 	    	NULL);
286 	pos = anjuta_token_insert_token_list (after, pos,
287 		    ANJUTA_TOKEN_EOL, "\n",
288 	    	NULL);
289 	amp_group_node_update_makefile (group, pos);
290 
291 
292 	return pos;
293 }
294 
295 static AnjutaToken *
anjuta_token_find_group_property_position(AmpGroupNode * group,AnjutaTokenType type)296 anjuta_token_find_group_property_position (AmpGroupNode *group,
297                                             AnjutaTokenType type)
298 {
299 	AnjutaToken *pos = NULL;
300 	gboolean after = FALSE;
301 	GList *list;
302 	AnjutaToken *makefile;
303 
304 
305 	/* Try to find a better position */
306 
307 	/* 1. With the other properties of the group */
308 	list = amp_group_node_get_all_token (group);
309 	if (list != NULL)
310 	{
311 		GList *link;
312 		AnjutaTokenType best = 0;
313 
314 		for (link = list; link != NULL; link = g_list_next (link))
315 		{
316 			AnjutaToken *token = (AnjutaToken *)link->data;
317 			AnjutaTokenType existing = anjuta_token_get_type (token);
318 
319 			if ((existing < AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) || (existing > AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
320 			{
321 				token = anjuta_token_list (token);
322 				if (token != NULL) existing = anjuta_token_get_type (token);
323 			}
324 
325 			if ((existing >= AM_TOKEN_FIRST_ORDERED_TARGET_MACRO) && (existing <= AM_TOKEN_LAST_ORDERED_TARGET_MACRO))
326 			{
327 				if (existing > type)
328 				{
329 					if ((best == 0) || ((existing - type) < best))
330 					{
331 						best = existing - type;
332 						pos = token;
333 						after = FALSE;
334 					}
335 				}
336 				else
337 				{
338 					if ((best == 0) || ((type -existing) < best))
339 					{
340 						best = type - existing;
341 						pos = token;
342 						after = TRUE;
343 					}
344 				}
345 			}
346 		}
347 		g_list_free (list);
348 	}
349 
350 	/* 2. At the end of the file */
351 	if (pos == NULL)
352 	{
353 		makefile = amp_group_node_get_makefile_token (group);
354 
355 		for (pos = anjuta_token_first_item (makefile); (pos != NULL) && (anjuta_token_next_item (pos) != NULL); pos = anjuta_token_next_item (pos));
356 
357 		after = TRUE;
358 	}
359 
360 	/* makefile can be NULL for the root node if there isn't any corresponding Makefile.am */
361 	if (makefile != NULL)
362 	{
363 		/* 3. Create new file */
364 		if (pos == NULL)
365 		{
366 			/* Empty file */
367 			pos = anjuta_token_new_string (ANJUTA_TOKEN_COMMENT | ANJUTA_TOKEN_ADDED, "## Process this file with automake to produce Makefile.in\n");
368 			anjuta_token_append_child (makefile, pos);
369 			amp_group_node_update_makefile (group, pos);
370 		}
371 
372 		/* Find end of line */
373 		if (after)
374 		{
375 			while (pos != NULL)
376 			{
377 				if (anjuta_token_get_type (pos) == ANJUTA_TOKEN_EOL) break;
378 				if (anjuta_token_next (pos) == NULL)
379 				{
380 					pos = anjuta_token_insert_token_list (after, pos,
381 						ANJUTA_TOKEN_EOL, "\n",
382 						NULL);
383 
384 					break;
385 				}
386 				pos = anjuta_token_next (pos);
387 			}
388 		}
389 
390 		pos = anjuta_token_insert_token_list (after, pos,
391 			    ANJUTA_TOKEN_EOL, "\n",
392 		    	NULL);
393 		pos = anjuta_token_insert_token_list (after, pos,
394 			    ANJUTA_TOKEN_EOL, "\n",
395 		    	NULL);
396 		amp_group_node_update_makefile (group, pos);
397 	}
398 
399 	return pos;
400 }
401 
402 
403 /* Public functions
404  *---------------------------------------------------------------------------*/
405 
406 static AnjutaToken *
amp_project_write_config_list(AmpProject * project)407 amp_project_write_config_list (AmpProject *project)
408 {
409 	AnjutaToken *pos;
410 	AnjutaToken *token;
411 	static gint output_type[] = {AC_TOKEN_AC_OUTPUT, 0};
412 	static gint eol_type[] = {ANJUTA_TOKEN_EOL, ANJUTA_TOKEN_SPACE, ANJUTA_TOKEN_COMMENT, 0};
413 	AnjutaToken *configure;
414 
415 	configure = amp_project_get_configure_token (project);
416 	pos = anjuta_token_find_type (configure, 0, output_type);
417 	if (pos == NULL)
418 	{
419 		gint other_type[] = {AC_TOKEN_AC_INIT,
420 			AC_TOKEN_PKG_CHECK_MODULES,
421 			AC_TOKEN_AC_CONFIG_FILES,
422 			AC_TOKEN_OBSOLETE_AC_OUTPUT,
423 			AC_TOKEN_AC_PREREQ,
424 			0};
425 
426 		pos = anjuta_token_find_type (configure, ANJUTA_TOKEN_SEARCH_LAST, other_type);
427 		if (pos == NULL)
428 		{
429 			pos = anjuta_token_skip_comment (configure);
430 		}
431 		else
432 		{
433 			AnjutaToken* next;
434 
435 			next = anjuta_token_find_type (pos, ANJUTA_TOKEN_SEARCH_NOT, eol_type);
436 		}
437 
438 	}
439 
440 	token = anjuta_token_insert_token_list (FALSE, pos,
441 	    		AC_TOKEN_AC_CONFIG_FILES, "AC_CONFIG_FILES(",
442 	    		ANJUTA_TOKEN_LIST, NULL,
443 	    		ANJUTA_TOKEN_LAST, NULL,
444 	    		RIGHT_PAREN, ")",
445 				ANJUTA_TOKEN_EOL, "\n",
446 	    		NULL);
447 
448 	return token;
449 }
450 
451 static AnjutaToken *
amp_project_write_config_file(AmpProject * project,AnjutaToken * list,gboolean after,AnjutaToken * sibling,const gchar * filename)452 amp_project_write_config_file (AmpProject *project, AnjutaToken *list, gboolean after, AnjutaToken *sibling, const gchar *filename)
453 {
454 	AnjutaToken *token;
455 
456 	token = anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, filename);
457 	//fprintf (stdout, "Dump config list:\n");
458 	//anjuta_token_dump (list);
459 	if (after)
460 	{
461 		anjuta_token_insert_word_after (list, sibling, token);
462 	}
463 	else
464 	{
465 		anjuta_token_insert_word_before (list, sibling, token);
466 	}
467 	//fprintf (stdout, "Dump config list after insertion:\n");
468 	//anjuta_token_dump (list);
469 
470 	anjuta_token_style_format (project->ac_space_list, list);
471 
472 	//fprintf (stdout, "Dump config list after format:\n");
473 	//anjuta_token_dump (list);
474 
475 	amp_project_update_configure (project, list);
476 
477 	return token;
478 }
479 
480 
481 /* Target objects
482  *---------------------------------------------------------------------------*/
483 
484 gboolean
amp_group_node_create_token(AmpProject * project,AmpGroupNode * group,GError ** error)485 amp_group_node_create_token (AmpProject  *project, AmpGroupNode *group, GError **error)
486 {
487 	GFile *directory;
488 	GFile *makefile;
489 	AnjutaToken *list;
490 	gchar *basename;
491 	AnjutaTokenFile* tfile;
492 	AnjutaProjectNode *sibling;
493 	AmpGroupNode *parent;
494 	gboolean after;
495 	const gchar *name;
496 
497 	/* Get parent target */
498 	name = anjuta_project_node_get_name (ANJUTA_PROJECT_NODE (group));
499 	parent = AMP_GROUP_NODE (anjuta_project_node_parent_type(ANJUTA_PROJECT_NODE (group), ANJUTA_PROJECT_GROUP));
500 	if (parent != NULL)
501 	{
502 		directory = g_file_get_child (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (parent)), name);
503 	}
504 	else
505 	{
506 		/* Used only when adding root group (a group named . in an empty project) */
507 		parent = group;
508 		directory = g_object_ref (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (parent)));
509 	}
510 
511 	/* Find a sibling if possible */
512 	after = TRUE;
513 	for (sibling = anjuta_project_node_prev_sibling (ANJUTA_PROJECT_NODE (group)); sibling != NULL; sibling = anjuta_project_node_prev_sibling (sibling))
514 	{
515 		if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_GROUP) break;
516 	}
517 	if (sibling == NULL)
518 	{
519 		after = FALSE;
520 		for (sibling = anjuta_project_node_next_sibling (ANJUTA_PROJECT_NODE (group)); sibling != NULL; sibling = anjuta_project_node_next_sibling (sibling))
521 		{
522 			if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_GROUP) break;
523 		}
524 	}
525 	if (sibling == NULL) after = TRUE;
526 
527 	/* Create Makefile.am */
528 	basename = amp_group_node_get_makefile_name  (parent);
529 	if (basename != NULL)
530 	{
531 		makefile = g_file_get_child (directory, basename);
532 		g_free (basename);
533 	}
534 	else
535 	{
536 		makefile = g_file_get_child (directory, "Makefile.am");
537 	}
538 
539 	/* Add in configure */
540 	list = NULL;
541 	if (sibling) list = amp_group_node_get_first_token (AMP_GROUP_NODE (sibling), AM_GROUP_TOKEN_CONFIGURE);
542 	if (list == NULL) list= amp_group_node_get_first_token (parent, AM_GROUP_TOKEN_CONFIGURE);
543 	if (list != NULL) list = anjuta_token_list (list);
544 	if (list == NULL)
545 	{
546 		list = amp_project_write_config_list (project);
547 		list = anjuta_token_next (list);
548 	}
549 	if (list != NULL)
550 	{
551 		gchar *relative_make;
552 		gchar *ext;
553 		AnjutaToken *prev = NULL;
554 		AnjutaToken *token;
555 
556 		if (sibling)
557 		{
558 			prev = amp_group_node_get_first_token (AMP_GROUP_NODE (sibling), AM_GROUP_TOKEN_CONFIGURE);
559 			/*if ((prev != NULL) && after)
560 			{
561 				prev = anjuta_token_next_word (prev);
562 			}*/
563 		}
564 		//prev_token = (AnjutaToken *)token_list->data;
565 
566 		relative_make = g_file_get_relative_path (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (project)), makefile);
567 		ext = relative_make + strlen (relative_make) - 3;
568 		if (strcmp (ext, ".am") == 0)
569 		{
570 			*ext = '\0';
571 		}
572 		token = amp_project_write_config_file (project, list, after, prev, relative_make);
573 		amp_group_node_add_token (AMP_GROUP_NODE (group), token, AM_GROUP_TOKEN_CONFIGURE);
574 		g_free (relative_make);
575 	}
576 
577 	/* Add in Makefile.am */
578 	if (sibling == NULL)
579 	{
580 		list = anjuta_token_find_group_property_position (parent, AM_TOKEN_SUBDIRS);
581 
582 		if (list != NULL)
583 		{
584 			list = anjuta_token_insert_token_list (FALSE, list,
585 	    			AM_TOKEN_SUBDIRS, "SUBDIRS",
586 		    		ANJUTA_TOKEN_SPACE, " ",
587 		    		ANJUTA_TOKEN_OPERATOR, "=",
588 	    			ANJUTA_TOKEN_LIST, NULL,
589 	    			ANJUTA_TOKEN_LAST, NULL,
590 	    			NULL);
591 			list = anjuta_token_next (anjuta_token_next ( anjuta_token_next (list)));
592 		}
593 	}
594 	else
595 	{
596 		AnjutaToken *prev;
597 
598 		prev = amp_group_node_get_first_token (AMP_GROUP_NODE (sibling), AM_GROUP_TOKEN_SUBDIRS);
599 		list = anjuta_token_list (prev);
600 	}
601 
602 	if (list != NULL)
603 	{
604 		AnjutaToken *token;
605 		AnjutaToken *prev;
606 		AnjutaTokenStyle *style;
607 
608 		style = anjuta_token_style_new_from_base (project->am_space_list);
609 		anjuta_token_style_update (style, list);
610 
611 		if (sibling)
612 		{
613 			prev = amp_group_node_get_first_token (AMP_GROUP_NODE (sibling), AM_GROUP_TOKEN_SUBDIRS);
614 		}
615 
616 		token = anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, name);
617 		if (after)
618 		{
619 			anjuta_token_insert_word_after (list, prev, token);
620 		}
621 		else
622 		{
623 			anjuta_token_insert_word_before (list, prev, token);
624 		}
625 
626 		/* Try to use the same style than the current group list */
627 		anjuta_token_style_format (style, list);
628 		anjuta_token_style_free (style);
629 
630 		amp_group_node_update_makefile (parent, token);
631 
632 		amp_group_node_add_token (group, token, AM_GROUP_TOKEN_SUBDIRS);
633 	}
634 
635 	tfile = amp_group_node_set_makefile (group, makefile, project);
636 	amp_project_add_file (project, makefile, tfile);
637 
638 	return TRUE;
639 }
640 
641 gboolean
amp_group_node_delete_token(AmpProject * project,AmpGroupNode * group,GError ** error)642 amp_group_node_delete_token (AmpProject  *project, AmpGroupNode *group, GError **error)
643 {
644 	GList *item;
645 	AnjutaProjectNode *parent;
646 
647 	/* Get parent group */
648 	parent =  anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (group), ANJUTA_PROJECT_GROUP);
649 	if (parent == NULL) return FALSE;
650 
651 	for (item = amp_group_node_get_token (group, AM_GROUP_TOKEN_SUBDIRS); item != NULL; item = g_list_next (item))
652 	{
653 		AnjutaToken *token = (AnjutaToken *)item->data;
654 		AnjutaTokenStyle *style;
655 		AnjutaToken *list;
656 
657 		list = anjuta_token_list (token);
658 
659 		/* Try to use the same style than the current target list */
660 		style = anjuta_token_style_new_from_base (project->am_space_list);
661 		anjuta_token_style_update (style, list);
662 
663 		anjuta_token_remove_word (token);
664 		anjuta_token_style_format (style, list);
665 		anjuta_token_style_free (style);
666 
667 		/* Remove whole variable if empty */
668 		if (anjuta_token_first_word (list) == NULL)
669 		{
670 			anjuta_token_remove_list (anjuta_token_list (list));
671 		}
672 
673 		amp_group_node_update_makefile (AMP_GROUP_NODE (parent), list);
674 	}
675 
676 	/* Remove from configure file */
677 	for (item = amp_group_node_get_token (group, AM_GROUP_TOKEN_CONFIGURE); item != NULL; item = g_list_next (item))
678 	{
679 		AnjutaToken *token = (AnjutaToken *)item->data;
680 		AnjutaToken *args;
681 		AnjutaTokenStyle *style;
682 
683 		args = anjuta_token_list (token);
684 
685 		/* Try to use the same style than the current group list */
686 		style = anjuta_token_style_new_from_base (project->ac_space_list);
687 		anjuta_token_style_update (style, args);
688 
689 		anjuta_token_remove_word (token);
690 
691 		anjuta_token_style_format (style, args);
692 		anjuta_token_style_free (style);
693 
694 		amp_project_update_configure (project, args);
695 	}
696 
697 	return TRUE;
698 }
699 
700 
701 /* Target objects
702  *---------------------------------------------------------------------------*/
703 
704 static AnjutaToken *
amp_project_write_target(AmpGroupNode * group,gint type,const gchar * name,gboolean after,AnjutaToken * sibling)705 amp_project_write_target (AmpGroupNode *group, gint type, const gchar *name, gboolean after, AnjutaToken* sibling)
706 {
707 	AnjutaToken *pos = sibling;
708 
709 	if (pos != NULL)
710 	{
711 		/* Find top level parent */
712 		do
713 		{
714 			AnjutaTokenType type = anjuta_token_get_type (pos);
715 
716 			if ((type >= AM_TOKEN_FIRST_ORDERED_MACRO) && (type <= AM_TOKEN_LAST_ORDERED_MACRO)) break;
717 			pos = anjuta_token_list (pos);
718 		}
719 		while (pos != NULL);
720 
721 		if (pos != NULL)
722 		{
723 			/* Add target just near sibling target */
724 			pos = anjuta_token_insert_token_list (after, pos,
725 				ANJUTA_TOKEN_EOL, "\n",
726 				NULL);
727 			pos = anjuta_token_insert_token_list (after, pos,
728 			    ANJUTA_TOKEN_EOL, "\n",
729 				NULL);
730 			amp_group_node_update_makefile (group, pos);
731 		}
732 	}
733 
734 	if (pos == NULL)
735 	{
736 		/* Find ordered position in Makefile.am */
737 		pos = anjuta_token_find_group_property_position (group, type);
738 	}
739 
740 	pos = anjuta_token_insert_token_list (after, pos,
741 	    		ANJUTA_TOKEN_LIST, NULL,
742 	    		type, name,
743 	    		ANJUTA_TOKEN_SPACE, " ",
744 	    		ANJUTA_TOKEN_OPERATOR, "=",
745 	    		ANJUTA_TOKEN_LIST, NULL,
746 	            ANJUTA_TOKEN_SPACE, " ",
747 	    		NULL);
748 	pos = anjuta_token_last_item (pos);
749 	amp_group_node_update_makefile (group, pos);
750 
751 	/* Return list token */
752 	return pos;
753 }
754 
755 static AnjutaToken *
amp_target_add_in_list(AmpProject * project,AnjutaToken * list,AnjutaProjectNode * target,gboolean after,AnjutaToken * sibling)756 amp_target_add_in_list (AmpProject *project, AnjutaToken *list, AnjutaProjectNode *target, gboolean after, AnjutaToken* sibling)
757 {
758 	AnjutaTokenStyle *style;
759 	AnjutaToken *token;
760 	AmpGroupNode *parent;
761 
762 	g_return_val_if_fail (list != NULL, NULL);
763 
764 	/* Get parent target */
765 	parent = AMP_GROUP_NODE (anjuta_project_node_parent_type (target, ANJUTA_PROJECT_GROUP));
766 
767 	style = anjuta_token_style_new_from_base (project->am_space_list);
768 	anjuta_token_style_update (style, list);
769 
770 	token = anjuta_token_new_string (ANJUTA_TOKEN_ARGUMENT | ANJUTA_TOKEN_ADDED, anjuta_project_node_get_name (target));
771 	if (after)
772 	{
773 		anjuta_token_insert_word_after (list, sibling, token);
774 	}
775 	else
776 	{
777 		anjuta_token_insert_word_before (list, sibling, token);
778 	}
779 
780 	/* Try to use the same style than the current target list */
781 	anjuta_token_style_format (style, list);
782 	anjuta_token_style_free (style);
783 
784 	amp_group_node_update_makefile (parent, token);
785 
786 	amp_target_node_add_token (AMP_TARGET_NODE (target), ANJUTA_TOKEN_ARGUMENT, token);
787 
788 	return token;
789 }
790 
791 
792 gboolean
amp_target_node_create_token(AmpProject * project,AmpTargetNode * target,GError ** error)793 amp_target_node_create_token (AmpProject  *project, AmpTargetNode *target, GError **error)
794 {
795 	AnjutaToken *args;
796 	AnjutaToken *var;
797 	AnjutaToken *prev;
798 	AmpNodeInfo *info;
799 	gchar *targetname;
800 	const gchar *name;
801 	GList *last;
802 	AnjutaProjectNode *sibling;
803 	AmpGroupNode *parent;
804 	gboolean after;
805 
806 	/* Get parent target */
807 	parent = AMP_GROUP_NODE (anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (target), ANJUTA_PROJECT_GROUP));
808 
809 	info = (AmpNodeInfo *)amp_project_get_type_info (project, anjuta_project_node_get_full_type (ANJUTA_PROJECT_NODE (target)));
810 	name = anjuta_project_node_get_name (ANJUTA_PROJECT_NODE (target));
811 
812 	/* Find a sibling if possible */
813 	after = TRUE;
814 	for (sibling = anjuta_project_node_prev_sibling (ANJUTA_PROJECT_NODE (target)); sibling != NULL; sibling = anjuta_project_node_prev_sibling (sibling))
815 	{
816 		if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_TARGET) break;
817 	}
818 	if (sibling == NULL)
819 	{
820 		after = FALSE;
821 		for (sibling = anjuta_project_node_next_sibling (ANJUTA_PROJECT_NODE (target)); sibling != NULL; sibling = anjuta_project_node_next_sibling (sibling))
822 		{
823 			if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_TARGET) break;
824 		}
825 	}
826 	if (sibling == NULL) after = TRUE;
827 
828 	/* Add in Makefile.am */
829 	targetname = g_strconcat (amp_target_node_get_install_directory (target) != NULL ? amp_target_node_get_install_directory (target) : info->install, "_", info->prefix, NULL);
830 
831 	// Get token corresponding to sibling and check if the target are compatible
832 	args = NULL;
833 	var = NULL;
834 	prev = NULL;
835 	if (sibling != NULL)
836 	{
837 		last = amp_target_node_get_token (AMP_TARGET_NODE (sibling), ANJUTA_TOKEN_ARGUMENT);
838 
839 		if (last != NULL)
840 		{
841 			AnjutaToken *token = (AnjutaToken *)last->data;
842 
843 			/* Check that the sibling is of the same kind */
844 			token = anjuta_token_list (token);
845 			if (token != NULL)
846 			{
847 				token = anjuta_token_list (token);
848 				var = token;
849 				if (token != NULL)
850 				{
851 					token = anjuta_token_first_item (token);
852 					if (token != NULL)
853 					{
854 						gchar *value;
855 
856 						value = anjuta_token_evaluate (token);
857 
858 						if ((value != NULL) && (strcmp (targetname, value) == 0))
859 						{
860 							g_free (value);
861 							prev = (AnjutaToken *)last->data;
862 							args = anjuta_token_list (prev);
863 						}
864 					}
865 				}
866 			}
867 		}
868 	}
869 
870 
871 	/* Check if a valid target variable is already defined */
872 	if (args == NULL)
873 	{
874 		for (last = amp_group_node_get_token (parent, AM_GROUP_TARGET); last != NULL; last = g_list_next (last))
875 		{
876 			gchar *value = anjuta_token_evaluate (anjuta_token_first_word ((AnjutaToken *)last->data));
877 
878 			if ((value != NULL) && (strcmp (targetname, value) == 0))
879 			{
880 				g_free (value);
881 				args = anjuta_token_last_item ((AnjutaToken *)last->data);
882 				break;
883 			}
884 			g_free (value);
885 		}
886 	}
887 
888 
889 	if (args == NULL)
890 	{
891 		args = amp_project_write_target (parent, info->token, targetname, FALSE, NULL);
892 	}
893 	g_free (targetname);
894 
895 	switch (anjuta_project_node_get_full_type (ANJUTA_PROJECT_NODE (target)) & ANJUTA_PROJECT_ID_MASK)
896 	{
897 	case ANJUTA_PROJECT_SHAREDLIB:
898 	case ANJUTA_PROJECT_STATICLIB:
899 	case ANJUTA_PROJECT_LT_MODULE:
900 	case ANJUTA_PROJECT_PROGRAM:
901 		amp_target_add_in_list (project, args, ANJUTA_PROJECT_NODE (target), after, prev);
902 		break;
903 	default:
904 		if (args != NULL)
905 		{
906 			amp_target_node_add_token (target, AM_TOKEN__SOURCES, args);
907 		}
908 		break;
909 	}
910 
911 	return TRUE;
912 }
913 
914 gboolean
amp_target_node_delete_token(AmpProject * project,AmpTargetNode * target,GList * list,GError ** error)915 amp_target_node_delete_token (AmpProject  *project, AmpTargetNode *target, GList *list, GError **error)
916 {
917 	GList *item;
918 	GList *removed_dir = NULL;
919 	AmpGroupNode *parent;
920 
921 	/* Get parent group */
922 	parent = AMP_GROUP_NODE (anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (target), ANJUTA_PROJECT_GROUP));
923 
924 	/* Remove all associated token */
925 	for (item = list; item != NULL;	 item = g_list_next (item))
926 	{
927 		AnjutaToken *token = (AnjutaToken *)item->data;
928 		AnjutaTokenStyle *style;
929 		AnjutaToken *list;
930 
931 		switch (anjuta_token_get_type (token))
932 		{
933 		case ANJUTA_TOKEN_ARGUMENT:
934 
935 			list = anjuta_token_list (token);
936 
937 			/* Try to use the same style than the current target list */
938 			style = anjuta_token_style_new_from_base (project->am_space_list);
939 			anjuta_token_style_update (style, list);
940 
941 			anjuta_token_remove_word (token);
942 			anjuta_token_style_format (style, list);
943 			anjuta_token_style_free (style);
944 
945 			/* Remove whole variable if empty */
946 			if (anjuta_token_first_word (list) == NULL)
947 			{
948 				AnjutaToken *variable = anjuta_token_list (list);
949 				gchar *value;
950 				gint flags;
951 				gchar *install = NULL;
952 
953 				value = anjuta_token_evaluate (anjuta_token_first_word (variable));
954 				split_automake_variable (value, &flags, &install, NULL);
955 
956 				if (install != NULL)
957 				{
958 					/* Mark all removed directory, normally only one */
959 					removed_dir = g_list_prepend (removed_dir, g_strdup (install));
960 				}
961 				g_free (value);
962 				anjuta_token_remove_list (variable);
963 			}
964 
965 			amp_group_node_update_makefile (parent, list);
966 
967 			break;
968 		case AM_TOKEN__SOURCES:
969 		case AM_TOKEN__DATA:
970 		case AM_TOKEN__HEADERS:
971 		case AM_TOKEN__LISP:
972 		case AM_TOKEN__MANS:
973 		case AM_TOKEN__PYTHON:
974 		case AM_TOKEN__JAVA:
975 		case AM_TOKEN__SCRIPTS:
976 		case AM_TOKEN__TEXINFOS:
977         case AM_TOKEN_TARGET_LDFLAGS:
978         case AM_TOKEN_TARGET_CPPFLAGS:
979         case AM_TOKEN_TARGET_CFLAGS:
980         case AM_TOKEN_TARGET_CXXFLAGS:
981         case AM_TOKEN_TARGET_JAVACFLAGS:
982         case AM_TOKEN_TARGET_VALAFLAGS:
983         case AM_TOKEN_TARGET_FCFLAGS:
984         case AM_TOKEN_TARGET_OBJCFLAGS:
985         case AM_TOKEN_TARGET_LFLAGS:
986         case AM_TOKEN_TARGET_YFLAGS:
987         case AM_TOKEN_TARGET_DEPENDENCIES:
988         case AM_TOKEN_TARGET_LIBADD:
989         case AM_TOKEN_TARGET_LDADD:
990 			anjuta_token_remove_list (token);
991 			amp_group_node_update_makefile (parent, token);
992 			break;
993 		};
994 		amp_target_node_remove_token (target, token);
995 	}
996 
997 	/* Check if we need to remove dir variable */
998 	for (item = removed_dir; item != NULL; item = g_list_next(item))
999 	{
1000 		gchar* dir = (gchar *)item->data;
1001 		GList *list;
1002 
1003 		/* Check if dir is used in another target */
1004 		for (list = amp_group_node_get_token (parent, AM_GROUP_TARGET); list != NULL; list = g_list_next (list))
1005 		{
1006 			AnjutaToken *target_list = (AnjutaToken *)list->data;
1007 			gchar *value;
1008 			gint flags;
1009 			gchar *install = NULL;
1010 			gboolean same;
1011 
1012 			value = anjuta_token_evaluate (anjuta_token_first_word (target_list));
1013 			/* value can be NULL if we have a list can has just been removed */
1014 			if (value != NULL) split_automake_variable (value, &flags, &install, NULL);
1015 
1016 			same = g_strcmp0 (install, dir) == 0;
1017 			g_free (value);
1018 
1019 			if (same)
1020 			{
1021 				/* directory use elsewhere */
1022 
1023 				g_free (dir);
1024 				dir = NULL;
1025 				break;
1026 			}
1027 		}
1028 
1029 		if (dir != NULL)
1030 		{
1031 			/* Directory is not used anymore, remove variable */
1032 			gchar* install = g_strconcat (dir, "dir", NULL);
1033 
1034 			for (list = anjuta_project_node_get_properties (ANJUTA_PROJECT_NODE(parent)); list != NULL; list = g_list_next (list))
1035 			{
1036 				AmpProperty *prop = (AmpProperty *)list->data;
1037 
1038 				if ((((AmpPropertyInfo *)prop->base.info)->token_type == AM_TOKEN_DIR) &&
1039 				    (g_strcmp0(prop->base.name, install) == 0))
1040 				{
1041 					AnjutaProjectProperty *new_prop;
1042 
1043 					new_prop = amp_node_map_property_set (ANJUTA_PROJECT_NODE (parent), prop->base.info->id, prop->base.name, NULL);
1044 					amp_project_update_am_property (project, ANJUTA_PROJECT_NODE (parent), new_prop);
1045 				}
1046 			}
1047 			g_free (install);
1048 			g_free (dir);
1049 		}
1050 	}
1051 	g_list_free (removed_dir);
1052 
1053 
1054 	return TRUE;
1055 }
1056 
1057 
1058 
1059 /* Source objects
1060  *---------------------------------------------------------------------------*/
1061 
1062 
1063 /* Source objects
1064  *---------------------------------------------------------------------------*/
1065 
1066 gboolean
amp_source_node_create_token(AmpProject * project,AmpSourceNode * source,GError ** error)1067 amp_source_node_create_token (AmpProject  *project, AmpSourceNode *source, GError **error)
1068 {
1069 	AmpGroupNode *group;
1070 	AmpTargetNode *target;
1071 	AnjutaProjectNode *sibling;
1072 	gboolean after;
1073 	AnjutaToken *token;
1074 	AnjutaToken *prev;
1075 	AnjutaToken *args;
1076 	gchar *relative_name;
1077 
1078 	/* Get parent target */
1079 	target = AMP_TARGET_NODE (anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (source), ANJUTA_PROJECT_TARGET));
1080 	if (target == NULL) return FALSE;
1081 
1082 	group = AMP_GROUP_NODE (anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (target), ANJUTA_PROJECT_GROUP));
1083 	relative_name = get_relative_path (anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (group)), anjuta_project_node_get_file (ANJUTA_PROJECT_NODE (source)));
1084 
1085 	/* Add in Makefile.am */
1086 	/* Find a sibling if possible */
1087 	after = TRUE;
1088 	for (sibling = anjuta_project_node_prev_sibling (ANJUTA_PROJECT_NODE (source)); sibling != NULL; sibling = anjuta_project_node_prev_sibling (sibling))
1089 	{
1090 		if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_SOURCE)
1091 		{
1092 			break;
1093 		}
1094 		else if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_OBJECT)
1095 		{
1096 			sibling = anjuta_project_node_first_child (sibling);
1097 			break;
1098 		}
1099 	}
1100 	if (sibling == NULL)
1101 	{
1102 		after = FALSE;
1103 		for (sibling = anjuta_project_node_next_sibling (ANJUTA_PROJECT_NODE (source)); sibling != NULL; sibling = anjuta_project_node_next_sibling (sibling))
1104 		{
1105 			if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_SOURCE)
1106 			{
1107 				break;
1108 			}
1109 			else if (anjuta_project_node_get_node_type (sibling) == ANJUTA_PROJECT_OBJECT)
1110 			{
1111 				sibling = anjuta_project_node_first_child (sibling);
1112 				break;
1113  			}
1114 		}
1115 	}
1116 	if (sibling == NULL)
1117 	{
1118 		after = TRUE;
1119 		prev = NULL;
1120 		args = NULL;
1121 	}
1122 	else
1123 	{
1124 		prev = amp_source_node_get_token (AMP_SOURCE_NODE (sibling));
1125 		args = anjuta_token_list (prev);
1126 	}
1127 
1128 	/* Check if a valid source variable is already defined */
1129 	if (args == NULL)
1130 	{
1131 		GList *last;
1132 		for (last = amp_target_node_get_token (target, AM_TOKEN__SOURCES); last != NULL; last = g_list_next (last))
1133 		{
1134 			args = anjuta_token_last_item ((AnjutaToken *)last->data);
1135 			break;
1136 		}
1137 		if (last == NULL)
1138 		{
1139 			for (last = amp_target_node_get_token (target, AM_TOKEN__DATA); last != NULL; last = g_list_next (last))
1140 			{
1141 				args = anjuta_token_last_item ((AnjutaToken *)last->data);
1142 				break;
1143 			}
1144 		}
1145 
1146 	}
1147 
1148 	if (args == NULL)
1149 	{
1150 		gchar *target_var;
1151 		gchar *canon_name;
1152 		AnjutaToken *var;
1153 
1154 		canon_name = canonicalize_automake_variable (anjuta_project_node_get_name (ANJUTA_PROJECT_NODE (target)));
1155 		target_var = g_strconcat (canon_name,  "_SOURCES", NULL);
1156 
1157 		var = anjuta_token_find_target_property_position (target, AM_TOKEN__SOURCES);
1158 		if (var == NULL)
1159 			var = anjuta_token_find_target_property_position (target, AM_TOKEN__DATA);
1160 
1161 		args = anjuta_token_insert_token_list (FALSE, var,
1162 					ANJUTA_TOKEN_LIST, NULL,
1163     				ANJUTA_TOKEN_NAME, target_var,
1164 	    			ANJUTA_TOKEN_SPACE, " ",
1165 					ANJUTA_TOKEN_OPERATOR, "=",
1166     				ANJUTA_TOKEN_LIST, NULL,
1167 	            	ANJUTA_TOKEN_SPACE, " ",
1168 					NULL);
1169 
1170 		args = anjuta_token_last_item (args);
1171 		g_free (target_var);
1172 	}
1173 
1174 	if (args != NULL)
1175 	{
1176 		AnjutaTokenStyle *style;
1177 
1178 		style = anjuta_token_style_new_from_base (project->am_space_list);
1179 		anjuta_token_style_update (style, args);
1180 
1181 		token = anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, relative_name);
1182 		if (after)
1183 		{
1184 			anjuta_token_insert_word_after (args, prev, token);
1185 		}
1186 		else
1187 		{
1188 			anjuta_token_insert_word_before (args, prev, token);
1189 		}
1190 
1191 		/* Try to use the same style than the current target list */
1192 		anjuta_token_style_format (style, args);
1193 		anjuta_token_style_free (style);
1194 
1195 		amp_group_node_update_makefile (group, token);
1196 
1197 		amp_source_node_add_token (source, token);
1198 	}
1199 
1200 	return TRUE;
1201 }
1202 
1203 gboolean
amp_source_node_delete_token(AmpProject * project,AmpSourceNode * source,GError ** error)1204 amp_source_node_delete_token (AmpProject  *project, AmpSourceNode *source, GError **error)
1205 {
1206 	AnjutaProjectNode *group;
1207 	AnjutaToken *token;
1208 
1209 	/* Get parent group */
1210 	group = anjuta_project_node_parent_type (ANJUTA_PROJECT_NODE (source), ANJUTA_PROJECT_GROUP);
1211 	if (group == NULL) return FALSE;
1212 
1213 	token = amp_source_node_get_token (source);
1214 	if (token != NULL)
1215 	{
1216 		AnjutaTokenStyle *style;
1217 		AnjutaToken *list;
1218 
1219 		list = anjuta_token_list (token);
1220 
1221 		/* Try to use the same style than the current target list */
1222 		style = anjuta_token_style_new_from_base (project->am_space_list);
1223 		anjuta_token_style_update (style, list);
1224 
1225 		anjuta_token_remove_word (token);
1226 		anjuta_token_style_format (style, list);
1227 		anjuta_token_style_free (style);
1228 
1229 		/* Remove whole variable if empty */
1230 		if (anjuta_token_first_word (list) == NULL)
1231 		{
1232 			anjuta_token_remove_list (anjuta_token_list (list));
1233 		}
1234 
1235 		amp_group_node_update_makefile (AMP_GROUP_NODE (group), list);
1236 	}
1237 
1238 	return TRUE;
1239 }
1240 
1241 
1242 /* Properties
1243  *---------------------------------------------------------------------------*/
1244 
1245 static AnjutaToken*
amp_property_delete_token(AmpProject * project,AnjutaToken * token)1246 amp_property_delete_token (AmpProject  *project, AnjutaToken *token)
1247 {
1248 	gboolean updated = FALSE;
1249 
1250 	if (token != NULL)
1251 	{
1252 		anjuta_token_remove_list (anjuta_token_list (token));
1253 
1254 		updated = TRUE;
1255 	}
1256 
1257 	return token;
1258 }
1259 
1260 static AnjutaToken *
amp_project_write_property_list(AmpGroupNode * group,AnjutaProjectNode * node,AmpPropertyInfo * info)1261 amp_project_write_property_list (AmpGroupNode *group, AnjutaProjectNode *node, AmpPropertyInfo *info)
1262 {
1263 	AnjutaToken *pos;
1264 	gchar *name;
1265 
1266 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1267 	{
1268 		/* Group property */
1269 		name = g_strdup (info->suffix);
1270 
1271 		pos = anjuta_token_find_group_property_position (AMP_GROUP_NODE (node), info->token_type);
1272 	}
1273 	else
1274 	{
1275 		/* Target property */
1276 		gchar *canon_name;
1277 
1278 		canon_name = canonicalize_automake_variable (anjuta_project_node_get_name (ANJUTA_PROJECT_NODE (node)));
1279 		name = g_strconcat (canon_name, info->suffix, NULL);
1280 		g_free (canon_name);
1281 
1282 		pos = anjuta_token_find_target_property_position (AMP_TARGET_NODE (node), info->token_type);
1283 	}
1284 
1285 	pos = anjuta_token_insert_token_list (FALSE, pos,
1286     			info->token_type, NULL,
1287     			ANJUTA_TOKEN_NAME, name,
1288     			ANJUTA_TOKEN_SPACE, " ",
1289     			ANJUTA_TOKEN_OPERATOR, "=",
1290             	ANJUTA_TOKEN_SPACE, " ",
1291     			ANJUTA_TOKEN_LIST, NULL,
1292             	ANJUTA_TOKEN_SPACE, " ",
1293     			NULL);
1294 
1295 	g_free (name);
1296 
1297 	return anjuta_token_last_item (pos);
1298 }
1299 
1300 static gint
compare_property_position(gconstpointer a,gconstpointer b)1301 compare_property_position (gconstpointer a, gconstpointer b)
1302 {
1303 	return ((const AmpPropertyInfo *)a)->position - ((const AmpPropertyInfo *)b)->position;
1304 }
1305 
1306 static AnjutaToken *
amp_property_rename_target(AmpProject * project,AnjutaProjectNode * node)1307 amp_property_rename_target (AmpProject *project, AnjutaProjectNode *node)
1308 {
1309 	AnjutaProjectNode *group;
1310 	GList *infos;
1311 	GList *item;
1312 	GString *new_name;
1313 	AmpNodeInfo *info;
1314 	GList *list;
1315 	AnjutaToken *update = NULL;
1316 	AnjutaToken *existing_target_list;
1317 	gboolean after;
1318 	gchar *target_dir;
1319 
1320 	g_return_val_if_fail (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_TARGET, NULL);
1321 
1322 	group = anjuta_project_node_parent_type (node, ANJUTA_PROJECT_GROUP);
1323 
1324 	/* Find all program properties */
1325 	infos = NULL;
1326 	for (item = anjuta_project_node_get_properties_info (node); item != NULL; item = g_list_next (item))
1327 	{
1328 		AmpPropertyInfo *info = (AmpPropertyInfo *)item->data;
1329 
1330 		if (info->token_type == AM_TOKEN__PROGRAMS)
1331 		{
1332 			infos = g_list_insert_sorted (infos, info, compare_property_position);
1333 		}
1334 	}
1335 
1336 	/* Create new name */
1337 	new_name = g_string_new (NULL);
1338 	for (item = infos; item != NULL; item = g_list_next (item))
1339 	{
1340 		AmpPropertyInfo *info = (AmpPropertyInfo *)item->data;
1341 		AmpProperty *prop;
1342 
1343 		/* Check if property is enabled by another property */
1344 		if (info->link != NULL)
1345 		{
1346 			AnjutaProjectProperty *en_prop;
1347 
1348 			en_prop = anjuta_project_node_get_property (node, info->link->id);
1349 
1350 			if ((en_prop->value != NULL) && (*en_prop->value == '1')) continue;
1351 		}
1352 
1353 		prop = (AmpProperty *)anjuta_project_node_get_property (node, info->base.id);
1354 		if ((prop == (AmpProperty *)info->base.default_value) || (g_strcmp0 (prop->base.value, info->base.default_value->value) == 0))
1355 		{
1356 			/* Default value, add only string properties */
1357 			if (info->base.type == ANJUTA_PROJECT_PROPERTY_STRING)
1358 			{
1359 				g_string_append (new_name, info->suffix);
1360 				g_string_append_c (new_name, '_');
1361 			}
1362 		}
1363 		else
1364 		{
1365 			switch (info->base.type)
1366 			{
1367 			case ANJUTA_PROJECT_PROPERTY_STRING:
1368 				if ((info->flags & AM_PROPERTY_DIRECTORY) &&
1369 				    (strlen (prop->base.value) > 4) &&
1370 				    (strcmp (prop->base.value + strlen (prop->base.value) - 3, "dir") == 0))
1371 				{
1372 					/* Remove "dir" suffix */
1373 					g_string_append_len (new_name, prop->base.value, strlen (prop->base.value) - 3);
1374 				}
1375 				else
1376 				{
1377 					g_string_append (new_name, prop->base.value);
1378 				}
1379 				g_string_append_c (new_name, '_');
1380 				break;
1381 			case ANJUTA_PROJECT_PROPERTY_BOOLEAN:
1382 				if ((prop->base.value != NULL) && (g_strcmp0 (prop->base.value, info->base.default_value->value) != 0))
1383 				{
1384 					g_string_append (new_name, info->suffix);
1385 				}
1386 				break;
1387 			default:
1388 				break;
1389 			}
1390 		}
1391 	}
1392 
1393 	info = (AmpNodeInfo *)amp_project_get_type_info (project, anjuta_project_node_get_full_type (node));
1394 	g_string_append (new_name, info->prefix);
1395 
1396 	if ((anjuta_project_node_get_full_type (node) & ANJUTA_PROJECT_ID_MASK) == ANJUTA_PROJECT_DATA)
1397 	{
1398 		list = amp_target_node_get_token (AMP_TARGET_NODE (node), AM_TOKEN__DATA);
1399 
1400 		if ((list != NULL) && (list->data != NULL))
1401 		{
1402 			AnjutaToken *old_token;
1403 			AnjutaToken *parent;
1404 
1405 			parent = (AnjutaToken *)list->data;
1406 			old_token = anjuta_token_first_word (parent);
1407 			if (old_token != NULL)
1408 			{
1409 				AnjutaToken *token;
1410 
1411 
1412 				token = anjuta_token_new_string (ANJUTA_TOKEN_ADDED, new_name->str);
1413 				update = anjuta_token_insert_word_after (parent, old_token, token);
1414 				anjuta_token_remove_word (old_token);
1415 				update = parent;
1416 			}
1417 		}
1418 	}
1419 	else
1420 	{
1421     	// Check if the target already exist.
1422 		after = TRUE;
1423 		for (item = amp_group_node_get_token (AMP_GROUP_NODE (group), AM_GROUP_TARGET); item != NULL; item = g_list_next (item))
1424 		{
1425 			existing_target_list = (AnjutaToken *)item->data;
1426 			gchar *target_name = anjuta_token_evaluate (anjuta_token_first_word (existing_target_list));
1427 			gboolean same;
1428 
1429 			same = strcmp (target_name,  new_name->str) == 0;
1430 			g_free (target_name);
1431 
1432 			if (after)
1433 			{
1434 				GList *list;
1435 				GList *item;
1436 
1437 				list = amp_target_node_get_token (AMP_TARGET_NODE (node), ANJUTA_TOKEN_ARGUMENT);
1438 				for (item = g_list_first (list); item != NULL; item = g_list_next (item))
1439 				{
1440 					AnjutaToken *arg = (AnjutaToken *)item->data;
1441 					AnjutaToken *target_list;
1442 
1443 					if (arg != NULL)
1444 					{
1445 						target_list = anjuta_token_list (arg);
1446 						if (anjuta_token_list (target_list) == existing_target_list)
1447 						{
1448 							/* token in group_node are stored in reverse order */
1449 							after = FALSE;
1450 							break;
1451 						}
1452 					}
1453 				}
1454 			}
1455 
1456 			if (same)
1457 			{
1458 				existing_target_list = anjuta_token_last_item (existing_target_list);
1459 				break;
1460 			}
1461 			existing_target_list = NULL;
1462 		}
1463 
1464 		if (existing_target_list != NULL)
1465 		{
1466 			GList *token_list;
1467 
1468 			/* Get old tokens */
1469 			token_list = g_list_copy (amp_target_node_get_token (AMP_TARGET_NODE (node), ANJUTA_TOKEN_ARGUMENT));
1470 
1471 			/* Add target in already existing list */
1472 			amp_target_add_in_list (project, existing_target_list, node, after, NULL);
1473 
1474 			/* Remove old token */
1475 			amp_target_node_delete_token (project, AMP_TARGET_NODE (node), token_list, NULL);
1476 			g_list_free (token_list);
1477 		}
1478 		else
1479 		{
1480 			list = amp_target_node_get_token (AMP_TARGET_NODE (node), ANJUTA_TOKEN_ARGUMENT);
1481 			for (item = g_list_first (list); item != NULL; item = g_list_next (item))
1482 			{
1483 				AnjutaToken *arg = (AnjutaToken *)item->data;
1484 				AnjutaToken *target_list;
1485 
1486 				if (arg == NULL) continue;
1487 
1488 				target_list = anjuta_token_list (arg);
1489 
1490 				if (anjuta_token_nth_word (target_list, 1) == NULL)
1491 				{
1492 					/* Only one target in list, just replace list name */
1493 					AnjutaToken *target_variable = anjuta_token_list (target_list);
1494 
1495 					if (target_variable != NULL)
1496 					{
1497 						AnjutaToken *old_token;
1498 
1499 						old_token = anjuta_token_first_word (target_variable);
1500 						if (old_token != NULL)
1501 						{
1502 							AnjutaToken *token;
1503 
1504 							token = anjuta_token_new_string (ANJUTA_TOKEN_ADDED, new_name->str);
1505 							update = anjuta_token_insert_word_after (target_variable, old_token, token);
1506 							anjuta_token_remove_word (old_token);
1507 							update = target_variable;
1508 						}
1509 					}
1510 				}
1511 				else
1512 				{
1513 					gchar *old_target;
1514 					AmpNodeInfo *info;
1515 					gboolean after = TRUE;
1516 					AnjutaToken *sibling = NULL;
1517 					AnjutaTokenStyle *style;
1518 					AnjutaToken *token;
1519 
1520 					old_target = anjuta_token_evaluate (arg);
1521 
1522 					/* Find sibling target */
1523 					if (anjuta_token_first_word (target_list) == arg)
1524 					{
1525 						sibling = anjuta_token_next_word (arg);
1526 						after = FALSE;
1527 					}
1528 					else
1529 					{
1530 						for (sibling = anjuta_token_first_word (target_list); sibling != NULL; sibling = anjuta_token_next_word (sibling))
1531 						{
1532 							if (anjuta_token_next_word (sibling) == arg) break;
1533 						}
1534 						after = TRUE;
1535 					}
1536 
1537 					/* More than one target, remove target in list */
1538 					arg = anjuta_token_remove_word (arg);
1539 					if (arg != NULL) amp_group_node_update_makefile (AMP_GROUP_NODE (group), arg);
1540 
1541 
1542 					/* Add target in new list */
1543 					style = anjuta_token_style_new_from_base (project->am_space_list);
1544 					anjuta_token_style_update (style, target_list);
1545 
1546 					info = (AmpNodeInfo *)amp_project_get_type_info (project, anjuta_project_node_get_full_type (node));
1547 					target_list = amp_project_write_target (AMP_GROUP_NODE (group), info->token, new_name->str, after, sibling);
1548 
1549 					token = anjuta_token_new_string (ANJUTA_TOKEN_ARGUMENT | ANJUTA_TOKEN_ADDED, old_target);
1550 					anjuta_token_insert_word_after (target_list, NULL, token);
1551 
1552 					/* Try to use the same style than the current target list */
1553 					anjuta_token_style_format (style, target_list);
1554 					anjuta_token_style_free (style);
1555 
1556 					amp_group_node_update_makefile (AMP_GROUP_NODE (group), token);
1557 					amp_target_node_add_token (AMP_TARGET_NODE (node), ANJUTA_TOKEN_ARGUMENT, token);
1558 
1559 					g_free (old_target);
1560 
1561 					update = anjuta_token_list (target_list);
1562 				}
1563 			}
1564 		}
1565 	}
1566 
1567 
1568 	/* Add directory variable if needed */
1569 	target_dir = NULL;
1570 	for (item = anjuta_project_node_get_properties (node); item != NULL; item = g_list_next (item))
1571 	{
1572 		AmpProperty *prop = (AmpProperty *)item->data;
1573 
1574 		if ((((AmpPropertyInfo *)prop->base.info)->token_type == AM_TOKEN__PROGRAMS) && (((AmpPropertyInfo *)prop->base.info)->flags & AM_PROPERTY_DIRECTORY))
1575 		{
1576 			target_dir = prop->base.value;
1577 			if ((strlen (target_dir) <= 3) || (strcmp (target_dir + strlen(target_dir) - 3, "dir") != 0))
1578 			{
1579 				target_dir = g_strconcat (target_dir, "dir", NULL);
1580 				g_free (prop->base.value);
1581 				prop->base.value = target_dir;
1582 			}
1583 			break;
1584 		}
1585 	}
1586 
1587 	/* If it is a standard directory do not add a variable*/
1588 	if (target_dir != NULL)
1589 	{
1590 		const gchar **std_dir;
1591 
1592 		for (std_dir = AmpStandardDirectory; *std_dir != NULL; std_dir++)
1593 		{
1594 			if (strcmp(*std_dir, target_dir) == 0)
1595 			{
1596 				target_dir = NULL;
1597 				break;
1598 			}
1599 		}
1600 	}
1601 
1602 	if (target_dir != NULL)
1603 	{
1604 		for (item = anjuta_project_node_get_properties (group); item != NULL; item = g_list_next (item))
1605 		{
1606 			AmpProperty *prop = (AmpProperty *)item->data;
1607 
1608 			if ((((AmpPropertyInfo *)prop->base.info)->token_type == AM_TOKEN_DIR) && (g_strcmp0 (prop->base.name, target_dir) == 0))
1609 			{
1610 				/* Find already existing directory variable */
1611 				target_dir = NULL;
1612 				break;
1613 			}
1614 		}
1615 	}
1616 
1617 	if ((update != NULL) && (target_dir != NULL))
1618 	{
1619 		update = anjuta_token_insert_token_list (FALSE, update,
1620 					AM_TOKEN_DIR, NULL,
1621     				ANJUTA_TOKEN_NAME, target_dir,
1622     				ANJUTA_TOKEN_SPACE, " ",
1623     				ANJUTA_TOKEN_OPERATOR, "=",
1624         			ANJUTA_TOKEN_SPACE, " ",
1625     				ANJUTA_TOKEN_LIST, NULL,
1626         			ANJUTA_TOKEN_SPACE, " ",
1627 					ANJUTA_TOKEN_EOL, "\n",
1628     				NULL);
1629 	}
1630 
1631 	g_string_free (new_name, TRUE);
1632 
1633 
1634 	return update;
1635 }
1636 
amp_project_update_am_property(AmpProject * project,AnjutaProjectNode * node,AnjutaProjectProperty * property)1637 gboolean amp_project_update_am_property (AmpProject *project, AnjutaProjectNode *node, AnjutaProjectProperty *property)
1638 {
1639 	AnjutaProjectNode *group;
1640 	AnjutaToken *args;
1641 
1642 	/* Find group  of the property */
1643 	if (anjuta_project_node_get_node_type (node) == ANJUTA_PROJECT_GROUP)
1644 	{
1645 		group = node;
1646 	}
1647 	else
1648 	{
1649 		group = anjuta_project_node_parent_type (node, ANJUTA_PROJECT_GROUP);
1650 	}
1651 
1652 	if (property->value == NULL)
1653 	{
1654 		/* Remove property */
1655 		if (((AmpPropertyInfo *)property->info)->token_type == AM_TOKEN__PROGRAMS)
1656 		{
1657 			/* Properties added in the target name */
1658 			args = amp_property_rename_target (project, node);
1659 		}
1660 		else
1661 		{
1662 			/* Other properties having their own variable */
1663 			args = amp_property_delete_token (project, ((AmpProperty *)property)->token);
1664 		}
1665 
1666 		anjuta_project_node_remove_property (node, property);
1667 	}
1668 	else
1669 	{
1670 		if (((AmpPropertyInfo *)property->info)->token_type == AM_TOKEN__PROGRAMS)
1671 		{
1672 			/* Properties added in the target name */
1673 			args = amp_property_rename_target (project, node);
1674 		}
1675 		else
1676 		{
1677 			/* Other properties having their own variable */
1678 			GString *new_value;
1679 			AnjutaToken *arg;
1680 			AnjutaToken *token;
1681 			const gchar *value;
1682 			AnjutaTokenStyle *style;
1683 
1684 			args = ((AmpProperty *)property)->token;
1685 
1686 			/* Try to use the same style than the current target list */
1687 			style = anjuta_token_style_new_from_base (project->am_space_list);
1688 			anjuta_token_style_update (style, args);
1689 
1690 			if (args == NULL)
1691 			{
1692 				args = amp_project_write_property_list (AMP_GROUP_NODE (group), node, (AmpPropertyInfo *)property->info);
1693 				((AmpProperty *)property)->token = args;
1694 			}
1695 
1696 			switch (property->info->type)
1697 			{
1698 			case ANJUTA_PROJECT_PROPERTY_LIST:
1699 				new_value = g_string_new (property->value);
1700 				g_string_assign (new_value, "");
1701 				value = property->value;
1702 
1703 				for (arg = anjuta_token_first_word (args); arg != NULL;)
1704 				{
1705 					gchar *arg_value = anjuta_token_evaluate_name (arg);
1706 
1707 					while (isspace (*value)) value++;
1708 
1709 					if (*value == '\0')
1710 					{
1711 						AnjutaToken *next;
1712 
1713 						next = anjuta_token_next_word (arg);
1714 						anjuta_token_remove_word (arg);
1715 						arg = next;
1716 					}
1717 					else
1718 					{
1719 						const gchar *end;
1720 						gchar *name;
1721 
1722 						for (end = value; !isspace (*end) && (*end != '\0'); end++);
1723 						name = g_strndup (value, end - value);
1724 
1725 						if (strcmp (arg_value, name) != 0)
1726 						{
1727 							/* New argument in property list */
1728 							AnjutaToken *token;
1729 
1730 							token = anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, name);
1731 							anjuta_token_insert_word_before (args, arg, token);
1732 						}
1733 						else
1734 						{
1735 							arg = anjuta_token_next_word (arg);
1736 						}
1737 						value = end;
1738 
1739 						if (arg_value != NULL)
1740 						{
1741 							if (new_value->len != 0) g_string_append_c (new_value, ' ');
1742 							g_string_append (new_value, name);
1743 						}
1744 					}
1745 					g_free (arg_value);
1746 				}
1747 
1748 				while (*value != '\0')
1749 				{
1750 					AnjutaToken *token;
1751 					const gchar *end;
1752 					gchar *name;
1753 
1754 					while (isspace (*value)) value++;
1755 					if (*value == '\0') break;
1756 
1757 					for (end = value; !isspace (*end) && (*end != '\0'); end++);
1758 
1759 					name = g_strndup (value, end - value);
1760 					token = anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, name);
1761 
1762 					anjuta_token_insert_word_before (args, NULL, token);
1763 
1764 					if (new_value->len != 0) g_string_append_c (new_value, ' ');
1765 					g_string_append (new_value, name);
1766 
1767 					g_free (name);
1768 					value = end;
1769 				}
1770 
1771 				anjuta_token_style_format (style, args);
1772 				anjuta_token_style_free (style);
1773 
1774 				g_free (property->value);
1775 				property->value = g_string_free (new_value, FALSE);
1776 
1777 				break;
1778 			case ANJUTA_PROJECT_PROPERTY_MAP:
1779 
1780 				token =  anjuta_token_new_string (ANJUTA_TOKEN_NAME | ANJUTA_TOKEN_ADDED, property->value);
1781 				anjuta_token_insert_word_after (args, NULL, token);
1782 
1783 				for (token = anjuta_token_next_word (token); token != NULL; token = anjuta_token_next_word (token))
1784 				{
1785 					anjuta_token_remove_word (token);
1786 				}
1787 				break;
1788 			default:
1789 				break;
1790 			}
1791 		}
1792 	}
1793 
1794 	if (args != NULL) amp_group_node_update_makefile (AMP_GROUP_NODE (group), args);
1795 
1796 	return args != NULL ? TRUE : FALSE;
1797 }
1798