xref: /netbsd-src/common/lib/libprop/prop_array.c (revision 95f94af30137064a6d8123b816fa7a480569ab55)
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