1 /*
2 *
3 ***** BEGIN LICENSE BLOCK *****
4
5 Copyright (C) 2009-2016 Olof Hagsand and Benny Holmgren
6 Copyright (C) 2017-2019 Olof Hagsand
7 Copyright (C) 2020 Olof Hagsand and Rubicon Communications, LLC(Netgate)
8
9 This file is part of CLIXON.
10
11 Licensed under the Apache License, Version 2.0 (the "License");
12 you may not use this file except in compliance with the License.
13 You may obtain a copy of the License at
14
15 http://www.apache.org/licenses/LICENSE-2.0
16
17 Unless required by applicable law or agreed to in writing, software
18 distributed under the License is distributed on an "AS IS" BASIS,
19 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 See the License for the specific language governing permissions and
21 limitations under the License.
22
23 Alternatively, the contents of this file may be used under the terms of
24 the GNU General Public License Version 3 or later (the "GPL"),
25 in which case the provisions of the GPL are applicable instead
26 of those above. If you wish to allow use of your version of this file only
27 under the terms of the GPL, and not to allow others to
28 use your version of this file under the terms of Apache License version 2,
29 indicate your decision by deleting the provisions above and replace them with
30 the notice and other provisions required by the GPL. If you do not delete
31 the provisions above, a recipient may use your version of this file under
32 the terms of any one of the Apache License version 2 or the GPL.
33
34 ***** END LICENSE BLOCK *****
35
36 * Clixon XML object vectors
37 */
38
39 #ifdef HAVE_CONFIG_H
40 #include "clixon_config.h" /* generated by config & autoconf */
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdint.h>
46 #include <inttypes.h>
47 #include <unistd.h>
48 #include <errno.h>
49 #include <string.h>
50 #include <limits.h>
51 #include <assert.h>
52
53 /* cligen */
54 #include <cligen/cligen.h>
55
56 /* clixon */
57 #include "clixon_err.h"
58 #include "clixon_string.h"
59 #include "clixon_queue.h"
60 #include "clixon_hash.h"
61 #include "clixon_handle.h"
62 #include "clixon_log.h"
63 #include "clixon_yang.h"
64 #include "clixon_xml.h"
65 #include "clixon_xml_io.h"
66 #include "clixon_xml_vec.h"
67
68 //typedef struct clixon_xml_vec clixon_xvec; /* struct defined in clicon_xml_vec.c */
69
70 /* How many XML children to start with if any (and then add exponentialy) */
71 #define XVEC_MAX_DEFAULT 4 /* start value */
72 #define XVEC_MAX_THRESHOLD 1024 /* exponential growth to here, then linear */
73
74 /*! Clixon xml vector concrete implementaion of the abstract clixon_xvec type
75 * Contiguous vector (not linked list) so that binary search can be done by direct index access
76 */
77 struct clixon_xml_vec {
78 cxobj **xv_vec; /* Sorted vector of xml object pointers */
79 int xv_len; /* Length of vector */
80 int xv_max; /* Vector allocation */
81 };
82
83 /*! Increment cxobj vector in an XML object vector
84 *
85 * Exponential growth to a threshold, then linear
86 * @param[in] xv XML tree vector
87 * @retval 0 OK
88 * @retval -1 Error
89 */
90 static int
clixon_xvec_inc(clixon_xvec * xv)91 clixon_xvec_inc(clixon_xvec *xv)
92 {
93 int retval = -1;
94
95 xv->xv_len++;
96 if (xv->xv_len > xv->xv_max){
97 if (xv->xv_max < XVEC_MAX_DEFAULT)
98 xv->xv_max = XVEC_MAX_DEFAULT;
99 else if (xv->xv_max < XVEC_MAX_THRESHOLD)
100 xv->xv_max *= 2; /* Double the space - exponential */
101 else
102 xv->xv_max += XVEC_MAX_THRESHOLD; /* Add - linear growth */
103 if ((xv->xv_vec = realloc(xv->xv_vec, sizeof(cxobj *) * xv->xv_max)) == NULL){
104 clicon_err(OE_XML, errno, "realloc");
105 goto done;
106 }
107 }
108 retval = 0;
109 done:
110 return retval;
111 }
112
113 /*! Create new XML object vector
114 *
115 * Exponential growth to a threshold, then linear
116 * @param[in] xv XML tree vector
117 * @retval 0 OK
118 * @retval -1 Error
119 */
120 clixon_xvec *
clixon_xvec_new(void)121 clixon_xvec_new(void)
122 {
123 clixon_xvec *xv = NULL;
124
125 if ((xv = malloc(sizeof(*xv))) == NULL){
126 clicon_err(OE_UNIX, errno, "malloc");
127 goto done;
128 }
129 memset(xv, 0, sizeof(*xv));
130 xv->xv_len = 0;
131 xv->xv_max = 0;
132
133 done:
134 return xv;
135 }
136
137 /*! Create and copy XML vector
138 *
139 * @param[in] xv0 XML tree vector
140 * @retval xv1 Duplicated XML vector
141 * @retval NULL Error
142 */
143 clixon_xvec *
clixon_xvec_dup(clixon_xvec * xv0)144 clixon_xvec_dup(clixon_xvec *xv0)
145 {
146 clixon_xvec *xv1 = NULL; /* retval */
147
148 if ((xv1 = clixon_xvec_new()) == NULL)
149 goto done;
150 *xv1 = *xv0;
151 xv1->xv_vec = NULL;
152 if (xv1->xv_max &&
153 (xv1->xv_vec = calloc(xv1->xv_max, sizeof(cxobj*))) == NULL){
154 clicon_err(OE_UNIX, errno, "calloc");
155 free(xv1);
156 xv1 = NULL;
157 goto done;
158 }
159 memcpy(xv1->xv_vec, xv0->xv_vec, xv0->xv_len*sizeof(cxobj*));
160 done:
161 return xv1;
162 }
163
164 /*! Free XML object list
165 */
166 int
clixon_xvec_free(clixon_xvec * xv)167 clixon_xvec_free(clixon_xvec *xv)
168 {
169 if (xv->xv_vec)
170 free(xv->xv_vec);
171 if (xv)
172 free(xv);
173 return 0;
174 }
175
176 /*! Return length of XML object list
177 * @param[in] xv XML tree vector
178 * @retval len Length of XML object vector
179 */
180 int
clixon_xvec_len(clixon_xvec * xv)181 clixon_xvec_len(clixon_xvec *xv)
182 {
183 return xv->xv_len;
184 }
185
186 /*! Return i:th XML object in XML object vector
187 * @param[in] xv XML tree vector
188 * @retval x OK
189 * @retval NULL Not found
190 */
191 cxobj*
clixon_xvec_i(clixon_xvec * xv,int i)192 clixon_xvec_i(clixon_xvec *xv,
193 int i)
194 {
195 if (i < xv->xv_len)
196 return xv->xv_vec[i];
197 else
198 return NULL;
199 }
200
201 /*! Return whole XML object vector and null it in original xvec, essentially moving it
202 *
203 * Used in glue code between clixon_xvec code and cxobj **, size_t code, may go AWAY?
204 * @param[in] xv XML tree vector
205 * @param[out] xvec XML object vector
206 * @retval 0 OK
207 * @retval -1 Error
208 */
209 int
clixon_xvec_extract(clixon_xvec * xv,cxobj *** xvec,int * xlen)210 clixon_xvec_extract(clixon_xvec *xv,
211 cxobj ***xvec,
212 int *xlen)
213 {
214 int retval = -1;
215
216 if (xv == NULL){
217 clicon_err(OE_XML, EINVAL, "xv is NULL");
218 goto done;
219 }
220 *xvec = xv->xv_vec;
221 *xlen = xv->xv_len;
222 if (xv->xv_vec != NULL){
223 xv->xv_len = 0;
224 xv->xv_max = 0;
225 xv->xv_vec = NULL;
226 }
227 retval = 0;
228 done:
229 return retval;
230 }
231
232 /*! Append a new xml tree to an existing xml vector last in the list
233 *
234 * @param[in] xv XML tree vector
235 * @param[in] x XML tree (append this to vector)
236 * @retval 0 OK
237 * @retval -1 Error
238 * @code
239 * if (clixon_xvec_append(xv, x) < 0)
240 * err;
241 * @endcode
242 * @see clixon_cxvec_prepend
243 */
244 int
clixon_xvec_append(clixon_xvec * xv,cxobj * x)245 clixon_xvec_append(clixon_xvec *xv,
246 cxobj *x)
247
248 {
249 int retval = -1;
250
251 if (clixon_xvec_inc(xv) < 0)
252 goto done;
253 xv->xv_vec[xv->xv_len-1] = x;
254 retval = 0;
255 done:
256 return retval;
257 }
258
259 /*! Prepend a new xml tree to an existing xml vector first in the list
260 *
261 * @param[in] xv XML tree vector
262 * @param[in] x XML tree (append this to vector)
263 * @retval 0 OK
264 * @retval -1 Error
265 * @code
266 * if (clixon_xvec_prepend(xv, x) < 0)
267 * err;
268 * @endcode
269 * @see clixon_cxvec_append
270 */
271 int
clixon_xvec_prepend(clixon_xvec * xv,cxobj * x)272 clixon_xvec_prepend(clixon_xvec *xv,
273 cxobj *x)
274 {
275 int retval = -1;
276
277 if (clixon_xvec_inc(xv) < 0)
278 goto done;
279 memmove(&xv->xv_vec[1], &xv->xv_vec[0], sizeof(cxobj *) * (xv->xv_len-1));
280 xv->xv_vec[0] = x;
281 retval = 0;
282 done:
283 return retval;
284 }
285
286 /*! Insert XML node x at position i in XML object vector
287 *
288 * @param[in] xv XML tree vector
289 * @param[in] x XML tree (append this to vector)
290 * @param[in] i Position
291 * @retval 0 OK
292 * @retval -1 Error
293 */
294 int
clixon_xvec_insert_pos(clixon_xvec * xv,cxobj * x,int i)295 clixon_xvec_insert_pos(clixon_xvec *xv,
296 cxobj *x,
297 int i)
298 {
299 int retval = -1;
300 size_t size;
301
302 if (clixon_xvec_inc(xv) < 0)
303 goto done;
304 size = (xv->xv_len - i -1)*sizeof(cxobj *);
305 memmove(&xv->xv_vec[i+1], &xv->xv_vec[i], size);
306 xv->xv_vec[i] = x;
307 retval = 0;
308 done:
309 return retval;
310 }
311
312 /*! Remove XML node x from position i in XML object vector
313 *
314 * @param[in] xv XML tree vector
315 * @param[in] i Position
316 * @retval 0 OK
317 * @retval -1 Error
318 */
319 int
clixon_xvec_rm_pos(clixon_xvec * xv,int i)320 clixon_xvec_rm_pos(clixon_xvec *xv,
321 int i)
322 {
323 size_t size;
324
325 size = (xv->xv_len - i + 1)*sizeof(cxobj *);
326 memmove(&xv->xv_vec[i], &xv->xv_vec[i+1], size);
327 xv->xv_len--;
328 return 0;
329 }
330
331 /*! Print an XML object vector to an output stream and encode chars "<>&"
332 *
333 * @param[in] f UNIX output stream
334 * @param[in] xv XML tree vector
335 * @retval 0 OK
336 */
337 int
clixon_xvec_print(FILE * f,clixon_xvec * xv)338 clixon_xvec_print(FILE *f,
339 clixon_xvec *xv)
340 {
341 int i;
342
343 for (i=0; i<xv->xv_len; i++)
344 clicon_xml2file(f, xv->xv_vec[i], 0, 1);
345 return 0;
346 }
347
348