xref: /minix3/common/lib/libprop/prop_array.c (revision f14fb602092e015ff630df58e17c2a9cd57d29b3)
1*f14fb602SLionel Sambuc /*	$NetBSD: prop_array.c,v 1.21 2012/07/27 09:10:59 pooka Exp $	*/
26b6d114aSBen Gras 
36b6d114aSBen Gras /*-
46b6d114aSBen Gras  * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
56b6d114aSBen Gras  * All rights reserved.
66b6d114aSBen Gras  *
76b6d114aSBen Gras  * This code is derived from software contributed to The NetBSD Foundation
86b6d114aSBen Gras  * by Jason R. Thorpe.
96b6d114aSBen Gras  *
106b6d114aSBen Gras  * Redistribution and use in source and binary forms, with or without
116b6d114aSBen Gras  * modification, are permitted provided that the following conditions
126b6d114aSBen Gras  * are met:
136b6d114aSBen Gras  * 1. Redistributions of source code must retain the above copyright
146b6d114aSBen Gras  *    notice, this list of conditions and the following disclaimer.
156b6d114aSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
166b6d114aSBen Gras  *    notice, this list of conditions and the following disclaimer in the
176b6d114aSBen Gras  *    documentation and/or other materials provided with the distribution.
186b6d114aSBen Gras  *
196b6d114aSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206b6d114aSBen Gras  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216b6d114aSBen Gras  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226b6d114aSBen Gras  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236b6d114aSBen Gras  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246b6d114aSBen Gras  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256b6d114aSBen Gras  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266b6d114aSBen Gras  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276b6d114aSBen Gras  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286b6d114aSBen Gras  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296b6d114aSBen Gras  * POSSIBILITY OF SUCH DAMAGE.
306b6d114aSBen Gras  */
316b6d114aSBen Gras 
326b6d114aSBen Gras #include "prop_object_impl.h"
33*f14fb602SLionel Sambuc #include <prop/prop_array.h>
346b6d114aSBen Gras 
356b6d114aSBen Gras #if !defined(_KERNEL) && !defined(_STANDALONE)
366b6d114aSBen Gras #include <errno.h>
376b6d114aSBen Gras #endif
386b6d114aSBen Gras 
396b6d114aSBen Gras struct _prop_array {
406b6d114aSBen Gras 	struct _prop_object	pa_obj;
416b6d114aSBen Gras 	_PROP_RWLOCK_DECL(pa_rwlock)
426b6d114aSBen Gras 	prop_object_t *		pa_array;
436b6d114aSBen Gras 	unsigned int		pa_capacity;
446b6d114aSBen Gras 	unsigned int		pa_count;
456b6d114aSBen Gras 	int			pa_flags;
466b6d114aSBen Gras 
476b6d114aSBen Gras 	uint32_t		pa_version;
486b6d114aSBen Gras };
496b6d114aSBen Gras 
506b6d114aSBen Gras #define PA_F_IMMUTABLE		0x01	/* array is immutable */
516b6d114aSBen Gras 
526b6d114aSBen Gras _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
536b6d114aSBen Gras _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
546b6d114aSBen Gras 		    "property array container object")
556b6d114aSBen Gras 
566b6d114aSBen Gras static _prop_object_free_rv_t
576b6d114aSBen Gras 		_prop_array_free(prop_stack_t, prop_object_t *);
586b6d114aSBen Gras static void	_prop_array_emergency_free(prop_object_t);
596b6d114aSBen Gras static bool	_prop_array_externalize(
606b6d114aSBen Gras 				struct _prop_object_externalize_context *,
616b6d114aSBen Gras 				void *);
626b6d114aSBen Gras static _prop_object_equals_rv_t
636b6d114aSBen Gras 		_prop_array_equals(prop_object_t, prop_object_t,
646b6d114aSBen Gras 				   void **, void **,
656b6d114aSBen Gras 				   prop_object_t *, prop_object_t *);
666b6d114aSBen Gras static void	_prop_array_equals_finish(prop_object_t, prop_object_t);
676b6d114aSBen Gras static prop_object_iterator_t
686b6d114aSBen Gras 		_prop_array_iterator_locked(prop_array_t);
696b6d114aSBen Gras static prop_object_t
706b6d114aSBen Gras 		_prop_array_iterator_next_object_locked(void *);
716b6d114aSBen Gras static void	_prop_array_iterator_reset_locked(void *);
726b6d114aSBen Gras 
736b6d114aSBen Gras static const struct _prop_object_type _prop_object_type_array = {
746b6d114aSBen Gras 	.pot_type		=	PROP_TYPE_ARRAY,
756b6d114aSBen Gras 	.pot_free		=	_prop_array_free,
766b6d114aSBen Gras 	.pot_emergency_free	=	_prop_array_emergency_free,
776b6d114aSBen Gras 	.pot_extern		=	_prop_array_externalize,
786b6d114aSBen Gras 	.pot_equals		=	_prop_array_equals,
796b6d114aSBen Gras 	.pot_equals_finish	=	_prop_array_equals_finish,
806b6d114aSBen Gras };
816b6d114aSBen Gras 
826b6d114aSBen Gras #define prop_object_is_array(x)		\
836b6d114aSBen Gras 	((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
846b6d114aSBen Gras 
856b6d114aSBen Gras #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
866b6d114aSBen Gras 
876b6d114aSBen Gras struct _prop_array_iterator {
886b6d114aSBen Gras 	struct _prop_object_iterator pai_base;
896b6d114aSBen Gras 	unsigned int		pai_index;
906b6d114aSBen Gras };
916b6d114aSBen Gras 
926b6d114aSBen Gras #define EXPAND_STEP		16
936b6d114aSBen Gras 
946b6d114aSBen Gras static _prop_object_free_rv_t
_prop_array_free(prop_stack_t stack,prop_object_t * obj)956b6d114aSBen Gras _prop_array_free(prop_stack_t stack, prop_object_t *obj)
966b6d114aSBen Gras {
976b6d114aSBen Gras 	prop_array_t pa = *obj;
986b6d114aSBen Gras 	prop_object_t po;
996b6d114aSBen Gras 
1006b6d114aSBen Gras 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
1016b6d114aSBen Gras 	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
1026b6d114aSBen Gras 		     (pa->pa_capacity != 0 && pa->pa_array != NULL));
1036b6d114aSBen Gras 
1046b6d114aSBen Gras 	/* The easy case is an empty array, just free and return. */
1056b6d114aSBen Gras 	if (pa->pa_count == 0) {
1066b6d114aSBen Gras 		if (pa->pa_array != NULL)
1076b6d114aSBen Gras 			_PROP_FREE(pa->pa_array, M_PROP_ARRAY);
1086b6d114aSBen Gras 
1096b6d114aSBen Gras 		_PROP_RWLOCK_DESTROY(pa->pa_rwlock);
1106b6d114aSBen Gras 
1116b6d114aSBen Gras 		_PROP_POOL_PUT(_prop_array_pool, pa);
1126b6d114aSBen Gras 
1136b6d114aSBen Gras 		return (_PROP_OBJECT_FREE_DONE);
1146b6d114aSBen Gras 	}
1156b6d114aSBen Gras 
1166b6d114aSBen Gras 	po = pa->pa_array[pa->pa_count - 1];
1176b6d114aSBen Gras 	_PROP_ASSERT(po != NULL);
1186b6d114aSBen Gras 
1196b6d114aSBen Gras 	if (stack == NULL) {
1206b6d114aSBen Gras 		/*
1216b6d114aSBen Gras 		 * If we are in emergency release mode,
1226b6d114aSBen Gras 		 * just let caller recurse down.
1236b6d114aSBen Gras 		 */
1246b6d114aSBen Gras 		*obj = po;
1256b6d114aSBen Gras 		return (_PROP_OBJECT_FREE_FAILED);
1266b6d114aSBen Gras 	}
1276b6d114aSBen Gras 
1286b6d114aSBen Gras 	/* Otherwise, try to push the current object on the stack. */
1296b6d114aSBen Gras 	if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
1306b6d114aSBen Gras 		/* Push failed, entering emergency release mode. */
1316b6d114aSBen Gras 		return (_PROP_OBJECT_FREE_FAILED);
1326b6d114aSBen Gras 	}
1336b6d114aSBen Gras 	/* Object pushed on stack, caller will release it. */
1346b6d114aSBen Gras 	--pa->pa_count;
1356b6d114aSBen Gras 	*obj = po;
1366b6d114aSBen Gras 	return (_PROP_OBJECT_FREE_RECURSE);
1376b6d114aSBen Gras }
1386b6d114aSBen Gras 
1396b6d114aSBen Gras static void
_prop_array_emergency_free(prop_object_t obj)1406b6d114aSBen Gras _prop_array_emergency_free(prop_object_t obj)
1416b6d114aSBen Gras {
1426b6d114aSBen Gras 	prop_array_t pa = obj;
1436b6d114aSBen Gras 
1446b6d114aSBen Gras 	_PROP_ASSERT(pa->pa_count != 0);
1456b6d114aSBen Gras 	--pa->pa_count;
1466b6d114aSBen Gras }
1476b6d114aSBen Gras 
1486b6d114aSBen Gras static bool
_prop_array_externalize(struct _prop_object_externalize_context * ctx,void * v)1496b6d114aSBen Gras _prop_array_externalize(struct _prop_object_externalize_context *ctx,
1506b6d114aSBen Gras 			void *v)
1516b6d114aSBen Gras {
1526b6d114aSBen Gras 	prop_array_t pa = v;
1536b6d114aSBen Gras 	struct _prop_object *po;
1546b6d114aSBen Gras 	prop_object_iterator_t pi;
1556b6d114aSBen Gras 	unsigned int i;
1566b6d114aSBen Gras 	bool rv = false;
1576b6d114aSBen Gras 
1586b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
1596b6d114aSBen Gras 
1606b6d114aSBen Gras 	if (pa->pa_count == 0) {
1616b6d114aSBen Gras 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
1626b6d114aSBen Gras 		return (_prop_object_externalize_empty_tag(ctx, "array"));
1636b6d114aSBen Gras 	}
1646b6d114aSBen Gras 
1656b6d114aSBen Gras 	/* XXXJRT Hint "count" for the internalize step? */
1666b6d114aSBen Gras 	if (_prop_object_externalize_start_tag(ctx, "array") == false ||
1676b6d114aSBen Gras 	    _prop_object_externalize_append_char(ctx, '\n') == false)
1686b6d114aSBen Gras 		goto out;
1696b6d114aSBen Gras 
1706b6d114aSBen Gras 	pi = _prop_array_iterator_locked(pa);
1716b6d114aSBen Gras 	if (pi == NULL)
1726b6d114aSBen Gras 		goto out;
1736b6d114aSBen Gras 
1746b6d114aSBen Gras 	ctx->poec_depth++;
1756b6d114aSBen Gras 	_PROP_ASSERT(ctx->poec_depth != 0);
1766b6d114aSBen Gras 
1776b6d114aSBen Gras 	while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
1786b6d114aSBen Gras 		if ((*po->po_type->pot_extern)(ctx, po) == false) {
1796b6d114aSBen Gras 			prop_object_iterator_release(pi);
1806b6d114aSBen Gras 			goto out;
1816b6d114aSBen Gras 		}
1826b6d114aSBen Gras 	}
1836b6d114aSBen Gras 
1846b6d114aSBen Gras 	prop_object_iterator_release(pi);
1856b6d114aSBen Gras 
1866b6d114aSBen Gras 	ctx->poec_depth--;
1876b6d114aSBen Gras 	for (i = 0; i < ctx->poec_depth; i++) {
1886b6d114aSBen Gras 		if (_prop_object_externalize_append_char(ctx, '\t') == false)
1896b6d114aSBen Gras 			goto out;
1906b6d114aSBen Gras 	}
1916b6d114aSBen Gras 	if (_prop_object_externalize_end_tag(ctx, "array") == false)
1926b6d114aSBen Gras 		goto out;
1936b6d114aSBen Gras 
1946b6d114aSBen Gras 	rv = true;
1956b6d114aSBen Gras 
1966b6d114aSBen Gras  out:
1976b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
1986b6d114aSBen Gras 	return (rv);
1996b6d114aSBen Gras }
2006b6d114aSBen Gras 
2016b6d114aSBen Gras /* ARGSUSED */
2026b6d114aSBen Gras 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)2036b6d114aSBen Gras _prop_array_equals(prop_object_t v1, prop_object_t v2,
2046b6d114aSBen Gras     void **stored_pointer1, void **stored_pointer2,
2056b6d114aSBen Gras     prop_object_t *next_obj1, prop_object_t *next_obj2)
2066b6d114aSBen Gras {
2076b6d114aSBen Gras 	prop_array_t array1 = v1;
2086b6d114aSBen Gras 	prop_array_t array2 = v2;
2096b6d114aSBen Gras 	uintptr_t idx;
2106b6d114aSBen Gras 	_prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
2116b6d114aSBen Gras 
2126b6d114aSBen Gras 	if (array1 == array2)
2136b6d114aSBen Gras 		return (_PROP_OBJECT_EQUALS_TRUE);
2146b6d114aSBen Gras 
2156b6d114aSBen Gras 	_PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
2166b6d114aSBen Gras 	idx = (uintptr_t)*stored_pointer1;
2176b6d114aSBen Gras 
2186b6d114aSBen Gras 	/* For the first iteration, lock the objects. */
2196b6d114aSBen Gras 	if (idx == 0) {
2206b6d114aSBen Gras 		if ((uintptr_t)array1 < (uintptr_t)array2) {
2216b6d114aSBen Gras 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
2226b6d114aSBen Gras 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
2236b6d114aSBen Gras 		} else {
2246b6d114aSBen Gras 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
2256b6d114aSBen Gras 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
2266b6d114aSBen Gras 		}
2276b6d114aSBen Gras 	}
2286b6d114aSBen Gras 
2296b6d114aSBen Gras 	if (array1->pa_count != array2->pa_count)
2306b6d114aSBen Gras 		goto out;
2316b6d114aSBen Gras 	if (idx == array1->pa_count) {
2326b6d114aSBen Gras 		rv = _PROP_OBJECT_EQUALS_TRUE;
2336b6d114aSBen Gras 		goto out;
2346b6d114aSBen Gras 	}
2356b6d114aSBen Gras 	_PROP_ASSERT(idx < array1->pa_count);
2366b6d114aSBen Gras 
2376b6d114aSBen Gras 	*stored_pointer1 = (void *)(idx + 1);
2386b6d114aSBen Gras 	*stored_pointer2 = (void *)(idx + 1);
2396b6d114aSBen Gras 
2406b6d114aSBen Gras 	*next_obj1 = array1->pa_array[idx];
2416b6d114aSBen Gras 	*next_obj2 = array2->pa_array[idx];
2426b6d114aSBen Gras 
2436b6d114aSBen Gras 	return (_PROP_OBJECT_EQUALS_RECURSE);
2446b6d114aSBen Gras 
2456b6d114aSBen Gras  out:
2466b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
2476b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
2486b6d114aSBen Gras 	return (rv);
2496b6d114aSBen Gras }
2506b6d114aSBen Gras 
2516b6d114aSBen Gras static void
_prop_array_equals_finish(prop_object_t v1,prop_object_t v2)2526b6d114aSBen Gras _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
2536b6d114aSBen Gras {
2546b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
2556b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
2566b6d114aSBen Gras }
2576b6d114aSBen Gras 
2586b6d114aSBen Gras static prop_array_t
_prop_array_alloc(unsigned int capacity)2596b6d114aSBen Gras _prop_array_alloc(unsigned int capacity)
2606b6d114aSBen Gras {
2616b6d114aSBen Gras 	prop_array_t pa;
2626b6d114aSBen Gras 	prop_object_t *array;
2636b6d114aSBen Gras 
2646b6d114aSBen Gras 	if (capacity != 0) {
2656b6d114aSBen Gras 		array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
2666b6d114aSBen Gras 				     M_PROP_ARRAY);
2676b6d114aSBen Gras 		if (array == NULL)
2686b6d114aSBen Gras 			return (NULL);
2696b6d114aSBen Gras 	} else
2706b6d114aSBen Gras 		array = NULL;
2716b6d114aSBen Gras 
2726b6d114aSBen Gras 	pa = _PROP_POOL_GET(_prop_array_pool);
2736b6d114aSBen Gras 	if (pa != NULL) {
2746b6d114aSBen Gras 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
2756b6d114aSBen Gras 		pa->pa_obj.po_type = &_prop_object_type_array;
2766b6d114aSBen Gras 
2776b6d114aSBen Gras 		_PROP_RWLOCK_INIT(pa->pa_rwlock);
2786b6d114aSBen Gras 		pa->pa_array = array;
2796b6d114aSBen Gras 		pa->pa_capacity = capacity;
2806b6d114aSBen Gras 		pa->pa_count = 0;
2816b6d114aSBen Gras 		pa->pa_flags = 0;
2826b6d114aSBen Gras 
2836b6d114aSBen Gras 		pa->pa_version = 0;
2846b6d114aSBen Gras 	} else if (array != NULL)
2856b6d114aSBen Gras 		_PROP_FREE(array, M_PROP_ARRAY);
2866b6d114aSBen Gras 
2876b6d114aSBen Gras 	return (pa);
2886b6d114aSBen Gras }
2896b6d114aSBen Gras 
2906b6d114aSBen Gras static bool
_prop_array_expand(prop_array_t pa,unsigned int capacity)2916b6d114aSBen Gras _prop_array_expand(prop_array_t pa, unsigned int capacity)
2926b6d114aSBen Gras {
2936b6d114aSBen Gras 	prop_object_t *array, *oarray;
2946b6d114aSBen Gras 
2956b6d114aSBen Gras 	/*
2966b6d114aSBen Gras 	 * Array must be WRITE-LOCKED.
2976b6d114aSBen Gras 	 */
2986b6d114aSBen Gras 
2996b6d114aSBen Gras 	oarray = pa->pa_array;
3006b6d114aSBen Gras 
3016b6d114aSBen Gras 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
3026b6d114aSBen Gras 	if (array == NULL)
3036b6d114aSBen Gras 		return (false);
3046b6d114aSBen Gras 	if (oarray != NULL)
3056b6d114aSBen Gras 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
3066b6d114aSBen Gras 	pa->pa_array = array;
3076b6d114aSBen Gras 	pa->pa_capacity = capacity;
3086b6d114aSBen Gras 
3096b6d114aSBen Gras 	if (oarray != NULL)
3106b6d114aSBen Gras 		_PROP_FREE(oarray, M_PROP_ARRAY);
3116b6d114aSBen Gras 
3126b6d114aSBen Gras 	return (true);
3136b6d114aSBen Gras }
3146b6d114aSBen Gras 
3156b6d114aSBen Gras static prop_object_t
_prop_array_iterator_next_object_locked(void * v)3166b6d114aSBen Gras _prop_array_iterator_next_object_locked(void *v)
3176b6d114aSBen Gras {
3186b6d114aSBen Gras 	struct _prop_array_iterator *pai = v;
3196b6d114aSBen Gras 	prop_array_t pa = pai->pai_base.pi_obj;
3206b6d114aSBen Gras 	prop_object_t po = NULL;
3216b6d114aSBen Gras 
3226b6d114aSBen Gras 	_PROP_ASSERT(prop_object_is_array(pa));
3236b6d114aSBen Gras 
3246b6d114aSBen Gras 	if (pa->pa_version != pai->pai_base.pi_version)
3256b6d114aSBen Gras 		goto out;	/* array changed during iteration */
3266b6d114aSBen Gras 
3276b6d114aSBen Gras 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
3286b6d114aSBen Gras 
3296b6d114aSBen Gras 	if (pai->pai_index == pa->pa_count)
3306b6d114aSBen Gras 		goto out;	/* we've iterated all objects */
3316b6d114aSBen Gras 
3326b6d114aSBen Gras 	po = pa->pa_array[pai->pai_index];
3336b6d114aSBen Gras 	pai->pai_index++;
3346b6d114aSBen Gras 
3356b6d114aSBen Gras  out:
3366b6d114aSBen Gras 	return (po);
3376b6d114aSBen Gras }
3386b6d114aSBen Gras 
3396b6d114aSBen Gras static prop_object_t
_prop_array_iterator_next_object(void * v)3406b6d114aSBen Gras _prop_array_iterator_next_object(void *v)
3416b6d114aSBen Gras {
3426b6d114aSBen Gras 	struct _prop_array_iterator *pai = v;
343*f14fb602SLionel Sambuc 	prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
3446b6d114aSBen Gras 	prop_object_t po;
3456b6d114aSBen Gras 
3466b6d114aSBen Gras 	_PROP_ASSERT(prop_object_is_array(pa));
3476b6d114aSBen Gras 
3486b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
3496b6d114aSBen Gras 	po = _prop_array_iterator_next_object_locked(pai);
3506b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
3516b6d114aSBen Gras 	return (po);
3526b6d114aSBen Gras }
3536b6d114aSBen Gras 
3546b6d114aSBen Gras static void
_prop_array_iterator_reset_locked(void * v)3556b6d114aSBen Gras _prop_array_iterator_reset_locked(void *v)
3566b6d114aSBen Gras {
3576b6d114aSBen Gras 	struct _prop_array_iterator *pai = v;
3586b6d114aSBen Gras 	prop_array_t pa = pai->pai_base.pi_obj;
3596b6d114aSBen Gras 
3606b6d114aSBen Gras 	_PROP_ASSERT(prop_object_is_array(pa));
3616b6d114aSBen Gras 
3626b6d114aSBen Gras 	pai->pai_index = 0;
3636b6d114aSBen Gras 	pai->pai_base.pi_version = pa->pa_version;
3646b6d114aSBen Gras }
3656b6d114aSBen Gras 
3666b6d114aSBen Gras static void
_prop_array_iterator_reset(void * v)3676b6d114aSBen Gras _prop_array_iterator_reset(void *v)
3686b6d114aSBen Gras {
3696b6d114aSBen Gras 	struct _prop_array_iterator *pai = v;
370*f14fb602SLionel Sambuc 	prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
3716b6d114aSBen Gras 
3726b6d114aSBen Gras 	_PROP_ASSERT(prop_object_is_array(pa));
3736b6d114aSBen Gras 
3746b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
3756b6d114aSBen Gras 	_prop_array_iterator_reset_locked(pai);
3766b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
3776b6d114aSBen Gras }
3786b6d114aSBen Gras 
3796b6d114aSBen Gras /*
3806b6d114aSBen Gras  * prop_array_create --
3816b6d114aSBen Gras  *	Create an empty array.
3826b6d114aSBen Gras  */
3836b6d114aSBen Gras prop_array_t
prop_array_create(void)3846b6d114aSBen Gras prop_array_create(void)
3856b6d114aSBen Gras {
3866b6d114aSBen Gras 
3876b6d114aSBen Gras 	return (_prop_array_alloc(0));
3886b6d114aSBen Gras }
3896b6d114aSBen Gras 
3906b6d114aSBen Gras /*
3916b6d114aSBen Gras  * prop_array_create_with_capacity --
3926b6d114aSBen Gras  *	Create an array with the capacity to store N objects.
3936b6d114aSBen Gras  */
3946b6d114aSBen Gras prop_array_t
prop_array_create_with_capacity(unsigned int capacity)3956b6d114aSBen Gras prop_array_create_with_capacity(unsigned int capacity)
3966b6d114aSBen Gras {
3976b6d114aSBen Gras 
3986b6d114aSBen Gras 	return (_prop_array_alloc(capacity));
3996b6d114aSBen Gras }
4006b6d114aSBen Gras 
4016b6d114aSBen Gras /*
4026b6d114aSBen Gras  * prop_array_copy --
4036b6d114aSBen Gras  *	Copy an array.	The new array has an initial capacity equal to
4046b6d114aSBen Gras  *	the number of objects stored in the original array.  The new
4056b6d114aSBen Gras  *	array contains references to the original array's objects, not
4066b6d114aSBen Gras  *	copies of those objects (i.e. a shallow copy).
4076b6d114aSBen Gras  */
4086b6d114aSBen Gras prop_array_t
prop_array_copy(prop_array_t opa)4096b6d114aSBen Gras prop_array_copy(prop_array_t opa)
4106b6d114aSBen Gras {
4116b6d114aSBen Gras 	prop_array_t pa;
4126b6d114aSBen Gras 	prop_object_t po;
4136b6d114aSBen Gras 	unsigned int idx;
4146b6d114aSBen Gras 
4156b6d114aSBen Gras 	if (! prop_object_is_array(opa))
4166b6d114aSBen Gras 		return (NULL);
4176b6d114aSBen Gras 
4186b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
4196b6d114aSBen Gras 
4206b6d114aSBen Gras 	pa = _prop_array_alloc(opa->pa_count);
4216b6d114aSBen Gras 	if (pa != NULL) {
4226b6d114aSBen Gras 		for (idx = 0; idx < opa->pa_count; idx++) {
4236b6d114aSBen Gras 			po = opa->pa_array[idx];
4246b6d114aSBen Gras 			prop_object_retain(po);
4256b6d114aSBen Gras 			pa->pa_array[idx] = po;
4266b6d114aSBen Gras 		}
4276b6d114aSBen Gras 		pa->pa_count = opa->pa_count;
4286b6d114aSBen Gras 		pa->pa_flags = opa->pa_flags;
4296b6d114aSBen Gras 	}
4306b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
4316b6d114aSBen Gras 	return (pa);
4326b6d114aSBen Gras }
4336b6d114aSBen Gras 
4346b6d114aSBen Gras /*
4356b6d114aSBen Gras  * prop_array_copy_mutable --
4366b6d114aSBen Gras  *	Like prop_array_copy(), but the resulting array is mutable.
4376b6d114aSBen Gras  */
4386b6d114aSBen Gras prop_array_t
prop_array_copy_mutable(prop_array_t opa)4396b6d114aSBen Gras prop_array_copy_mutable(prop_array_t opa)
4406b6d114aSBen Gras {
4416b6d114aSBen Gras 	prop_array_t pa;
4426b6d114aSBen Gras 
4436b6d114aSBen Gras 	pa = prop_array_copy(opa);
4446b6d114aSBen Gras 	if (pa != NULL)
4456b6d114aSBen Gras 		pa->pa_flags &= ~PA_F_IMMUTABLE;
4466b6d114aSBen Gras 
4476b6d114aSBen Gras 	return (pa);
4486b6d114aSBen Gras }
4496b6d114aSBen Gras 
4506b6d114aSBen Gras /*
4516b6d114aSBen Gras  * prop_array_capacity --
4526b6d114aSBen Gras  *	Return the capacity of the array.
4536b6d114aSBen Gras  */
4546b6d114aSBen Gras unsigned int
prop_array_capacity(prop_array_t pa)4556b6d114aSBen Gras prop_array_capacity(prop_array_t pa)
4566b6d114aSBen Gras {
4576b6d114aSBen Gras 	unsigned int rv;
4586b6d114aSBen Gras 
4596b6d114aSBen Gras 	if (! prop_object_is_array(pa))
4606b6d114aSBen Gras 		return (0);
4616b6d114aSBen Gras 
4626b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
4636b6d114aSBen Gras 	rv = pa->pa_capacity;
4646b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
4656b6d114aSBen Gras 
4666b6d114aSBen Gras 	return (rv);
4676b6d114aSBen Gras }
4686b6d114aSBen Gras 
4696b6d114aSBen Gras /*
4706b6d114aSBen Gras  * prop_array_count --
4716b6d114aSBen Gras  *	Return the number of objects stored in the array.
4726b6d114aSBen Gras  */
4736b6d114aSBen Gras unsigned int
prop_array_count(prop_array_t pa)4746b6d114aSBen Gras prop_array_count(prop_array_t pa)
4756b6d114aSBen Gras {
4766b6d114aSBen Gras 	unsigned int rv;
4776b6d114aSBen Gras 
4786b6d114aSBen Gras 	if (! prop_object_is_array(pa))
4796b6d114aSBen Gras 		return (0);
4806b6d114aSBen Gras 
4816b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
4826b6d114aSBen Gras 	rv = pa->pa_count;
4836b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
4846b6d114aSBen Gras 
4856b6d114aSBen Gras 	return (rv);
4866b6d114aSBen Gras }
4876b6d114aSBen Gras 
4886b6d114aSBen Gras /*
4896b6d114aSBen Gras  * prop_array_ensure_capacity --
4906b6d114aSBen Gras  *	Ensure that the array has the capacity to store the specified
4916b6d114aSBen Gras  *	total number of objects (inluding the objects already stored
4926b6d114aSBen Gras  *	in the array).
4936b6d114aSBen Gras  */
4946b6d114aSBen Gras bool
prop_array_ensure_capacity(prop_array_t pa,unsigned int capacity)4956b6d114aSBen Gras prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
4966b6d114aSBen Gras {
4976b6d114aSBen Gras 	bool rv;
4986b6d114aSBen Gras 
4996b6d114aSBen Gras 	if (! prop_object_is_array(pa))
5006b6d114aSBen Gras 		return (false);
5016b6d114aSBen Gras 
5026b6d114aSBen Gras 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
5036b6d114aSBen Gras 	if (capacity > pa->pa_capacity)
5046b6d114aSBen Gras 		rv = _prop_array_expand(pa, capacity);
5056b6d114aSBen Gras 	else
5066b6d114aSBen Gras 		rv = true;
5076b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5086b6d114aSBen Gras 
5096b6d114aSBen Gras 	return (rv);
5106b6d114aSBen Gras }
5116b6d114aSBen Gras 
5126b6d114aSBen Gras static prop_object_iterator_t
_prop_array_iterator_locked(prop_array_t pa)5136b6d114aSBen Gras _prop_array_iterator_locked(prop_array_t pa)
5146b6d114aSBen Gras {
5156b6d114aSBen Gras 	struct _prop_array_iterator *pai;
5166b6d114aSBen Gras 
5176b6d114aSBen Gras 	if (! prop_object_is_array(pa))
5186b6d114aSBen Gras 		return (NULL);
5196b6d114aSBen Gras 
5206b6d114aSBen Gras 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
5216b6d114aSBen Gras 	if (pai == NULL)
5226b6d114aSBen Gras 		return (NULL);
5236b6d114aSBen Gras 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
5246b6d114aSBen Gras 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
5256b6d114aSBen Gras 	prop_object_retain(pa);
5266b6d114aSBen Gras 	pai->pai_base.pi_obj = pa;
5276b6d114aSBen Gras 	_prop_array_iterator_reset_locked(pai);
5286b6d114aSBen Gras 
5296b6d114aSBen Gras 	return (&pai->pai_base);
5306b6d114aSBen Gras }
5316b6d114aSBen Gras 
5326b6d114aSBen Gras /*
5336b6d114aSBen Gras  * prop_array_iterator --
5346b6d114aSBen Gras  *	Return an iterator for the array.  The array is retained by
5356b6d114aSBen Gras  *	the iterator.
5366b6d114aSBen Gras  */
5376b6d114aSBen Gras prop_object_iterator_t
prop_array_iterator(prop_array_t pa)5386b6d114aSBen Gras prop_array_iterator(prop_array_t pa)
5396b6d114aSBen Gras {
5406b6d114aSBen Gras 	prop_object_iterator_t pi;
5416b6d114aSBen Gras 
5426b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5436b6d114aSBen Gras 	pi = _prop_array_iterator_locked(pa);
5446b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5456b6d114aSBen Gras 	return (pi);
5466b6d114aSBen Gras }
5476b6d114aSBen Gras 
5486b6d114aSBen Gras /*
5496b6d114aSBen Gras  * prop_array_make_immutable --
5506b6d114aSBen Gras  *	Make the array immutable.
5516b6d114aSBen Gras  */
5526b6d114aSBen Gras void
prop_array_make_immutable(prop_array_t pa)5536b6d114aSBen Gras prop_array_make_immutable(prop_array_t pa)
5546b6d114aSBen Gras {
5556b6d114aSBen Gras 
5566b6d114aSBen Gras 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
5576b6d114aSBen Gras 	if (prop_array_is_immutable(pa) == false)
5586b6d114aSBen Gras 		pa->pa_flags |= PA_F_IMMUTABLE;
5596b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5606b6d114aSBen Gras }
5616b6d114aSBen Gras 
5626b6d114aSBen Gras /*
5636b6d114aSBen Gras  * prop_array_mutable --
5646b6d114aSBen Gras  *	Returns true if the array is mutable.
5656b6d114aSBen Gras  */
5666b6d114aSBen Gras bool
prop_array_mutable(prop_array_t pa)5676b6d114aSBen Gras prop_array_mutable(prop_array_t pa)
5686b6d114aSBen Gras {
5696b6d114aSBen Gras 	bool rv;
5706b6d114aSBen Gras 
5716b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5726b6d114aSBen Gras 	rv = prop_array_is_immutable(pa) == false;
5736b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5746b6d114aSBen Gras 
5756b6d114aSBen Gras 	return (rv);
5766b6d114aSBen Gras }
5776b6d114aSBen Gras 
5786b6d114aSBen Gras /*
5796b6d114aSBen Gras  * prop_array_get --
5806b6d114aSBen Gras  *	Return the object stored at the specified array index.
5816b6d114aSBen Gras  */
5826b6d114aSBen Gras prop_object_t
prop_array_get(prop_array_t pa,unsigned int idx)5836b6d114aSBen Gras prop_array_get(prop_array_t pa, unsigned int idx)
5846b6d114aSBen Gras {
5856b6d114aSBen Gras 	prop_object_t po = NULL;
5866b6d114aSBen Gras 
5876b6d114aSBen Gras 	if (! prop_object_is_array(pa))
5886b6d114aSBen Gras 		return (NULL);
5896b6d114aSBen Gras 
5906b6d114aSBen Gras 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
5916b6d114aSBen Gras 	if (idx >= pa->pa_count)
5926b6d114aSBen Gras 		goto out;
5936b6d114aSBen Gras 	po = pa->pa_array[idx];
5946b6d114aSBen Gras 	_PROP_ASSERT(po != NULL);
5956b6d114aSBen Gras  out:
5966b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
5976b6d114aSBen Gras 	return (po);
5986b6d114aSBen Gras }
5996b6d114aSBen Gras 
6006b6d114aSBen Gras static bool
_prop_array_add(prop_array_t pa,prop_object_t po)6016b6d114aSBen Gras _prop_array_add(prop_array_t pa, prop_object_t po)
6026b6d114aSBen Gras {
6036b6d114aSBen Gras 
6046b6d114aSBen Gras 	/*
6056b6d114aSBen Gras 	 * Array must be WRITE-LOCKED.
6066b6d114aSBen Gras 	 */
6076b6d114aSBen Gras 
6086b6d114aSBen Gras 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
6096b6d114aSBen Gras 
6106b6d114aSBen Gras 	if (prop_array_is_immutable(pa) ||
6116b6d114aSBen Gras 	    (pa->pa_count == pa->pa_capacity &&
6126b6d114aSBen Gras 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
6136b6d114aSBen Gras 		return (false);
6146b6d114aSBen Gras 
6156b6d114aSBen Gras 	prop_object_retain(po);
6166b6d114aSBen Gras 	pa->pa_array[pa->pa_count++] = po;
6176b6d114aSBen Gras 	pa->pa_version++;
6186b6d114aSBen Gras 
6196b6d114aSBen Gras 	return (true);
6206b6d114aSBen Gras }
6216b6d114aSBen Gras 
6226b6d114aSBen Gras /*
6236b6d114aSBen Gras  * prop_array_set --
6246b6d114aSBen Gras  *	Store a reference to an object at the specified array index.
6256b6d114aSBen Gras  *	This method is not allowed to create holes in the array; the
6266b6d114aSBen Gras  *	caller must either be setting the object just beyond the existing
6276b6d114aSBen Gras  *	count or replacing an already existing object reference.
6286b6d114aSBen Gras  */
6296b6d114aSBen Gras bool
prop_array_set(prop_array_t pa,unsigned int idx,prop_object_t po)6306b6d114aSBen Gras prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
6316b6d114aSBen Gras {
6326b6d114aSBen Gras 	prop_object_t opo;
6336b6d114aSBen Gras 	bool rv = false;
6346b6d114aSBen Gras 
6356b6d114aSBen Gras 	if (! prop_object_is_array(pa))
6366b6d114aSBen Gras 		return (false);
6376b6d114aSBen Gras 
6386b6d114aSBen Gras 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
6396b6d114aSBen Gras 
6406b6d114aSBen Gras 	if (prop_array_is_immutable(pa))
6416b6d114aSBen Gras 		goto out;
6426b6d114aSBen Gras 
6436b6d114aSBen Gras 	if (idx == pa->pa_count) {
6446b6d114aSBen Gras 		rv = _prop_array_add(pa, po);
6456b6d114aSBen Gras 		goto out;
6466b6d114aSBen Gras 	}
6476b6d114aSBen Gras 
6486b6d114aSBen Gras 	_PROP_ASSERT(idx < pa->pa_count);
6496b6d114aSBen Gras 
6506b6d114aSBen Gras 	opo = pa->pa_array[idx];
6516b6d114aSBen Gras 	_PROP_ASSERT(opo != NULL);
6526b6d114aSBen Gras 
6536b6d114aSBen Gras 	prop_object_retain(po);
6546b6d114aSBen Gras 	pa->pa_array[idx] = po;
6556b6d114aSBen Gras 	pa->pa_version++;
6566b6d114aSBen Gras 
6576b6d114aSBen Gras 	prop_object_release(opo);
6586b6d114aSBen Gras 
6596b6d114aSBen Gras 	rv = true;
6606b6d114aSBen Gras 
6616b6d114aSBen Gras  out:
6626b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
6636b6d114aSBen Gras 	return (rv);
6646b6d114aSBen Gras }
6656b6d114aSBen Gras 
6666b6d114aSBen Gras /*
6676b6d114aSBen Gras  * prop_array_add --
6686b6d114aSBen Gras  *	Add a reference to an object to the specified array, appending
6696b6d114aSBen Gras  *	to the end and growing the array's capacity, if necessary.
6706b6d114aSBen Gras  */
6716b6d114aSBen Gras bool
prop_array_add(prop_array_t pa,prop_object_t po)6726b6d114aSBen Gras prop_array_add(prop_array_t pa, prop_object_t po)
6736b6d114aSBen Gras {
6746b6d114aSBen Gras 	bool rv;
6756b6d114aSBen Gras 
6766b6d114aSBen Gras 	if (! prop_object_is_array(pa))
6776b6d114aSBen Gras 		return (false);
6786b6d114aSBen Gras 
6796b6d114aSBen Gras 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
6806b6d114aSBen Gras 	rv = _prop_array_add(pa, po);
6816b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
6826b6d114aSBen Gras 
6836b6d114aSBen Gras 	return (rv);
6846b6d114aSBen Gras }
6856b6d114aSBen Gras 
6866b6d114aSBen Gras /*
6876b6d114aSBen Gras  * prop_array_remove --
6886b6d114aSBen Gras  *	Remove the reference to an object from an array at the specified
6896b6d114aSBen Gras  *	index.	The array will be compacted following the removal.
6906b6d114aSBen Gras  */
6916b6d114aSBen Gras void
prop_array_remove(prop_array_t pa,unsigned int idx)6926b6d114aSBen Gras prop_array_remove(prop_array_t pa, unsigned int idx)
6936b6d114aSBen Gras {
6946b6d114aSBen Gras 	prop_object_t po;
6956b6d114aSBen Gras 
6966b6d114aSBen Gras 	if (! prop_object_is_array(pa))
6976b6d114aSBen Gras 		return;
6986b6d114aSBen Gras 
6996b6d114aSBen Gras 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
7006b6d114aSBen Gras 
7016b6d114aSBen Gras 	_PROP_ASSERT(idx < pa->pa_count);
7026b6d114aSBen Gras 
7036b6d114aSBen Gras 	/* XXX Should this be a _PROP_ASSERT()? */
7046b6d114aSBen Gras 	if (prop_array_is_immutable(pa)) {
7056b6d114aSBen Gras 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
7066b6d114aSBen Gras 		return;
7076b6d114aSBen Gras 	}
7086b6d114aSBen Gras 
7096b6d114aSBen Gras 	po = pa->pa_array[idx];
7106b6d114aSBen Gras 	_PROP_ASSERT(po != NULL);
7116b6d114aSBen Gras 
7126b6d114aSBen Gras 	for (++idx; idx < pa->pa_count; idx++)
7136b6d114aSBen Gras 		pa->pa_array[idx - 1] = pa->pa_array[idx];
7146b6d114aSBen Gras 	pa->pa_count--;
7156b6d114aSBen Gras 	pa->pa_version++;
7166b6d114aSBen Gras 
7176b6d114aSBen Gras 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
7186b6d114aSBen Gras 
7196b6d114aSBen Gras 	prop_object_release(po);
7206b6d114aSBen Gras }
7216b6d114aSBen Gras 
7226b6d114aSBen Gras /*
7236b6d114aSBen Gras  * prop_array_equals --
7246b6d114aSBen Gras  *	Return true if the two arrays are equivalent.  Note we do a
7256b6d114aSBen Gras  *	by-value comparison of the objects in the array.
7266b6d114aSBen Gras  */
7276b6d114aSBen Gras bool
prop_array_equals(prop_array_t array1,prop_array_t array2)7286b6d114aSBen Gras prop_array_equals(prop_array_t array1, prop_array_t array2)
7296b6d114aSBen Gras {
7306b6d114aSBen Gras 	if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
7316b6d114aSBen Gras 		return (false);
7326b6d114aSBen Gras 
7336b6d114aSBen Gras 	return (prop_object_equals(array1, array2));
7346b6d114aSBen Gras }
7356b6d114aSBen Gras 
7366b6d114aSBen Gras /*
7376b6d114aSBen Gras  * prop_array_externalize --
7386b6d114aSBen Gras  *	Externalize an array, return a NUL-terminated buffer
7396b6d114aSBen Gras  *	containing the XML-style representation.  The buffer is allocated
7406b6d114aSBen Gras  *	with the M_TEMP memory type.
7416b6d114aSBen Gras  */
7426b6d114aSBen Gras char *
prop_array_externalize(prop_array_t pa)7436b6d114aSBen Gras prop_array_externalize(prop_array_t pa)
7446b6d114aSBen Gras {
7456b6d114aSBen Gras 	struct _prop_object_externalize_context *ctx;
7466b6d114aSBen Gras 	char *cp;
7476b6d114aSBen Gras 
7486b6d114aSBen Gras 	ctx = _prop_object_externalize_context_alloc();
7496b6d114aSBen Gras 	if (ctx == NULL)
7506b6d114aSBen Gras 		return (NULL);
7516b6d114aSBen Gras 
7526b6d114aSBen Gras 	if (_prop_object_externalize_header(ctx) == false ||
7536b6d114aSBen Gras 	    (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
7546b6d114aSBen Gras 	    _prop_object_externalize_footer(ctx) == false) {
7556b6d114aSBen Gras 		/* We are responsible for releasing the buffer. */
7566b6d114aSBen Gras 		_PROP_FREE(ctx->poec_buf, M_TEMP);
7576b6d114aSBen Gras 		_prop_object_externalize_context_free(ctx);
7586b6d114aSBen Gras 		return (NULL);
7596b6d114aSBen Gras 	}
7606b6d114aSBen Gras 
7616b6d114aSBen Gras 	cp = ctx->poec_buf;
7626b6d114aSBen Gras 	_prop_object_externalize_context_free(ctx);
7636b6d114aSBen Gras 
7646b6d114aSBen Gras 	return (cp);
7656b6d114aSBen Gras }
7666b6d114aSBen Gras 
7676b6d114aSBen Gras /*
7686b6d114aSBen Gras  * _prop_array_internalize --
7696b6d114aSBen Gras  *	Parse an <array>...</array> and return the object created from the
7706b6d114aSBen Gras  *	external representation.
7716b6d114aSBen Gras  */
7726b6d114aSBen Gras static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
7736b6d114aSBen Gras     struct _prop_object_internalize_context *);
7746b6d114aSBen Gras 
7756b6d114aSBen Gras bool
_prop_array_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)7766b6d114aSBen Gras _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
7776b6d114aSBen Gras     struct _prop_object_internalize_context *ctx)
7786b6d114aSBen Gras {
7796b6d114aSBen Gras 	/* We don't currently understand any attributes. */
7806b6d114aSBen Gras 	if (ctx->poic_tagattr != NULL)
7816b6d114aSBen Gras 		return (true);
7826b6d114aSBen Gras 
7836b6d114aSBen Gras 	*obj = prop_array_create();
7846b6d114aSBen Gras 	/*
7856b6d114aSBen Gras 	 * We are done if the create failed or no child elements exist.
7866b6d114aSBen Gras 	 */
7876b6d114aSBen Gras 	if (*obj == NULL || ctx->poic_is_empty_element)
7886b6d114aSBen Gras 		return (true);
7896b6d114aSBen Gras 
7906b6d114aSBen Gras 	/*
7916b6d114aSBen Gras 	 * Opening tag is found, now continue to the first element.
7926b6d114aSBen Gras 	 */
7936b6d114aSBen Gras 	return (_prop_array_internalize_body(stack, obj, ctx));
7946b6d114aSBen Gras }
7956b6d114aSBen Gras 
7966b6d114aSBen Gras 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)7976b6d114aSBen Gras _prop_array_internalize_continue(prop_stack_t stack,
7986b6d114aSBen Gras     prop_object_t *obj,
7996b6d114aSBen Gras     struct _prop_object_internalize_context *ctx,
8006b6d114aSBen Gras     void *data, prop_object_t child)
8016b6d114aSBen Gras {
8026b6d114aSBen Gras 	prop_array_t array;
8036b6d114aSBen Gras 
8046b6d114aSBen Gras 	_PROP_ASSERT(data == NULL);
8056b6d114aSBen Gras 
8066b6d114aSBen Gras 	if (child == NULL)
8076b6d114aSBen Gras 		goto bad; /* Element could not be parsed. */
8086b6d114aSBen Gras 
8096b6d114aSBen Gras 	array = *obj;
8106b6d114aSBen Gras 
8116b6d114aSBen Gras 	if (prop_array_add(array, child) == false) {
8126b6d114aSBen Gras 		prop_object_release(child);
8136b6d114aSBen Gras 		goto bad;
8146b6d114aSBen Gras 	}
8156b6d114aSBen Gras 	prop_object_release(child);
8166b6d114aSBen Gras 
8176b6d114aSBen Gras 	/*
8186b6d114aSBen Gras 	 * Current element is processed and added, look for next.
8196b6d114aSBen Gras 	 */
8206b6d114aSBen Gras 	return (_prop_array_internalize_body(stack, obj, ctx));
8216b6d114aSBen Gras 
8226b6d114aSBen Gras  bad:
8236b6d114aSBen Gras 	prop_object_release(*obj);
8246b6d114aSBen Gras 	*obj = NULL;
8256b6d114aSBen Gras 	return (true);
8266b6d114aSBen Gras }
8276b6d114aSBen Gras 
8286b6d114aSBen Gras static bool
_prop_array_internalize_body(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)8296b6d114aSBen Gras _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
8306b6d114aSBen Gras     struct _prop_object_internalize_context *ctx)
8316b6d114aSBen Gras {
8326b6d114aSBen Gras 	prop_array_t array = *obj;
8336b6d114aSBen Gras 
8346b6d114aSBen Gras 	_PROP_ASSERT(array != NULL);
8356b6d114aSBen Gras 
8366b6d114aSBen Gras 	/* Fetch the next tag. */
8376b6d114aSBen Gras 	if (_prop_object_internalize_find_tag(ctx, NULL,
8386b6d114aSBen Gras 				_PROP_TAG_TYPE_EITHER) == false)
8396b6d114aSBen Gras 		goto bad;
8406b6d114aSBen Gras 
8416b6d114aSBen Gras 	/* Check to see if this is the end of the array. */
8426b6d114aSBen Gras 	if (_PROP_TAG_MATCH(ctx, "array") &&
8436b6d114aSBen Gras 	    ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
8446b6d114aSBen Gras 		/* It is, so don't iterate any further. */
8456b6d114aSBen Gras 		return (true);
8466b6d114aSBen Gras 	}
8476b6d114aSBen Gras 
8486b6d114aSBen Gras 	if (_prop_stack_push(stack, array,
8496b6d114aSBen Gras 			     _prop_array_internalize_continue, NULL, NULL))
8506b6d114aSBen Gras 		return (false);
8516b6d114aSBen Gras 
8526b6d114aSBen Gras  bad:
8536b6d114aSBen Gras 	prop_object_release(array);
8546b6d114aSBen Gras 	*obj = NULL;
8556b6d114aSBen Gras 	return (true);
8566b6d114aSBen Gras }
8576b6d114aSBen Gras 
8586b6d114aSBen Gras /*
8596b6d114aSBen Gras  * prop_array_internalize --
8606b6d114aSBen Gras  *	Create an array by parsing the XML-style representation.
8616b6d114aSBen Gras  */
8626b6d114aSBen Gras prop_array_t
prop_array_internalize(const char * xml)8636b6d114aSBen Gras prop_array_internalize(const char *xml)
8646b6d114aSBen Gras {
8656b6d114aSBen Gras 	return _prop_generic_internalize(xml, "array");
8666b6d114aSBen Gras }
8676b6d114aSBen Gras 
8686b6d114aSBen Gras #if !defined(_KERNEL) && !defined(_STANDALONE)
8696b6d114aSBen Gras /*
8706b6d114aSBen Gras  * prop_array_externalize_to_file --
8716b6d114aSBen Gras  *	Externalize an array to the specified file.
8726b6d114aSBen Gras  */
8736b6d114aSBen Gras bool
prop_array_externalize_to_file(prop_array_t array,const char * fname)8746b6d114aSBen Gras prop_array_externalize_to_file(prop_array_t array, const char *fname)
8756b6d114aSBen Gras {
8766b6d114aSBen Gras 	char *xml;
8776b6d114aSBen Gras 	bool rv;
8786b6d114aSBen Gras 	int save_errno = 0;	/* XXXGCC -Wuninitialized [mips, ...] */
8796b6d114aSBen Gras 
8806b6d114aSBen Gras 	xml = prop_array_externalize(array);
8816b6d114aSBen Gras 	if (xml == NULL)
8826b6d114aSBen Gras 		return (false);
8836b6d114aSBen Gras 	rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
8846b6d114aSBen Gras 	if (rv == false)
8856b6d114aSBen Gras 		save_errno = errno;
8866b6d114aSBen Gras 	_PROP_FREE(xml, M_TEMP);
8876b6d114aSBen Gras 	if (rv == false)
8886b6d114aSBen Gras 		errno = save_errno;
8896b6d114aSBen Gras 
8906b6d114aSBen Gras 	return (rv);
8916b6d114aSBen Gras }
8926b6d114aSBen Gras 
8936b6d114aSBen Gras /*
8946b6d114aSBen Gras  * prop_array_internalize_from_file --
8956b6d114aSBen Gras  *	Internalize an array from a file.
8966b6d114aSBen Gras  */
8976b6d114aSBen Gras prop_array_t
prop_array_internalize_from_file(const char * fname)8986b6d114aSBen Gras prop_array_internalize_from_file(const char *fname)
8996b6d114aSBen Gras {
9006b6d114aSBen Gras 	struct _prop_object_internalize_mapped_file *mf;
9016b6d114aSBen Gras 	prop_array_t array;
9026b6d114aSBen Gras 
9036b6d114aSBen Gras 	mf = _prop_object_internalize_map_file(fname);
9046b6d114aSBen Gras 	if (mf == NULL)
9056b6d114aSBen Gras 		return (NULL);
9066b6d114aSBen Gras 	array = prop_array_internalize(mf->poimf_xml);
9076b6d114aSBen Gras 	_prop_object_internalize_unmap_file(mf);
9086b6d114aSBen Gras 
9096b6d114aSBen Gras 	return (array);
9106b6d114aSBen Gras }
9116b6d114aSBen Gras #endif /* _KERNEL && !_STANDALONE */
912