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 AnjutaTokenType type
;
126 AnjutaToken
*children
;
127 AnjutaTokenData data
;
131 *---------------------------------------------------------------------------*/
134 *---------------------------------------------------------------------------*/
137 anjuta_token_next_child (AnjutaToken
*child
, AnjutaToken
**last
)
139 if (child
== NULL
) return child
;
141 if (child
->children
!= NULL
)
143 child
= child
->children
;
149 if ((*last
== NULL
) || (child
== *last
))
151 if (child
->last
== NULL
)
158 if (child
->next
!= NULL
)
163 child
= child
->parent
;
164 if (child
== NULL
) break;
172 anjuta_token_next_after_children (AnjutaToken
*token
)
174 while (token
->last
!= NULL
) token
= token
->last
;
175 while (token
->next
== NULL
)
177 token
= token
->parent
;
178 if (token
== NULL
) return NULL
;
179 while (token
->last
!= NULL
) token
= token
->last
;
186 anjuta_token_copy (AnjutaToken
*token
)
188 AnjutaToken
*copy
= NULL
;
192 copy
= g_slice_new0 (AnjutaToken
);
193 copy
->data
.type
= token
->data
.type
;
194 copy
->data
.flags
= token
->data
.flags
;
195 if ((copy
->data
.flags
& ANJUTA_TOKEN_STATIC
) || (token
->data
.pos
== NULL
))
197 copy
->data
.pos
= token
->data
.pos
;
201 copy
->data
.pos
= g_strdup (token
->data
.pos
);
203 copy
->data
.length
= token
->data
.length
;
210 * anjuta_token_unlink_token:
211 * @token: a #AnjutaToken object.
213 * Unlink a single token, not the complete item, from the token tree.
215 * Return value: the removed token tree
218 anjuta_token_unlink_token (AnjutaToken
*token
)
221 if (token
->prev
!= NULL
)
223 token
->prev
->next
= token
->next
;
225 else if ((token
->parent
!= NULL
) && (token
->parent
->children
== token
))
227 token
->parent
->children
= token
->next
;
229 token
->parent
= NULL
;
231 if ((token
->group
!= NULL
) && (token
->group
->last
== token
))
235 for (prev
= token
->prev
; prev
!= NULL
; prev
= prev
->prev
)
237 if (prev
->group
== token
->group
)
239 /* Find previous token in the same group */
240 token
->group
->last
= prev
;
243 else if (prev
== token
->group
)
245 /* No more token in group */
246 token
->group
->last
= NULL
;
252 if (token
->next
!= NULL
)
254 token
->next
->prev
= token
->prev
;
263 * anjuta_token_insert_token_before:
264 * @sibling: a #AnjutaToken object.
265 * @token: a #AnjutaToken object.
267 * Insert token before sibling.
269 * Return value: inserted token
272 anjuta_token_insert_token_before (AnjutaToken
*sibling
, AnjutaToken
*token
)
274 token
->prev
= sibling
->prev
;
275 token
->next
= sibling
;
277 if (token
->prev
!= NULL
)
279 token
->prev
->next
= token
;
281 sibling
->prev
= token
;
283 if ((sibling
->parent
!= NULL
) && (sibling
->parent
->children
== sibling
))
285 sibling
->parent
->children
= token
;
287 token
->parent
= sibling
->parent
;
293 anjuta_token_evaluate_token (AnjutaToken
*token
, GString
*value
, gboolean raw
)
295 if ((token
!= NULL
) && (token
->data
.length
!= 0))
299 switch (anjuta_token_get_type (token
))
301 case ANJUTA_TOKEN_COMMENT
:
302 case ANJUTA_TOKEN_OPEN_QUOTE
:
303 case ANJUTA_TOKEN_CLOSE_QUOTE
:
304 case ANJUTA_TOKEN_ESCAPE
:
305 case ANJUTA_TOKEN_MACRO
:
306 case ANJUTA_TOKEN_EOV
:
312 g_string_append_len (value
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
317 anjuta_token_show (AnjutaToken
*token
, gint indent
, gchar parent
)
319 static gchar type
[] = "\0";
324 fprintf (stderr
, "%*s%s %p", indent
, "", type
, token
);
325 fprintf (stderr
, ": %d ",
326 anjuta_token_get_type (token
));
327 string
= anjuta_token_get_string (token
);
328 length
= anjuta_token_get_length (token
);
331 /* Value doesn't contain a newline */
332 fprintf (stderr
, "(%lu)", length
);
336 const gchar
*newline
;
338 newline
= g_strrstr_len (string
, length
, "\n");
341 /* Value doesn't contain a newline */
342 fprintf (stderr
, "\"%.*s\"",
348 /* Value contains a newline, take care of indentation */
350 fprintf (stderr
, "\"%.*s",
355 length
-= newline
- string
;
358 newline
= g_strrstr_len (string
, length
, "\n");
359 if (newline
== NULL
) break;
362 fprintf (stderr
, "%*s %.*s",
367 fprintf (stderr
, "%*s %.*s\"",
373 fprintf (stderr
, " %p/%p (%p/%p) %s\n",
374 token
->last
, token
->children
,
375 token
->group
, token
->parent
,
376 anjuta_token_get_flags (token
) & ANJUTA_TOKEN_REMOVED
? " (removed)" : "");
380 anjuta_token_dump_child (AnjutaToken
*token
, gint indent
, gchar type
)
385 anjuta_token_show (token
, indent
, type
);
389 if (token
->last
!= NULL
)
394 if (child
== NULL
) break;
395 last
= anjuta_token_dump_child (child
, indent
, '+');
397 while (child
!= token
->last
);
400 if (token
->children
!= NULL
)
402 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
404 child
= anjuta_token_dump_child (child
, indent
, '*');
412 anjuta_token_check_child (AnjutaToken
*token
, AnjutaToken
*parent
)
414 if (token
->parent
!= parent
)
416 anjuta_token_show (token
, 0, 0);
417 fprintf(stderr
, "Error: Children has %p as parent instead of %p\n", token
->parent
, parent
);
421 return anjuta_token_check (token
);
424 /* Get and set functions
425 *---------------------------------------------------------------------------*/
428 anjuta_token_set_type (AnjutaToken
*token
, gint type
)
430 token
->data
.type
= type
;
434 anjuta_token_get_type (AnjutaToken
*token
)
436 return token
->data
.type
;
440 anjuta_token_set_flags (AnjutaToken
*token
, gint flags
)
443 AnjutaToken
*last
= token
->last
;
445 for (child
= token
; child
!= NULL
; child
= anjuta_token_next_child (child
, &last
))
447 child
->data
.flags
|= flags
;
452 anjuta_token_clear_flags (AnjutaToken
*token
, gint flags
)
454 token
->data
.flags
&= ~flags
;
458 anjuta_token_get_flags (AnjutaToken
*token
)
460 return token
->data
.flags
;
464 anjuta_token_set_string (AnjutaToken
*token
, const gchar
*data
, gsize length
)
466 if (!(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
468 g_free (token
->data
.pos
);
469 token
->data
.flags
|= ANJUTA_TOKEN_STATIC
;
471 token
->data
.pos
= (gchar
*)data
;
472 token
->data
.length
= length
;
476 anjuta_token_get_string (AnjutaToken
*token
)
478 return token
->data
.pos
;
482 anjuta_token_set_length (AnjutaToken
*token
, gsize length
)
484 token
->data
.length
= length
;
488 anjuta_token_get_length (AnjutaToken
*token
)
490 return token
->data
.length
;
493 /* Basic move functions
494 *---------------------------------------------------------------------------*/
497 anjuta_token_next (AnjutaToken
*token
)
499 if (token
->children
!= NULL
)
501 return token
->children
;
503 else if (token
->next
!= NULL
)
507 else if (token
->parent
!= NULL
)
509 return anjuta_token_next_after_children (token
->parent
);
518 anjuta_token_previous (AnjutaToken
*token
)
520 if (token
->prev
!= NULL
)
526 return token
->parent
;
531 anjuta_token_last (AnjutaToken
*token
)
535 for (last
= token
; last
->last
!= NULL
; last
= last
->last
);
536 if (last
->children
!= NULL
)
538 for (last
= last
->children
; last
->next
!= NULL
; last
= last
->next
);
545 anjuta_token_parent (AnjutaToken
*token
)
547 return token
->parent
;
551 anjuta_token_list (AnjutaToken
*token
)
556 /* Item move functions
557 *---------------------------------------------------------------------------*/
560 anjuta_token_last_item (AnjutaToken
*list
)
566 anjuta_token_first_item (AnjutaToken
*list
)
568 AnjutaToken
*first
= NULL
;
572 if (list
->children
!= NULL
)
574 first
= list
->children
;
576 else if (list
->last
!= NULL
)
586 anjuta_token_next_item (AnjutaToken
*item
)
595 if ((item
->group
== NULL
) || (item
->group
->last
!= item
))
598 for (last
= item
; last
->last
!= NULL
; last
= last
->last
);
599 next
= anjuta_token_next (last
);
600 if ((next
!= NULL
) && (next
->group
!= item
->group
)) next
= NULL
;
604 /* Loop if the current item has been deleted */
605 while ((next
!= NULL
) && (anjuta_token_get_flags (next
) & ANJUTA_TOKEN_REMOVED
));
612 anjuta_token_previous_item (AnjutaToken
*item
)
614 AnjutaToken
*prev
= NULL
;
621 for (prev
= item
->prev
; (prev
!= NULL
) && (prev
->group
!= item
->group
); prev
= prev
->group
);
624 /* Loop if the current item has been deleted */
625 while ((prev
!= NULL
) && (anjuta_token_get_flags (prev
) & ANJUTA_TOKEN_REMOVED
));
631 /* Add/Insert/Remove tokens
632 *---------------------------------------------------------------------------*/
635 * anjuta_token_append_child:
636 * @parent: a #AnjutaToken object used as parent.
637 * @children: a #AnjutaToken object.
639 * Insert all tokens in children as the last children of the given parent.
641 * Return value: The first token append.
644 anjuta_token_append_child (AnjutaToken
*parent
, AnjutaToken
*children
)
648 AnjutaToken
*old_group
;
649 AnjutaToken
*old_parent
;
651 g_return_val_if_fail (parent
!= NULL
, NULL
);
652 g_return_val_if_fail (children
!= NULL
, NULL
);
654 old_group
= children
->group
;
655 old_parent
= children
->parent
;
657 if (parent
->children
== NULL
)
659 parent
->children
= children
;
661 children
->prev
= NULL
;
665 /* Find last children */
666 for (last
= parent
->children
; last
->next
!= NULL
;)
668 if ((last
->last
!= NULL
) && (last
->last
->parent
== last
->parent
))
678 last
->next
= children
;
679 children
->prev
= last
;
682 /* Update each token */
683 for (token
= children
;;)
685 if (token
->parent
== old_parent
) token
->parent
= parent
;
686 if (token
->group
== old_group
) token
->group
= parent
->group
;
688 if (token
->children
!= NULL
)
690 token
= token
->children
;
692 else if (token
->next
!= NULL
)
698 while (token
->parent
!= parent
)
700 token
= token
->parent
;
701 if (token
->next
!= NULL
) break;
703 if (token
->next
== NULL
) break;
712 * anjuta_token_prepend_child:
713 * @parent: a #AnjutaToken object used as parent.
714 * @children: a #AnjutaToken object.
716 * Insert all tokens in children as the first children of the given parent.
718 * Return value: The first token append.
721 anjuta_token_prepend_child (AnjutaToken
*parent
, AnjutaToken
*children
)
724 AnjutaToken
*last
= NULL
;
726 g_return_val_if_fail (parent
!= NULL
, NULL
);
727 g_return_val_if_fail (children
!= NULL
, NULL
);
729 /* Update each token */
730 for (child
= children
;;)
734 if (child
->parent
== children
->parent
) child
->parent
= parent
;
735 if (child
->group
== children
->group
) child
->group
= parent
->group
;
737 next
= anjuta_token_next_child (child
, &last
);
738 if (next
== NULL
) break;
742 child
->next
= parent
->children
;
743 if (child
->next
) child
->next
->prev
= child
;
744 parent
->children
= children
;
750 * anjuta_token_prepend_items:
751 * @list: a #AnjutaToken object used as list.
752 * @item: a #AnjutaToken object.
754 * Insert all tokens in item as item of the given list.
756 * Return value: The first token append.
759 anjuta_token_prepend_items (AnjutaToken
*list
, AnjutaToken
*item
)
762 AnjutaToken
*old_group
;
763 AnjutaToken
*old_parent
;
765 g_return_val_if_fail (list
!= NULL
, NULL
);
766 g_return_val_if_fail (item
!= NULL
, NULL
);
768 old_group
= item
->group
;
769 old_parent
= item
->parent
;
771 /* Update each token */
774 if (token
->parent
== old_parent
) token
->parent
= list
->parent
;
775 if (token
->group
== old_group
) token
->group
= list
;
777 if (token
->children
!= NULL
)
779 token
= token
->children
;
781 else if (token
->next
!= NULL
)
787 while (token
->parent
!= list
->parent
)
789 token
= token
->parent
;
790 if (token
->next
!= NULL
) break;
792 if (token
->next
== NULL
) break;
797 token
->next
= list
->next
;
798 if (token
->next
) token
->next
->prev
= token
;
803 if (list
->last
== NULL
)
805 while (token
->group
!= list
) token
= token
->group
;
813 * anjuta_token_insert_after:
814 * @sibling: a #AnjutaToken object.
815 * @list: a #AnjutaToken object.
817 * Insert all tokens after sibling.
819 * Return value: The first token inserted.
822 anjuta_token_insert_after (AnjutaToken
*sibling
, AnjutaToken
*list
)
826 AnjutaToken
*old_group
;
827 AnjutaToken
*old_parent
;
829 g_return_val_if_fail (sibling
!= NULL
, NULL
);
830 g_return_val_if_fail (list
!= NULL
, NULL
);
832 old_group
= list
->group
;
833 old_parent
= list
->parent
;
835 /* Update each token */
838 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
839 if (token
->group
== old_group
) token
->group
= sibling
->group
;
841 if (token
->children
!= NULL
)
843 token
= token
->children
;
845 else if (token
->next
!= NULL
)
851 while (token
->parent
!= sibling
->parent
)
853 token
= token
->parent
;
854 if (token
->next
!= NULL
) break;
856 if (token
->next
== NULL
) break;
861 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
863 token
->next
= last
->next
;
864 if (token
->next
) token
->next
->prev
= token
;
869 if ((sibling
->group
!= NULL
) && (sibling
->group
->last
== sibling
))
871 while (token
->group
!= sibling
->group
) token
= token
->group
;
872 sibling
->group
->last
= token
;
879 * anjuta_token_insert_before:
880 * @sibling: a #AnjutaToken object.
881 * @list: a #AnjutaToken object.
883 * Insert all tokens before sibling.
885 * Return value: The first token inserted.
888 anjuta_token_insert_before (AnjutaToken
*sibling
, AnjutaToken
*list
)
892 AnjutaToken
*old_group
;
893 AnjutaToken
*old_parent
;
895 g_return_val_if_fail (sibling
!= NULL
, NULL
);
896 g_return_val_if_fail (list
!= NULL
, NULL
);
898 old_group
= list
->group
;
899 old_parent
= list
->parent
;
901 /* Update each token */
904 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
905 if (token
->group
== old_group
) token
->group
= sibling
->group
;
907 if (token
->children
!= NULL
)
909 token
= token
->children
;
911 else if (token
->next
!= NULL
)
917 while (token
->parent
!= sibling
->parent
)
919 token
= token
->parent
;
920 if (token
->next
!= NULL
) break;
922 if (token
->next
== NULL
) break;
927 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
929 token
->next
= sibling
;
930 list
->prev
= sibling
->prev
;
931 sibling
->prev
= token
;
933 if (list
->prev
) list
->prev
->next
= list
;
935 if ((list
->parent
!= NULL
) && (list
->parent
->children
== sibling
)) list
->parent
->children
= list
;
941 * anjuta_token_delete_parent:
942 * @parent: a #AnjutaToken object used as parent.
944 * Delete only the parent token.
946 * Return value: the first children
949 anjuta_token_delete_parent (AnjutaToken
*parent
)
953 g_return_val_if_fail (parent
!= NULL
, NULL
);
955 if (parent
->children
== NULL
) return NULL
;
957 /* Update each token */
958 for (token
= parent
->children
;;)
960 if (token
->parent
== parent
) token
->parent
= parent
->parent
;
962 if (token
->children
!= NULL
)
964 token
= token
->children
;
966 else if (token
->next
!= NULL
)
972 while (token
->parent
!= parent
->parent
)
974 token
= token
->parent
;
975 if (token
->next
!= NULL
) break;
977 if (token
->next
== NULL
) break;
982 token
->next
= parent
->next
;
983 if (token
->next
) token
->next
->prev
= token
;
985 parent
->next
= parent
->children
;
986 parent
->children
->prev
= parent
;
987 parent
->children
= NULL
;
989 return anjuta_token_free (parent
);
993 *---------------------------------------------------------------------------*/
995 /* anjuta_token_merge can be used with first or end being a floating token and
996 * on already grouped tokens to change the group organisation */
998 anjuta_token_merge (AnjutaToken
*first
, AnjutaToken
*end
)
1002 if ((first
== end
) || (end
== NULL
)) return first
;
1004 /* Insert first or end in the same sequence if it is not already the case */
1005 for (next
= first
; next
!= end
; next
= anjuta_token_next (next
))
1009 if (first
->parent
== NULL
)
1011 anjuta_token_insert_before (end
, first
);
1015 anjuta_token_insert_after (first
, end
);
1021 if ((end
->group
!= NULL
) && (end
->group
!= first
) && (end
->group
->last
== end
)) end
->group
->last
= first
;
1028 anjuta_token_merge_own_children (AnjutaToken
*group
)
1031 AnjutaToken
*next
= NULL
;
1033 if (group
->last
!= NULL
) return group
;
1035 if (group
->last
->last
!= NULL
) group
->last
= group
->last
->last
;
1037 for (token
= anjuta_token_next (group
); (token
!= NULL
) && (token
!= group
->last
); token
= anjuta_token_next (token
))
1041 if (token
->last
!= NULL
)
1044 //token->last = NULL;
1046 token
->group
= group
;
1048 else if (next
== token
)
1058 anjuta_token_merge_children (AnjutaToken
*first
, AnjutaToken
*end
)
1064 if ((first
== end
) || (end
== NULL
))
1069 if (first
->parent
== NULL
)
1071 first
->parent
= end
->parent
;
1073 if (first
->next
== NULL
)
1075 anjuta_token_insert_before (end
, first
);
1077 anjuta_token_unlink_token (end
);
1078 if (end
->last
!= NULL
)
1082 first
->last
= end
->last
;
1083 for (child
= anjuta_token_next (first
); child
!= first
->last
; child
= anjuta_token_next (child
))
1085 if (child
->group
== end
) child
->group
= first
;
1087 first
->last
->group
= first
;
1090 anjuta_token_free (end
);
1096 * anjuta_token_merge_previous:
1097 * @list: a #AnjutaToken object representing a list
1098 * @first: a #AnjutaToken object for the new beginning of the list
1100 * If the list token is not already linked with first, it is inserted
1101 * just before first.
1102 * If the list token is already linked, it must be in the same list after
1103 * first token. It it possible to have several tokens beweent list and
1106 * Return value: the new list
1109 anjuta_token_merge_previous (AnjutaToken
*list
, AnjutaToken
*first
)
1113 if ((first
== NULL
) || (list
== first
)) return list
;
1115 /* Change group of all tokens from end to first
1116 * if the list is already linked */
1117 if ((list
->prev
!= NULL
) || (list
->parent
!= NULL
))
1119 for (token
= first
; token
!= NULL
; token
= anjuta_token_next_item (token
))
1121 token
->group
= list
;
1125 token
= anjuta_token_next (list
);
1126 anjuta_token_unlink_token (list
);
1127 anjuta_token_insert_token_before (first
, list
);
1132 AnjutaToken
*anjuta_token_split (AnjutaToken
*token
, guint size
)
1134 if (token
->data
.length
> size
)
1138 copy
= anjuta_token_copy (token
);
1139 anjuta_token_insert_before (token
, copy
);
1141 copy
->data
.length
= size
;
1142 if (token
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1144 token
->data
.pos
+= size
;
1145 token
->data
.length
-= size
;
1149 memcpy(token
->data
.pos
, token
->data
.pos
+ size
, token
->data
.length
- size
);
1161 anjuta_token_cut (AnjutaToken
*token
, guint pos
, guint size
)
1165 copy
= anjuta_token_copy (token
);
1167 if (pos
>= token
->data
.length
)
1169 if (!(copy
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1171 g_free (copy
->data
.pos
);
1173 copy
->data
.pos
= NULL
;
1174 copy
->data
.length
= 0;
1176 if ((pos
+ size
) > token
->data
.length
)
1178 size
= token
->data
.length
- pos
;
1181 if (copy
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1183 copy
->data
.pos
+= pos
;
1187 memmove(copy
->data
.pos
, copy
->data
.pos
+ pos
, size
);
1189 copy
->data
.length
= size
;
1195 concat_token (AnjutaToken
*token
, gpointer user_data
)
1197 AnjutaToken
*first
= (AnjutaToken
*)user_data
;
1199 if (anjuta_token_get_length (token
) > 0)
1201 if (anjuta_token_get_string (first
) == NULL
)
1203 anjuta_token_set_string (first
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
1205 else if ((first
!= NULL
) && ((anjuta_token_get_string(first
) + anjuta_token_get_length (first
)) == anjuta_token_get_string (token
)))
1207 anjuta_token_set_string (first
, anjuta_token_get_string (first
), anjuta_token_get_length (first
) + anjuta_token_get_length (token
));
1213 new = anjuta_token_new_static_len (ANJUTA_TOKEN_CONTENT
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
1214 anjuta_token_insert_after (first
, new);
1215 anjuta_token_merge (first
, new);
1222 anjuta_token_concat(AnjutaToken
*token
)
1226 new = anjuta_token_new_static (ANJUTA_TOKEN_CONTENT
, NULL
);
1227 anjuta_token_foreach_token (token
, concat_token
, new);
1229 anjuta_token_insert_token_before (token
, new);
1230 anjuta_token_free (token
);
1236 *---------------------------------------------------------------------------*/
1239 anjuta_token_foreach_token (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1243 AnjutaToken
*last_token
;
1246 last_token
= token
->last
== NULL
? token
: token
->last
;
1247 while (token
!= NULL
)
1249 if (child
== 0) func (token
, user_data
);
1251 /* Check if we have found the last token */
1252 if (token
== last_token
)
1254 /* Find last token */
1255 if (token
->last
== NULL
)
1259 /* Last token still include additional tokens */
1260 last_token
= token
->last
;
1263 if (token
->children
!= NULL
)
1265 /* Check children, only for last token */
1267 token
= token
->children
;
1269 else if (token
->next
!= NULL
)
1271 /* Get next sibling */
1272 token
= token
->next
;
1280 token
= token
->parent
;
1281 if (token
== NULL
) break;
1282 if (token
->next
!= NULL
)
1284 token
= token
->next
;
1296 anjuta_token_foreach_content (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1300 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent and
1301 * are not taken into account */
1302 AnjutaToken
*last_token
;
1303 gboolean expand
= TRUE
;
1306 last_token
= token
->last
== NULL
? token
: token
->last
;
1309 if (expand
&& (token
->children
!= NULL
))
1311 /* Children of the last token does not belong to the group */
1312 if (token
== last_token
)
1314 /* Find last token */
1315 if (token
->last
== NULL
)
1319 /* Last token still include additional tokens */
1320 last_token
= token
->last
;
1323 /* Enumerate children */
1324 token
= token
->children
;
1328 if (token
->children
== NULL
)
1330 /* Take into account only the content of token having no children */
1331 if (last_parent
== NULL
)
1333 /* Take into account only the content of group having no children */
1334 func (token
, user_data
);
1338 /* Check if we have found the last token */
1339 if (token
== last_token
)
1341 /* Find last token */
1342 if (token
->last
== NULL
)
1346 /* Last token still include additional tokens */
1347 last_token
= token
->last
;
1350 if (token
== last_parent
)
1352 /* Find last parent */
1353 if (token
->last
== NULL
)
1355 /* Found complete group having children */
1360 /* Parent group has additional token */
1361 last_parent
= token
->last
;
1365 if (token
->next
!= NULL
)
1367 /* Get next sibling */
1368 token
= token
->next
;
1374 token
= token
->parent
;
1376 if (token
== NULL
) break;
1377 last_parent
= token
->last
;
1387 anjuta_token_foreach_container (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1391 AnjutaToken
*parent
; /* If not NULL, token belong to a parent and
1392 * are not taken into account */
1393 AnjutaToken
*last_token
;
1394 gboolean expand
= TRUE
;
1397 last_token
= token
->last
== NULL
? token
: token
->last
;
1400 /* Take into account only the content of parent token */
1401 if (expand
&& (parent
== NULL
))
1403 func (token
, user_data
);
1405 if (expand
&& (token
->children
!= NULL
))
1407 if (parent
== NULL
) parent
= token
;
1408 /* Enumerate children */
1409 token
= token
->children
;
1413 /* Check if we have found the last token */
1414 if (token
== last_token
)
1416 /* Find last token */
1417 if (token
->last
== NULL
)
1421 /* Last token still include additional tokens */
1422 last_token
= token
->last
;
1425 if (token
->next
!= NULL
)
1427 /* Get next sibling */
1428 token
= token
->next
;
1434 token
= token
->parent
;
1435 if (token
== parent
) parent
= NULL
;
1446 anjuta_token_foreach_post_order (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1450 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent */
1451 AnjutaToken
*last_token
;
1452 AnjutaToken buffer
; /* Temporary token allowing func to destroy
1453 * the current token */
1454 gboolean expand
= TRUE
;
1457 last_token
= token
->last
== NULL
? token
: token
->last
;
1458 while (token
!= NULL
)
1460 if (expand
&& (token
->children
!= NULL
))
1462 /* Check if we have found the last token */
1463 if (token
== last_token
)
1465 /* Find last token */
1466 if (token
->last
== NULL
)
1470 /* Last token still include additional tokens */
1471 last_token
= token
->last
;
1474 /* Enumerate children */
1475 token
= token
->children
;
1479 /* Save token data in case it is destroyed */
1480 memcpy (&buffer
, token
, sizeof (buffer
));
1481 /* Take into account all token */
1482 func (token
, user_data
);
1484 /* Check if we have found the last token */
1485 if (token
== last_token
)
1487 /* Find last token */
1488 if (buffer
.last
== NULL
)
1493 /* Last token still include additional tokens */
1494 last_token
= buffer
.last
;
1497 if (token
== last_parent
)
1499 /* Find last parent */
1500 if (buffer
.last
== NULL
)
1502 /* Found complete group having children */
1507 /* Parent group has additional token */
1508 last_parent
= buffer
.last
;
1512 if (buffer
.next
!= NULL
)
1514 /* Get next sibling */
1515 token
= buffer
.next
;
1521 token
= buffer
.parent
;
1522 if (token
!= NULL
) last_parent
= token
->last
;
1528 while ((token
!= NULL
) && (token
->next
== NULL
))
1530 token
= token
->parent
;
1533 if (token
!= NULL
) token
= token
->next
;
1540 *---------------------------------------------------------------------------*/
1543 evaluate_raw_token (AnjutaToken
*token
, gpointer user_data
)
1545 GString
*value
= (GString
*)user_data
;
1547 anjuta_token_evaluate_token (token
, value
, TRUE
);
1551 evaluate_token (AnjutaToken
*token
, gpointer user_data
)
1553 GString
*value
= (GString
*)user_data
;
1555 anjuta_token_evaluate_token (token
, value
, FALSE
);
1560 anjuta_token_evaluate (AnjutaToken
*token
)
1562 GString
*value
= g_string_new (NULL
);
1564 anjuta_token_foreach_content (token
, evaluate_token
, value
);
1566 /* Return NULL and free data for an empty string */
1567 return g_string_free (value
, *(value
->str
) == '\0');
1570 /* Does not evaluate content if token is a variable */
1572 anjuta_token_evaluate_name (AnjutaToken
*token
)
1574 GString
*value
= g_string_new (NULL
);
1576 anjuta_token_foreach_container (token
, evaluate_token
, value
);
1578 /* Return NULL and free data for an empty string */
1579 return g_string_free (value
, *(value
->str
) == '\0');
1583 anjuta_token_is_empty (AnjutaToken
*token
)
1585 return (token
== NULL
) || ((token
->data
.length
== 0) && (token
->last
== NULL
) && (token
->children
== NULL
));
1590 *---------------------------------------------------------------------------*/
1593 anjuta_token_compare (AnjutaToken
*toka
, AnjutaToken
*tokb
)
1595 if (tokb
->data
.type
)
1597 if (tokb
->data
.type
!= toka
->data
.type
) return FALSE
;
1600 if (tokb
->data
.type
!= ANJUTA_TOKEN_NONE
)
1602 if (tokb
->data
.length
!= 0)
1604 if (toka
->data
.length
!= tokb
->data
.length
) return FALSE
;
1606 if ((toka
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
) && (tokb
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
))
1608 if (g_ascii_strncasecmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1612 if (strncmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1617 if (tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
)
1619 if ((toka
->data
.flags
& tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
) == 0)
1627 anjuta_token_dump (AnjutaToken
*token
)
1629 if (token
== NULL
) return;
1631 anjuta_token_dump_child (token
, 0, 0);
1635 anjuta_token_dump_link (AnjutaToken
*token
)
1637 AnjutaToken
*last
= token
;
1639 while (last
->last
!= NULL
) last
= last
->last
;
1641 for (; token
!= last
; token
= anjuta_token_next (token
))
1643 anjuta_token_show (token
, 0, 0);
1648 anjuta_token_check (AnjutaToken
*token
)
1650 if ((token
->children
!= NULL
) && (token
->last
!= NULL
))
1652 anjuta_token_show (token
, 0, 0);
1653 fprintf(stderr
, "Error: Previous token has both non NULL children and last\n");
1658 if (token
->children
!= NULL
)
1662 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
1664 if (!anjuta_token_check_child (child
, token
)) return FALSE
;
1668 if (token
->last
!= NULL
)
1672 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (child
))
1674 if (!anjuta_token_check (child
)) return FALSE
;
1675 if (child
== token
->last
) break;
1682 /* Constructor & Destructor
1683 *---------------------------------------------------------------------------*/
1685 AnjutaToken
*anjuta_token_new_string (AnjutaTokenType type
, const gchar
*value
)
1691 token
= anjuta_token_new_static (type
, NULL
);
1695 token
= g_slice_new0 (AnjutaToken
);
1696 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1697 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1698 token
->data
.pos
= g_strdup (value
);
1699 token
->data
.length
= strlen (value
);
1706 anjuta_token_new_string_len (AnjutaTokenType type
, gchar
*value
, gsize length
)
1712 token
= anjuta_token_new_static (type
, NULL
);
1716 token
= g_slice_new0 (AnjutaToken
);
1717 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1718 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1719 token
->data
.pos
= value
;
1720 token
->data
.length
= length
;
1727 anjuta_token_new_static_len (gint type
, const gchar
*pos
, gsize length
)
1731 token
= g_slice_new0 (AnjutaToken
);
1732 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1733 token
->data
.flags
= (type
& ANJUTA_TOKEN_FLAGS
) | ANJUTA_TOKEN_STATIC
;
1734 token
->data
.pos
= (gchar
*)pos
;
1735 token
->data
.length
= length
;
1740 AnjutaToken
*anjuta_token_new_static (AnjutaTokenType type
, const char *value
)
1742 return anjuta_token_new_static_len (type
, value
, value
== NULL
? 0 : strlen (value
));
1746 anjuta_token_free_children (AnjutaToken
*token
)
1751 if (token
== NULL
) return NULL
;
1753 for (child
= token
->children
; child
!= NULL
; child
= token
->children
)
1755 anjuta_token_free (child
);
1757 token
->children
= NULL
;
1759 if (token
->last
!= NULL
)
1762 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (token
))
1764 anjuta_token_free (child
);
1765 if (child
== last
) break;
1774 free_token (AnjutaToken
*token
, gpointer user_data
)
1776 anjuta_token_unlink_token (token
);
1777 if ((token
->data
.pos
!= NULL
) && !(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1779 g_free (token
->data
.pos
);
1781 g_slice_free (AnjutaToken
, token
);
1786 anjuta_token_free (AnjutaToken
*token
)
1790 if (token
== NULL
) return NULL
;
1792 next
= anjuta_token_foreach_post_order (token
, free_token
, NULL
);