1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
4 * Copyright (C) Sébastien Granjoux 2009 <seb.sfo@free.fr>
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "anjuta-token.h"
22 #include "anjuta-debug.h"
24 #include <glib-object.h>
31 * SECTION:anjuta-token
32 * @title: Anjuta token
33 * @short_description: Anjuta token
35 * @stability: Unstable
36 * @include: libanjuta/anjuta-token.h
38 * A #AnjutaToken represents a token. It is a sequence of characters associated
39 * with a type representing its meaning. By example, a token can represent
40 * a keyword, a comment, a variable...
42 * The token can own the string or has only a pointer on some data allocated
43 * somewhere else with a length.
45 * A token is linked with other tokens using three double linked lists.
47 * The first list using next and prev fields is used to keep the token in the
48 * order where there are in the file. The first character of the first token is
49 * the first character in the file.
51 * A second list is used to represent included
52 * files. Such file is represented by a special token in the first list which
53 * has a pointer, named children to a token list. Each token in this secondary
54 * list has a pointer to its parent, it means the token representing the file
55 * where is the token. It looks like a tree. In fact, every file is represented
56 * by a special token, so the root node is normally a file token and has as
57 * children all the token representing the file content. This parent/child list
58 * is used for expanded variable too.
60 * A third list is used to group several tokens. A token can have a pointer to
61 * another last token. It means that this token is a group starting from this
62 * token to the one indicated by the last field. In addition each token in this
63 * group has a pointer on the first token of the group. This grouping is
64 * independent of the parent/child list. So a group can start in one file and
65 * end in another included file. The grouping can be nested too. Typically
66 * we can have a group representing a command, a sub group representing the
67 * arguments and then one sub group for each argument.
71 * A token with its pointer can be put in one of the following case:
74 * children = NULL && last = NULL
75 * This is the case of a simple token without any children.
78 * children = NULL && last != NULL
79 * This is the case of a token grouping several other tokens, representing
80 * by example an item in a list.
83 * children != NULL && last == NULL
84 * This is the case of a token having children, by example a variable where
85 * the children represent the content. Most of the time the value of the
86 * parent token is ignored.
88 * * Composite parent token:
89 * children != NULL && last != NULL && (last in list)
90 * This case represents a variable which is split into several tokens. The
91 * children represents the content of the variable. The token up to last
92 * corresponds to the variable name. After getting the variable content, the
93 * next token is after the last token of the variable.
95 * * Composite parent token:
96 * children != NULL && last != NULL && (last in children)
97 * This case would represent a variable which is split into several token
98 * with one inside the children of the variable. This is not possible as
99 * the complete name of the variable is needed to get the children.
101 * * Composite parent token:
102 * children != NULL && last != NULL && (last in parent)
103 * This case represents a variable split into several token where the
104 * last element is a sibling of one parent of the token. I think this case
109 typedef struct _AnjutaTokenData AnjutaTokenData
;
111 struct _AnjutaTokenData
113 AnjutaTokenData
*data
;
114 AnjutaTokenType type
;
127 AnjutaToken
*children
;
128 AnjutaTokenData data
;
132 *---------------------------------------------------------------------------*/
135 *---------------------------------------------------------------------------*/
138 anjuta_token_next_child (AnjutaToken
*child
, AnjutaToken
**last
)
140 if (child
== NULL
) return child
;
142 if (child
->children
!= NULL
)
144 child
= child
->children
;
150 if ((*last
== NULL
) || (child
== *last
))
152 if (child
->last
== NULL
)
159 if (child
->next
!= NULL
)
164 child
= child
->parent
;
172 anjuta_token_next_after_children (AnjutaToken
*token
)
174 while (token
->next
== NULL
)
176 token
= token
->parent
;
177 if (token
== NULL
) return NULL
;
184 anjuta_token_copy (AnjutaToken
*token
)
186 AnjutaToken
*copy
= NULL
;
190 copy
= g_slice_new0 (AnjutaToken
);
191 copy
->data
.type
= token
->data
.type
;
192 copy
->data
.flags
= token
->data
.flags
;
193 if ((copy
->data
.flags
& ANJUTA_TOKEN_STATIC
) || (token
->data
.pos
== NULL
))
195 copy
->data
.pos
= token
->data
.pos
;
199 copy
->data
.pos
= g_strdup (token
->data
.pos
);
201 copy
->data
.length
= token
->data
.length
;
208 * anjuta_token_unlink_token:
209 * @token: a #AnjutaToken object.
211 * Unlink a single token, not the complete item, from the token tree.
213 * Return value: the removed token tree
216 anjuta_token_unlink_token (AnjutaToken
*token
)
219 if (token
->prev
!= NULL
)
221 token
->prev
->next
= token
->next
;
223 else if ((token
->parent
!= NULL
) && (token
->parent
->children
== token
))
225 token
->parent
->children
= token
->next
;
227 token
->parent
= NULL
;
229 if ((token
->group
!= NULL
) && (token
->group
->last
== token
))
233 for (prev
= token
->prev
; prev
!= NULL
; prev
= prev
->prev
)
235 if (prev
->group
== token
->group
)
237 /* Find previous token in the same group */
238 token
->group
->last
= prev
;
241 else if (prev
== token
->group
)
243 /* No more token in group */
244 token
->group
->last
= NULL
;
250 if (token
->next
!= NULL
)
252 token
->next
->prev
= token
->prev
;
261 * anjuta_token_insert_token_before:
262 * @sibling: a #AnjutaToken object.
263 * @token: a #AnjutaToken object.
265 * Insert token before sibling.
267 * Return value: inserted token
270 anjuta_token_insert_token_before (AnjutaToken
*sibling
, AnjutaToken
*token
)
272 token
->prev
= sibling
->prev
;
273 token
->next
= sibling
;
275 if (token
->prev
!= NULL
)
277 token
->prev
->next
= token
;
279 sibling
->prev
= token
;
281 if ((sibling
->parent
!= NULL
) && (sibling
->parent
->children
== sibling
))
283 sibling
->parent
->children
= token
;
285 token
->parent
= sibling
->parent
;
291 anjuta_token_evaluate_token (AnjutaToken
*token
, GString
*value
, gboolean raw
)
293 if ((token
!= NULL
) && (token
->data
.length
!= 0))
297 switch (anjuta_token_get_type (token
))
299 case ANJUTA_TOKEN_COMMENT
:
300 case ANJUTA_TOKEN_OPEN_QUOTE
:
301 case ANJUTA_TOKEN_CLOSE_QUOTE
:
302 case ANJUTA_TOKEN_ESCAPE
:
303 case ANJUTA_TOKEN_MACRO
:
304 case ANJUTA_TOKEN_EOV
:
310 g_string_append_len (value
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
315 anjuta_token_show (AnjutaToken
*token
, gint indent
, gchar parent
)
317 static gchar type
[] = "\0";
320 const gchar
*newline
;
323 fprintf (stderr
, "%*s%s %p", indent
, "", type
, token
);
324 fprintf (stderr
, ": %d ",
325 anjuta_token_get_type (token
));
326 string
= anjuta_token_get_string (token
);
327 length
= anjuta_token_get_length (token
);
328 newline
= string
== NULL
? NULL
: g_strrstr_len (string
, length
, "\n");
331 /* Value doesn't contain a newline */
332 fprintf (stderr
, "\"%.*s\"",
338 /* Value contains a newline, take care of indentation */
340 fprintf (stderr
, "\"%.*s",
345 length
-= newline
- string
;
348 newline
= g_strrstr_len (string
, length
, "\n");
349 if (newline
== NULL
) break;
352 fprintf (stderr
, "%*s %.*s",
357 fprintf (stderr
, "%*s %.*s\"",
362 fprintf (stderr
, " %p/%p (%p/%p) %s\n",
363 token
->last
, token
->children
,
364 token
->group
, token
->parent
,
365 anjuta_token_get_flags (token
) & ANJUTA_TOKEN_REMOVED
? " (removed)" : "");
369 anjuta_token_dump_child (AnjutaToken
*token
, gint indent
, gchar type
)
374 anjuta_token_show (token
, indent
, type
);
378 if (token
->last
!= NULL
)
383 if (child
== NULL
) break;
384 last
= anjuta_token_dump_child (child
, indent
, '+');
386 while (child
!= token
->last
);
389 if (token
->children
!= NULL
)
391 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
393 child
= anjuta_token_dump_child (child
, indent
, '*');
401 anjuta_token_check_child (AnjutaToken
*token
, AnjutaToken
*parent
)
403 if (token
->parent
!= parent
)
405 anjuta_token_show (token
, 0, 0);
406 fprintf(stderr
, "Error: Children has %p as parent instead of %p\n", token
->parent
, parent
);
410 return anjuta_token_check (token
);
413 /* Get and set functions
414 *---------------------------------------------------------------------------*/
417 anjuta_token_set_type (AnjutaToken
*token
, gint type
)
419 token
->data
.type
= type
;
423 anjuta_token_get_type (AnjutaToken
*token
)
425 return token
->data
.type
;
429 anjuta_token_set_flags (AnjutaToken
*token
, gint flags
)
432 AnjutaToken
*last
= token
->last
;
434 for (child
= token
; child
!= NULL
; child
= anjuta_token_next_child (child
, &last
))
436 child
->data
.flags
|= flags
;
441 anjuta_token_clear_flags (AnjutaToken
*token
, gint flags
)
443 token
->data
.flags
&= ~flags
;
447 anjuta_token_get_flags (AnjutaToken
*token
)
449 return token
->data
.flags
;
453 anjuta_token_set_string (AnjutaToken
*token
, const gchar
*data
, guint length
)
455 if (!(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
457 g_free (token
->data
.pos
);
458 token
->data
.flags
|= ANJUTA_TOKEN_STATIC
;
460 token
->data
.pos
= (gchar
*)data
;
461 token
->data
.length
= length
;
465 anjuta_token_get_string (AnjutaToken
*token
)
467 return token
->data
.pos
;
471 anjuta_token_get_length (AnjutaToken
*token
)
473 return token
->data
.length
;
476 /* Basic move functions
477 *---------------------------------------------------------------------------*/
480 anjuta_token_next (AnjutaToken
*token
)
482 if (token
->children
!= NULL
)
484 return token
->children
;
486 else if (token
->next
!= NULL
)
490 else if (token
->parent
!= NULL
)
492 return anjuta_token_next_after_children (token
->parent
);
501 anjuta_token_previous (AnjutaToken
*token
)
503 if (token
->prev
!= NULL
)
509 return token
->parent
;
514 anjuta_token_last (AnjutaToken
*token
)
518 for (last
= token
; last
->last
!= NULL
; last
= last
->last
);
519 if (last
->children
!= NULL
)
521 for (last
= last
->children
; last
->next
!= NULL
; last
= last
->next
);
528 anjuta_token_parent (AnjutaToken
*token
)
530 return token
->parent
;
534 anjuta_token_list (AnjutaToken
*token
)
539 /* Item move functions
540 *---------------------------------------------------------------------------*/
543 anjuta_token_last_item (AnjutaToken
*list
)
549 anjuta_token_first_item (AnjutaToken
*list
)
551 AnjutaToken
*first
= NULL
;
555 if (list
->children
!= NULL
)
557 first
= list
->children
;
559 else if (list
->last
!= NULL
)
569 anjuta_token_next_item (AnjutaToken
*item
)
578 if ((item
->group
== NULL
) || (item
->group
->last
!= item
))
581 for (last
= item
; last
->last
!= NULL
; last
= last
->last
);
582 next
= anjuta_token_next (last
);
583 if ((next
!= NULL
) && (next
->group
!= item
->group
)) next
= NULL
;
587 /* Loop if the current item has been deleted */
588 while ((next
!= NULL
) && (anjuta_token_get_flags (next
) & ANJUTA_TOKEN_REMOVED
));
595 anjuta_token_previous_item (AnjutaToken
*item
)
597 AnjutaToken
*prev
= NULL
;
604 for (prev
= item
->prev
; (prev
!= NULL
) && (prev
->group
!= item
->group
); prev
= prev
->group
);
607 /* Loop if the current item has been deleted */
608 while ((prev
!= NULL
) && (anjuta_token_get_flags (prev
) & ANJUTA_TOKEN_REMOVED
));
614 /* Add/Insert/Remove tokens
615 *---------------------------------------------------------------------------*/
618 * anjuta_token_append_child:
619 * @parent: a #AnjutaToken object used as parent.
620 * @children: a #AnjutaToken object.
622 * Insert all tokens in children as the last children of the given parent.
624 * Return value: The first token append.
627 anjuta_token_append_child (AnjutaToken
*parent
, AnjutaToken
*children
)
631 AnjutaToken
*old_group
;
632 AnjutaToken
*old_parent
;
634 g_return_val_if_fail (parent
!= NULL
, NULL
);
635 g_return_val_if_fail (children
!= NULL
, NULL
);
637 old_group
= children
->group
;
638 old_parent
= children
->parent
;
640 if (parent
->children
== NULL
)
642 parent
->children
= children
;
644 children
->prev
= NULL
;
648 /* Find last children */
649 for (last
= parent
->children
; last
->next
!= NULL
;)
651 if ((last
->last
!= NULL
) && (last
->last
->parent
== last
->parent
))
661 last
->next
= children
;
662 children
->prev
= last
;
665 /* Update each token */
666 for (token
= children
;;)
668 if (token
->parent
== old_parent
) token
->parent
= parent
;
669 if (token
->group
== old_group
) token
->group
= parent
->group
;
671 if (token
->children
!= NULL
)
673 token
= token
->children
;
675 else if (token
->next
!= NULL
)
681 while (token
->parent
!= parent
)
683 token
= token
->parent
;
684 if (token
->next
!= NULL
) break;
686 if (token
->next
== NULL
) break;
695 * anjuta_token_prepend_child:
696 * @parent: a #AnjutaToken object used as parent.
697 * @children: a #AnjutaToken object.
699 * Insert all tokens in children as the first children of the given parent.
701 * Return value: The first token append.
704 anjuta_token_prepend_child (AnjutaToken
*parent
, AnjutaToken
*children
)
707 AnjutaToken
*last
= NULL
;
709 g_return_val_if_fail (parent
!= NULL
, NULL
);
710 g_return_val_if_fail (children
!= NULL
, NULL
);
712 /* Update each token */
713 for (child
= children
;;)
717 if (child
->parent
== children
->parent
) child
->parent
= parent
;
718 if (child
->group
== children
->group
) child
->group
= parent
->group
;
720 next
= anjuta_token_next_child (child
, &last
);
721 if (next
== NULL
) break;
725 child
->next
= parent
->children
;
726 if (child
->next
) child
->next
->prev
= child
;
727 parent
->children
= children
;
733 * anjuta_token_prepend_items:
734 * @list: a #AnjutaToken object used as list.
735 * @item: a #AnjutaToken object.
737 * Insert all tokens in item as item of the given list.
739 * Return value: The first token append.
742 anjuta_token_prepend_items (AnjutaToken
*list
, AnjutaToken
*item
)
745 AnjutaToken
*old_group
;
746 AnjutaToken
*old_parent
;
748 g_return_val_if_fail (list
!= NULL
, NULL
);
749 g_return_val_if_fail (item
!= NULL
, NULL
);
751 old_group
= item
->group
;
752 old_parent
= item
->parent
;
754 /* Update each token */
757 if (token
->parent
== old_parent
) token
->parent
= list
->parent
;
758 if (token
->group
== old_group
) token
->group
= list
;
760 if (token
->children
!= NULL
)
762 token
= token
->children
;
764 else if (token
->next
!= NULL
)
770 while (token
->parent
!= list
->parent
)
772 token
= token
->parent
;
773 if (token
->next
!= NULL
) break;
775 if (token
->next
== NULL
) break;
780 token
->next
= list
->next
;
781 if (token
->next
) token
->next
->prev
= token
;
786 if (list
->last
== NULL
)
788 while (token
->group
!= list
) token
= token
->group
;
796 * anjuta_token_insert_after:
797 * @sibling: a #AnjutaToken object.
798 * @item: a #AnjutaToken object.
800 * Insert all tokens after sibling.
802 * Return value: The first token inserted.
805 anjuta_token_insert_after (AnjutaToken
*sibling
, AnjutaToken
*list
)
809 AnjutaToken
*old_group
;
810 AnjutaToken
*old_parent
;
812 g_return_val_if_fail (sibling
!= NULL
, NULL
);
813 g_return_val_if_fail (list
!= NULL
, NULL
);
815 old_group
= list
->group
;
816 old_parent
= list
->parent
;
818 /* Update each token */
821 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
822 if (token
->group
== old_group
) token
->group
= sibling
->group
;
824 if (token
->children
!= NULL
)
826 token
= token
->children
;
828 else if (token
->next
!= NULL
)
834 while (token
->parent
!= sibling
->parent
)
836 token
= token
->parent
;
837 if (token
->next
!= NULL
) break;
839 if (token
->next
== NULL
) break;
844 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
846 token
->next
= last
->next
;
847 if (token
->next
) token
->next
->prev
= token
;
852 if ((sibling
->group
!= NULL
) && (sibling
->group
->last
== sibling
))
854 while (token
->group
!= sibling
->group
) token
= token
->group
;
855 sibling
->group
->last
= token
;
862 * anjuta_token_insert_before:
863 * @sibling: a #AnjutaToken object.
864 * @item: a #AnjutaToken object.
866 * Insert all tokens before sibling.
868 * Return value: The first token inserted.
871 anjuta_token_insert_before (AnjutaToken
*sibling
, AnjutaToken
*list
)
875 AnjutaToken
*old_group
;
876 AnjutaToken
*old_parent
;
878 g_return_val_if_fail (sibling
!= NULL
, NULL
);
879 g_return_val_if_fail (list
!= NULL
, NULL
);
881 old_group
= list
->group
;
882 old_parent
= list
->parent
;
884 /* Update each token */
887 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
888 if (token
->group
== old_group
) token
->group
= sibling
->group
;
890 if (token
->children
!= NULL
)
892 token
= token
->children
;
894 else if (token
->next
!= NULL
)
900 while (token
->parent
!= sibling
->parent
)
902 token
= token
->parent
;
903 if (token
->next
!= NULL
) break;
905 if (token
->next
== NULL
) break;
910 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
912 token
->next
= sibling
;
913 list
->prev
= sibling
->prev
;
914 sibling
->prev
= token
;
916 if (list
->prev
) list
->prev
->next
= list
;
918 if ((list
->parent
!= NULL
) && (list
->parent
->children
== sibling
)) list
->parent
->children
= list
;
924 * anjuta_token_delete_parent:
925 * @parent: a #AnjutaToken object used as parent.
927 * Delete only the parent token.
929 * Return value: the first children
932 anjuta_token_delete_parent (AnjutaToken
*parent
)
936 g_return_val_if_fail (parent
!= NULL
, NULL
);
938 if (parent
->children
== NULL
) return NULL
;
940 /* Update each token */
941 for (token
= parent
->children
;;)
943 if (token
->parent
== parent
) token
->parent
= parent
->parent
;
945 if (token
->children
!= NULL
)
947 token
= token
->children
;
949 else if (token
->next
!= NULL
)
955 while (token
->parent
!= parent
->parent
)
957 token
= token
->parent
;
958 if (token
->next
!= NULL
) break;
960 if (token
->next
== NULL
) break;
965 token
->next
= parent
->next
;
966 if (token
->next
) token
->next
->prev
= token
;
968 parent
->next
= parent
->children
;
969 parent
->children
->prev
= parent
;
970 parent
->children
= NULL
;
972 return anjuta_token_free (parent
);
976 *---------------------------------------------------------------------------*/
979 anjuta_token_merge (AnjutaToken
*first
, AnjutaToken
*end
)
981 if ((first
== end
) || (end
== NULL
)) return first
;
983 if (first
->parent
== NULL
)
985 first
->parent
= end
->parent
;
987 if (first
->next
== NULL
)
989 anjuta_token_insert_before (end
, first
);
998 anjuta_token_merge_own_children (AnjutaToken
*group
)
1001 AnjutaToken
*next
= NULL
;
1003 if (group
->last
!= NULL
) return group
;
1005 if (group
->last
->last
!= NULL
) group
->last
= group
->last
->last
;
1007 for (token
= anjuta_token_next (group
); (token
!= NULL
) && (token
!= group
->last
); token
= anjuta_token_next (token
))
1011 if (token
->last
!= NULL
)
1014 //token->last = NULL;
1016 token
->group
= group
;
1018 else if (next
== token
)
1028 anjuta_token_merge_children (AnjutaToken
*first
, AnjutaToken
*end
)
1030 if ((first
== end
) || (end
== NULL
))
1035 if (first
->parent
== NULL
)
1037 first
->parent
= end
->parent
;
1039 if (first
->next
== NULL
)
1041 anjuta_token_insert_before (end
, first
);
1043 anjuta_token_unlink_token (end
);
1044 if (end
->last
!= NULL
)
1046 first
->last
= end
->last
;
1047 end
->last
->group
= first
;
1050 anjuta_token_free (end
);
1056 * anjuta_token_merge_previous:
1057 * @list: a #AnjutaToken object representing a list
1058 * @first: a #AnjutaToken object for the new beginning of the list
1060 * If the list token is not already linked with first, it is inserted
1061 * just before first.
1062 * If the list token is already linked, it must be in the same list after
1063 * first token. It it possible to have several tokens beweent list and
1066 * Return value: the new list
1069 anjuta_token_merge_previous (AnjutaToken
*list
, AnjutaToken
*first
)
1073 if ((first
== NULL
) || (list
== first
)) return list
;
1075 /* Change group of all tokens from end to first
1076 * if the list is already linked */
1077 if ((list
->prev
!= NULL
) || (list
->parent
!= NULL
))
1079 for (token
= first
; token
!= NULL
; token
= anjuta_token_next_item (token
))
1081 token
->group
= list
;
1085 token
= anjuta_token_next (list
);
1086 anjuta_token_unlink_token (list
);
1087 anjuta_token_insert_token_before (first
, list
);
1092 AnjutaToken
*anjuta_token_split (AnjutaToken
*token
, guint size
)
1094 if (token
->data
.length
> size
)
1098 copy
= anjuta_token_copy (token
);
1099 anjuta_token_insert_before (token
, copy
);
1101 copy
->data
.length
= size
;
1102 if (token
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1104 token
->data
.pos
+= size
;
1105 token
->data
.length
-= size
;
1109 memcpy(token
->data
.pos
, token
->data
.pos
+ size
, token
->data
.length
- size
);
1120 AnjutaToken
*anjuta_token_cut (AnjutaToken
*token
, guint pos
, guint size
)
1124 copy
= anjuta_token_copy (token
);
1126 if (pos
>= token
->data
.length
)
1128 if (!(copy
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1130 g_free (copy
->data
.pos
);
1132 copy
->data
.pos
= NULL
;
1133 copy
->data
.length
= 0;
1135 if ((pos
+ size
) > token
->data
.length
)
1137 size
= token
->data
.length
- pos
;
1140 if (copy
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1142 copy
->data
.pos
+= pos
;
1146 memcpy(copy
->data
.pos
, copy
->data
.pos
+ pos
, size
);
1148 copy
->data
.length
= size
;
1154 *---------------------------------------------------------------------------*/
1157 anjuta_token_foreach_content (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1161 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent and
1162 * are not taken into account */
1163 AnjutaToken
*last_token
;
1164 gboolean expand
= TRUE
;
1167 last_token
= token
->last
== NULL
? token
: token
->last
;
1168 while (token
!= NULL
)
1170 if (expand
&& (token
->children
!= NULL
))
1172 /* Check if we have found the last token */
1173 if (token
== last_token
)
1175 /* Find last token */
1176 if (token
->last
== NULL
)
1180 /* Last token still include additional tokens */
1181 last_token
= token
->last
;
1184 /* Enumerate children */
1185 token
= token
->children
;
1189 if (token
->children
== NULL
)
1191 /* Take into account only the content of token having no children */
1192 if (last_parent
== NULL
)
1194 /* Take into account only the content of group having no children */
1195 func (token
, user_data
);
1199 /* Check if we have found the last token */
1200 if (token
== last_token
)
1202 /* Find last token */
1203 if (token
->last
== NULL
)
1207 /* Last token still include additional tokens */
1208 last_token
= token
->last
;
1211 if (token
== last_parent
)
1213 /* Find last parent */
1214 if (token
->last
== NULL
)
1216 /* Found complete group having children */
1221 /* Parent group has additional token */
1222 last_parent
= token
->last
;
1226 if (token
->next
!= NULL
)
1228 /* Get next sibling */
1229 token
= token
->next
;
1235 token
= token
->parent
;
1236 if (token
!= NULL
) last_parent
= token
->last
;
1247 anjuta_token_foreach_post_order (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1251 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent */
1252 AnjutaToken
*last_token
;
1253 AnjutaToken buffer
; /* Temporary token allowing func to destroy
1254 * the current token */
1255 gboolean expand
= TRUE
;
1258 last_token
= token
->last
== NULL
? token
: token
->last
;
1259 while (token
!= NULL
)
1261 if (expand
&& (token
->children
!= NULL
))
1263 /* Check if we have found the last token */
1264 if (token
== last_token
)
1266 /* Find last token */
1267 if (token
->last
== NULL
)
1271 /* Last token still include additional tokens */
1272 last_token
= token
->last
;
1275 /* Enumerate children */
1276 token
= token
->children
;
1280 /* Save token data in case it is destroyed */
1281 memcpy (&buffer
, token
, sizeof (buffer
));
1282 /* Take into account all token */
1283 func (token
, user_data
);
1285 /* Check if we have found the last token */
1286 if (token
== last_token
)
1288 /* Find last token */
1289 if (buffer
.last
== NULL
)
1294 /* Last token still include additional tokens */
1295 last_token
= buffer
.last
;
1298 if (token
== last_parent
)
1300 /* Find last parent */
1301 if (buffer
.last
== NULL
)
1303 /* Found complete group having children */
1308 /* Parent group has additional token */
1309 last_parent
= buffer
.last
;
1313 if (buffer
.next
!= NULL
)
1315 /* Get next sibling */
1316 token
= buffer
.next
;
1322 token
= buffer
.parent
;
1323 if (token
!= NULL
) last_parent
= token
->last
;
1329 while ((token
!= NULL
) && (token
->next
== NULL
))
1331 token
= token
->parent
;
1334 if (token
!= NULL
) token
= token
->next
;
1341 *---------------------------------------------------------------------------*/
1344 evaluate_raw_token (AnjutaToken
*token
, gpointer user_data
)
1346 GString
*value
= (GString
*)user_data
;
1348 anjuta_token_evaluate_token (token
, value
, TRUE
);
1352 evaluate_token (AnjutaToken
*token
, gpointer user_data
)
1354 GString
*value
= (GString
*)user_data
;
1356 anjuta_token_evaluate_token (token
, value
, FALSE
);
1361 anjuta_token_evaluate (AnjutaToken
*token
)
1363 GString
*value
= g_string_new (NULL
);
1365 anjuta_token_foreach_content (token
, evaluate_token
, value
);
1367 /* Return NULL and free data for an empty string */
1368 return g_string_free (value
, *(value
->str
) == '\0');
1372 anjuta_token_is_empty (AnjutaToken
*token
)
1374 return (token
== NULL
) || ((token
->data
.length
== 0) && (token
->last
== NULL
) && (token
->children
== NULL
));
1379 *---------------------------------------------------------------------------*/
1382 anjuta_token_compare (AnjutaToken
*toka
, AnjutaToken
*tokb
)
1384 if (tokb
->data
.type
)
1386 if (tokb
->data
.type
!= toka
->data
.type
) return FALSE
;
1389 if (tokb
->data
.type
!= ANJUTA_TOKEN_NONE
)
1391 if (tokb
->data
.length
!= 0)
1393 if (toka
->data
.length
!= tokb
->data
.length
) return FALSE
;
1395 if ((toka
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
) && (tokb
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
))
1397 if (g_ascii_strncasecmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1401 if (strncmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1406 if (tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
)
1408 if ((toka
->data
.flags
& tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
) == 0)
1416 anjuta_token_dump (AnjutaToken
*token
)
1418 if (token
== NULL
) return;
1420 anjuta_token_dump_child (token
, 0, 0);
1424 anjuta_token_dump_link (AnjutaToken
*token
)
1426 AnjutaToken
*last
= token
;
1428 while (last
->last
!= NULL
) last
= last
->last
;
1430 for (; token
!= last
; token
= anjuta_token_next (token
))
1432 anjuta_token_show (token
, 0, 0);
1437 anjuta_token_check (AnjutaToken
*token
)
1439 if ((token
->children
!= NULL
) && (token
->last
!= NULL
))
1441 anjuta_token_show (token
, 0, 0);
1442 fprintf(stderr
, "Error: Previous token has both non NULL children and last\n");
1447 if (token
->children
!= NULL
)
1451 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
1453 if (!anjuta_token_check_child (child
, token
)) return FALSE
;
1457 if (token
->last
!= NULL
)
1461 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (child
))
1463 if (!anjuta_token_check (child
)) return FALSE
;
1464 if (child
== token
->last
) break;
1471 /* Constructor & Destructor
1472 *---------------------------------------------------------------------------*/
1474 AnjutaToken
*anjuta_token_new_string (AnjutaTokenType type
, const gchar
*value
)
1480 token
= anjuta_token_new_static (type
, NULL
);
1484 token
= g_slice_new0 (AnjutaToken
);
1485 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1486 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1487 token
->data
.pos
= g_strdup (value
);
1488 token
->data
.length
= strlen (value
);
1495 anjuta_token_new_with_string (AnjutaTokenType type
, gchar
*value
, gsize length
)
1501 token
= anjuta_token_new_static (type
, NULL
);
1505 token
= g_slice_new0 (AnjutaToken
);
1506 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1507 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1508 token
->data
.pos
= value
;
1509 token
->data
.length
= length
;
1516 anjuta_token_new_fragment (gint type
, const gchar
*pos
, gsize length
)
1520 token
= g_slice_new0 (AnjutaToken
);
1521 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1522 token
->data
.flags
= (type
& ANJUTA_TOKEN_FLAGS
) | ANJUTA_TOKEN_STATIC
;
1523 token
->data
.pos
= (gchar
*)pos
;
1524 token
->data
.length
= length
;
1529 AnjutaToken
*anjuta_token_new_static (AnjutaTokenType type
, const char *value
)
1531 return anjuta_token_new_fragment (type
, value
, value
== NULL
? 0 : strlen (value
));
1535 anjuta_token_free_children (AnjutaToken
*token
)
1540 if (token
== NULL
) return NULL
;
1542 for (child
= token
->children
; child
!= NULL
; child
= token
->children
)
1544 anjuta_token_free (child
);
1546 token
->children
= NULL
;
1548 if (token
->last
!= NULL
)
1551 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (token
))
1553 anjuta_token_free (child
);
1554 if (child
== last
) break;
1563 free_token (AnjutaToken
*token
, gpointer user_data
)
1565 anjuta_token_unlink_token (token
);
1566 if ((token
->data
.pos
!= NULL
) && !(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1568 g_free (token
->data
.pos
);
1570 g_slice_free (AnjutaToken
, token
);
1575 anjuta_token_free (AnjutaToken
*token
)
1579 if (token
== NULL
) return NULL
;
1581 next
= anjuta_token_foreach_post_order (token
, free_token
, NULL
);