Update the liveinfo
[apps/livebox/data-provider-master.git] / util_liveinfo / src / node.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5
6 #include "node.h"
7
8 struct node {
9         char *name;
10         enum node_type type;
11
12         void *data;
13
14         struct node *parent;
15         unsigned char mode;
16         int age;
17
18         struct {
19                 struct node *next;
20                 struct node *prev;
21         } sibling;
22
23         struct node *child;
24 };
25
26 int errno; /* External symbol */
27
28 char *node_to_abspath(const struct node *node)
29 {
30         char *path;
31         char *ptr;
32         const struct node *tmp;
33         int len = 0;
34
35         tmp = node;
36         while (tmp && node_name(tmp)) {
37                 len += strlen(node_name(tmp)) + 1; /* trail '/' */
38                 tmp = node_parent(tmp);
39         }
40
41         path = malloc(len + 3); /* '/' and '\0' */
42         if (!path)
43                 return NULL;
44
45         if (!len) {
46                 path[0] = '/';
47                 path[1] = '\0';
48         } else {
49                 ptr = path + len + 1;
50                 *ptr = '\0';
51                 ptr--;
52                 *ptr = '/';
53                 tmp = node;
54                 while (tmp && node_name(tmp)) {
55                         ptr -= (strlen(node_name(tmp)) + 1);
56                         *ptr = '/';
57                         strncpy(ptr + 1, node_name(tmp), strlen(node_name(tmp)));
58                         tmp = node_parent(tmp);
59                 }
60         }
61
62         return path;
63 }
64
65 static inline int next_state(int from, char ch)
66 {
67         switch ( ch )
68         {
69                 case '\0':
70                 case '/':
71                         return 1;
72                 case '.':
73                         if ( from == 1 ) return 2;
74                         if ( from == 2 ) return 3;
75         }
76
77         return 4;
78 }
79
80 static inline void abspath(const char* pBuffer, char* pRet)
81 {
82         int idx=0;
83         int state = 1;
84         int from;
85         int src_idx = 0;
86         int src_len = strlen(pBuffer);
87         pRet[idx] = '/';
88         idx ++;
89
90         while (src_idx <= src_len) {
91                 from = state;
92                 state = next_state(from, pBuffer[src_idx]);
93
94                 switch (from) {
95                         case 1:
96                                 if ( state != 1 ) {
97                                         pRet[idx] = pBuffer[src_idx];
98                                         idx ++;
99                                 }
100                                 break;
101                         case 2:
102                                 if ( state == 1 ) {
103                                         if ( idx > 1 ) idx --;
104                                 } else {
105                                         pRet[idx] = pBuffer[src_idx];
106                                         idx ++;
107                                 }
108                                 break;
109                         case 3:
110                                 // Only can go to the 1 or 4
111                                 if ( state == 1 ) {
112                                         idx -= 2;
113                                         if ( idx < 1 ) idx = 1;
114
115                                         while ( idx > 1 && pRet[idx] != '/' ) idx --; /* Remove .. */
116                                         if ( idx > 1 && pRet[idx] == '/' ) idx --;
117                                         while ( idx > 1 && pRet[idx] != '/' ) idx --; /* Remove parent folder */
118                                 }
119                         case 4:
120                                 pRet[idx] = pBuffer[src_idx];
121                                 idx ++;
122                                 break;
123                 }
124
125                 pRet[idx] = '\0';
126                 src_idx ++;
127         }
128 }
129
130 struct node *node_find(const struct node *node, const char *path)
131 {
132         int len = 0;
133         char *ptr;
134         char *buffer;
135
136         if (*path != '/') {
137                 while (node->parent && path[0] == '.' && path[1] == '.') {
138                         if (path[2] != '/' && path[2] != '\0')
139                                 break;
140
141                         path += 2;
142                         path += (path[2] == '/');
143                         node = node->parent;
144                 }
145         }
146
147         buffer = malloc(strlen(path) + 3); /* add 2 more bytes */
148         if (!buffer) {
149                 printf("Error: %s\n", strerror(errno));
150                 return NULL;
151         }
152
153         abspath(path, buffer);
154
155         ptr = buffer;
156         do {
157                 ptr += (*ptr == '/');
158                 for (len = 0; ptr[len] && ptr[len] != '/'; len++);
159                 if (!len)
160                         break;
161
162                 if (!strncmp("..", ptr, len)) {
163                         ptr += len;
164                         node = node->parent ? node->parent : node;
165                         continue;
166                 }
167
168                 if (!strncmp(".", ptr, len)) {
169                         ptr += len;
170                         continue;
171                 }
172
173                 node = node->child;
174                 if (!node)
175                         break;
176
177                 while (node) {
178                         if (!strncmp(node->name, ptr, len) && node->name[len] == '\0') {
179                                 ptr += len;
180                                 break;
181                         }
182
183                         node = node->sibling.next;
184                 }
185         } while (*ptr && node);
186
187         free(buffer);
188         return (struct node *)node;
189 }
190
191 struct node *node_create(struct node *parent, const char *name, enum node_type type)
192 {
193         struct node *node;
194
195         node = malloc(sizeof(*node));
196         if (!node) {
197                 printf("Error: %s\n", strerror(errno));
198                 return NULL;
199         }
200
201         node->parent = parent;
202
203         if (name) {
204                 node->name = strdup(name);
205                 if (!node->name) {
206                         printf("Error: %s\n", strerror(errno));
207                         return NULL;
208                 }
209         } else {
210                 node->name = NULL;
211         }
212
213         node->type = type;
214
215         node->sibling.next = NULL;
216         node->sibling.prev = NULL;
217
218         node->child = NULL;
219         node->data = NULL;
220
221         if (parent) {
222                 if (parent->child) {
223                         struct node *tmp;
224                         tmp = parent->child;
225                         while (tmp->sibling.next)
226                                 tmp = tmp->sibling.next;
227
228                         tmp->sibling.next = node;
229                         node->sibling.prev = tmp;
230                 } else {
231                         parent->child = node;
232                 }
233         }
234         return node;
235 }
236
237 void *node_destroy(struct node *node)
238 {
239         void *data;
240
241         data = node->data;
242         free(node->name);
243         free(node);
244
245         return data;
246 }
247
248 void node_delete(struct node *node, void (del_cb)(struct node *node))
249 {
250         struct node *tmp;
251         struct node *next;
252         struct node *parent;
253
254         if (node->sibling.prev)
255                 node->sibling.prev->sibling.next = node->sibling.next;
256
257         if (node->sibling.next)
258                 node->sibling.next->sibling.prev = node->sibling.prev;
259
260         if (node->parent) {
261                 node->parent->child = NULL;
262                 node->parent = NULL;
263         }
264
265         tmp = node;
266         while (tmp) {
267                 while (tmp->child) tmp = tmp->child;
268
269                 parent = tmp->parent;
270                 next = tmp->sibling.next;
271
272                 if (del_cb)
273                         del_cb(tmp);
274
275                 node_destroy(tmp);
276
277                 if (next)
278                         tmp = next;
279                 else if (parent)
280                         tmp = parent;
281                 else
282                         tmp = NULL;
283         }
284 }
285
286 struct node * const node_next_sibling(const struct node *node)
287 {
288         return node->sibling.next;
289 }
290
291 struct node * const node_prev_sibling(const struct node *node)
292 {
293         return node->sibling.prev;
294 }
295
296 void node_set_mode(struct node *node, int mode)
297 {
298         node->mode = mode;
299 }
300
301 void node_set_data(struct node *node, void *data)
302 {
303         node->data = data;
304 }
305
306 void node_set_type(struct node *node, enum node_type type)
307 {
308         node->type = type;
309 }
310
311 struct node * const node_child(const struct node *node)
312 {
313         return node->child;
314 }
315
316 struct node * const node_parent(const struct node *node)
317 {
318         return node->parent;
319 }
320
321 const int const node_mode(const struct node *node)
322 {
323         return node->mode;
324 }
325
326 void * const node_data(const struct node *node)
327 {
328         return node->data;
329 }
330
331 const enum node_type const node_type(const struct node *node)
332 {
333         return node->type;
334 }
335
336 const char * const node_name(const struct node *node)
337 {
338         return node->name;
339 }
340
341 void node_set_age(struct node *node, int age)
342 {
343         node->age = age;
344 }
345
346 int node_age(struct node *node)
347 {
348         return node->age;
349 }
350
351 /* End of a file */