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
;
171 anjuta_token_next_after_children (AnjutaToken
*token
)
173 while (token
->last
!= NULL
) token
= token
->last
;
174 while (token
->next
== NULL
)
176 token
= token
->parent
;
177 if (token
== NULL
) return NULL
;
178 while (token
->last
!= NULL
) token
= token
->last
;
185 anjuta_token_copy (AnjutaToken
*token
)
187 AnjutaToken
*copy
= NULL
;
191 copy
= g_slice_new0 (AnjutaToken
);
192 copy
->data
.type
= token
->data
.type
;
193 copy
->data
.flags
= token
->data
.flags
;
194 if ((copy
->data
.flags
& ANJUTA_TOKEN_STATIC
) || (token
->data
.pos
== NULL
))
196 copy
->data
.pos
= token
->data
.pos
;
200 copy
->data
.pos
= g_strdup (token
->data
.pos
);
202 copy
->data
.length
= token
->data
.length
;
209 * anjuta_token_unlink_token:
210 * @token: a #AnjutaToken object.
212 * Unlink a single token, not the complete item, from the token tree.
214 * Return value: the removed token tree
217 anjuta_token_unlink_token (AnjutaToken
*token
)
220 if (token
->prev
!= NULL
)
222 token
->prev
->next
= token
->next
;
224 else if ((token
->parent
!= NULL
) && (token
->parent
->children
== token
))
226 token
->parent
->children
= token
->next
;
228 token
->parent
= NULL
;
230 if ((token
->group
!= NULL
) && (token
->group
->last
== token
))
234 for (prev
= token
->prev
; prev
!= NULL
; prev
= prev
->prev
)
236 if (prev
->group
== token
->group
)
238 /* Find previous token in the same group */
239 token
->group
->last
= prev
;
242 else if (prev
== token
->group
)
244 /* No more token in group */
245 token
->group
->last
= NULL
;
251 if (token
->next
!= NULL
)
253 token
->next
->prev
= token
->prev
;
262 * anjuta_token_insert_token_before:
263 * @sibling: a #AnjutaToken object.
264 * @token: a #AnjutaToken object.
266 * Insert token before sibling.
268 * Return value: inserted token
271 anjuta_token_insert_token_before (AnjutaToken
*sibling
, AnjutaToken
*token
)
273 token
->prev
= sibling
->prev
;
274 token
->next
= sibling
;
276 if (token
->prev
!= NULL
)
278 token
->prev
->next
= token
;
280 sibling
->prev
= token
;
282 if ((sibling
->parent
!= NULL
) && (sibling
->parent
->children
== sibling
))
284 sibling
->parent
->children
= token
;
286 token
->parent
= sibling
->parent
;
292 anjuta_token_evaluate_token (AnjutaToken
*token
, GString
*value
, gboolean raw
)
294 if ((token
!= NULL
) && (token
->data
.length
!= 0))
298 switch (anjuta_token_get_type (token
))
300 case ANJUTA_TOKEN_COMMENT
:
301 case ANJUTA_TOKEN_OPEN_QUOTE
:
302 case ANJUTA_TOKEN_CLOSE_QUOTE
:
303 case ANJUTA_TOKEN_ESCAPE
:
304 case ANJUTA_TOKEN_MACRO
:
305 case ANJUTA_TOKEN_EOV
:
311 g_string_append_len (value
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
316 anjuta_token_show (AnjutaToken
*token
, gint indent
, gchar parent
)
318 static gchar type
[] = "\0";
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
);
330 /* Value doesn't contain a newline */
331 fprintf (stderr
, "(%lu)", length
);
335 const gchar
*newline
;
337 newline
= g_strrstr_len (string
, length
, "\n");
340 /* Value doesn't contain a newline */
341 fprintf (stderr
, "\"%.*s\"",
347 /* Value contains a newline, take care of indentation */
349 fprintf (stderr
, "\"%.*s",
354 length
-= newline
- string
;
357 newline
= g_strrstr_len (string
, length
, "\n");
358 if (newline
== NULL
) break;
361 fprintf (stderr
, "%*s %.*s",
366 fprintf (stderr
, "%*s %.*s\"",
372 fprintf (stderr
, " %p/%p (%p/%p) %s\n",
373 token
->last
, token
->children
,
374 token
->group
, token
->parent
,
375 anjuta_token_get_flags (token
) & ANJUTA_TOKEN_REMOVED
? " (removed)" : "");
379 anjuta_token_dump_child (AnjutaToken
*token
, gint indent
, gchar type
)
384 anjuta_token_show (token
, indent
, type
);
388 if (token
->last
!= NULL
)
393 if (child
== NULL
) break;
394 last
= anjuta_token_dump_child (child
, indent
, '+');
396 while (child
!= token
->last
);
399 if (token
->children
!= NULL
)
401 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
403 child
= anjuta_token_dump_child (child
, indent
, '*');
411 anjuta_token_check_child (AnjutaToken
*token
, AnjutaToken
*parent
)
413 if (token
->parent
!= parent
)
415 anjuta_token_show (token
, 0, 0);
416 fprintf(stderr
, "Error: Children has %p as parent instead of %p\n", token
->parent
, parent
);
420 return anjuta_token_check (token
);
423 /* Get and set functions
424 *---------------------------------------------------------------------------*/
427 anjuta_token_set_type (AnjutaToken
*token
, gint type
)
429 token
->data
.type
= type
;
433 anjuta_token_get_type (AnjutaToken
*token
)
435 return token
->data
.type
;
439 anjuta_token_set_flags (AnjutaToken
*token
, gint flags
)
442 AnjutaToken
*last
= token
->last
;
444 for (child
= token
; child
!= NULL
; child
= anjuta_token_next_child (child
, &last
))
446 child
->data
.flags
|= flags
;
451 anjuta_token_clear_flags (AnjutaToken
*token
, gint flags
)
453 token
->data
.flags
&= ~flags
;
457 anjuta_token_get_flags (AnjutaToken
*token
)
459 return token
->data
.flags
;
463 anjuta_token_set_string (AnjutaToken
*token
, const gchar
*data
, gsize length
)
465 if (!(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
467 g_free (token
->data
.pos
);
468 token
->data
.flags
|= ANJUTA_TOKEN_STATIC
;
470 token
->data
.pos
= (gchar
*)data
;
471 token
->data
.length
= length
;
475 anjuta_token_get_string (AnjutaToken
*token
)
477 return token
->data
.pos
;
481 anjuta_token_set_length (AnjutaToken
*token
, gsize length
)
483 token
->data
.length
= length
;
487 anjuta_token_get_length (AnjutaToken
*token
)
489 return token
->data
.length
;
492 /* Basic move functions
493 *---------------------------------------------------------------------------*/
496 anjuta_token_next (AnjutaToken
*token
)
498 if (token
->children
!= NULL
)
500 return token
->children
;
502 else if (token
->next
!= NULL
)
506 else if (token
->parent
!= NULL
)
508 return anjuta_token_next_after_children (token
->parent
);
517 anjuta_token_previous (AnjutaToken
*token
)
519 if (token
->prev
!= NULL
)
525 return token
->parent
;
530 anjuta_token_last (AnjutaToken
*token
)
534 for (last
= token
; last
->last
!= NULL
; last
= last
->last
);
535 if (last
->children
!= NULL
)
537 for (last
= last
->children
; last
->next
!= NULL
; last
= last
->next
);
544 anjuta_token_parent (AnjutaToken
*token
)
546 return token
->parent
;
550 anjuta_token_list (AnjutaToken
*token
)
555 /* Item move functions
556 *---------------------------------------------------------------------------*/
559 anjuta_token_last_item (AnjutaToken
*list
)
565 anjuta_token_first_item (AnjutaToken
*list
)
567 AnjutaToken
*first
= NULL
;
571 if (list
->children
!= NULL
)
573 first
= list
->children
;
575 else if (list
->last
!= NULL
)
585 anjuta_token_next_item (AnjutaToken
*item
)
594 if ((item
->group
== NULL
) || (item
->group
->last
!= item
))
597 for (last
= item
; last
->last
!= NULL
; last
= last
->last
);
598 next
= anjuta_token_next (last
);
599 if ((next
!= NULL
) && (next
->group
!= item
->group
)) next
= NULL
;
603 /* Loop if the current item has been deleted */
604 while ((next
!= NULL
) && (anjuta_token_get_flags (next
) & ANJUTA_TOKEN_REMOVED
));
611 anjuta_token_previous_item (AnjutaToken
*item
)
613 AnjutaToken
*prev
= NULL
;
620 for (prev
= item
->prev
; (prev
!= NULL
) && (prev
->group
!= item
->group
); prev
= prev
->group
);
623 /* Loop if the current item has been deleted */
624 while ((prev
!= NULL
) && (anjuta_token_get_flags (prev
) & ANJUTA_TOKEN_REMOVED
));
630 /* Add/Insert/Remove tokens
631 *---------------------------------------------------------------------------*/
634 * anjuta_token_append_child:
635 * @parent: a #AnjutaToken object used as parent.
636 * @children: a #AnjutaToken object.
638 * Insert all tokens in children as the last children of the given parent.
640 * Return value: The first token append.
643 anjuta_token_append_child (AnjutaToken
*parent
, AnjutaToken
*children
)
647 AnjutaToken
*old_group
;
648 AnjutaToken
*old_parent
;
650 g_return_val_if_fail (parent
!= NULL
, NULL
);
651 g_return_val_if_fail (children
!= NULL
, NULL
);
653 old_group
= children
->group
;
654 old_parent
= children
->parent
;
656 if (parent
->children
== NULL
)
658 parent
->children
= children
;
660 children
->prev
= NULL
;
664 /* Find last children */
665 for (last
= parent
->children
; last
->next
!= NULL
;)
667 if ((last
->last
!= NULL
) && (last
->last
->parent
== last
->parent
))
677 last
->next
= children
;
678 children
->prev
= last
;
681 /* Update each token */
682 for (token
= children
;;)
684 if (token
->parent
== old_parent
) token
->parent
= parent
;
685 if (token
->group
== old_group
) token
->group
= parent
->group
;
687 if (token
->children
!= NULL
)
689 token
= token
->children
;
691 else if (token
->next
!= NULL
)
697 while (token
->parent
!= parent
)
699 token
= token
->parent
;
700 if (token
->next
!= NULL
) break;
702 if (token
->next
== NULL
) break;
711 * anjuta_token_prepend_child:
712 * @parent: a #AnjutaToken object used as parent.
713 * @children: a #AnjutaToken object.
715 * Insert all tokens in children as the first children of the given parent.
717 * Return value: The first token append.
720 anjuta_token_prepend_child (AnjutaToken
*parent
, AnjutaToken
*children
)
723 AnjutaToken
*last
= NULL
;
725 g_return_val_if_fail (parent
!= NULL
, NULL
);
726 g_return_val_if_fail (children
!= NULL
, NULL
);
728 /* Update each token */
729 for (child
= children
;;)
733 if (child
->parent
== children
->parent
) child
->parent
= parent
;
734 if (child
->group
== children
->group
) child
->group
= parent
->group
;
736 next
= anjuta_token_next_child (child
, &last
);
737 if (next
== NULL
) break;
741 child
->next
= parent
->children
;
742 if (child
->next
) child
->next
->prev
= child
;
743 parent
->children
= children
;
749 * anjuta_token_prepend_items:
750 * @list: a #AnjutaToken object used as list.
751 * @item: a #AnjutaToken object.
753 * Insert all tokens in item as item of the given list.
755 * Return value: The first token append.
758 anjuta_token_prepend_items (AnjutaToken
*list
, AnjutaToken
*item
)
761 AnjutaToken
*old_group
;
762 AnjutaToken
*old_parent
;
764 g_return_val_if_fail (list
!= NULL
, NULL
);
765 g_return_val_if_fail (item
!= NULL
, NULL
);
767 old_group
= item
->group
;
768 old_parent
= item
->parent
;
770 /* Update each token */
773 if (token
->parent
== old_parent
) token
->parent
= list
->parent
;
774 if (token
->group
== old_group
) token
->group
= list
;
776 if (token
->children
!= NULL
)
778 token
= token
->children
;
780 else if (token
->next
!= NULL
)
786 while (token
->parent
!= list
->parent
)
788 token
= token
->parent
;
789 if (token
->next
!= NULL
) break;
791 if (token
->next
== NULL
) break;
796 token
->next
= list
->next
;
797 if (token
->next
) token
->next
->prev
= token
;
802 if (list
->last
== NULL
)
804 while (token
->group
!= list
) token
= token
->group
;
812 * anjuta_token_insert_after:
813 * @sibling: a #AnjutaToken object.
814 * @list: a #AnjutaToken object.
816 * Insert all tokens after sibling.
818 * Return value: The first token inserted.
821 anjuta_token_insert_after (AnjutaToken
*sibling
, AnjutaToken
*list
)
825 AnjutaToken
*old_group
;
826 AnjutaToken
*old_parent
;
828 g_return_val_if_fail (sibling
!= NULL
, NULL
);
829 g_return_val_if_fail (list
!= NULL
, NULL
);
831 old_group
= list
->group
;
832 old_parent
= list
->parent
;
834 /* Update each token */
837 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
838 if (token
->group
== old_group
) token
->group
= sibling
->group
;
840 if (token
->children
!= NULL
)
842 token
= token
->children
;
844 else if (token
->next
!= NULL
)
850 while (token
->parent
!= sibling
->parent
)
852 token
= token
->parent
;
853 if (token
->next
!= NULL
) break;
855 if (token
->next
== NULL
) break;
860 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
862 token
->next
= last
->next
;
863 if (token
->next
) token
->next
->prev
= token
;
868 if ((sibling
->group
!= NULL
) && (sibling
->group
->last
== sibling
))
870 while (token
->group
!= sibling
->group
) token
= token
->group
;
871 sibling
->group
->last
= token
;
878 * anjuta_token_insert_before:
879 * @sibling: a #AnjutaToken object.
880 * @list: a #AnjutaToken object.
882 * Insert all tokens before sibling.
884 * Return value: The first token inserted.
887 anjuta_token_insert_before (AnjutaToken
*sibling
, AnjutaToken
*list
)
891 AnjutaToken
*old_group
;
892 AnjutaToken
*old_parent
;
894 g_return_val_if_fail (sibling
!= NULL
, NULL
);
895 g_return_val_if_fail (list
!= NULL
, NULL
);
897 old_group
= list
->group
;
898 old_parent
= list
->parent
;
900 /* Update each token */
903 if (token
->parent
== old_parent
) token
->parent
= sibling
->parent
;
904 if (token
->group
== old_group
) token
->group
= sibling
->group
;
906 if (token
->children
!= NULL
)
908 token
= token
->children
;
910 else if (token
->next
!= NULL
)
916 while (token
->parent
!= sibling
->parent
)
918 token
= token
->parent
;
919 if (token
->next
!= NULL
) break;
921 if (token
->next
== NULL
) break;
926 for (last
= sibling
; last
->last
!= NULL
; last
= last
->last
);
928 token
->next
= sibling
;
929 list
->prev
= sibling
->prev
;
930 sibling
->prev
= token
;
932 if (list
->prev
) list
->prev
->next
= list
;
934 if ((list
->parent
!= NULL
) && (list
->parent
->children
== sibling
)) list
->parent
->children
= list
;
940 * anjuta_token_delete_parent:
941 * @parent: a #AnjutaToken object used as parent.
943 * Delete only the parent token.
945 * Return value: the first children
948 anjuta_token_delete_parent (AnjutaToken
*parent
)
952 g_return_val_if_fail (parent
!= NULL
, NULL
);
954 if (parent
->children
== NULL
) return NULL
;
956 /* Update each token */
957 for (token
= parent
->children
;;)
959 if (token
->parent
== parent
) token
->parent
= parent
->parent
;
961 if (token
->children
!= NULL
)
963 token
= token
->children
;
965 else if (token
->next
!= NULL
)
971 while (token
->parent
!= parent
->parent
)
973 token
= token
->parent
;
974 if (token
->next
!= NULL
) break;
976 if (token
->next
== NULL
) break;
981 token
->next
= parent
->next
;
982 if (token
->next
) token
->next
->prev
= token
;
984 parent
->next
= parent
->children
;
985 parent
->children
->prev
= parent
;
986 parent
->children
= NULL
;
988 return anjuta_token_free (parent
);
992 *---------------------------------------------------------------------------*/
994 /* anjuta_token_merge can be used with first or end being a floating token and
995 * on already grouped tokens to change the group organisation */
997 anjuta_token_merge (AnjutaToken
*first
, AnjutaToken
*end
)
1001 if ((first
== end
) || (end
== NULL
)) return first
;
1003 /* Insert first or end in the same sequence if it is not already the case */
1004 for (next
= first
; next
!= end
; next
= anjuta_token_next (next
))
1008 if (first
->parent
== NULL
)
1010 anjuta_token_insert_before (end
, first
);
1014 anjuta_token_insert_after (first
, end
);
1020 if ((end
->group
!= NULL
) && (end
->group
!= first
) && (end
->group
->last
== end
)) end
->group
->last
= first
;
1027 anjuta_token_merge_own_children (AnjutaToken
*group
)
1030 AnjutaToken
*next
= NULL
;
1032 if (group
->last
!= NULL
) return group
;
1034 if (group
->last
->last
!= NULL
) group
->last
= group
->last
->last
;
1036 for (token
= anjuta_token_next (group
); (token
!= NULL
) && (token
!= group
->last
); token
= anjuta_token_next (token
))
1040 if (token
->last
!= NULL
)
1043 //token->last = NULL;
1045 token
->group
= group
;
1047 else if (next
== token
)
1057 anjuta_token_merge_children (AnjutaToken
*first
, AnjutaToken
*end
)
1063 if ((first
== end
) || (end
== NULL
))
1068 if (first
->parent
== NULL
)
1070 first
->parent
= end
->parent
;
1072 if (first
->next
== NULL
)
1074 anjuta_token_insert_before (end
, first
);
1076 anjuta_token_unlink_token (end
);
1077 if (end
->last
!= NULL
)
1081 first
->last
= end
->last
;
1082 for (child
= anjuta_token_next (first
); child
!= first
->last
; child
= anjuta_token_next (child
))
1084 if (child
->group
== end
) child
->group
= first
;
1086 first
->last
->group
= first
;
1089 anjuta_token_free (end
);
1095 * anjuta_token_merge_previous:
1096 * @list: a #AnjutaToken object representing a list
1097 * @first: a #AnjutaToken object for the new beginning of the list
1099 * If the list token is not already linked with first, it is inserted
1100 * just before first.
1101 * If the list token is already linked, it must be in the same list after
1102 * first token. It it possible to have several tokens beweent list and
1105 * Return value: the new list
1108 anjuta_token_merge_previous (AnjutaToken
*list
, AnjutaToken
*first
)
1112 if ((first
== NULL
) || (list
== first
)) return list
;
1114 /* Change group of all tokens from end to first
1115 * if the list is already linked */
1116 if ((list
->prev
!= NULL
) || (list
->parent
!= NULL
))
1118 for (token
= first
; token
!= NULL
; token
= anjuta_token_next_item (token
))
1120 token
->group
= list
;
1124 token
= anjuta_token_next (list
);
1125 anjuta_token_unlink_token (list
);
1126 anjuta_token_insert_token_before (first
, list
);
1131 AnjutaToken
*anjuta_token_split (AnjutaToken
*token
, guint size
)
1133 if (token
->data
.length
> size
)
1137 copy
= anjuta_token_copy (token
);
1138 anjuta_token_insert_before (token
, copy
);
1140 copy
->data
.length
= size
;
1141 if (token
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1143 token
->data
.pos
+= size
;
1144 token
->data
.length
-= size
;
1148 memcpy(token
->data
.pos
, token
->data
.pos
+ size
, token
->data
.length
- size
);
1160 anjuta_token_cut (AnjutaToken
*token
, guint pos
, guint size
)
1164 copy
= anjuta_token_copy (token
);
1166 if (pos
>= token
->data
.length
)
1168 if (!(copy
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1170 g_free (copy
->data
.pos
);
1172 copy
->data
.pos
= NULL
;
1173 copy
->data
.length
= 0;
1175 if ((pos
+ size
) > token
->data
.length
)
1177 size
= token
->data
.length
- pos
;
1180 if (copy
->data
.flags
& ANJUTA_TOKEN_STATIC
)
1182 copy
->data
.pos
+= pos
;
1186 memmove(copy
->data
.pos
, copy
->data
.pos
+ pos
, size
);
1188 copy
->data
.length
= size
;
1194 concat_token (AnjutaToken
*token
, gpointer user_data
)
1196 AnjutaToken
*first
= (AnjutaToken
*)user_data
;
1198 if (anjuta_token_get_length (token
) > 0)
1200 if (anjuta_token_get_string (first
) == NULL
)
1202 anjuta_token_set_string (first
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
1204 else if ((first
!= NULL
) && ((anjuta_token_get_string(first
) + anjuta_token_get_length (first
)) == anjuta_token_get_string (token
)))
1206 anjuta_token_set_string (first
, anjuta_token_get_string (first
), anjuta_token_get_length (first
) + anjuta_token_get_length (token
));
1212 new = anjuta_token_new_static_len (ANJUTA_TOKEN_CONTENT
, anjuta_token_get_string (token
), anjuta_token_get_length (token
));
1213 anjuta_token_insert_after (first
, new);
1214 anjuta_token_merge (first
, new);
1221 anjuta_token_concat(AnjutaToken
*token
)
1225 new = anjuta_token_new_static (ANJUTA_TOKEN_CONTENT
, NULL
);
1226 anjuta_token_foreach_token (token
, concat_token
, new);
1228 anjuta_token_insert_token_before (token
, new);
1229 anjuta_token_free (token
);
1235 *---------------------------------------------------------------------------*/
1238 anjuta_token_foreach_token (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1242 AnjutaToken
*last_token
;
1245 last_token
= token
->last
== NULL
? token
: token
->last
;
1246 while (token
!= NULL
)
1248 if (child
== 0) func (token
, user_data
);
1250 /* Check if we have found the last token */
1251 if (token
== last_token
)
1253 /* Find last token */
1254 if (token
->last
== NULL
)
1258 /* Last token still include additional tokens */
1259 last_token
= token
->last
;
1262 if (token
->children
!= NULL
)
1264 /* Check children, only for last token */
1266 token
= token
->children
;
1268 else if (token
->next
!= NULL
)
1270 /* Get next sibling */
1271 token
= token
->next
;
1279 token
= token
->parent
;
1280 if (token
== NULL
) break;
1281 if (token
->next
!= NULL
)
1283 token
= token
->next
;
1295 anjuta_token_foreach_content (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1299 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent and
1300 * are not taken into account */
1301 AnjutaToken
*last_token
;
1302 gboolean expand
= TRUE
;
1305 last_token
= token
->last
== NULL
? token
: token
->last
;
1308 if (expand
&& (token
->children
!= NULL
))
1310 /* Children of the last token does not belong to the group */
1311 if (token
== last_token
)
1313 /* Find last token */
1314 if (token
->last
== NULL
)
1318 /* Last token still include additional tokens */
1319 last_token
= token
->last
;
1322 /* Enumerate children */
1323 token
= token
->children
;
1327 if (token
->children
== NULL
)
1329 /* Take into account only the content of token having no children */
1330 if (last_parent
== NULL
)
1332 /* Take into account only the content of group having no children */
1333 func (token
, user_data
);
1337 /* Check if we have found the last token */
1338 if (token
== last_token
)
1340 /* Find last token */
1341 if (token
->last
== NULL
)
1345 /* Last token still include additional tokens */
1346 last_token
= token
->last
;
1349 if (token
== last_parent
)
1351 /* Find last parent */
1352 if (token
->last
== NULL
)
1354 /* Found complete group having children */
1359 /* Parent group has additional token */
1360 last_parent
= token
->last
;
1364 if (token
->next
!= NULL
)
1366 /* Get next sibling */
1367 token
= token
->next
;
1373 token
= token
->parent
;
1374 if (token
!= NULL
) last_parent
= token
->last
;
1385 anjuta_token_foreach_container (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1389 AnjutaToken
*parent
; /* If not NULL, token belong to a parent and
1390 * are not taken into account */
1391 AnjutaToken
*last_token
;
1392 gboolean expand
= TRUE
;
1395 last_token
= token
->last
== NULL
? token
: token
->last
;
1398 /* Take into account only the content of parent token */
1399 if (expand
&& (parent
== NULL
))
1401 func (token
, user_data
);
1403 if (expand
&& (token
->children
!= NULL
))
1405 if (parent
== NULL
) parent
= token
;
1406 /* Enumerate children */
1407 token
= token
->children
;
1411 /* Check if we have found the last token */
1412 if (token
== last_token
)
1414 /* Find last token */
1415 if (token
->last
== NULL
)
1419 /* Last token still include additional tokens */
1420 last_token
= token
->last
;
1423 if (token
->next
!= NULL
)
1425 /* Get next sibling */
1426 token
= token
->next
;
1432 token
= token
->parent
;
1433 if (token
== parent
) parent
= NULL
;
1444 anjuta_token_foreach_post_order (AnjutaToken
*token
, AnjutaTokenForeachFunc func
, gpointer user_data
)
1448 AnjutaToken
*last_parent
; /* If not NULL, token belong to a parent */
1449 AnjutaToken
*last_token
;
1450 AnjutaToken buffer
; /* Temporary token allowing func to destroy
1451 * the current token */
1452 gboolean expand
= TRUE
;
1455 last_token
= token
->last
== NULL
? token
: token
->last
;
1456 while (token
!= NULL
)
1458 if (expand
&& (token
->children
!= NULL
))
1460 /* Check if we have found the last token */
1461 if (token
== last_token
)
1463 /* Find last token */
1464 if (token
->last
== NULL
)
1468 /* Last token still include additional tokens */
1469 last_token
= token
->last
;
1472 /* Enumerate children */
1473 token
= token
->children
;
1477 /* Save token data in case it is destroyed */
1478 memcpy (&buffer
, token
, sizeof (buffer
));
1479 /* Take into account all token */
1480 func (token
, user_data
);
1482 /* Check if we have found the last token */
1483 if (token
== last_token
)
1485 /* Find last token */
1486 if (buffer
.last
== NULL
)
1491 /* Last token still include additional tokens */
1492 last_token
= buffer
.last
;
1495 if (token
== last_parent
)
1497 /* Find last parent */
1498 if (buffer
.last
== NULL
)
1500 /* Found complete group having children */
1505 /* Parent group has additional token */
1506 last_parent
= buffer
.last
;
1510 if (buffer
.next
!= NULL
)
1512 /* Get next sibling */
1513 token
= buffer
.next
;
1519 token
= buffer
.parent
;
1520 if (token
!= NULL
) last_parent
= token
->last
;
1526 while ((token
!= NULL
) && (token
->next
== NULL
))
1528 token
= token
->parent
;
1531 if (token
!= NULL
) token
= token
->next
;
1538 *---------------------------------------------------------------------------*/
1541 evaluate_raw_token (AnjutaToken
*token
, gpointer user_data
)
1543 GString
*value
= (GString
*)user_data
;
1545 anjuta_token_evaluate_token (token
, value
, TRUE
);
1549 evaluate_token (AnjutaToken
*token
, gpointer user_data
)
1551 GString
*value
= (GString
*)user_data
;
1553 anjuta_token_evaluate_token (token
, value
, FALSE
);
1558 anjuta_token_evaluate (AnjutaToken
*token
)
1560 GString
*value
= g_string_new (NULL
);
1562 anjuta_token_foreach_content (token
, evaluate_token
, value
);
1564 /* Return NULL and free data for an empty string */
1565 return g_string_free (value
, *(value
->str
) == '\0');
1568 /* Does not evaluate content if token is a variable */
1570 anjuta_token_evaluate_name (AnjutaToken
*token
)
1572 GString
*value
= g_string_new (NULL
);
1574 anjuta_token_foreach_container (token
, evaluate_token
, value
);
1576 /* Return NULL and free data for an empty string */
1577 return g_string_free (value
, *(value
->str
) == '\0');
1581 anjuta_token_is_empty (AnjutaToken
*token
)
1583 return (token
== NULL
) || ((token
->data
.length
== 0) && (token
->last
== NULL
) && (token
->children
== NULL
));
1588 *---------------------------------------------------------------------------*/
1591 anjuta_token_compare (AnjutaToken
*toka
, AnjutaToken
*tokb
)
1593 if (tokb
->data
.type
)
1595 if (tokb
->data
.type
!= toka
->data
.type
) return FALSE
;
1598 if (tokb
->data
.type
!= ANJUTA_TOKEN_NONE
)
1600 if (tokb
->data
.length
!= 0)
1602 if (toka
->data
.length
!= tokb
->data
.length
) return FALSE
;
1604 if ((toka
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
) && (tokb
->data
.flags
& ANJUTA_TOKEN_CASE_INSENSITIVE
))
1606 if (g_ascii_strncasecmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1610 if (strncmp (toka
->data
.pos
, tokb
->data
.pos
, toka
->data
.length
) != 0) return FALSE
;
1615 if (tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
)
1617 if ((toka
->data
.flags
& tokb
->data
.flags
& ANJUTA_TOKEN_PUBLIC_FLAGS
) == 0)
1625 anjuta_token_dump (AnjutaToken
*token
)
1627 if (token
== NULL
) return;
1629 anjuta_token_dump_child (token
, 0, 0);
1633 anjuta_token_dump_link (AnjutaToken
*token
)
1635 AnjutaToken
*last
= token
;
1637 while (last
->last
!= NULL
) last
= last
->last
;
1639 for (; token
!= last
; token
= anjuta_token_next (token
))
1641 anjuta_token_show (token
, 0, 0);
1646 anjuta_token_check (AnjutaToken
*token
)
1648 if ((token
->children
!= NULL
) && (token
->last
!= NULL
))
1650 anjuta_token_show (token
, 0, 0);
1651 fprintf(stderr
, "Error: Previous token has both non NULL children and last\n");
1656 if (token
->children
!= NULL
)
1660 for (child
= token
->children
; child
!= NULL
; child
= child
->next
)
1662 if (!anjuta_token_check_child (child
, token
)) return FALSE
;
1666 if (token
->last
!= NULL
)
1670 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (child
))
1672 if (!anjuta_token_check (child
)) return FALSE
;
1673 if (child
== token
->last
) break;
1680 /* Constructor & Destructor
1681 *---------------------------------------------------------------------------*/
1683 AnjutaToken
*anjuta_token_new_string (AnjutaTokenType type
, const gchar
*value
)
1689 token
= anjuta_token_new_static (type
, NULL
);
1693 token
= g_slice_new0 (AnjutaToken
);
1694 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1695 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1696 token
->data
.pos
= g_strdup (value
);
1697 token
->data
.length
= strlen (value
);
1704 anjuta_token_new_string_len (AnjutaTokenType type
, gchar
*value
, gsize length
)
1710 token
= anjuta_token_new_static (type
, NULL
);
1714 token
= g_slice_new0 (AnjutaToken
);
1715 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1716 token
->data
.flags
= type
& ANJUTA_TOKEN_FLAGS
;
1717 token
->data
.pos
= value
;
1718 token
->data
.length
= length
;
1725 anjuta_token_new_static_len (gint type
, const gchar
*pos
, gsize length
)
1729 token
= g_slice_new0 (AnjutaToken
);
1730 token
->data
.type
= type
& ANJUTA_TOKEN_TYPE
;
1731 token
->data
.flags
= (type
& ANJUTA_TOKEN_FLAGS
) | ANJUTA_TOKEN_STATIC
;
1732 token
->data
.pos
= (gchar
*)pos
;
1733 token
->data
.length
= length
;
1738 AnjutaToken
*anjuta_token_new_static (AnjutaTokenType type
, const char *value
)
1740 return anjuta_token_new_static_len (type
, value
, value
== NULL
? 0 : strlen (value
));
1744 anjuta_token_free_children (AnjutaToken
*token
)
1749 if (token
== NULL
) return NULL
;
1751 for (child
= token
->children
; child
!= NULL
; child
= token
->children
)
1753 anjuta_token_free (child
);
1755 token
->children
= NULL
;
1757 if (token
->last
!= NULL
)
1760 for (child
= anjuta_token_next (token
); child
!= NULL
; child
= anjuta_token_next (token
))
1762 anjuta_token_free (child
);
1763 if (child
== last
) break;
1772 free_token (AnjutaToken
*token
, gpointer user_data
)
1774 anjuta_token_unlink_token (token
);
1775 if ((token
->data
.pos
!= NULL
) && !(token
->data
.flags
& ANJUTA_TOKEN_STATIC
))
1777 g_free (token
->data
.pos
);
1779 g_slice_free (AnjutaToken
, token
);
1784 anjuta_token_free (AnjutaToken
*token
)
1788 if (token
== NULL
) return NULL
;
1790 next
= anjuta_token_foreach_post_order (token
, free_token
, NULL
);