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