1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 #include <Inventor/C/XML/path.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif // HAVE_CONFIG_H
38
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #include <cassert>
43
44 #include <Inventor/C/base/string.h>
45 #include <Inventor/C/XML/element.h>
46 #include "utils.h"
47
48 /* ********************************************************************** */
49
50 struct cc_xml_path {
51 struct path_node * head;
52 };
53
54 /* ********************************************************************** */
55
56 struct path_node {
57 char * element;
58 int idx;
59 struct path_node * next;
60 // make list doubly-linked for match_p use?
61 };
62
63 static
64 path_node *
path_node_new(const char * element,int idx)65 path_node_new(const char * element, int idx)
66 {
67 path_node * node = new path_node;
68 node->element = cc_xml_strdup(element);
69 node->idx = idx;
70 node->next = NULL;
71 return node;
72 }
73
74 static
75 path_node *
path_node_clone(path_node * node)76 path_node_clone(path_node * node)
77 {
78 return path_node_new(node->element, node->idx);
79 }
80
81 static
82 path_node *
path_node_delete(path_node * node)83 path_node_delete(path_node * node)
84 {
85 path_node * next;
86 next = node->next;
87 delete[] node->element;
88 delete node;
89 return next;
90 }
91
92 static
93 void
path_node_delete_chain(path_node * head)94 path_node_delete_chain(path_node * head)
95 {
96 while ( head != NULL ) {
97 path_node * prev = head;
98 head = head->next;
99 delete[] prev->element;
100 delete prev;
101 }
102 }
103
104 static
105 int
path_node_match_p(path_node * node,const cc_xml_elt * elt)106 path_node_match_p(path_node * node, const cc_xml_elt * elt)
107 {
108 if ( strcmp(node->element, cc_xml_elt_get_type(elt)) != 0 ) return FALSE;
109 if ( node->idx != -1 ) {
110 cc_xml_elt * parent = cc_xml_elt_get_parent(elt);
111 if ( parent == NULL ) return (node->idx == 0) ? TRUE : FALSE;
112 int i = cc_xml_elt_get_child_type_index(parent, elt);
113 return (i == node->idx) ? TRUE : FALSE;
114 }
115 return TRUE;
116 }
117
118 /* ********************************************************************** */
119
120 cc_xml_path *
cc_xml_path_new(void)121 cc_xml_path_new(void)
122 {
123 cc_xml_path * path = new cc_xml_path;
124 path->head = NULL;
125 assert(path);
126 return path;
127 } // cc_xml_path_new()
128
129 void
cc_xml_path_delete_x(cc_xml_path * path)130 cc_xml_path_delete_x(cc_xml_path * path)
131 {
132 assert(path);
133 path_node_delete_chain(path->head);
134 delete path;
135 } // cc_xml_path_delete_x()
136
137 void
cc_xml_path_clear_x(cc_xml_path * path)138 cc_xml_path_clear_x(cc_xml_path * path)
139 {
140 assert(path);
141 path_node_delete_chain(path->head);
142 path->head = NULL;
143 } // cc_xml_path_clear_x()
144
145 static
146 void
cc_xml_path_set_x_va(cc_xml_path * path,va_list args)147 cc_xml_path_set_x_va(cc_xml_path * path, va_list args)
148 {
149 path_node_delete_chain(path->head);
150 path->head = NULL;
151 char * arg;
152 while ( (arg = va_arg(args, char *)) != NULL ) {
153 char * ptr;
154 if ( (ptr = strchr(arg, '[')) == NULL ) {
155 cc_xml_path_prepend_x(path, arg, -1);
156 } else {
157 int idx = atoi(ptr + 1);
158 assert(idx >= -1);
159 char * str = cc_xml_strndup(arg, static_cast<int>(ptr - arg));
160 cc_xml_path_prepend_x(path, str, idx);
161 delete [] str;
162 }
163 }
164 cc_xml_path_reverse_x(path);
165 } // cc_xml_path_set_x_va()
166
167 void
cc_xml_path_copy_x(cc_xml_path * path,cc_xml_path * path2)168 cc_xml_path_copy_x(cc_xml_path * path, cc_xml_path * path2)
169 {
170 assert(path && path2);
171 cc_xml_path_clear_x(path);
172 path_node * p1node;
173 path_node * p1prev = NULL;
174 path_node * p2node = path2->head;
175 while ( p2node != NULL ) {
176 p1node = path_node_clone(p2node);
177 if ( p1prev == NULL ) path->head = p1node;
178 else p1prev->next = p1node;
179 p1prev = p1node;
180 }
181 } // cc_xml_path_copy_x()
182
183 void
cc_xml_path_set_x(cc_xml_path * path,...)184 cc_xml_path_set_x(cc_xml_path * path, ...)
185 {
186 assert(path);
187 va_list args;
188 va_start(args, path);
189 cc_xml_path_set_x_va(path, args);
190 va_end(args);
191 } // cc_xml_path_set_x()
192
193 void
cc_xml_path_reverse_x(cc_xml_path * path)194 cc_xml_path_reverse_x(cc_xml_path * path)
195 {
196 assert(path);
197 struct path_node * prev = NULL;
198 struct path_node * node = path->head;
199 while ( node != NULL ) {
200 struct path_node * next = node->next;
201 node->next = prev;
202 prev = node;
203 node = next;
204 }
205 path->head = prev;
206 } // cc_xml_path_reverse_x()
207
208 int
cc_xml_path_get_length(const cc_xml_path * path)209 cc_xml_path_get_length(const cc_xml_path * path)
210 {
211 assert(path);
212 int len = 0;
213 struct path_node * node = path->head;
214 while ( node != NULL ) {
215 assert(len < 100);
216 len++;
217 node = node->next;
218 }
219 return len;
220 } // cc_xml_path_get_length()
221
222 const char *
cc_xml_path_get_type(const cc_xml_path * path,int idx)223 cc_xml_path_get_type(const cc_xml_path * path, int idx)
224 {
225 assert(path && path->head && idx >= 0);
226 struct path_node * node = path->head;
227 int i;
228 for ( i = 0; i < idx; i++ ) {
229 assert(node->next != NULL);
230 node = node->next;
231 }
232 return node->element;
233 } // cc_xml_path_get_type()
234
235 int
cc_xml_path_get_index(const cc_xml_path * path,int idx)236 cc_xml_path_get_index(const cc_xml_path * path, int idx)
237 {
238 assert(path && path->head && idx >= 0);
239 struct path_node * node = path->head;
240 int i;
241 for ( i = 0; i < idx; i++ ) {
242 assert(node->next != NULL);
243 node = node->next;
244 }
245 return node->idx;
246 } // cc_xml_path_get_index()
247
248 int
cc_xml_path_match_p(const cc_xml_path * path,const cc_xml_elt * elt)249 cc_xml_path_match_p(const cc_xml_path * path, const cc_xml_elt * elt)
250 {
251 // consider using a doubly-linked list instead of continous head->tail traversal
252 int length = cc_xml_path_get_length(path);
253 struct path_node * head = path->head;
254 int i, j;
255 for ( i = length - 1; i >= 0; i-- ) {
256 struct path_node * node = head;
257 for ( j = 0; j < i; j++ ) {
258 node = node->next;
259 assert(node);
260 }
261 if ( !path_node_match_p(node, elt) ) return FALSE;
262 elt = cc_xml_elt_get_parent(elt);
263 assert(elt);
264 }
265 return TRUE;
266 } // cc_xml_path_match_p()
267
268 void
cc_xml_path_append_x(cc_xml_path * path,const char * elt,int idx)269 cc_xml_path_append_x(cc_xml_path * path, const char * elt, int idx)
270 {
271 assert(path);
272 struct path_node * node = path->head;
273 if ( node == NULL ) {
274 path->head = path_node_new(elt, idx);
275 } else {
276 while ( node->next != NULL )
277 node = node->next;
278 node->next = path_node_new(elt, idx);
279 }
280 } // cc_xml_path_append_x()
281
282 void
cc_xml_path_append_path_x(cc_xml_path * path,cc_xml_path * path2)283 cc_xml_path_append_path_x(cc_xml_path * path, cc_xml_path * path2)
284 {
285 assert(path && path2);
286 struct path_node * p1node = path->head;
287 struct path_node * p1prev = NULL;
288 if ( p1node != NULL ) {
289 while ( p1node->next != NULL ) {
290 p1prev = p1node;
291 p1node = p1node->next;
292 }
293 }
294 struct path_node * p2node = path2->head;
295 while ( p2node != NULL ) {
296 p1node = path_node_clone(p2node);
297 if ( p1prev == NULL ) path->head = p1node;
298 else p1prev->next = p1node;
299 p1prev = p1node;
300 }
301 } // cc_xml_path_append_path_x()
302
303 void
cc_xml_path_prepend_x(cc_xml_path * path,const char * elt,int idx)304 cc_xml_path_prepend_x(cc_xml_path * path, const char * elt, int idx)
305 {
306 assert(path);
307 struct path_node * node = path->head;
308 path->head = path_node_new(elt, idx);
309 path->head->next = node;
310 } // cc_xml_path_prepend_x()
311
312 void
cc_xml_path_prepend_path_x(cc_xml_path * path,cc_xml_path * path2)313 cc_xml_path_prepend_path_x(cc_xml_path * path, cc_xml_path * path2)
314 {
315 assert(path && path2);
316 struct path_node * p1node = NULL;
317 struct path_node * p1head = NULL;
318 struct path_node * p1tail = NULL;
319 struct path_node * p2node = path2->head;
320 while ( p2node != NULL ) {
321 p1tail = path_node_clone(p2node);
322 if ( p1head == NULL ) p1head = p1tail;
323 else p1node->next = p1tail;
324 p1node = p1tail;
325 }
326 if ( p1tail != NULL ) {
327 p1tail->next = path->head;
328 path->head = p1head;
329 }
330 } // cc_xml_path_prepend_path_x()
331
332 void
cc_xml_path_truncate_x(cc_xml_path * path,int length)333 cc_xml_path_truncate_x(cc_xml_path * path, int length)
334 {
335 assert(path);
336 int len = 0;
337 struct path_node * node = path->head;
338 while ( (node != NULL) && (len < length) ) {
339 len++;
340 node = node->next;
341 }
342 if ( node ) {
343 path_node_delete_chain(node->next);
344 node->next = NULL;
345 }
346 } // cc_xml_path_truncate_x()
347
348 /* ********************************************************************** */
349
350 void
cc_xml_path_dump(cc_xml_path * path)351 cc_xml_path_dump(cc_xml_path * path)
352 {
353 assert(path);
354 struct path_node * node = path->head;
355 while ( node != NULL ) {
356 if ( node != path->head )
357 fprintf(stderr, ".");
358 fprintf(stderr, "%s", node->element);
359 if ( node->idx != -1 ) {
360 fprintf(stderr, "[%d]", node->idx);
361 }
362 node = node->next;
363 }
364 fprintf(stderr, "\n");
365 }
366
367 /* ********************************************************************** */
368