3 * @author aurelien.morelle@parrot.com
5 * modified on 2010/07/19 by stephane.piskorski.ext@parrot.fr (bug fix+comments)
8 #include <VP_Os/vp_os_types.h>
9 #include <VP_Os/vp_os_assert.h>
10 #include <VP_Os/vp_os_print.h>
11 #include <VP_Os/vp_os_malloc.h>
12 #include <ATcodec/ATcodec_Tree.h>
13 #include <ATcodec/ATcodec_api.h>
14 #include <ATcodec/ATcodec_Buffer.h>
15 #include <ATcodec/ATcodec.h>
18 /* \todo Remove nodes fields initializations that are not necessary in each function */
24 ATcodec_Tree_Node_init(ATcodec_Tree_Node_t *node)
31 vp_os_memset(node->sons,0,sizeof(node->sons));
33 node->type = ATCODEC_TREE_NODE_TYPE_EMPTY;
39 /********************************************************************
\r
40 * @brief Initialises the AT command search tree.
\r
41 * @param[in] tree The tree to initialise.
\r
44 ATcodec_Tree_init(ATcodec_Tree_t *tree, size_t leaf_size, int nb_start)
46 ATcodec_Tree_Node_t s_node;
50 ATcodec_Buffer_init(&tree->leaves, leaf_size, nb_start);
51 ATcodec_Buffer_init(&tree->strs, sizeof(char), nb_start);
52 ATcodec_Buffer_init(&tree->sons, sizeof(ATcodec_Tree_Node_t), nb_start);
54 ATcodec_Tree_Node_init(&s_node);
55 tree->root = tree->sons.nbElements;
56 ATcodec_Buffer_pushElement(&tree->sons, &s_node);
62 /********************************************************************
\r
63 * @param[in] tree Tree in which the node is inserted.
\r
64 * @brief Creates a new node in the tree.
\r
67 ATcodec_Tree_Node_insert(ATcodec_Tree_t *tree, ATCODEC_TREE_NODE_TYPE type, int depth, int str_index, int data, ATcodec_Tree_Node_t *father, int son_index)
69 /* The new node's value */
70 ATcodec_Tree_Node_t s_node;
71 /* Index of the new node inside the tree's nodes list */
74 /* Clears the new node */
75 vp_os_memset(&s_node,0,sizeof(s_node));
77 node_index = tree->sons.nbElements;
79 father->sons[son_index] = node_index;
83 s_node.strkey = str_index;
86 ATcodec_Buffer_pushElement(&tree->sons, &s_node);
93 /********************************************************************
\r
94 * @param[in] tree Tree in which the command is inserted.
\r
95 * @brief Inserts an AT command string in the tree.
\r
98 ATcodec_Tree_Node_search(ATcodec_Tree_t *tree, char *str)
100 ATcodec_Tree_Node_t *node;
112 str_index = tree->strs.nbElements;
114 /* Adds the new string to the list of commands */
115 ATcodec_Buffer_pushElements(&tree->strs, str, strlen(str)+1);
117 /* !! WARNING !! this pointer might be invalid after inserting an element in the tree */
118 node = ATcodec_Tree_Node_get(tree, tree->root);
125 /* Tree is empty -> we insert the string as the only element */
126 case ATCODEC_TREE_NODE_TYPE_EMPTY:
128 /* Initialise the root element */
129 node->type = ATCODEC_TREE_NODE_TYPE_LEAF;
131 node->strkey = str_index; /* str_index = place of the newly inserted string */
133 /* Stop the search */
139 Parse an intermediate node, which means that previously inserted
140 command strings began with the same characters.
142 case ATCODEC_TREE_NODE_TYPE_NODE:
144 /* Gets the node representing the next character of the command string */
145 node_index = node->sons[(int)*str];
147 /* If there is no such node, the remaining part of the string is stored in the
148 tree as a terminal node (a leaf of the tree).*/
151 node_index = ATcodec_Tree_Node_insert(tree,
152 ATCODEC_TREE_NODE_TYPE_LEAF,
154 str_index, /* str_index = place of the newly inserted string */
157 /*index*/(int)*(str));
160 /* Otherwise, we get the node representing this character and continue scanning the tree.*/
161 node = ATcodec_Tree_Node_get(tree, node_index);
168 Scanning arrives on a leaf -> this leaf must be split to store the two
169 possible command-string endings.
171 case ATCODEC_TREE_NODE_TYPE_LEAF:
174 Retrieves the already-stored string.
175 We have to insert as many additional intermediate nodes as there are common
176 characters in the two string remainders.
177 Two terminal leaves will then be added to store the parts of those strings which differ.
179 char *leaf_str = (char *)ATcodec_Buffer_getElement(&tree->strs, node->strkey);
182 /* As far as strings endings are the same, insert the intermediate nodes ...*/
183 while(*str && *str == leaf_str[depth])
185 /* Change the current leaf node to an intermediate node and initialises the list of sons. */
186 node->type = ATCODEC_TREE_NODE_TYPE_NODE;
187 for(i = 0 ; i < AT_CODEC_TREE_MAX_SONS ; i++) { node->sons[i] = -1; }
189 /* Create a new leaf */
190 node_index = ATcodec_Tree_Node_insert(tree,
191 /*node type*/ATCODEC_TREE_NODE_TYPE_LEAF,
192 /*node depth*/depth+1,
193 /*str_index*/node->strkey, /* Points to the old command-string by default */
196 /*son_index*/(int)leaf_str[depth]);
199 node = ATcodec_Tree_Node_get(tree, node_index);
203 /* If the new string was in fact a subpart of the old one ...*/
204 if(*str == leaf_str[depth])
206 /* Change the leaf to a multileaves */
207 node->type = ATCODEC_TREE_NODE_TYPE_MULTILEAVES;
209 temp_data = node->data;
211 father_index = node_index;
213 /* Insert a leaf for the old longer string */
214 node_index = ATcodec_Tree_Node_insert(tree,
215 ATCODEC_TREE_NODE_TYPE_LEAF,
222 /* Pointer 'node' is invalid from here because it points
223 to a buffer which might have been resized by 'ATcodec_Tree_Node_insert'.
224 We fetch a valid address computed from the index.*/
225 node = ATcodec_Tree_Node_get(tree,father_index);
227 /* Insert a leaf for the new, shorter string */
228 node_index = ATcodec_Tree_Node_insert(tree,
229 ATCODEC_TREE_NODE_TYPE_LEAF,
237 /* If the two strings have different endings ...*/
240 /* The old leaf becomes an intermediate node with two daughter leaves */
241 node->type = ATCODEC_TREE_NODE_TYPE_NODE;
242 for(i = 0 ; i < AT_CODEC_TREE_MAX_SONS ; i++) { node->sons[i] = -1; }
243 father_index = node_index;
245 /* Recreate a leaf for the old command string */
246 node_index = ATcodec_Tree_Node_insert(tree,
247 ATCODEC_TREE_NODE_TYPE_LEAF,
249 node->strkey, /* strkey was propagated from the original leaf */
250 node->data, /* keeps the data of the old command string */
252 /*son_index*/(int)leaf_str[depth]
255 /* Pointer 'node' is invalid from here because it points
256 to a buffer which might have been resized by 'ATcodec_Tree_Node_insert'.
257 We fetch a valid address computed from the index.*/
258 node = ATcodec_Tree_Node_get(tree,father_index);
261 //node->sons[(int)leaf_str[depth]] = node_index;
263 /* Create a new leaf for the new command string */
264 node_index = ATcodec_Tree_Node_insert(tree,
265 ATCODEC_TREE_NODE_TYPE_LEAF,
267 str_index, /* str_index = place of the newly inserted string */
268 -1, /* data is initialised later in the ATcodec_Tree_insert function */
270 /*son_index*/(int)*str);
278 If there are already at leat two several end-of-command-strings starting with the current character,
279 these are represented by a 'multileaves' node and we just add a new son to this node.
281 case ATCODEC_TREE_NODE_TYPE_MULTILEAVES:
283 node_index = ATcodec_Tree_Node_insert(tree,
284 ATCODEC_TREE_NODE_TYPE_LEAF,
286 str_index, /* str_index = place of the newly inserted string */
287 /*data*/-1, /* data is initialised later in the ATcodec_Tree_insert function */
289 /*son_index*/node->nb_sons++
301 /********************************************************************
\r
302 * @param[in] tree Tree in which the command is inserted.
\r
303 * @brief Inserts an AT command string in the AT tree with its associated parameters.
\r
306 ATcodec_Tree_insert(ATcodec_Tree_t *tree, char *str, void *data)
308 ATcodec_Tree_Node_t *node;
314 Insert the 'command part' (until the '=' symbol, without parameter)
317 node_i = ATcodec_Tree_Node_search(tree, str);
318 node = ATcodec_Tree_Node_get(tree, node_i);
319 node->data = tree->leaves.nbElements;
320 /* Stores the string containing the parameters */
321 ATcodec_Buffer_pushElement(&tree->leaves, data);
328 /********************************************************************
\r
329 * @param[in] tree Tree from which the node is retrieved.
\r
330 * @param[in] node Index of the node whose pointer is to be returned.
\r
331 * @brief Gets a pointer the node-th node of the tree.
\r
332 * @return Pointer to the asked node.
\r
333 * Be extremely careful not to use this pointer anymore after a tree->sons buffer resize.
\r
335 ATcodec_Tree_Node_t *
336 ATcodec_Tree_Node_get(ATcodec_Tree_t *tree, int node)
338 ATcodec_Tree_Node_t * res = (ATcodec_Tree_Node_t *)ATcodec_Buffer_getElement(&tree->sons, node);
343 #define AT_CODEC_PRINT_NODE_CHAR_CASE(CARAC_SRC,STR_DST) \
348 #define AT_CODEC_PRINT_NODE_CHAR(CARAC) \
351 AT_CODEC_PRINT_NODE_CHAR_CASE('\r',"<CR>"); \
352 AT_CODEC_PRINT_NODE_CHAR_CASE('\n',"<LF>"); \
353 AT_CODEC_PRINT_NODE_CHAR_CASE('\0',"<\\0>"); \
354 AT_CODEC_PRINT_NODE_CHAR_CASE(' ',"< >"); \
356 PRINT("%c", CARAC); \
361 ATcodec_Tree_Node_print(ATcodec_Tree_t *tree, ATcodec_Tree_Node_t *node)
368 if(node->type == ATCODEC_TREE_NODE_TYPE_LEAF)
370 /* Get the end-of-command-string stored on the leaf */
371 sta = ATcodec_Buffer_getElement(&tree->strs, node->strkey);
372 for(j = 0 ; j < tab ; j++)
373 ATCODEC_PRINT(" . ");
376 /* Print the end-of-command-string */
377 AT_CODEC_PRINT_NODE_CHAR(*sta);
380 ATCODEC_PRINT("\"\n");
382 else if(node->type == ATCODEC_TREE_NODE_TYPE_NODE)
384 /* For each possible character of the ascii map, check if a command-string is stored. */
385 for(i = 0 ; i < AT_CODEC_TREE_MAX_SONS ; i++)
387 if(node->sons[i] != -1)
389 for(j = 0 ; j < tab ; j++)
390 ATCODEC_PRINT(" . ");
391 AT_CODEC_PRINT_NODE_CHAR((char)i);
394 ATcodec_Tree_Node_print(tree, ATcodec_Tree_Node_get(tree, node->sons[i]));
399 else if(node->type == ATCODEC_TREE_NODE_TYPE_MULTILEAVES)
401 for(i = 0 ; i < node->nb_sons ; i++)
404 ATcodec_Tree_Node_print(tree, ATcodec_Tree_Node_get(tree, node->sons[i]));
408 #endif // > ATCODEC_DEBUG
413 ATcodec_Tree_print(ATcodec_Tree_t *tree)
416 ATcodec_Tree_Node_print(tree, ATcodec_Tree_Node_get(tree, tree->root));
417 #endif // > ATCODEC_DEBUG