1*95f94af3Sandvar /* $NetBSD: prop_array.c,v 1.22 2023/03/26 19:10:32 andvar Exp $ */
2774eb1a3Sthorpej
3774eb1a3Sthorpej /*-
4e835604cSjoerg * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
5774eb1a3Sthorpej * All rights reserved.
6774eb1a3Sthorpej *
7774eb1a3Sthorpej * This code is derived from software contributed to The NetBSD Foundation
8774eb1a3Sthorpej * by Jason R. Thorpe.
9774eb1a3Sthorpej *
10774eb1a3Sthorpej * Redistribution and use in source and binary forms, with or without
11774eb1a3Sthorpej * modification, are permitted provided that the following conditions
12774eb1a3Sthorpej * are met:
13774eb1a3Sthorpej * 1. Redistributions of source code must retain the above copyright
14774eb1a3Sthorpej * notice, this list of conditions and the following disclaimer.
15774eb1a3Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
16774eb1a3Sthorpej * notice, this list of conditions and the following disclaimer in the
17774eb1a3Sthorpej * documentation and/or other materials provided with the distribution.
18774eb1a3Sthorpej *
19774eb1a3Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20774eb1a3Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21774eb1a3Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22774eb1a3Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23774eb1a3Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24774eb1a3Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25774eb1a3Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26774eb1a3Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27774eb1a3Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28774eb1a3Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29774eb1a3Sthorpej * POSSIBILITY OF SUCH DAMAGE.
30774eb1a3Sthorpej */
31774eb1a3Sthorpej
32774eb1a3Sthorpej #include "prop_object_impl.h"
33c303bcbeSpooka #include <prop/prop_array.h>
34774eb1a3Sthorpej
35d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
36d21620b2Sthorpej #include <errno.h>
37d21620b2Sthorpej #endif
38d21620b2Sthorpej
39774eb1a3Sthorpej struct _prop_array {
40774eb1a3Sthorpej struct _prop_object pa_obj;
41eb2acb85Sthorpej _PROP_RWLOCK_DECL(pa_rwlock)
42774eb1a3Sthorpej prop_object_t * pa_array;
43774eb1a3Sthorpej unsigned int pa_capacity;
44774eb1a3Sthorpej unsigned int pa_count;
45774eb1a3Sthorpej int pa_flags;
46774eb1a3Sthorpej
47774eb1a3Sthorpej uint32_t pa_version;
48774eb1a3Sthorpej };
49774eb1a3Sthorpej
50774eb1a3Sthorpej #define PA_F_IMMUTABLE 0x01 /* array is immutable */
51774eb1a3Sthorpej
52774eb1a3Sthorpej _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
53774eb1a3Sthorpej _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
54774eb1a3Sthorpej "property array container object")
55774eb1a3Sthorpej
564ce0dc3aSthorpej static _prop_object_free_rv_t
574ce0dc3aSthorpej _prop_array_free(prop_stack_t, prop_object_t *);
58e835604cSjoerg static void _prop_array_emergency_free(prop_object_t);
5904377267Sthorpej static bool _prop_array_externalize(
603e69f1b2Sthorpej struct _prop_object_externalize_context *,
613e69f1b2Sthorpej void *);
624ce0dc3aSthorpej static _prop_object_equals_rv_t
634ce0dc3aSthorpej _prop_array_equals(prop_object_t, prop_object_t,
644deb5931Sjoerg void **, void **,
654deb5931Sjoerg prop_object_t *, prop_object_t *);
664deb5931Sjoerg static void _prop_array_equals_finish(prop_object_t, prop_object_t);
674ce0dc3aSthorpej static prop_object_iterator_t
684ce0dc3aSthorpej _prop_array_iterator_locked(prop_array_t);
694ce0dc3aSthorpej static prop_object_t
704ce0dc3aSthorpej _prop_array_iterator_next_object_locked(void *);
7175b1a2ecSyamt static void _prop_array_iterator_reset_locked(void *);
723e69f1b2Sthorpej
733e69f1b2Sthorpej static const struct _prop_object_type _prop_object_type_array = {
743e69f1b2Sthorpej .pot_type = PROP_TYPE_ARRAY,
753e69f1b2Sthorpej .pot_free = _prop_array_free,
76e835604cSjoerg .pot_emergency_free = _prop_array_emergency_free,
773e69f1b2Sthorpej .pot_extern = _prop_array_externalize,
783e69f1b2Sthorpej .pot_equals = _prop_array_equals,
794deb5931Sjoerg .pot_equals_finish = _prop_array_equals_finish,
803e69f1b2Sthorpej };
813e69f1b2Sthorpej
823e69f1b2Sthorpej #define prop_object_is_array(x) \
83beabdd9bSthorpej ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
84774eb1a3Sthorpej
85774eb1a3Sthorpej #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
86774eb1a3Sthorpej
87774eb1a3Sthorpej struct _prop_array_iterator {
88774eb1a3Sthorpej struct _prop_object_iterator pai_base;
89774eb1a3Sthorpej unsigned int pai_index;
90774eb1a3Sthorpej };
91774eb1a3Sthorpej
92774eb1a3Sthorpej #define EXPAND_STEP 16
93774eb1a3Sthorpej
944ce0dc3aSthorpej static _prop_object_free_rv_t
_prop_array_free(prop_stack_t stack,prop_object_t * obj)95e835604cSjoerg _prop_array_free(prop_stack_t stack, prop_object_t *obj)
96774eb1a3Sthorpej {
97e835604cSjoerg prop_array_t pa = *obj;
98774eb1a3Sthorpej prop_object_t po;
99774eb1a3Sthorpej
100774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
101774eb1a3Sthorpej _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
102774eb1a3Sthorpej (pa->pa_capacity != 0 && pa->pa_array != NULL));
103774eb1a3Sthorpej
104e835604cSjoerg /* The easy case is an empty array, just free and return. */
105e835604cSjoerg if (pa->pa_count == 0) {
106774eb1a3Sthorpej if (pa->pa_array != NULL)
107774eb1a3Sthorpej _PROP_FREE(pa->pa_array, M_PROP_ARRAY);
108774eb1a3Sthorpej
109eb2acb85Sthorpej _PROP_RWLOCK_DESTROY(pa->pa_rwlock);
110eb2acb85Sthorpej
111774eb1a3Sthorpej _PROP_POOL_PUT(_prop_array_pool, pa);
112e835604cSjoerg
113e835604cSjoerg return (_PROP_OBJECT_FREE_DONE);
114e835604cSjoerg }
115e835604cSjoerg
116e835604cSjoerg po = pa->pa_array[pa->pa_count - 1];
117e835604cSjoerg _PROP_ASSERT(po != NULL);
118e835604cSjoerg
119e835604cSjoerg if (stack == NULL) {
120e835604cSjoerg /*
121e835604cSjoerg * If we are in emergency release mode,
122e835604cSjoerg * just let caller recurse down.
123e835604cSjoerg */
124e835604cSjoerg *obj = po;
125e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED);
126e835604cSjoerg }
127e835604cSjoerg
128e835604cSjoerg /* Otherwise, try to push the current object on the stack. */
1294deb5931Sjoerg if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
130e835604cSjoerg /* Push failed, entering emergency release mode. */
131e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED);
132e835604cSjoerg }
133e835604cSjoerg /* Object pushed on stack, caller will release it. */
134e835604cSjoerg --pa->pa_count;
135e835604cSjoerg *obj = po;
136e835604cSjoerg return (_PROP_OBJECT_FREE_RECURSE);
137e835604cSjoerg }
138e835604cSjoerg
139e835604cSjoerg static void
_prop_array_emergency_free(prop_object_t obj)140e835604cSjoerg _prop_array_emergency_free(prop_object_t obj)
141e835604cSjoerg {
142e835604cSjoerg prop_array_t pa = obj;
143e835604cSjoerg
144e835604cSjoerg _PROP_ASSERT(pa->pa_count != 0);
145e835604cSjoerg --pa->pa_count;
146774eb1a3Sthorpej }
147774eb1a3Sthorpej
14804377267Sthorpej static bool
_prop_array_externalize(struct _prop_object_externalize_context * ctx,void * v)149774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx,
150774eb1a3Sthorpej void *v)
151774eb1a3Sthorpej {
152774eb1a3Sthorpej prop_array_t pa = v;
153774eb1a3Sthorpej struct _prop_object *po;
154774eb1a3Sthorpej prop_object_iterator_t pi;
155774eb1a3Sthorpej unsigned int i;
15604377267Sthorpej bool rv = false;
157774eb1a3Sthorpej
158eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
159eb2acb85Sthorpej
160eb2acb85Sthorpej if (pa->pa_count == 0) {
161eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
162774eb1a3Sthorpej return (_prop_object_externalize_empty_tag(ctx, "array"));
163eb2acb85Sthorpej }
164774eb1a3Sthorpej
165774eb1a3Sthorpej /* XXXJRT Hint "count" for the internalize step? */
16604377267Sthorpej if (_prop_object_externalize_start_tag(ctx, "array") == false ||
16704377267Sthorpej _prop_object_externalize_append_char(ctx, '\n') == false)
168eb2acb85Sthorpej goto out;
169774eb1a3Sthorpej
17075b1a2ecSyamt pi = _prop_array_iterator_locked(pa);
171774eb1a3Sthorpej if (pi == NULL)
172eb2acb85Sthorpej goto out;
173774eb1a3Sthorpej
174774eb1a3Sthorpej ctx->poec_depth++;
175774eb1a3Sthorpej _PROP_ASSERT(ctx->poec_depth != 0);
176774eb1a3Sthorpej
17775b1a2ecSyamt while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
17804377267Sthorpej if ((*po->po_type->pot_extern)(ctx, po) == false) {
179774eb1a3Sthorpej prop_object_iterator_release(pi);
180eb2acb85Sthorpej goto out;
181774eb1a3Sthorpej }
182774eb1a3Sthorpej }
183774eb1a3Sthorpej
184774eb1a3Sthorpej prop_object_iterator_release(pi);
185774eb1a3Sthorpej
186774eb1a3Sthorpej ctx->poec_depth--;
187774eb1a3Sthorpej for (i = 0; i < ctx->poec_depth; i++) {
18804377267Sthorpej if (_prop_object_externalize_append_char(ctx, '\t') == false)
189eb2acb85Sthorpej goto out;
190774eb1a3Sthorpej }
19104377267Sthorpej if (_prop_object_externalize_end_tag(ctx, "array") == false)
192eb2acb85Sthorpej goto out;
193774eb1a3Sthorpej
19404377267Sthorpej rv = true;
195eb2acb85Sthorpej
196eb2acb85Sthorpej out:
197eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
198eb2acb85Sthorpej return (rv);
199774eb1a3Sthorpej }
200774eb1a3Sthorpej
2014deb5931Sjoerg /* ARGSUSED */
2024ce0dc3aSthorpej static _prop_object_equals_rv_t
_prop_array_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)2034deb5931Sjoerg _prop_array_equals(prop_object_t v1, prop_object_t v2,
2044deb5931Sjoerg void **stored_pointer1, void **stored_pointer2,
2054deb5931Sjoerg prop_object_t *next_obj1, prop_object_t *next_obj2)
2063e69f1b2Sthorpej {
2073e69f1b2Sthorpej prop_array_t array1 = v1;
2083e69f1b2Sthorpej prop_array_t array2 = v2;
2094deb5931Sjoerg uintptr_t idx;
2104ce0dc3aSthorpej _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
2113e69f1b2Sthorpej
2123e69f1b2Sthorpej if (array1 == array2)
2134deb5931Sjoerg return (_PROP_OBJECT_EQUALS_TRUE);
214eb2acb85Sthorpej
2154deb5931Sjoerg _PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
2164deb5931Sjoerg idx = (uintptr_t)*stored_pointer1;
2174deb5931Sjoerg
2184deb5931Sjoerg /* For the first iteration, lock the objects. */
2194deb5931Sjoerg if (idx == 0) {
220eb2acb85Sthorpej if ((uintptr_t)array1 < (uintptr_t)array2) {
221eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
222eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
223eb2acb85Sthorpej } else {
224eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
225eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
226eb2acb85Sthorpej }
2274deb5931Sjoerg }
228eb2acb85Sthorpej
2293e69f1b2Sthorpej if (array1->pa_count != array2->pa_count)
230eb2acb85Sthorpej goto out;
2314deb5931Sjoerg if (idx == array1->pa_count) {
2324ce0dc3aSthorpej rv = _PROP_OBJECT_EQUALS_TRUE;
233eb2acb85Sthorpej goto out;
2343e69f1b2Sthorpej }
2354deb5931Sjoerg _PROP_ASSERT(idx < array1->pa_count);
2363e69f1b2Sthorpej
2374deb5931Sjoerg *stored_pointer1 = (void *)(idx + 1);
2384deb5931Sjoerg *stored_pointer2 = (void *)(idx + 1);
2394deb5931Sjoerg
2404deb5931Sjoerg *next_obj1 = array1->pa_array[idx];
2414deb5931Sjoerg *next_obj2 = array2->pa_array[idx];
2424deb5931Sjoerg
2434deb5931Sjoerg return (_PROP_OBJECT_EQUALS_RECURSE);
244eb2acb85Sthorpej
245eb2acb85Sthorpej out:
246eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
247eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
248eb2acb85Sthorpej return (rv);
2493e69f1b2Sthorpej }
2503e69f1b2Sthorpej
2514deb5931Sjoerg static void
_prop_array_equals_finish(prop_object_t v1,prop_object_t v2)2524deb5931Sjoerg _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
2534deb5931Sjoerg {
2544deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
2554deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
2564deb5931Sjoerg }
2574deb5931Sjoerg
258774eb1a3Sthorpej static prop_array_t
_prop_array_alloc(unsigned int capacity)259774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity)
260774eb1a3Sthorpej {
261774eb1a3Sthorpej prop_array_t pa;
262774eb1a3Sthorpej prop_object_t *array;
263774eb1a3Sthorpej
264774eb1a3Sthorpej if (capacity != 0) {
265774eb1a3Sthorpej array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
266774eb1a3Sthorpej M_PROP_ARRAY);
267774eb1a3Sthorpej if (array == NULL)
268774eb1a3Sthorpej return (NULL);
269774eb1a3Sthorpej } else
270774eb1a3Sthorpej array = NULL;
271774eb1a3Sthorpej
272774eb1a3Sthorpej pa = _PROP_POOL_GET(_prop_array_pool);
273774eb1a3Sthorpej if (pa != NULL) {
2743e69f1b2Sthorpej _prop_object_init(&pa->pa_obj, &_prop_object_type_array);
2753e69f1b2Sthorpej pa->pa_obj.po_type = &_prop_object_type_array;
276774eb1a3Sthorpej
277eb2acb85Sthorpej _PROP_RWLOCK_INIT(pa->pa_rwlock);
278774eb1a3Sthorpej pa->pa_array = array;
279774eb1a3Sthorpej pa->pa_capacity = capacity;
280774eb1a3Sthorpej pa->pa_count = 0;
281774eb1a3Sthorpej pa->pa_flags = 0;
282774eb1a3Sthorpej
283774eb1a3Sthorpej pa->pa_version = 0;
284774eb1a3Sthorpej } else if (array != NULL)
285774eb1a3Sthorpej _PROP_FREE(array, M_PROP_ARRAY);
286774eb1a3Sthorpej
287774eb1a3Sthorpej return (pa);
288774eb1a3Sthorpej }
289774eb1a3Sthorpej
29004377267Sthorpej static bool
_prop_array_expand(prop_array_t pa,unsigned int capacity)291774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity)
292774eb1a3Sthorpej {
293774eb1a3Sthorpej prop_object_t *array, *oarray;
294774eb1a3Sthorpej
295eb2acb85Sthorpej /*
296eb2acb85Sthorpej * Array must be WRITE-LOCKED.
297eb2acb85Sthorpej */
298eb2acb85Sthorpej
299774eb1a3Sthorpej oarray = pa->pa_array;
300774eb1a3Sthorpej
30142e8dee3Sthorpej array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
302774eb1a3Sthorpej if (array == NULL)
30304377267Sthorpej return (false);
304774eb1a3Sthorpej if (oarray != NULL)
30542e8dee3Sthorpej memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
306774eb1a3Sthorpej pa->pa_array = array;
307774eb1a3Sthorpej pa->pa_capacity = capacity;
308774eb1a3Sthorpej
309774eb1a3Sthorpej if (oarray != NULL)
310774eb1a3Sthorpej _PROP_FREE(oarray, M_PROP_ARRAY);
311774eb1a3Sthorpej
31204377267Sthorpej return (true);
313774eb1a3Sthorpej }
314774eb1a3Sthorpej
315774eb1a3Sthorpej static prop_object_t
_prop_array_iterator_next_object_locked(void * v)31675b1a2ecSyamt _prop_array_iterator_next_object_locked(void *v)
317774eb1a3Sthorpej {
318774eb1a3Sthorpej struct _prop_array_iterator *pai = v;
319774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj;
320eb2acb85Sthorpej prop_object_t po = NULL;
321774eb1a3Sthorpej
322774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa));
3236787eedeSyamt
324774eb1a3Sthorpej if (pa->pa_version != pai->pai_base.pi_version)
325eb2acb85Sthorpej goto out; /* array changed during iteration */
326774eb1a3Sthorpej
327774eb1a3Sthorpej _PROP_ASSERT(pai->pai_index <= pa->pa_count);
328774eb1a3Sthorpej
329774eb1a3Sthorpej if (pai->pai_index == pa->pa_count)
330eb2acb85Sthorpej goto out; /* we've iterated all objects */
331774eb1a3Sthorpej
332774eb1a3Sthorpej po = pa->pa_array[pai->pai_index];
333774eb1a3Sthorpej pai->pai_index++;
334774eb1a3Sthorpej
335eb2acb85Sthorpej out:
33675b1a2ecSyamt return (po);
33775b1a2ecSyamt }
33875b1a2ecSyamt
33975b1a2ecSyamt static prop_object_t
_prop_array_iterator_next_object(void * v)34075b1a2ecSyamt _prop_array_iterator_next_object(void *v)
34175b1a2ecSyamt {
34275b1a2ecSyamt struct _prop_array_iterator *pai = v;
343c303bcbeSpooka prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
34475b1a2ecSyamt prop_object_t po;
34575b1a2ecSyamt
34675b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa));
34775b1a2ecSyamt
34875b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
34975b1a2ecSyamt po = _prop_array_iterator_next_object_locked(pai);
350eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
351774eb1a3Sthorpej return (po);
352774eb1a3Sthorpej }
353774eb1a3Sthorpej
354774eb1a3Sthorpej static void
_prop_array_iterator_reset_locked(void * v)35575b1a2ecSyamt _prop_array_iterator_reset_locked(void *v)
356774eb1a3Sthorpej {
357774eb1a3Sthorpej struct _prop_array_iterator *pai = v;
358774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj;
359774eb1a3Sthorpej
360774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa));
3616787eedeSyamt
362774eb1a3Sthorpej pai->pai_index = 0;
363774eb1a3Sthorpej pai->pai_base.pi_version = pa->pa_version;
36475b1a2ecSyamt }
36535fe7cdcSxtraeme
36675b1a2ecSyamt static void
_prop_array_iterator_reset(void * v)36775b1a2ecSyamt _prop_array_iterator_reset(void *v)
36875b1a2ecSyamt {
36975b1a2ecSyamt struct _prop_array_iterator *pai = v;
370c303bcbeSpooka prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
37175b1a2ecSyamt
37275b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa));
37375b1a2ecSyamt
37475b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
37575b1a2ecSyamt _prop_array_iterator_reset_locked(pai);
37635fe7cdcSxtraeme _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
37735fe7cdcSxtraeme }
378774eb1a3Sthorpej
379774eb1a3Sthorpej /*
380774eb1a3Sthorpej * prop_array_create --
381774eb1a3Sthorpej * Create an empty array.
382774eb1a3Sthorpej */
383774eb1a3Sthorpej prop_array_t
prop_array_create(void)384774eb1a3Sthorpej prop_array_create(void)
385774eb1a3Sthorpej {
386774eb1a3Sthorpej
387774eb1a3Sthorpej return (_prop_array_alloc(0));
388774eb1a3Sthorpej }
389774eb1a3Sthorpej
390774eb1a3Sthorpej /*
391774eb1a3Sthorpej * prop_array_create_with_capacity --
392774eb1a3Sthorpej * Create an array with the capacity to store N objects.
393774eb1a3Sthorpej */
394774eb1a3Sthorpej prop_array_t
prop_array_create_with_capacity(unsigned int capacity)395774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity)
396774eb1a3Sthorpej {
397774eb1a3Sthorpej
398774eb1a3Sthorpej return (_prop_array_alloc(capacity));
399774eb1a3Sthorpej }
400774eb1a3Sthorpej
401774eb1a3Sthorpej /*
402774eb1a3Sthorpej * prop_array_copy --
403774eb1a3Sthorpej * Copy an array. The new array has an initial capacity equal to
404774eb1a3Sthorpej * the number of objects stored in the original array. The new
405774eb1a3Sthorpej * array contains references to the original array's objects, not
406774eb1a3Sthorpej * copies of those objects (i.e. a shallow copy).
407774eb1a3Sthorpej */
408774eb1a3Sthorpej prop_array_t
prop_array_copy(prop_array_t opa)409774eb1a3Sthorpej prop_array_copy(prop_array_t opa)
410774eb1a3Sthorpej {
411774eb1a3Sthorpej prop_array_t pa;
412774eb1a3Sthorpej prop_object_t po;
413774eb1a3Sthorpej unsigned int idx;
414774eb1a3Sthorpej
415d21620b2Sthorpej if (! prop_object_is_array(opa))
416d21620b2Sthorpej return (NULL);
417774eb1a3Sthorpej
418eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
419eb2acb85Sthorpej
420774eb1a3Sthorpej pa = _prop_array_alloc(opa->pa_count);
421774eb1a3Sthorpej if (pa != NULL) {
422774eb1a3Sthorpej for (idx = 0; idx < opa->pa_count; idx++) {
423774eb1a3Sthorpej po = opa->pa_array[idx];
424774eb1a3Sthorpej prop_object_retain(po);
425774eb1a3Sthorpej pa->pa_array[idx] = po;
426774eb1a3Sthorpej }
427774eb1a3Sthorpej pa->pa_count = opa->pa_count;
428774eb1a3Sthorpej pa->pa_flags = opa->pa_flags;
429774eb1a3Sthorpej }
430eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
431774eb1a3Sthorpej return (pa);
432774eb1a3Sthorpej }
433774eb1a3Sthorpej
434774eb1a3Sthorpej /*
435774eb1a3Sthorpej * prop_array_copy_mutable --
436774eb1a3Sthorpej * Like prop_array_copy(), but the resulting array is mutable.
437774eb1a3Sthorpej */
438774eb1a3Sthorpej prop_array_t
prop_array_copy_mutable(prop_array_t opa)439774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa)
440774eb1a3Sthorpej {
441774eb1a3Sthorpej prop_array_t pa;
442774eb1a3Sthorpej
443774eb1a3Sthorpej pa = prop_array_copy(opa);
444774eb1a3Sthorpej if (pa != NULL)
445774eb1a3Sthorpej pa->pa_flags &= ~PA_F_IMMUTABLE;
446774eb1a3Sthorpej
447774eb1a3Sthorpej return (pa);
448774eb1a3Sthorpej }
449774eb1a3Sthorpej
450774eb1a3Sthorpej /*
451774eb1a3Sthorpej * prop_array_capacity --
452774eb1a3Sthorpej * Return the capacity of the array.
453774eb1a3Sthorpej */
454774eb1a3Sthorpej unsigned int
prop_array_capacity(prop_array_t pa)455774eb1a3Sthorpej prop_array_capacity(prop_array_t pa)
456774eb1a3Sthorpej {
457eb2acb85Sthorpej unsigned int rv;
458774eb1a3Sthorpej
459d21620b2Sthorpej if (! prop_object_is_array(pa))
460d21620b2Sthorpej return (0);
461d21620b2Sthorpej
462eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
463eb2acb85Sthorpej rv = pa->pa_capacity;
464eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
465eb2acb85Sthorpej
466eb2acb85Sthorpej return (rv);
467774eb1a3Sthorpej }
468774eb1a3Sthorpej
469774eb1a3Sthorpej /*
470774eb1a3Sthorpej * prop_array_count --
471774eb1a3Sthorpej * Return the number of objects stored in the array.
472774eb1a3Sthorpej */
473774eb1a3Sthorpej unsigned int
prop_array_count(prop_array_t pa)474774eb1a3Sthorpej prop_array_count(prop_array_t pa)
475774eb1a3Sthorpej {
476eb2acb85Sthorpej unsigned int rv;
477774eb1a3Sthorpej
478d21620b2Sthorpej if (! prop_object_is_array(pa))
479d21620b2Sthorpej return (0);
480d21620b2Sthorpej
481eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
482eb2acb85Sthorpej rv = pa->pa_count;
483eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
484eb2acb85Sthorpej
485eb2acb85Sthorpej return (rv);
486774eb1a3Sthorpej }
487774eb1a3Sthorpej
488774eb1a3Sthorpej /*
489774eb1a3Sthorpej * prop_array_ensure_capacity --
490774eb1a3Sthorpej * Ensure that the array has the capacity to store the specified
491*95f94af3Sandvar * total number of objects (including the objects already stored
492774eb1a3Sthorpej * in the array).
493774eb1a3Sthorpej */
49404377267Sthorpej bool
prop_array_ensure_capacity(prop_array_t pa,unsigned int capacity)495774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
496774eb1a3Sthorpej {
49704377267Sthorpej bool rv;
498774eb1a3Sthorpej
499d21620b2Sthorpej if (! prop_object_is_array(pa))
50004377267Sthorpej return (false);
501d21620b2Sthorpej
502eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
503774eb1a3Sthorpej if (capacity > pa->pa_capacity)
504eb2acb85Sthorpej rv = _prop_array_expand(pa, capacity);
505eb2acb85Sthorpej else
50604377267Sthorpej rv = true;
507eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
508eb2acb85Sthorpej
509eb2acb85Sthorpej return (rv);
510774eb1a3Sthorpej }
511774eb1a3Sthorpej
51275b1a2ecSyamt static prop_object_iterator_t
_prop_array_iterator_locked(prop_array_t pa)51375b1a2ecSyamt _prop_array_iterator_locked(prop_array_t pa)
514774eb1a3Sthorpej {
515774eb1a3Sthorpej struct _prop_array_iterator *pai;
516774eb1a3Sthorpej
517d21620b2Sthorpej if (! prop_object_is_array(pa))
518d21620b2Sthorpej return (NULL);
519774eb1a3Sthorpej
520774eb1a3Sthorpej pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
521774eb1a3Sthorpej if (pai == NULL)
522774eb1a3Sthorpej return (NULL);
523774eb1a3Sthorpej pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
524774eb1a3Sthorpej pai->pai_base.pi_reset = _prop_array_iterator_reset;
525774eb1a3Sthorpej prop_object_retain(pa);
526774eb1a3Sthorpej pai->pai_base.pi_obj = pa;
52775b1a2ecSyamt _prop_array_iterator_reset_locked(pai);
528774eb1a3Sthorpej
529774eb1a3Sthorpej return (&pai->pai_base);
530774eb1a3Sthorpej }
531774eb1a3Sthorpej
532774eb1a3Sthorpej /*
53375b1a2ecSyamt * prop_array_iterator --
53475b1a2ecSyamt * Return an iterator for the array. The array is retained by
53575b1a2ecSyamt * the iterator.
53675b1a2ecSyamt */
53775b1a2ecSyamt prop_object_iterator_t
prop_array_iterator(prop_array_t pa)53875b1a2ecSyamt prop_array_iterator(prop_array_t pa)
53975b1a2ecSyamt {
54075b1a2ecSyamt prop_object_iterator_t pi;
54175b1a2ecSyamt
54275b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
54375b1a2ecSyamt pi = _prop_array_iterator_locked(pa);
54475b1a2ecSyamt _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
54575b1a2ecSyamt return (pi);
54675b1a2ecSyamt }
54775b1a2ecSyamt
54875b1a2ecSyamt /*
549774eb1a3Sthorpej * prop_array_make_immutable --
550774eb1a3Sthorpej * Make the array immutable.
551774eb1a3Sthorpej */
552774eb1a3Sthorpej void
prop_array_make_immutable(prop_array_t pa)553774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa)
554774eb1a3Sthorpej {
555774eb1a3Sthorpej
556eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
55704377267Sthorpej if (prop_array_is_immutable(pa) == false)
558774eb1a3Sthorpej pa->pa_flags |= PA_F_IMMUTABLE;
559eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
560774eb1a3Sthorpej }
561774eb1a3Sthorpej
562774eb1a3Sthorpej /*
563774eb1a3Sthorpej * prop_array_mutable --
56404377267Sthorpej * Returns true if the array is mutable.
565774eb1a3Sthorpej */
56604377267Sthorpej bool
prop_array_mutable(prop_array_t pa)567774eb1a3Sthorpej prop_array_mutable(prop_array_t pa)
568774eb1a3Sthorpej {
56904377267Sthorpej bool rv;
570774eb1a3Sthorpej
571eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
57204377267Sthorpej rv = prop_array_is_immutable(pa) == false;
573eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
574eb2acb85Sthorpej
575eb2acb85Sthorpej return (rv);
576774eb1a3Sthorpej }
577774eb1a3Sthorpej
578774eb1a3Sthorpej /*
579774eb1a3Sthorpej * prop_array_get --
580774eb1a3Sthorpej * Return the object stored at the specified array index.
581774eb1a3Sthorpej */
582774eb1a3Sthorpej prop_object_t
prop_array_get(prop_array_t pa,unsigned int idx)583774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx)
584774eb1a3Sthorpej {
585eb2acb85Sthorpej prop_object_t po = NULL;
586774eb1a3Sthorpej
587d21620b2Sthorpej if (! prop_object_is_array(pa))
588d21620b2Sthorpej return (NULL);
589d21620b2Sthorpej
590eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
591774eb1a3Sthorpej if (idx >= pa->pa_count)
592eb2acb85Sthorpej goto out;
593774eb1a3Sthorpej po = pa->pa_array[idx];
594774eb1a3Sthorpej _PROP_ASSERT(po != NULL);
595eb2acb85Sthorpej out:
596eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
597774eb1a3Sthorpej return (po);
598774eb1a3Sthorpej }
599774eb1a3Sthorpej
60004377267Sthorpej static bool
_prop_array_add(prop_array_t pa,prop_object_t po)601eb2acb85Sthorpej _prop_array_add(prop_array_t pa, prop_object_t po)
602774eb1a3Sthorpej {
603774eb1a3Sthorpej
604eb2acb85Sthorpej /*
605eb2acb85Sthorpej * Array must be WRITE-LOCKED.
606eb2acb85Sthorpej */
607d21620b2Sthorpej
608774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
609774eb1a3Sthorpej
610774eb1a3Sthorpej if (prop_array_is_immutable(pa) ||
611774eb1a3Sthorpej (pa->pa_count == pa->pa_capacity &&
61204377267Sthorpej _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
61304377267Sthorpej return (false);
614774eb1a3Sthorpej
615774eb1a3Sthorpej prop_object_retain(po);
616774eb1a3Sthorpej pa->pa_array[pa->pa_count++] = po;
617774eb1a3Sthorpej pa->pa_version++;
618774eb1a3Sthorpej
61904377267Sthorpej return (true);
620774eb1a3Sthorpej }
621774eb1a3Sthorpej
622774eb1a3Sthorpej /*
623eb2acb85Sthorpej * prop_array_set --
624eb2acb85Sthorpej * Store a reference to an object at the specified array index.
625eb2acb85Sthorpej * This method is not allowed to create holes in the array; the
626eb2acb85Sthorpej * caller must either be setting the object just beyond the existing
627eb2acb85Sthorpej * count or replacing an already existing object reference.
628eb2acb85Sthorpej */
62904377267Sthorpej bool
prop_array_set(prop_array_t pa,unsigned int idx,prop_object_t po)630eb2acb85Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
631eb2acb85Sthorpej {
632eb2acb85Sthorpej prop_object_t opo;
63304377267Sthorpej bool rv = false;
634eb2acb85Sthorpej
635eb2acb85Sthorpej if (! prop_object_is_array(pa))
63604377267Sthorpej return (false);
637eb2acb85Sthorpej
638eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
639eb2acb85Sthorpej
640eb2acb85Sthorpej if (prop_array_is_immutable(pa))
641eb2acb85Sthorpej goto out;
642eb2acb85Sthorpej
643eb2acb85Sthorpej if (idx == pa->pa_count) {
644eb2acb85Sthorpej rv = _prop_array_add(pa, po);
645eb2acb85Sthorpej goto out;
646eb2acb85Sthorpej }
647eb2acb85Sthorpej
648eb2acb85Sthorpej _PROP_ASSERT(idx < pa->pa_count);
649eb2acb85Sthorpej
650eb2acb85Sthorpej opo = pa->pa_array[idx];
651eb2acb85Sthorpej _PROP_ASSERT(opo != NULL);
652eb2acb85Sthorpej
653eb2acb85Sthorpej prop_object_retain(po);
654eb2acb85Sthorpej pa->pa_array[idx] = po;
655eb2acb85Sthorpej pa->pa_version++;
656eb2acb85Sthorpej
657eb2acb85Sthorpej prop_object_release(opo);
658eb2acb85Sthorpej
65904377267Sthorpej rv = true;
660eb2acb85Sthorpej
661eb2acb85Sthorpej out:
662eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
663eb2acb85Sthorpej return (rv);
664eb2acb85Sthorpej }
665eb2acb85Sthorpej
666eb2acb85Sthorpej /*
667eb2acb85Sthorpej * prop_array_add --
668ecd6bc70Schristos * Add a reference to an object to the specified array, appending
669eb2acb85Sthorpej * to the end and growing the array's capacity, if necessary.
670eb2acb85Sthorpej */
67104377267Sthorpej bool
prop_array_add(prop_array_t pa,prop_object_t po)672eb2acb85Sthorpej prop_array_add(prop_array_t pa, prop_object_t po)
673eb2acb85Sthorpej {
67404377267Sthorpej bool rv;
675eb2acb85Sthorpej
676eb2acb85Sthorpej if (! prop_object_is_array(pa))
67704377267Sthorpej return (false);
678eb2acb85Sthorpej
679eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
680eb2acb85Sthorpej rv = _prop_array_add(pa, po);
681eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
682eb2acb85Sthorpej
683eb2acb85Sthorpej return (rv);
684eb2acb85Sthorpej }
685eb2acb85Sthorpej
686eb2acb85Sthorpej /*
687774eb1a3Sthorpej * prop_array_remove --
688774eb1a3Sthorpej * Remove the reference to an object from an array at the specified
689774eb1a3Sthorpej * index. The array will be compacted following the removal.
690774eb1a3Sthorpej */
691774eb1a3Sthorpej void
prop_array_remove(prop_array_t pa,unsigned int idx)692774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx)
693774eb1a3Sthorpej {
694774eb1a3Sthorpej prop_object_t po;
695774eb1a3Sthorpej
696d21620b2Sthorpej if (! prop_object_is_array(pa))
697d21620b2Sthorpej return;
698d21620b2Sthorpej
699eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
700eb2acb85Sthorpej
701774eb1a3Sthorpej _PROP_ASSERT(idx < pa->pa_count);
702774eb1a3Sthorpej
703774eb1a3Sthorpej /* XXX Should this be a _PROP_ASSERT()? */
704eb2acb85Sthorpej if (prop_array_is_immutable(pa)) {
705eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
706774eb1a3Sthorpej return;
707eb2acb85Sthorpej }
708774eb1a3Sthorpej
709774eb1a3Sthorpej po = pa->pa_array[idx];
710774eb1a3Sthorpej _PROP_ASSERT(po != NULL);
711774eb1a3Sthorpej
712774eb1a3Sthorpej for (++idx; idx < pa->pa_count; idx++)
713774eb1a3Sthorpej pa->pa_array[idx - 1] = pa->pa_array[idx];
714774eb1a3Sthorpej pa->pa_count--;
715774eb1a3Sthorpej pa->pa_version++;
716774eb1a3Sthorpej
717eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
718eb2acb85Sthorpej
719774eb1a3Sthorpej prop_object_release(po);
720774eb1a3Sthorpej }
721774eb1a3Sthorpej
722774eb1a3Sthorpej /*
7233e69f1b2Sthorpej * prop_array_equals --
72404377267Sthorpej * Return true if the two arrays are equivalent. Note we do a
7253e69f1b2Sthorpej * by-value comparison of the objects in the array.
7263e69f1b2Sthorpej */
72704377267Sthorpej bool
prop_array_equals(prop_array_t array1,prop_array_t array2)7283e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2)
7293e69f1b2Sthorpej {
7304deb5931Sjoerg if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
7314deb5931Sjoerg return (false);
7323e69f1b2Sthorpej
7334deb5931Sjoerg return (prop_object_equals(array1, array2));
7343e69f1b2Sthorpej }
7353e69f1b2Sthorpej
7363e69f1b2Sthorpej /*
737d21620b2Sthorpej * prop_array_externalize --
738d21620b2Sthorpej * Externalize an array, return a NUL-terminated buffer
739d21620b2Sthorpej * containing the XML-style representation. The buffer is allocated
740d21620b2Sthorpej * with the M_TEMP memory type.
741d21620b2Sthorpej */
742d21620b2Sthorpej char *
prop_array_externalize(prop_array_t pa)743d21620b2Sthorpej prop_array_externalize(prop_array_t pa)
744d21620b2Sthorpej {
745d21620b2Sthorpej struct _prop_object_externalize_context *ctx;
746d21620b2Sthorpej char *cp;
747d21620b2Sthorpej
748d21620b2Sthorpej ctx = _prop_object_externalize_context_alloc();
749d21620b2Sthorpej if (ctx == NULL)
750d21620b2Sthorpej return (NULL);
751d21620b2Sthorpej
75204377267Sthorpej if (_prop_object_externalize_header(ctx) == false ||
75304377267Sthorpej (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
75404377267Sthorpej _prop_object_externalize_footer(ctx) == false) {
755d21620b2Sthorpej /* We are responsible for releasing the buffer. */
756d21620b2Sthorpej _PROP_FREE(ctx->poec_buf, M_TEMP);
757d21620b2Sthorpej _prop_object_externalize_context_free(ctx);
758d21620b2Sthorpej return (NULL);
759d21620b2Sthorpej }
760d21620b2Sthorpej
761d21620b2Sthorpej cp = ctx->poec_buf;
762d21620b2Sthorpej _prop_object_externalize_context_free(ctx);
763d21620b2Sthorpej
764d21620b2Sthorpej return (cp);
765d21620b2Sthorpej }
766d21620b2Sthorpej
767d21620b2Sthorpej /*
768774eb1a3Sthorpej * _prop_array_internalize --
769774eb1a3Sthorpej * Parse an <array>...</array> and return the object created from the
770774eb1a3Sthorpej * external representation.
771774eb1a3Sthorpej */
772e835604cSjoerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
773e835604cSjoerg struct _prop_object_internalize_context *);
774774eb1a3Sthorpej
775e835604cSjoerg bool
_prop_array_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)776e835604cSjoerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
777e835604cSjoerg struct _prop_object_internalize_context *ctx)
778e835604cSjoerg {
779774eb1a3Sthorpej /* We don't currently understand any attributes. */
780774eb1a3Sthorpej if (ctx->poic_tagattr != NULL)
781e835604cSjoerg return (true);
782774eb1a3Sthorpej
783e835604cSjoerg *obj = prop_array_create();
784e835604cSjoerg /*
785e835604cSjoerg * We are done if the create failed or no child elements exist.
786e835604cSjoerg */
787e835604cSjoerg if (*obj == NULL || ctx->poic_is_empty_element)
788e835604cSjoerg return (true);
789774eb1a3Sthorpej
790e835604cSjoerg /*
791e835604cSjoerg * Opening tag is found, now continue to the first element.
792e835604cSjoerg */
793e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx));
794e835604cSjoerg }
795774eb1a3Sthorpej
796e835604cSjoerg static bool
_prop_array_internalize_continue(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx,void * data,prop_object_t child)797e835604cSjoerg _prop_array_internalize_continue(prop_stack_t stack,
798e835604cSjoerg prop_object_t *obj,
799e835604cSjoerg struct _prop_object_internalize_context *ctx,
800e835604cSjoerg void *data, prop_object_t child)
801e835604cSjoerg {
802e835604cSjoerg prop_array_t array;
803e835604cSjoerg
804e835604cSjoerg _PROP_ASSERT(data == NULL);
805e835604cSjoerg
806e835604cSjoerg if (child == NULL)
807e835604cSjoerg goto bad; /* Element could not be parsed. */
808e835604cSjoerg
809e835604cSjoerg array = *obj;
810e835604cSjoerg
811e835604cSjoerg if (prop_array_add(array, child) == false) {
812e835604cSjoerg prop_object_release(child);
813e835604cSjoerg goto bad;
814e835604cSjoerg }
815e835604cSjoerg prop_object_release(child);
816e835604cSjoerg
817e835604cSjoerg /*
818e835604cSjoerg * Current element is processed and added, look for next.
819e835604cSjoerg */
820e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx));
821e835604cSjoerg
822e835604cSjoerg bad:
823e835604cSjoerg prop_object_release(*obj);
824e835604cSjoerg *obj = NULL;
825e835604cSjoerg return (true);
826e835604cSjoerg }
827e835604cSjoerg
828e835604cSjoerg static bool
_prop_array_internalize_body(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)829e835604cSjoerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
830e835604cSjoerg struct _prop_object_internalize_context *ctx)
831e835604cSjoerg {
832e835604cSjoerg prop_array_t array = *obj;
833e835604cSjoerg
834e835604cSjoerg _PROP_ASSERT(array != NULL);
835e835604cSjoerg
836774eb1a3Sthorpej /* Fetch the next tag. */
837774eb1a3Sthorpej if (_prop_object_internalize_find_tag(ctx, NULL,
83804377267Sthorpej _PROP_TAG_TYPE_EITHER) == false)
839774eb1a3Sthorpej goto bad;
840774eb1a3Sthorpej
841774eb1a3Sthorpej /* Check to see if this is the end of the array. */
842774eb1a3Sthorpej if (_PROP_TAG_MATCH(ctx, "array") &&
843e835604cSjoerg ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
844e835604cSjoerg /* It is, so don't iterate any further. */
845e835604cSjoerg return (true);
846774eb1a3Sthorpej }
847774eb1a3Sthorpej
8484deb5931Sjoerg if (_prop_stack_push(stack, array,
8494deb5931Sjoerg _prop_array_internalize_continue, NULL, NULL))
850e835604cSjoerg return (false);
851774eb1a3Sthorpej
852774eb1a3Sthorpej bad:
853774eb1a3Sthorpej prop_object_release(array);
854e835604cSjoerg *obj = NULL;
855e835604cSjoerg return (true);
856774eb1a3Sthorpej }
857d21620b2Sthorpej
858d21620b2Sthorpej /*
859d21620b2Sthorpej * prop_array_internalize --
860d21620b2Sthorpej * Create an array by parsing the XML-style representation.
861d21620b2Sthorpej */
862d21620b2Sthorpej prop_array_t
prop_array_internalize(const char * xml)863d21620b2Sthorpej prop_array_internalize(const char *xml)
864d21620b2Sthorpej {
86539dccbf2Sjoerg return _prop_generic_internalize(xml, "array");
866d21620b2Sthorpej }
867d21620b2Sthorpej
868d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
869d21620b2Sthorpej /*
870d21620b2Sthorpej * prop_array_externalize_to_file --
871d21620b2Sthorpej * Externalize an array to the specified file.
872d21620b2Sthorpej */
87304377267Sthorpej bool
prop_array_externalize_to_file(prop_array_t array,const char * fname)874d21620b2Sthorpej prop_array_externalize_to_file(prop_array_t array, const char *fname)
875d21620b2Sthorpej {
876d21620b2Sthorpej char *xml;
87704377267Sthorpej bool rv;
8781a119b51She int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */
879d21620b2Sthorpej
880d21620b2Sthorpej xml = prop_array_externalize(array);
881d21620b2Sthorpej if (xml == NULL)
88204377267Sthorpej return (false);
883d21620b2Sthorpej rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
88404377267Sthorpej if (rv == false)
885d21620b2Sthorpej save_errno = errno;
886d21620b2Sthorpej _PROP_FREE(xml, M_TEMP);
88704377267Sthorpej if (rv == false)
888d21620b2Sthorpej errno = save_errno;
889d21620b2Sthorpej
890d21620b2Sthorpej return (rv);
891d21620b2Sthorpej }
892d21620b2Sthorpej
893d21620b2Sthorpej /*
894d21620b2Sthorpej * prop_array_internalize_from_file --
895d21620b2Sthorpej * Internalize an array from a file.
896d21620b2Sthorpej */
897d21620b2Sthorpej prop_array_t
prop_array_internalize_from_file(const char * fname)898d21620b2Sthorpej prop_array_internalize_from_file(const char *fname)
899d21620b2Sthorpej {
900d21620b2Sthorpej struct _prop_object_internalize_mapped_file *mf;
901d21620b2Sthorpej prop_array_t array;
902d21620b2Sthorpej
903d21620b2Sthorpej mf = _prop_object_internalize_map_file(fname);
904d21620b2Sthorpej if (mf == NULL)
905d21620b2Sthorpej return (NULL);
906d21620b2Sthorpej array = prop_array_internalize(mf->poimf_xml);
907d21620b2Sthorpej _prop_object_internalize_unmap_file(mf);
908d21620b2Sthorpej
909d21620b2Sthorpej return (array);
910d21620b2Sthorpej }
911d21620b2Sthorpej #endif /* _KERNEL && !_STANDALONE */
912