xref: /netbsd-src/common/lib/libprop/prop_array.c (revision 75b1a2ec184ed5f3b4f651d62b3343f5678bbdd8)
1*75b1a2ecSyamt /*	$NetBSD: prop_array.c,v 1.18 2008/05/24 14:32:48 yamt 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/prop_array.h>
33774eb1a3Sthorpej #include "prop_object_impl.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 
56e835604cSjoerg static int		_prop_array_free(prop_stack_t, prop_object_t *);
57e835604cSjoerg static void		_prop_array_emergency_free(prop_object_t);
5804377267Sthorpej static bool	_prop_array_externalize(
593e69f1b2Sthorpej 				struct _prop_object_externalize_context *,
603e69f1b2Sthorpej 				void *);
614deb5931Sjoerg static bool	_prop_array_equals(prop_object_t, prop_object_t,
624deb5931Sjoerg 				   void **, void **,
634deb5931Sjoerg 				   prop_object_t *, prop_object_t *);
644deb5931Sjoerg static void	_prop_array_equals_finish(prop_object_t, prop_object_t);
65*75b1a2ecSyamt static prop_object_iterator_t _prop_array_iterator_locked(prop_array_t);
66*75b1a2ecSyamt static prop_object_t _prop_array_iterator_next_object_locked(void *);
67*75b1a2ecSyamt static void _prop_array_iterator_reset_locked(void *);
683e69f1b2Sthorpej 
693e69f1b2Sthorpej static const struct _prop_object_type _prop_object_type_array = {
703e69f1b2Sthorpej 	.pot_type		=	PROP_TYPE_ARRAY,
713e69f1b2Sthorpej 	.pot_free		=	_prop_array_free,
72e835604cSjoerg 	.pot_emergency_free	=	_prop_array_emergency_free,
733e69f1b2Sthorpej 	.pot_extern		=	_prop_array_externalize,
743e69f1b2Sthorpej 	.pot_equals		=	_prop_array_equals,
754deb5931Sjoerg 	.pot_equals_finish	=	_prop_array_equals_finish,
763e69f1b2Sthorpej };
773e69f1b2Sthorpej 
783e69f1b2Sthorpej #define	prop_object_is_array(x) 	\
79beabdd9bSthorpej 	((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
80774eb1a3Sthorpej 
81774eb1a3Sthorpej #define	prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
82774eb1a3Sthorpej 
83774eb1a3Sthorpej struct _prop_array_iterator {
84774eb1a3Sthorpej 	struct _prop_object_iterator pai_base;
85774eb1a3Sthorpej 	unsigned int		pai_index;
86774eb1a3Sthorpej };
87774eb1a3Sthorpej 
88774eb1a3Sthorpej #define	EXPAND_STEP		16
89774eb1a3Sthorpej 
90e835604cSjoerg static int
91e835604cSjoerg _prop_array_free(prop_stack_t stack, prop_object_t *obj)
92774eb1a3Sthorpej {
93e835604cSjoerg 	prop_array_t pa = *obj;
94774eb1a3Sthorpej 	prop_object_t po;
95774eb1a3Sthorpej 
96774eb1a3Sthorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
97774eb1a3Sthorpej 	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
98774eb1a3Sthorpej 		     (pa->pa_capacity != 0 && pa->pa_array != NULL));
99774eb1a3Sthorpej 
100e835604cSjoerg 	/* The easy case is an empty array, just free and return. */
101e835604cSjoerg 	if (pa->pa_count == 0) {
102774eb1a3Sthorpej 		if (pa->pa_array != NULL)
103774eb1a3Sthorpej 			_PROP_FREE(pa->pa_array, M_PROP_ARRAY);
104774eb1a3Sthorpej 
105eb2acb85Sthorpej 		_PROP_RWLOCK_DESTROY(pa->pa_rwlock);
106eb2acb85Sthorpej 
107774eb1a3Sthorpej 		_PROP_POOL_PUT(_prop_array_pool, pa);
108e835604cSjoerg 
109e835604cSjoerg 		return (_PROP_OBJECT_FREE_DONE);
110e835604cSjoerg 	}
111e835604cSjoerg 
112e835604cSjoerg 	po = pa->pa_array[pa->pa_count - 1];
113e835604cSjoerg 	_PROP_ASSERT(po != NULL);
114e835604cSjoerg 
115e835604cSjoerg 	if (stack == NULL) {
116e835604cSjoerg 		/*
117e835604cSjoerg 		 * If we are in emergency release mode,
118e835604cSjoerg 		 * just let caller recurse down.
119e835604cSjoerg 		 */
120e835604cSjoerg 		*obj = po;
121e835604cSjoerg 		return (_PROP_OBJECT_FREE_FAILED);
122e835604cSjoerg 	}
123e835604cSjoerg 
124e835604cSjoerg 	/* Otherwise, try to push the current object on the stack. */
1254deb5931Sjoerg 	if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
126e835604cSjoerg 		/* Push failed, entering emergency release mode. */
127e835604cSjoerg 		return (_PROP_OBJECT_FREE_FAILED);
128e835604cSjoerg 	}
129e835604cSjoerg 	/* Object pushed on stack, caller will release it. */
130e835604cSjoerg 	--pa->pa_count;
131e835604cSjoerg 	*obj = po;
132e835604cSjoerg 	return (_PROP_OBJECT_FREE_RECURSE);
133e835604cSjoerg }
134e835604cSjoerg 
135e835604cSjoerg static void
136e835604cSjoerg _prop_array_emergency_free(prop_object_t obj)
137e835604cSjoerg {
138e835604cSjoerg 	prop_array_t pa = obj;
139e835604cSjoerg 
140e835604cSjoerg 	_PROP_ASSERT(pa->pa_count != 0);
141e835604cSjoerg 	--pa->pa_count;
142774eb1a3Sthorpej }
143774eb1a3Sthorpej 
14404377267Sthorpej static bool
145774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx,
146774eb1a3Sthorpej 			void *v)
147774eb1a3Sthorpej {
148774eb1a3Sthorpej 	prop_array_t pa = v;
149774eb1a3Sthorpej 	struct _prop_object *po;
150774eb1a3Sthorpej 	prop_object_iterator_t pi;
151774eb1a3Sthorpej 	unsigned int i;
15204377267Sthorpej 	bool rv = false;
153774eb1a3Sthorpej 
154eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
155eb2acb85Sthorpej 
156eb2acb85Sthorpej 	if (pa->pa_count == 0) {
157eb2acb85Sthorpej 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
158774eb1a3Sthorpej 		return (_prop_object_externalize_empty_tag(ctx, "array"));
159eb2acb85Sthorpej 	}
160774eb1a3Sthorpej 
161774eb1a3Sthorpej 	/* XXXJRT Hint "count" for the internalize step? */
16204377267Sthorpej 	if (_prop_object_externalize_start_tag(ctx, "array") == false ||
16304377267Sthorpej 	    _prop_object_externalize_append_char(ctx, '\n') == false)
164eb2acb85Sthorpej 		goto out;
165774eb1a3Sthorpej 
166*75b1a2ecSyamt 	pi = _prop_array_iterator_locked(pa);
167774eb1a3Sthorpej 	if (pi == NULL)
168eb2acb85Sthorpej 		goto out;
169774eb1a3Sthorpej 
170774eb1a3Sthorpej 	ctx->poec_depth++;
171774eb1a3Sthorpej 	_PROP_ASSERT(ctx->poec_depth != 0);
172774eb1a3Sthorpej 
173*75b1a2ecSyamt 	while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
17404377267Sthorpej 		if ((*po->po_type->pot_extern)(ctx, po) == false) {
175774eb1a3Sthorpej 			prop_object_iterator_release(pi);
176eb2acb85Sthorpej 			goto out;
177774eb1a3Sthorpej 		}
178774eb1a3Sthorpej 	}
179774eb1a3Sthorpej 
180774eb1a3Sthorpej 	prop_object_iterator_release(pi);
181774eb1a3Sthorpej 
182774eb1a3Sthorpej 	ctx->poec_depth--;
183774eb1a3Sthorpej 	for (i = 0; i < ctx->poec_depth; i++) {
18404377267Sthorpej 		if (_prop_object_externalize_append_char(ctx, '\t') == false)
185eb2acb85Sthorpej 			goto out;
186774eb1a3Sthorpej 	}
18704377267Sthorpej 	if (_prop_object_externalize_end_tag(ctx, "array") == false)
188eb2acb85Sthorpej 		goto out;
189774eb1a3Sthorpej 
19004377267Sthorpej 	rv = true;
191eb2acb85Sthorpej 
192eb2acb85Sthorpej  out:
193eb2acb85Sthorpej  	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
194eb2acb85Sthorpej 	return (rv);
195774eb1a3Sthorpej }
196774eb1a3Sthorpej 
1974deb5931Sjoerg /* ARGSUSED */
19804377267Sthorpej static bool
1994deb5931Sjoerg _prop_array_equals(prop_object_t v1, prop_object_t v2,
2004deb5931Sjoerg     void **stored_pointer1, void **stored_pointer2,
2014deb5931Sjoerg     prop_object_t *next_obj1, prop_object_t *next_obj2)
2023e69f1b2Sthorpej {
2033e69f1b2Sthorpej 	prop_array_t array1 = v1;
2043e69f1b2Sthorpej 	prop_array_t array2 = v2;
2054deb5931Sjoerg 	uintptr_t idx;
2064deb5931Sjoerg 	bool rv = _PROP_OBJECT_EQUALS_FALSE;
2073e69f1b2Sthorpej 
2083e69f1b2Sthorpej 	if (array1 == array2)
2094deb5931Sjoerg 		return (_PROP_OBJECT_EQUALS_TRUE);
210eb2acb85Sthorpej 
2114deb5931Sjoerg 	_PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
2124deb5931Sjoerg 	idx = (uintptr_t)*stored_pointer1;
2134deb5931Sjoerg 
2144deb5931Sjoerg 	/* For the first iteration, lock the objects. */
2154deb5931Sjoerg 	if (idx == 0) {
216eb2acb85Sthorpej 		if ((uintptr_t)array1 < (uintptr_t)array2) {
217eb2acb85Sthorpej 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
218eb2acb85Sthorpej 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
219eb2acb85Sthorpej 		} else {
220eb2acb85Sthorpej 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
221eb2acb85Sthorpej 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
222eb2acb85Sthorpej 		}
2234deb5931Sjoerg 	}
224eb2acb85Sthorpej 
2253e69f1b2Sthorpej 	if (array1->pa_count != array2->pa_count)
226eb2acb85Sthorpej 		goto out;
2274deb5931Sjoerg 	if (idx == array1->pa_count) {
2284deb5931Sjoerg 		rv = true;
229eb2acb85Sthorpej 		goto out;
2303e69f1b2Sthorpej 	}
2314deb5931Sjoerg 	_PROP_ASSERT(idx < array1->pa_count);
2323e69f1b2Sthorpej 
2334deb5931Sjoerg 	*stored_pointer1 = (void *)(idx + 1);
2344deb5931Sjoerg 	*stored_pointer2 = (void *)(idx + 1);
2354deb5931Sjoerg 
2364deb5931Sjoerg 	*next_obj1 = array1->pa_array[idx];
2374deb5931Sjoerg 	*next_obj2 = array2->pa_array[idx];
2384deb5931Sjoerg 
2394deb5931Sjoerg 	return (_PROP_OBJECT_EQUALS_RECURSE);
240eb2acb85Sthorpej 
241eb2acb85Sthorpej  out:
242eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
243eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
244eb2acb85Sthorpej 	return (rv);
2453e69f1b2Sthorpej }
2463e69f1b2Sthorpej 
2474deb5931Sjoerg static void
2484deb5931Sjoerg _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
2494deb5931Sjoerg {
2504deb5931Sjoerg 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
2514deb5931Sjoerg 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
2524deb5931Sjoerg }
2534deb5931Sjoerg 
254774eb1a3Sthorpej static prop_array_t
255774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity)
256774eb1a3Sthorpej {
257774eb1a3Sthorpej 	prop_array_t pa;
258774eb1a3Sthorpej 	prop_object_t *array;
259774eb1a3Sthorpej 
260774eb1a3Sthorpej 	if (capacity != 0) {
261774eb1a3Sthorpej 		array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
262774eb1a3Sthorpej 				     M_PROP_ARRAY);
263774eb1a3Sthorpej 		if (array == NULL)
264774eb1a3Sthorpej 			return (NULL);
265774eb1a3Sthorpej 	} else
266774eb1a3Sthorpej 		array = NULL;
267774eb1a3Sthorpej 
268774eb1a3Sthorpej 
269774eb1a3Sthorpej 	pa = _PROP_POOL_GET(_prop_array_pool);
270774eb1a3Sthorpej 	if (pa != NULL) {
2713e69f1b2Sthorpej 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
2723e69f1b2Sthorpej 		pa->pa_obj.po_type = &_prop_object_type_array;
273774eb1a3Sthorpej 
274eb2acb85Sthorpej 		_PROP_RWLOCK_INIT(pa->pa_rwlock);
275774eb1a3Sthorpej 		pa->pa_array = array;
276774eb1a3Sthorpej 		pa->pa_capacity = capacity;
277774eb1a3Sthorpej 		pa->pa_count = 0;
278774eb1a3Sthorpej 		pa->pa_flags = 0;
279774eb1a3Sthorpej 
280774eb1a3Sthorpej 		pa->pa_version = 0;
281774eb1a3Sthorpej 	} else if (array != NULL)
282774eb1a3Sthorpej 		_PROP_FREE(array, M_PROP_ARRAY);
283774eb1a3Sthorpej 
284774eb1a3Sthorpej 	return (pa);
285774eb1a3Sthorpej }
286774eb1a3Sthorpej 
28704377267Sthorpej static bool
288774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity)
289774eb1a3Sthorpej {
290774eb1a3Sthorpej 	prop_object_t *array, *oarray;
291774eb1a3Sthorpej 
292eb2acb85Sthorpej 	/*
293eb2acb85Sthorpej 	 * Array must be WRITE-LOCKED.
294eb2acb85Sthorpej 	 */
295eb2acb85Sthorpej 
296774eb1a3Sthorpej 	oarray = pa->pa_array;
297774eb1a3Sthorpej 
29842e8dee3Sthorpej 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
299774eb1a3Sthorpej 	if (array == NULL)
30004377267Sthorpej 		return (false);
301774eb1a3Sthorpej 	if (oarray != NULL)
30242e8dee3Sthorpej 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
303774eb1a3Sthorpej 	pa->pa_array = array;
304774eb1a3Sthorpej 	pa->pa_capacity = capacity;
305774eb1a3Sthorpej 
306774eb1a3Sthorpej 	if (oarray != NULL)
307774eb1a3Sthorpej 		_PROP_FREE(oarray, M_PROP_ARRAY);
308774eb1a3Sthorpej 
30904377267Sthorpej 	return (true);
310774eb1a3Sthorpej }
311774eb1a3Sthorpej 
312774eb1a3Sthorpej static prop_object_t
313*75b1a2ecSyamt _prop_array_iterator_next_object_locked(void *v)
314774eb1a3Sthorpej {
315774eb1a3Sthorpej 	struct _prop_array_iterator *pai = v;
316774eb1a3Sthorpej 	prop_array_t pa = pai->pai_base.pi_obj;
317eb2acb85Sthorpej 	prop_object_t po = NULL;
318774eb1a3Sthorpej 
319774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
3206787eedeSyamt 
321774eb1a3Sthorpej 	if (pa->pa_version != pai->pai_base.pi_version)
322eb2acb85Sthorpej 		goto out;	/* array changed during iteration */
323774eb1a3Sthorpej 
324774eb1a3Sthorpej 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
325774eb1a3Sthorpej 
326774eb1a3Sthorpej 	if (pai->pai_index == pa->pa_count)
327eb2acb85Sthorpej 		goto out;	/* we've iterated all objects */
328774eb1a3Sthorpej 
329774eb1a3Sthorpej 	po = pa->pa_array[pai->pai_index];
330774eb1a3Sthorpej 	pai->pai_index++;
331774eb1a3Sthorpej 
332eb2acb85Sthorpej  out:
333*75b1a2ecSyamt 	return (po);
334*75b1a2ecSyamt }
335*75b1a2ecSyamt 
336*75b1a2ecSyamt static prop_object_t
337*75b1a2ecSyamt _prop_array_iterator_next_object(void *v)
338*75b1a2ecSyamt {
339*75b1a2ecSyamt 	struct _prop_array_iterator *pai = v;
340*75b1a2ecSyamt 	prop_array_t pa __unused = pai->pai_base.pi_obj;
341*75b1a2ecSyamt 	prop_object_t po;
342*75b1a2ecSyamt 
343*75b1a2ecSyamt 	_PROP_ASSERT(prop_object_is_array(pa));
344*75b1a2ecSyamt 
345*75b1a2ecSyamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
346*75b1a2ecSyamt 	po = _prop_array_iterator_next_object_locked(pai);
347eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
348774eb1a3Sthorpej 	return (po);
349774eb1a3Sthorpej }
350774eb1a3Sthorpej 
351774eb1a3Sthorpej static void
352*75b1a2ecSyamt _prop_array_iterator_reset_locked(void *v)
353774eb1a3Sthorpej {
354774eb1a3Sthorpej 	struct _prop_array_iterator *pai = v;
355774eb1a3Sthorpej 	prop_array_t pa = pai->pai_base.pi_obj;
356774eb1a3Sthorpej 
357774eb1a3Sthorpej 	_PROP_ASSERT(prop_object_is_array(pa));
3586787eedeSyamt 
359774eb1a3Sthorpej 	pai->pai_index = 0;
360774eb1a3Sthorpej 	pai->pai_base.pi_version = pa->pa_version;
361*75b1a2ecSyamt }
36235fe7cdcSxtraeme 
363*75b1a2ecSyamt static void
364*75b1a2ecSyamt _prop_array_iterator_reset(void *v)
365*75b1a2ecSyamt {
366*75b1a2ecSyamt 	struct _prop_array_iterator *pai = v;
367*75b1a2ecSyamt 	prop_array_t pa __unused = pai->pai_base.pi_obj;
368*75b1a2ecSyamt 
369*75b1a2ecSyamt 	_PROP_ASSERT(prop_object_is_array(pa));
370*75b1a2ecSyamt 
371*75b1a2ecSyamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
372*75b1a2ecSyamt 	_prop_array_iterator_reset_locked(pai);
37335fe7cdcSxtraeme 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
37435fe7cdcSxtraeme }
375774eb1a3Sthorpej 
376774eb1a3Sthorpej /*
377774eb1a3Sthorpej  * prop_array_create --
378774eb1a3Sthorpej  *	Create an empty array.
379774eb1a3Sthorpej  */
380774eb1a3Sthorpej prop_array_t
381774eb1a3Sthorpej prop_array_create(void)
382774eb1a3Sthorpej {
383774eb1a3Sthorpej 
384774eb1a3Sthorpej 	return (_prop_array_alloc(0));
385774eb1a3Sthorpej }
386774eb1a3Sthorpej 
387774eb1a3Sthorpej /*
388774eb1a3Sthorpej  * prop_array_create_with_capacity --
389774eb1a3Sthorpej  *	Create an array with the capacity to store N objects.
390774eb1a3Sthorpej  */
391774eb1a3Sthorpej prop_array_t
392774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity)
393774eb1a3Sthorpej {
394774eb1a3Sthorpej 
395774eb1a3Sthorpej 	return (_prop_array_alloc(capacity));
396774eb1a3Sthorpej }
397774eb1a3Sthorpej 
398774eb1a3Sthorpej /*
399774eb1a3Sthorpej  * prop_array_copy --
400774eb1a3Sthorpej  *	Copy an array.  The new array has an initial capacity equal to
401774eb1a3Sthorpej  *	the number of objects stored in the original array.  The new
402774eb1a3Sthorpej  *	array contains references to the original array's objects, not
403774eb1a3Sthorpej  *	copies of those objects (i.e. a shallow copy).
404774eb1a3Sthorpej  */
405774eb1a3Sthorpej prop_array_t
406774eb1a3Sthorpej prop_array_copy(prop_array_t opa)
407774eb1a3Sthorpej {
408774eb1a3Sthorpej 	prop_array_t pa;
409774eb1a3Sthorpej 	prop_object_t po;
410774eb1a3Sthorpej 	unsigned int idx;
411774eb1a3Sthorpej 
412d21620b2Sthorpej 	if (! prop_object_is_array(opa))
413d21620b2Sthorpej 		return (NULL);
414774eb1a3Sthorpej 
415eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
416eb2acb85Sthorpej 
417774eb1a3Sthorpej 	pa = _prop_array_alloc(opa->pa_count);
418774eb1a3Sthorpej 	if (pa != NULL) {
419774eb1a3Sthorpej 		for (idx = 0; idx < opa->pa_count; idx++) {
420774eb1a3Sthorpej 			po = opa->pa_array[idx];
421774eb1a3Sthorpej 			prop_object_retain(po);
422774eb1a3Sthorpej 			pa->pa_array[idx] = po;
423774eb1a3Sthorpej 		}
424774eb1a3Sthorpej 		pa->pa_count = opa->pa_count;
425774eb1a3Sthorpej 		pa->pa_flags = opa->pa_flags;
426774eb1a3Sthorpej 	}
427eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
428774eb1a3Sthorpej 	return (pa);
429774eb1a3Sthorpej }
430774eb1a3Sthorpej 
431774eb1a3Sthorpej /*
432774eb1a3Sthorpej  * prop_array_copy_mutable --
433774eb1a3Sthorpej  *	Like prop_array_copy(), but the resulting array is mutable.
434774eb1a3Sthorpej  */
435774eb1a3Sthorpej prop_array_t
436774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa)
437774eb1a3Sthorpej {
438774eb1a3Sthorpej 	prop_array_t pa;
439774eb1a3Sthorpej 
440774eb1a3Sthorpej 	pa = prop_array_copy(opa);
441774eb1a3Sthorpej 	if (pa != NULL)
442774eb1a3Sthorpej 		pa->pa_flags &= ~PA_F_IMMUTABLE;
443774eb1a3Sthorpej 
444774eb1a3Sthorpej 	return (pa);
445774eb1a3Sthorpej }
446774eb1a3Sthorpej 
447774eb1a3Sthorpej /*
448774eb1a3Sthorpej  * prop_array_capacity --
449774eb1a3Sthorpej  *	Return the capacity of the array.
450774eb1a3Sthorpej  */
451774eb1a3Sthorpej unsigned int
452774eb1a3Sthorpej prop_array_capacity(prop_array_t pa)
453774eb1a3Sthorpej {
454eb2acb85Sthorpej 	unsigned int rv;
455774eb1a3Sthorpej 
456d21620b2Sthorpej 	if (! prop_object_is_array(pa))
457d21620b2Sthorpej 		return (0);
458d21620b2Sthorpej 
459eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
460eb2acb85Sthorpej 	rv = pa->pa_capacity;
461eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
462eb2acb85Sthorpej 
463eb2acb85Sthorpej 	return (rv);
464774eb1a3Sthorpej }
465774eb1a3Sthorpej 
466774eb1a3Sthorpej /*
467774eb1a3Sthorpej  * prop_array_count --
468774eb1a3Sthorpej  *	Return the number of objects stored in the array.
469774eb1a3Sthorpej  */
470774eb1a3Sthorpej unsigned int
471774eb1a3Sthorpej prop_array_count(prop_array_t pa)
472774eb1a3Sthorpej {
473eb2acb85Sthorpej 	unsigned int rv;
474774eb1a3Sthorpej 
475d21620b2Sthorpej 	if (! prop_object_is_array(pa))
476d21620b2Sthorpej 		return (0);
477d21620b2Sthorpej 
478eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
479eb2acb85Sthorpej 	rv = pa->pa_count;
480eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
481eb2acb85Sthorpej 
482eb2acb85Sthorpej 	return (rv);
483774eb1a3Sthorpej }
484774eb1a3Sthorpej 
485774eb1a3Sthorpej /*
486774eb1a3Sthorpej  * prop_array_ensure_capacity --
487774eb1a3Sthorpej  *	Ensure that the array has the capacity to store the specified
488774eb1a3Sthorpej  *	total number of objects (inluding the objects already stored
489774eb1a3Sthorpej  *	in the array).
490774eb1a3Sthorpej  */
49104377267Sthorpej bool
492774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
493774eb1a3Sthorpej {
49404377267Sthorpej 	bool rv;
495774eb1a3Sthorpej 
496d21620b2Sthorpej 	if (! prop_object_is_array(pa))
49704377267Sthorpej 		return (false);
498d21620b2Sthorpej 
499eb2acb85Sthorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
500774eb1a3Sthorpej 	if (capacity > pa->pa_capacity)
501eb2acb85Sthorpej 		rv = _prop_array_expand(pa, capacity);
502eb2acb85Sthorpej 	else
50304377267Sthorpej 		rv = true;
504eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
505eb2acb85Sthorpej 
506eb2acb85Sthorpej 	return (rv);
507774eb1a3Sthorpej }
508774eb1a3Sthorpej 
509*75b1a2ecSyamt static prop_object_iterator_t
510*75b1a2ecSyamt _prop_array_iterator_locked(prop_array_t pa)
511774eb1a3Sthorpej {
512774eb1a3Sthorpej 	struct _prop_array_iterator *pai;
513774eb1a3Sthorpej 
514d21620b2Sthorpej 	if (! prop_object_is_array(pa))
515d21620b2Sthorpej 		return (NULL);
516774eb1a3Sthorpej 
517774eb1a3Sthorpej 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
518774eb1a3Sthorpej 	if (pai == NULL)
519774eb1a3Sthorpej 		return (NULL);
520774eb1a3Sthorpej 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
521774eb1a3Sthorpej 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
522774eb1a3Sthorpej 	prop_object_retain(pa);
523774eb1a3Sthorpej 	pai->pai_base.pi_obj = pa;
524*75b1a2ecSyamt 	_prop_array_iterator_reset_locked(pai);
525774eb1a3Sthorpej 
526774eb1a3Sthorpej 	return (&pai->pai_base);
527774eb1a3Sthorpej }
528774eb1a3Sthorpej 
529774eb1a3Sthorpej /*
530*75b1a2ecSyamt  * prop_array_iterator --
531*75b1a2ecSyamt  *	Return an iterator for the array.  The array is retained by
532*75b1a2ecSyamt  *	the iterator.
533*75b1a2ecSyamt  */
534*75b1a2ecSyamt prop_object_iterator_t
535*75b1a2ecSyamt prop_array_iterator(prop_array_t pa)
536*75b1a2ecSyamt {
537*75b1a2ecSyamt 	prop_object_iterator_t pi;
538*75b1a2ecSyamt 
539*75b1a2ecSyamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
540*75b1a2ecSyamt 	pi = _prop_array_iterator_locked(pa);
541*75b1a2ecSyamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
542*75b1a2ecSyamt 	return (pi);
543*75b1a2ecSyamt }
544*75b1a2ecSyamt 
545*75b1a2ecSyamt /*
546774eb1a3Sthorpej  * prop_array_make_immutable --
547774eb1a3Sthorpej  *	Make the array immutable.
548774eb1a3Sthorpej  */
549774eb1a3Sthorpej void
550774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa)
551774eb1a3Sthorpej {
552774eb1a3Sthorpej 
553eb2acb85Sthorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
55404377267Sthorpej 	if (prop_array_is_immutable(pa) == false)
555774eb1a3Sthorpej 		pa->pa_flags |= PA_F_IMMUTABLE;
556eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
557774eb1a3Sthorpej }
558774eb1a3Sthorpej 
559774eb1a3Sthorpej /*
560774eb1a3Sthorpej  * prop_array_mutable --
56104377267Sthorpej  *	Returns true if the array is mutable.
562774eb1a3Sthorpej  */
56304377267Sthorpej bool
564774eb1a3Sthorpej prop_array_mutable(prop_array_t pa)
565774eb1a3Sthorpej {
56604377267Sthorpej 	bool rv;
567774eb1a3Sthorpej 
568eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
56904377267Sthorpej 	rv = prop_array_is_immutable(pa) == false;
570eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
571eb2acb85Sthorpej 
572eb2acb85Sthorpej 	return (rv);
573774eb1a3Sthorpej }
574774eb1a3Sthorpej 
575774eb1a3Sthorpej /*
576774eb1a3Sthorpej  * prop_array_get --
577774eb1a3Sthorpej  *	Return the object stored at the specified array index.
578774eb1a3Sthorpej  */
579774eb1a3Sthorpej prop_object_t
580774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx)
581774eb1a3Sthorpej {
582eb2acb85Sthorpej 	prop_object_t po = NULL;
583774eb1a3Sthorpej 
584d21620b2Sthorpej 	if (! prop_object_is_array(pa))
585d21620b2Sthorpej 		return (NULL);
586d21620b2Sthorpej 
587eb2acb85Sthorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
588774eb1a3Sthorpej 	if (idx >= pa->pa_count)
589eb2acb85Sthorpej 		goto out;
590774eb1a3Sthorpej 	po = pa->pa_array[idx];
591774eb1a3Sthorpej 	_PROP_ASSERT(po != NULL);
592eb2acb85Sthorpej  out:
593eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
594774eb1a3Sthorpej 	return (po);
595774eb1a3Sthorpej }
596774eb1a3Sthorpej 
59704377267Sthorpej static bool
598eb2acb85Sthorpej _prop_array_add(prop_array_t pa, prop_object_t po)
599774eb1a3Sthorpej {
600774eb1a3Sthorpej 
601eb2acb85Sthorpej 	/*
602eb2acb85Sthorpej 	 * Array must be WRITE-LOCKED.
603eb2acb85Sthorpej 	 */
604d21620b2Sthorpej 
605774eb1a3Sthorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
606774eb1a3Sthorpej 
607774eb1a3Sthorpej 	if (prop_array_is_immutable(pa) ||
608774eb1a3Sthorpej 	    (pa->pa_count == pa->pa_capacity &&
60904377267Sthorpej 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
61004377267Sthorpej 		return (false);
611774eb1a3Sthorpej 
612774eb1a3Sthorpej 	prop_object_retain(po);
613774eb1a3Sthorpej 	pa->pa_array[pa->pa_count++] = po;
614774eb1a3Sthorpej 	pa->pa_version++;
615774eb1a3Sthorpej 
61604377267Sthorpej 	return (true);
617774eb1a3Sthorpej }
618774eb1a3Sthorpej 
619774eb1a3Sthorpej /*
620eb2acb85Sthorpej  * prop_array_set --
621eb2acb85Sthorpej  *	Store a reference to an object at the specified array index.
622eb2acb85Sthorpej  *	This method is not allowed to create holes in the array; the
623eb2acb85Sthorpej  *	caller must either be setting the object just beyond the existing
624eb2acb85Sthorpej  *	count or replacing an already existing object reference.
625eb2acb85Sthorpej  */
62604377267Sthorpej bool
627eb2acb85Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
628eb2acb85Sthorpej {
629eb2acb85Sthorpej 	prop_object_t opo;
63004377267Sthorpej 	bool rv = false;
631eb2acb85Sthorpej 
632eb2acb85Sthorpej 	if (! prop_object_is_array(pa))
63304377267Sthorpej 		return (false);
634eb2acb85Sthorpej 
635eb2acb85Sthorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
636eb2acb85Sthorpej 
637eb2acb85Sthorpej 	if (prop_array_is_immutable(pa))
638eb2acb85Sthorpej 		goto out;
639eb2acb85Sthorpej 
640eb2acb85Sthorpej 	if (idx == pa->pa_count) {
641eb2acb85Sthorpej 		rv = _prop_array_add(pa, po);
642eb2acb85Sthorpej 		goto out;
643eb2acb85Sthorpej 	}
644eb2acb85Sthorpej 
645eb2acb85Sthorpej 	_PROP_ASSERT(idx < pa->pa_count);
646eb2acb85Sthorpej 
647eb2acb85Sthorpej 	opo = pa->pa_array[idx];
648eb2acb85Sthorpej 	_PROP_ASSERT(opo != NULL);
649eb2acb85Sthorpej 
650eb2acb85Sthorpej 	prop_object_retain(po);
651eb2acb85Sthorpej 	pa->pa_array[idx] = po;
652eb2acb85Sthorpej 	pa->pa_version++;
653eb2acb85Sthorpej 
654eb2acb85Sthorpej 	prop_object_release(opo);
655eb2acb85Sthorpej 
65604377267Sthorpej 	rv = true;
657eb2acb85Sthorpej 
658eb2acb85Sthorpej  out:
659eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
660eb2acb85Sthorpej 	return (rv);
661eb2acb85Sthorpej }
662eb2acb85Sthorpej 
663eb2acb85Sthorpej /*
664eb2acb85Sthorpej  * prop_array_add --
665eb2acb85Sthorpej  *	Add a refrerence to an object to the specified array, appending
666eb2acb85Sthorpej  *	to the end and growing the array's capacity, if necessary.
667eb2acb85Sthorpej  */
66804377267Sthorpej bool
669eb2acb85Sthorpej prop_array_add(prop_array_t pa, prop_object_t po)
670eb2acb85Sthorpej {
67104377267Sthorpej 	bool rv;
672eb2acb85Sthorpej 
673eb2acb85Sthorpej 	if (! prop_object_is_array(pa))
67404377267Sthorpej 		return (false);
675eb2acb85Sthorpej 
676eb2acb85Sthorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
677eb2acb85Sthorpej 	rv = _prop_array_add(pa, po);
678eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
679eb2acb85Sthorpej 
680eb2acb85Sthorpej 	return (rv);
681eb2acb85Sthorpej }
682eb2acb85Sthorpej 
683eb2acb85Sthorpej /*
684774eb1a3Sthorpej  * prop_array_remove --
685774eb1a3Sthorpej  *	Remove the reference to an object from an array at the specified
686774eb1a3Sthorpej  *	index.  The array will be compacted following the removal.
687774eb1a3Sthorpej  */
688774eb1a3Sthorpej void
689774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx)
690774eb1a3Sthorpej {
691774eb1a3Sthorpej 	prop_object_t po;
692774eb1a3Sthorpej 
693d21620b2Sthorpej 	if (! prop_object_is_array(pa))
694d21620b2Sthorpej 		return;
695d21620b2Sthorpej 
696eb2acb85Sthorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
697eb2acb85Sthorpej 
698774eb1a3Sthorpej 	_PROP_ASSERT(idx < pa->pa_count);
699774eb1a3Sthorpej 
700774eb1a3Sthorpej 	/* XXX Should this be a _PROP_ASSERT()? */
701eb2acb85Sthorpej 	if (prop_array_is_immutable(pa)) {
702eb2acb85Sthorpej 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
703774eb1a3Sthorpej 		return;
704eb2acb85Sthorpej 	}
705774eb1a3Sthorpej 
706774eb1a3Sthorpej 	po = pa->pa_array[idx];
707774eb1a3Sthorpej 	_PROP_ASSERT(po != NULL);
708774eb1a3Sthorpej 
709774eb1a3Sthorpej 	for (++idx; idx < pa->pa_count; idx++)
710774eb1a3Sthorpej 		pa->pa_array[idx - 1] = pa->pa_array[idx];
711774eb1a3Sthorpej 	pa->pa_count--;
712774eb1a3Sthorpej 	pa->pa_version++;
713774eb1a3Sthorpej 
714eb2acb85Sthorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
715eb2acb85Sthorpej 
716774eb1a3Sthorpej 	prop_object_release(po);
717774eb1a3Sthorpej }
718774eb1a3Sthorpej 
719774eb1a3Sthorpej /*
7203e69f1b2Sthorpej  * prop_array_equals --
72104377267Sthorpej  *	Return true if the two arrays are equivalent.  Note we do a
7223e69f1b2Sthorpej  *	by-value comparison of the objects in the array.
7233e69f1b2Sthorpej  */
72404377267Sthorpej bool
7253e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2)
7263e69f1b2Sthorpej {
7274deb5931Sjoerg 	if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
7284deb5931Sjoerg 		return (false);
7293e69f1b2Sthorpej 
7304deb5931Sjoerg 	return (prop_object_equals(array1, array2));
7313e69f1b2Sthorpej }
7323e69f1b2Sthorpej 
7333e69f1b2Sthorpej /*
734d21620b2Sthorpej  * prop_array_externalize --
735d21620b2Sthorpej  *	Externalize an array, return a NUL-terminated buffer
736d21620b2Sthorpej  *	containing the XML-style representation.  The buffer is allocated
737d21620b2Sthorpej  * 	with the M_TEMP memory type.
738d21620b2Sthorpej  */
739d21620b2Sthorpej char *
740d21620b2Sthorpej prop_array_externalize(prop_array_t pa)
741d21620b2Sthorpej {
742d21620b2Sthorpej 	struct _prop_object_externalize_context *ctx;
743d21620b2Sthorpej 	char *cp;
744d21620b2Sthorpej 
745d21620b2Sthorpej 	ctx = _prop_object_externalize_context_alloc();
746d21620b2Sthorpej 	if (ctx == NULL)
747d21620b2Sthorpej 		return (NULL);
748d21620b2Sthorpej 
74904377267Sthorpej 	if (_prop_object_externalize_header(ctx) == false ||
75004377267Sthorpej 	    (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
75104377267Sthorpej 	    _prop_object_externalize_footer(ctx) == false) {
752d21620b2Sthorpej 		/* We are responsible for releasing the buffer. */
753d21620b2Sthorpej 		_PROP_FREE(ctx->poec_buf, M_TEMP);
754d21620b2Sthorpej 		_prop_object_externalize_context_free(ctx);
755d21620b2Sthorpej 		return (NULL);
756d21620b2Sthorpej 	}
757d21620b2Sthorpej 
758d21620b2Sthorpej 	cp = ctx->poec_buf;
759d21620b2Sthorpej 	_prop_object_externalize_context_free(ctx);
760d21620b2Sthorpej 
761d21620b2Sthorpej 	return (cp);
762d21620b2Sthorpej }
763d21620b2Sthorpej 
764d21620b2Sthorpej /*
765774eb1a3Sthorpej  * _prop_array_internalize --
766774eb1a3Sthorpej  *	Parse an <array>...</array> and return the object created from the
767774eb1a3Sthorpej  *	external representation.
768774eb1a3Sthorpej  */
769e835604cSjoerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
770e835604cSjoerg     struct _prop_object_internalize_context *);
771774eb1a3Sthorpej 
772e835604cSjoerg bool
773e835604cSjoerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
774e835604cSjoerg     struct _prop_object_internalize_context *ctx)
775e835604cSjoerg {
776774eb1a3Sthorpej 	/* We don't currently understand any attributes. */
777774eb1a3Sthorpej 	if (ctx->poic_tagattr != NULL)
778e835604cSjoerg 		return (true);
779774eb1a3Sthorpej 
780e835604cSjoerg 	*obj = prop_array_create();
781e835604cSjoerg 	/*
782e835604cSjoerg 	 * We are done if the create failed or no child elements exist.
783e835604cSjoerg 	 */
784e835604cSjoerg 	if (*obj == NULL || ctx->poic_is_empty_element)
785e835604cSjoerg 		return (true);
786774eb1a3Sthorpej 
787e835604cSjoerg 	/*
788e835604cSjoerg 	 * Opening tag is found, now continue to the first element.
789e835604cSjoerg 	 */
790e835604cSjoerg 	return (_prop_array_internalize_body(stack, obj, ctx));
791e835604cSjoerg }
792774eb1a3Sthorpej 
793e835604cSjoerg static bool
794e835604cSjoerg _prop_array_internalize_continue(prop_stack_t stack,
795e835604cSjoerg     prop_object_t *obj,
796e835604cSjoerg     struct _prop_object_internalize_context *ctx,
797e835604cSjoerg     void *data, prop_object_t child)
798e835604cSjoerg {
799e835604cSjoerg 	prop_array_t array;
800e835604cSjoerg 
801e835604cSjoerg 	_PROP_ASSERT(data == NULL);
802e835604cSjoerg 
803e835604cSjoerg 	if (child == NULL)
804e835604cSjoerg 		goto bad; /* Element could not be parsed. */
805e835604cSjoerg 
806e835604cSjoerg 	array = *obj;
807e835604cSjoerg 
808e835604cSjoerg 	if (prop_array_add(array, child) == false) {
809e835604cSjoerg 		prop_object_release(child);
810e835604cSjoerg 		goto bad;
811e835604cSjoerg 	}
812e835604cSjoerg 	prop_object_release(child);
813e835604cSjoerg 
814e835604cSjoerg 	/*
815e835604cSjoerg 	 * Current element is processed and added, look for next.
816e835604cSjoerg 	 */
817e835604cSjoerg 	return (_prop_array_internalize_body(stack, obj, ctx));
818e835604cSjoerg 
819e835604cSjoerg  bad:
820e835604cSjoerg 	prop_object_release(*obj);
821e835604cSjoerg 	*obj = NULL;
822e835604cSjoerg 	return (true);
823e835604cSjoerg }
824e835604cSjoerg 
825e835604cSjoerg static bool
826e835604cSjoerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
827e835604cSjoerg     struct _prop_object_internalize_context *ctx)
828e835604cSjoerg {
829e835604cSjoerg 	prop_array_t array = *obj;
830e835604cSjoerg 
831e835604cSjoerg 	_PROP_ASSERT(array != NULL);
832e835604cSjoerg 
833774eb1a3Sthorpej 	/* Fetch the next tag. */
834774eb1a3Sthorpej 	if (_prop_object_internalize_find_tag(ctx, NULL,
83504377267Sthorpej 				_PROP_TAG_TYPE_EITHER) == false)
836774eb1a3Sthorpej 		goto bad;
837774eb1a3Sthorpej 
838774eb1a3Sthorpej 	/* Check to see if this is the end of the array. */
839774eb1a3Sthorpej 	if (_PROP_TAG_MATCH(ctx, "array") &&
840e835604cSjoerg 	    ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
841e835604cSjoerg 		/* It is, so don't iterate any further. */
842e835604cSjoerg 		return (true);
843774eb1a3Sthorpej 	}
844774eb1a3Sthorpej 
8454deb5931Sjoerg 	if (_prop_stack_push(stack, array,
8464deb5931Sjoerg 			     _prop_array_internalize_continue, NULL, NULL))
847e835604cSjoerg 		return (false);
848774eb1a3Sthorpej 
849774eb1a3Sthorpej  bad:
850774eb1a3Sthorpej 	prop_object_release(array);
851e835604cSjoerg 	*obj = NULL;
852e835604cSjoerg 	return (true);
853774eb1a3Sthorpej }
854d21620b2Sthorpej 
855d21620b2Sthorpej /*
856d21620b2Sthorpej  * prop_array_internalize --
857d21620b2Sthorpej  *	Create an array by parsing the XML-style representation.
858d21620b2Sthorpej  */
859d21620b2Sthorpej prop_array_t
860d21620b2Sthorpej prop_array_internalize(const char *xml)
861d21620b2Sthorpej {
86239dccbf2Sjoerg 	return _prop_generic_internalize(xml, "array");
863d21620b2Sthorpej }
864d21620b2Sthorpej 
865d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
866d21620b2Sthorpej /*
867d21620b2Sthorpej  * prop_array_externalize_to_file --
868d21620b2Sthorpej  *	Externalize an array to the specified file.
869d21620b2Sthorpej  */
87004377267Sthorpej bool
871d21620b2Sthorpej prop_array_externalize_to_file(prop_array_t array, const char *fname)
872d21620b2Sthorpej {
873d21620b2Sthorpej 	char *xml;
87404377267Sthorpej 	bool rv;
8751a119b51She 	int save_errno = 0;	/* XXXGCC -Wuninitialized [mips, ...] */
876d21620b2Sthorpej 
877d21620b2Sthorpej 	xml = prop_array_externalize(array);
878d21620b2Sthorpej 	if (xml == NULL)
87904377267Sthorpej 		return (false);
880d21620b2Sthorpej 	rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
88104377267Sthorpej 	if (rv == false)
882d21620b2Sthorpej 		save_errno = errno;
883d21620b2Sthorpej 	_PROP_FREE(xml, M_TEMP);
88404377267Sthorpej 	if (rv == false)
885d21620b2Sthorpej 		errno = save_errno;
886d21620b2Sthorpej 
887d21620b2Sthorpej 	return (rv);
888d21620b2Sthorpej }
889d21620b2Sthorpej 
890d21620b2Sthorpej /*
891d21620b2Sthorpej  * prop_array_internalize_from_file --
892d21620b2Sthorpej  *	Internalize an array from a file.
893d21620b2Sthorpej  */
894d21620b2Sthorpej prop_array_t
895d21620b2Sthorpej prop_array_internalize_from_file(const char *fname)
896d21620b2Sthorpej {
897d21620b2Sthorpej 	struct _prop_object_internalize_mapped_file *mf;
898d21620b2Sthorpej 	prop_array_t array;
899d21620b2Sthorpej 
900d21620b2Sthorpej 	mf = _prop_object_internalize_map_file(fname);
901d21620b2Sthorpej 	if (mf == NULL)
902d21620b2Sthorpej 		return (NULL);
903d21620b2Sthorpej 	array = prop_array_internalize(mf->poimf_xml);
904d21620b2Sthorpej 	_prop_object_internalize_unmap_file(mf);
905d21620b2Sthorpej 
906d21620b2Sthorpej 	return (array);
907d21620b2Sthorpej }
908d21620b2Sthorpej #endif /* _KERNEL && !_STANDALONE */
909