core, lib, modules: restructured source code tree
[sip-router] / src / lib / kmi / tree.c
1 /*
2  * $Id: tree.c 4518 2008-07-28 15:39:28Z henningw $
3  *
4  * Copyright (C) 2006 Voice Sistem SRL
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21  *
22  *
23  * History:
24  * ---------
25  *  2006-09-08  first version (bogdan)
26  */
27
28 /*!
29  * \file 
30  * \brief MI :: Tree 
31  * \ingroup mi
32  */
33
34 #include <string.h>
35 #include <stdio.h>
36 #include <errno.h>
37 #include "../../dprint.h"
38 #include "mi_mem.h"
39 #include "tree.h"
40 #include "fmt.h"
41
42
43 static int use_shm = 0;
44
45 struct mi_root *init_mi_tree(unsigned int code, char *reason, int reason_len)
46 {
47         struct mi_root *root;
48
49         if (use_shm)
50                 root = (struct mi_root *)shm_malloc(sizeof(struct mi_root));
51         else
52                 root = (struct mi_root *)mi_malloc(sizeof(struct mi_root));
53         if (!root) {
54                 LM_ERR("no more pkg mem\n");
55                 return NULL;
56         }
57
58         memset(root,0,sizeof(struct mi_root));
59         root->node.next = root->node.last = &root->node;
60
61         if (reason && reason_len) {
62                 root->reason.s = reason;
63                 root->reason.len = reason_len;
64         }
65         root->code = code;
66
67         return root;
68 }
69
70
71 static void free_mi_node(struct mi_node *parent)
72 {
73         struct mi_node *p, *q;
74
75         for(p = parent->kids ; p ; ){
76                 q = p;
77                 p = p->next;
78                 free_mi_node(q);
79         }
80
81         if (use_shm) {
82                 shm_free(parent);
83         } else {
84                 del_mi_attr_list(parent);
85                 mi_free(parent);
86         }
87 }
88
89 void free_mi_tree(struct mi_root *parent)
90 {
91         struct mi_node *p, *q;
92
93         for(p = parent->node.kids ; p ; ){
94                 q = p;
95                 p = p->next;
96                 free_mi_node(q);
97         }
98
99         if (use_shm)
100                 shm_free(parent);
101         else
102                 mi_free(parent);
103 }
104
105
106 static inline struct mi_node *create_mi_node(char *name, int name_len,
107                                                                         char *value, int value_len, int flags)
108 {
109         struct mi_node *new;
110         int size_mem;
111         int name_pos;
112         int value_pos;
113
114         if (!name) name_len=0;
115         if (!name_len) name=0;
116         if (!value) value_len=0;
117         if (!value_len) value=0;
118
119         if (!name && !value)
120                 return NULL;
121
122         size_mem = sizeof(struct mi_node);
123         value_pos = name_pos = 0;
124
125         if (name && (flags & MI_DUP_NAME)){
126                 name_pos = size_mem;
127                 size_mem += name_len;
128         }
129         if (value && (flags & MI_DUP_VALUE)){
130                 value_pos = size_mem;
131                 size_mem += value_len;
132         }
133
134         if (use_shm)
135                 new = (struct mi_node *)shm_malloc(size_mem);
136         else
137                 new = (struct mi_node *)mi_malloc(size_mem);
138         if(!new) {
139                 LM_ERR("no more pkg mem\n");
140                 return NULL;
141         }
142         memset(new,0,size_mem);
143
144         if (name) {
145                 new->name.len = name_len;
146                 if(flags & MI_DUP_NAME){
147                         new->name.s = ((char *)new) + name_pos;
148                         strncpy(new->name.s, name, name_len);
149                 } else{
150                         new->name.s = name;
151                 }
152         }
153
154         if (value) {
155                 new->value.len = value_len;
156                 if(flags & MI_DUP_VALUE){
157                         new->value.s = ((char *)new) + value_pos;
158                         strncpy(new->value.s, value, value_len);
159                 }else{
160                         new->value.s = value;
161                 }
162         }
163         new->last = new;
164
165         return new;
166 }
167
168
169 static inline struct mi_node *add_next(struct mi_node *brother,
170                         char *name, int name_len, char *value, int value_len, int flags)
171 {
172         struct mi_node *new;
173
174         if(!brother)
175                 return NULL;
176         
177         new = create_mi_node(name, name_len, value, value_len, flags);
178         if(!new)
179                 return NULL;
180
181         brother->last->next = new;
182         brother->last = new;
183
184         return new;
185 }
186
187
188 struct mi_node *add_mi_node_sibling( struct mi_node *brother, int flags,
189                                                 char *name, int name_len, char *value, int value_len)
190 {
191         return add_next(brother, name, name_len, value, value_len, flags);
192 }
193
194
195 struct mi_node *addf_mi_node_sibling(struct mi_node *brother, int flags,
196                                                         char *name, int name_len, char *fmt_val, ...)
197 {
198         va_list ap;
199         char *p;
200         int  len;
201
202         va_start(ap, fmt_val);
203         p = mi_print_fmt( fmt_val, ap, &len);
204         va_end(ap);
205         if (p==NULL)
206                 return 0;
207         return add_mi_node_sibling( brother, flags|MI_DUP_VALUE,
208                 name, name_len, p, len);
209 }
210
211
212 struct mi_node *add_mi_node_child( struct mi_node *parent, int flags,
213                                                 char *name, int name_len, char *value, int value_len)
214 {
215         if(parent->kids){
216                 return add_next(parent->kids, name, name_len, value, value_len, flags);
217         }else{
218                 parent->kids = create_mi_node(name, name_len, value, value_len, flags);
219                 return parent->kids;
220         }
221 }
222
223
224 struct mi_node *addf_mi_node_child(struct mi_node *parent, int flags,
225                                                         char *name, int name_len, char *fmt_val, ...)
226 {
227         va_list ap;
228         char *p;
229         int  len;
230
231         va_start(ap, fmt_val);
232         p = mi_print_fmt( fmt_val, ap, &len);
233         va_end(ap);
234         if (p==NULL)
235                 return 0;
236         return add_mi_node_child( parent, flags|MI_DUP_VALUE,
237                 name, name_len, p, len);
238 }
239
240
241 static int clone_mi_node(struct mi_node *org, struct mi_node *parent)
242 {
243         struct mi_node *p, *q;
244
245         for(p = org->kids ; p ; p=p->next){
246                 q = add_mi_node_child( parent, MI_DUP_VALUE|MI_DUP_NAME,
247                         p->name.s, p->name.len, p->value.s, p->value.len);
248                 if (q==NULL)
249                         return -1;
250                 if (clone_mi_node( p, q)!=0)
251                         return -1;
252         }
253         return 0;
254 }
255
256
257 struct mi_root* clone_mi_tree(struct mi_root *org, int shm)
258 {
259         struct mi_root *root;
260
261         use_shm = shm?1:0;
262
263         root = init_mi_tree( org->code, org->reason.s, org->reason.len);
264         if (root==NULL)
265                 goto done;
266
267         if (clone_mi_node( &(org->node), &(root->node) )!=0 ) {
268                 free_mi_tree(root);
269                 root = NULL;
270                 goto done;
271         }
272
273 done:
274         use_shm=0;
275         return root;
276 }
277
278
279
280 void free_shm_mi_tree(struct mi_root *parent)
281 {
282         use_shm = 1;
283         free_mi_tree(parent);
284         use_shm = 0;
285 }