blob: aefe0fee8fd3eebff24e492faed60155a98b8e16 [file] [log] [blame]
Daniel Lezcanoc193b602011-06-08 23:30:00 +02001/*******************************************************************************
2 * Copyright (C) 2010, Linaro Limited.
3 *
4 * This file is part of PowerDebug.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of the Eclipse Public License v1.0
8 * which accompanies this distribution, and is available at
9 * http://www.eclipse.org/legal/epl-v10.html
10 *
11 * Author:
12 * Daniel Lezcano <daniel.lezcano@linaro.org>
13 *
14 *******************************************************************************/
15
16#define _GNU_SOURCE
17#include <stdio.h>
18#undef _GNU_SOURCE
19#include <stdlib.h>
20#include <string.h>
21#include <dirent.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <unistd.h>
25
26#include "tree.h"
27
28/*
29 * Allocate a tree structure and initialize the different fields.
30 *
31 * @path : the absolute path to the directory
32 * @depth : the depth in the tree
33 * Returns a tree structure on success, NULL otherwise
34 */
35static inline struct tree *tree_alloc(const char *path, int depth)
36{
37 struct tree *t;
38
39 t = malloc(sizeof(*t));
40 if (!t)
41 return NULL;
42
43 /* Full pathname */
44 t->path = strdup(path);
45 if (!t->path) {
46 free(t);
47 return NULL;
48 }
49
50 /* Basename pointer on the full path name */
51 t->name = strrchr(t->path, '/') + 1;
52
53 t->depth = depth;
54 t->tail = t;
55 t->child = NULL;
56 t->parent = NULL;
57 t->next = NULL;
58 t->prev = NULL;
59 t->private = NULL;
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +020060 t->nrchild = 0;
Daniel Lezcanoc193b602011-06-08 23:30:00 +020061
62 return t;
63}
64
65/*
66 * Free a tree structure and the fields we allocated in the
67 * tree_alloc function.
68 *
69 * @t : the tree structure to be freed
70 */
71static inline void tree_free(struct tree *t)
72{
73 free(t->path);
74 free(t);
75}
76
77/*
78 * Add at the end of the list the new list element.
79 *
80 * @head : the list to be appened
81 * @new : the new element to be added at the end of the list
82 */
83static inline void tree_add_tail(struct tree *head, struct tree *new)
84{
85 new->prev = head->tail;
86 head->tail->next = new;
87 head->tail = new;
88}
89
90/*
91 * Add a child in to a parent list, at the end of this list.
92 *
93 * @parent : the parent list to add the child
94 * @child : the child to be added
95 */
96static inline void tree_add_child(struct tree *parent, struct tree *child)
97{
98 child->parent = parent;
99
100 if (parent->child)
101 return tree_add_tail(parent->child, child);
102
103 parent->child = child;
104}
105
106/*
107 * This function will browse the directory structure and build a
108 * tree reflecting the content of the directory tree.
109 *
110 * @tree : the root node of the tree
111 * @filter : a callback to filter out the directories
112 * Returns 0 on success, -1 otherwise
113 */
114static int tree_scan(struct tree *tree, tree_filter_t filter)
115{
116 DIR *dir;
117 char *basedir, *newpath;
118 struct dirent dirent, *direntp;
119 struct stat s;
120 int ret = 0;
121
122 dir = opendir(tree->path);
123 if (!dir)
124 return -1;
125
126 while (!readdir_r(dir, &dirent, &direntp)) {
127
128 struct tree *child;
129
130 if (!direntp)
131 break;
132
133 if (direntp->d_name[0] == '.')
134 continue;
135
136 if (filter && filter(direntp->d_name))
137 continue;
138
139 ret = asprintf(&basedir, "%s", tree->path);
140 if (ret < 0)
141 return -1;
142
143 ret = basename(basedir) ? 0 : -1;
144 if (ret < 0)
145 goto out_free_basedir;
146
147 ret = asprintf(&newpath, "%s/%s", basedir, direntp->d_name);
148 if (ret < 0)
149 goto out_free_basedir;
150
151 ret = stat(newpath, &s);
152 if (ret)
153 goto out_free_newpath;
154
155 if (S_ISDIR(s.st_mode)) {
156
157 ret = -1;
158
159 child = tree_alloc(newpath, tree->depth + 1);
160 if (!child)
161 goto out_free_newpath;
162
163 tree_add_child(tree, child);
164
Daniel Lezcanocb86e1d2011-06-08 23:30:01 +0200165 tree->nrchild++;
166
Daniel Lezcanoc193b602011-06-08 23:30:00 +0200167 ret = tree_scan(child, filter);
168 }
169
170 out_free_newpath:
171 free(newpath);
172
173 out_free_basedir:
174 free(basedir);
175
176 if (ret)
177 break;
178 }
179
180 closedir(dir);
181
182 return ret;
183}
184
185/*
186 * This function takes the topmost directory path and populate the
187 * directory tree structures.
188 *
189 * @tree : a path to the topmost directory path
190 * Returns a tree structure corresponding to the root node of the
191 * directory tree representation on success, NULL otherwise
192 */
193struct tree *tree_load(const char *path, tree_filter_t filter)
194{
195 struct tree *tree;
196
197 tree = tree_alloc(path, 0);
198 if (!tree)
199 return NULL;
200
201 if (tree_scan(tree, filter)) {
202 tree_free(tree);
203 return NULL;
204 }
205
206 return tree;
207}
208
209/*
210 * This function will go over the tree passed as parameter and
211 * will call the callback passed as parameter for each node.
212 *
213 * @tree : the topmost node where we begin to browse the tree
214 * Returns 0 on success, < 0 otherwise
215 */
216int tree_for_each(struct tree *tree, tree_cb_t cb, void *data)
217{
218 if (!tree)
219 return 0;
220
221 if (cb(tree, data))
222 return -1;
223
224 if (tree_for_each(tree->child, cb, data))
225 return -1;
226
227 return tree_for_each(tree->next, cb, data);
228}
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200229
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200230/*
231 * This function will go over the tree passed as parameter at the reverse
232 * order and will call the callback passed as parameter for each.
233 * @tree : the lower node where we begin to browse the tree at the reverse
234 * order
235 * cb : a callback for each node the function will go over
236 * data : some private data to be passed across the callbacks
237 * Returns 0 on success, < 0 otherwise
238 */
Daniel Lezcano6d42e812011-06-08 23:30:01 +0200239int tree_for_each_reverse(struct tree *tree, tree_cb_t cb, void *data)
240{
241 if (!tree)
242 return 0;
243
244 if (cb(tree, data))
245 return -1;
246
247 if (tree_for_each_reverse(tree->prev, cb, data))
248 return -1;
249
250 return tree_for_each_reverse(tree->parent, cb, data);
251}
252
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200253
254/*
255 * The function will go over all the parent of the specified node passed
256 * as parameter.
257 * @tree : the child node from where we back path to the parent
258 * cb : a callback for each node the function will go over
259 * data : some private data to be passed across the callbacks
260 * Returns 0 on success, < 0 otherwise
261 */
Daniel Lezcanoafe62252011-06-08 23:30:00 +0200262int tree_for_each_parent(struct tree *tree, tree_cb_t cb, void *data)
263{
264 if (!tree)
265 return 0;
266
267 if (tree_for_each_parent(tree->parent, cb, data))
268 return -1;
269
270 return cb(tree, data);
271}
272
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200273/*
274 * The function will return the first node which match with the name as
275 * parameter.
276 * @tree : the tree where we begin to find
277 * @name : the name of the node the function must look for.
278 * Returns a pointer to the tree structure if found, NULL otherwise.
279 */
Daniel Lezcano357dd8a2011-06-08 23:30:00 +0200280struct tree *tree_find(struct tree *tree, const char *name)
281{
282 struct tree *t;
283
284 if (!tree)
285 return NULL;
286
287 if (!strcmp(tree->name, name))
288 return tree;
289
290 t = tree_find(tree->child, name);
291 if (t)
292 return t;
293
294 return tree_find(tree->next, name);
295}
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200296
297struct struct_find {
298 int nr;
299 const char *name;
300 struct tree ***ptree;
301};
302
303static int tree_finds_cb(struct tree *tree, void *data)
304{
305 struct struct_find *sf = data;
306
Daniel Lezcano528bb3f2011-06-21 00:57:08 +0200307 if (!strlen(sf->name))
308 return 0;
309
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200310 if (strncmp(sf->name, tree->name, strlen(sf->name)))
311 return 0;
312
313 if (sf->ptree)
314 (*(sf->ptree))[sf->nr] = tree;
315
316 sf->nr++;
317
318 return 0;
319}
320
Daniel Lezcano02f8f402011-06-08 23:30:01 +0200321/*
322 * This function will search for all the nodes where the name begin
323 * with the name passed as parameter. *Note* the function allocates
324 * the array, it is up to the caller to free this array.
325 * @tree : the topmost node of the tree where we being to search
326 * @name : the name to find in the tree
327 * @ptr : a pointer to a pointer of pointer of tree structure :)
328 * Returns the number of elements found in the tree, < 0 if something
329 * went wrong.
330 */
Daniel Lezcanofabe20a2011-06-08 23:30:01 +0200331int tree_finds(struct tree *tree, const char *name, struct tree ***ptr)
332{
333 struct struct_find sf = { .nr = 0, .ptree = NULL, .name = name };
334 int nmatch;
335
336 /* first pass : count # of matching nodes */
337 tree_for_each(tree, tree_finds_cb, &sf);
338
339 /* no match */
340 if (!sf.nr)
341 return 0;
342
343 *ptr = malloc(sizeof(struct tree *) * sf.nr);
344 if (!*ptr)
345 return -1;
346
347 /* store the result as it will be overwritten by the next call */
348 nmatch = sf.nr;
349 sf.nr = 0;
350 sf.ptree = ptr;
351
352 /* second pass : fill with the matching nodes */
353 tree_for_each(tree, tree_finds_cb, &sf);
354
355 return nmatch;
356}