Home | History | Annotate | Line # | Download | only in libprop
prop_array.c revision 1.21.34.2
      1  1.21.34.1    martin /*	$NetBSD: prop_array.c,v 1.21.34.2 2020/04/21 19:37:51 martin Exp $	*/
      2        1.1   thorpej 
      3        1.1   thorpej /*-
      4       1.10     joerg  * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
      5        1.1   thorpej  * All rights reserved.
      6        1.1   thorpej  *
      7        1.1   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8        1.1   thorpej  * by Jason R. Thorpe.
      9        1.1   thorpej  *
     10        1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     11        1.1   thorpej  * modification, are permitted provided that the following conditions
     12        1.1   thorpej  * are met:
     13        1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     14        1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     15        1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16        1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     17        1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     18        1.1   thorpej  *
     19        1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20        1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21        1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22        1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23        1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24        1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25        1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26        1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27        1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28        1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29        1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30        1.1   thorpej  */
     31        1.1   thorpej 
     32       1.21     pooka #include "prop_object_impl.h"
     33        1.1   thorpej #include <prop/prop_array.h>
     34        1.1   thorpej 
     35        1.4   thorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
     36        1.4   thorpej #include <errno.h>
     37        1.4   thorpej #endif
     38        1.4   thorpej 
     39        1.1   thorpej struct _prop_array {
     40        1.1   thorpej 	struct _prop_object	pa_obj;
     41        1.7   thorpej 	_PROP_RWLOCK_DECL(pa_rwlock)
     42        1.1   thorpej 	prop_object_t *		pa_array;
     43        1.1   thorpej 	unsigned int		pa_capacity;
     44        1.1   thorpej 	unsigned int		pa_count;
     45        1.1   thorpej 	int			pa_flags;
     46        1.1   thorpej 
     47        1.1   thorpej 	uint32_t		pa_version;
     48        1.1   thorpej };
     49        1.1   thorpej 
     50       1.20  christos #define PA_F_IMMUTABLE		0x01	/* array is immutable */
     51        1.1   thorpej 
     52        1.1   thorpej _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
     53        1.1   thorpej _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
     54        1.1   thorpej 		    "property array container object")
     55        1.1   thorpej 
     56       1.19   thorpej static _prop_object_free_rv_t
     57       1.19   thorpej 		_prop_array_free(prop_stack_t, prop_object_t *);
     58       1.19   thorpej static void	_prop_array_emergency_free(prop_object_t);
     59        1.9   thorpej static bool	_prop_array_externalize(
     60        1.2   thorpej 				struct _prop_object_externalize_context *,
     61        1.2   thorpej 				void *);
     62       1.19   thorpej static _prop_object_equals_rv_t
     63       1.19   thorpej 		_prop_array_equals(prop_object_t, prop_object_t,
     64       1.11     joerg 				   void **, void **,
     65       1.11     joerg 				   prop_object_t *, prop_object_t *);
     66       1.11     joerg static void	_prop_array_equals_finish(prop_object_t, prop_object_t);
     67       1.19   thorpej static prop_object_iterator_t
     68       1.19   thorpej 		_prop_array_iterator_locked(prop_array_t);
     69       1.19   thorpej static prop_object_t
     70       1.19   thorpej 		_prop_array_iterator_next_object_locked(void *);
     71       1.19   thorpej static void	_prop_array_iterator_reset_locked(void *);
     72        1.2   thorpej 
     73        1.2   thorpej static const struct _prop_object_type _prop_object_type_array = {
     74       1.10     joerg 	.pot_type		=	PROP_TYPE_ARRAY,
     75       1.10     joerg 	.pot_free		=	_prop_array_free,
     76       1.10     joerg 	.pot_emergency_free	=	_prop_array_emergency_free,
     77       1.10     joerg 	.pot_extern		=	_prop_array_externalize,
     78       1.10     joerg 	.pot_equals		=	_prop_array_equals,
     79       1.11     joerg 	.pot_equals_finish	=	_prop_array_equals_finish,
     80        1.2   thorpej };
     81        1.2   thorpej 
     82       1.20  christos #define prop_object_is_array(x)		\
     83        1.6   thorpej 	((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
     84        1.1   thorpej 
     85       1.20  christos #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
     86        1.1   thorpej 
     87        1.1   thorpej struct _prop_array_iterator {
     88        1.1   thorpej 	struct _prop_object_iterator pai_base;
     89        1.1   thorpej 	unsigned int		pai_index;
     90        1.1   thorpej };
     91        1.1   thorpej 
     92       1.20  christos #define EXPAND_STEP		16
     93        1.1   thorpej 
     94       1.19   thorpej static _prop_object_free_rv_t
     95       1.10     joerg _prop_array_free(prop_stack_t stack, prop_object_t *obj)
     96        1.1   thorpej {
     97       1.10     joerg 	prop_array_t pa = *obj;
     98        1.1   thorpej 	prop_object_t po;
     99        1.1   thorpej 
    100        1.1   thorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
    101        1.1   thorpej 	_PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
    102        1.1   thorpej 		     (pa->pa_capacity != 0 && pa->pa_array != NULL));
    103        1.1   thorpej 
    104       1.10     joerg 	/* The easy case is an empty array, just free and return. */
    105       1.10     joerg 	if (pa->pa_count == 0) {
    106       1.10     joerg 		if (pa->pa_array != NULL)
    107       1.10     joerg 			_PROP_FREE(pa->pa_array, M_PROP_ARRAY);
    108       1.10     joerg 
    109       1.10     joerg 		_PROP_RWLOCK_DESTROY(pa->pa_rwlock);
    110       1.10     joerg 
    111       1.10     joerg 		_PROP_POOL_PUT(_prop_array_pool, pa);
    112       1.10     joerg 
    113       1.10     joerg 		return (_PROP_OBJECT_FREE_DONE);
    114        1.1   thorpej 	}
    115        1.1   thorpej 
    116       1.10     joerg 	po = pa->pa_array[pa->pa_count - 1];
    117       1.10     joerg 	_PROP_ASSERT(po != NULL);
    118        1.1   thorpej 
    119       1.10     joerg 	if (stack == NULL) {
    120       1.10     joerg 		/*
    121       1.10     joerg 		 * If we are in emergency release mode,
    122       1.10     joerg 		 * just let caller recurse down.
    123       1.10     joerg 		 */
    124       1.10     joerg 		*obj = po;
    125       1.10     joerg 		return (_PROP_OBJECT_FREE_FAILED);
    126       1.10     joerg 	}
    127       1.10     joerg 
    128       1.10     joerg 	/* Otherwise, try to push the current object on the stack. */
    129       1.11     joerg 	if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
    130       1.10     joerg 		/* Push failed, entering emergency release mode. */
    131       1.10     joerg 		return (_PROP_OBJECT_FREE_FAILED);
    132       1.10     joerg 	}
    133       1.10     joerg 	/* Object pushed on stack, caller will release it. */
    134       1.10     joerg 	--pa->pa_count;
    135       1.10     joerg 	*obj = po;
    136       1.10     joerg 	return (_PROP_OBJECT_FREE_RECURSE);
    137       1.10     joerg }
    138        1.7   thorpej 
    139       1.10     joerg static void
    140       1.10     joerg _prop_array_emergency_free(prop_object_t obj)
    141       1.10     joerg {
    142       1.10     joerg 	prop_array_t pa = obj;
    143       1.10     joerg 
    144       1.10     joerg 	_PROP_ASSERT(pa->pa_count != 0);
    145       1.10     joerg 	--pa->pa_count;
    146        1.1   thorpej }
    147        1.1   thorpej 
    148        1.9   thorpej static bool
    149        1.1   thorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx,
    150        1.1   thorpej 			void *v)
    151        1.1   thorpej {
    152        1.1   thorpej 	prop_array_t pa = v;
    153        1.1   thorpej 	struct _prop_object *po;
    154        1.1   thorpej 	prop_object_iterator_t pi;
    155        1.1   thorpej 	unsigned int i;
    156        1.9   thorpej 	bool rv = false;
    157        1.7   thorpej 
    158        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    159        1.1   thorpej 
    160        1.7   thorpej 	if (pa->pa_count == 0) {
    161        1.7   thorpej 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    162        1.1   thorpej 		return (_prop_object_externalize_empty_tag(ctx, "array"));
    163        1.7   thorpej 	}
    164       1.20  christos 
    165        1.1   thorpej 	/* XXXJRT Hint "count" for the internalize step? */
    166        1.9   thorpej 	if (_prop_object_externalize_start_tag(ctx, "array") == false ||
    167        1.9   thorpej 	    _prop_object_externalize_append_char(ctx, '\n') == false)
    168        1.7   thorpej 		goto out;
    169        1.1   thorpej 
    170       1.18      yamt 	pi = _prop_array_iterator_locked(pa);
    171        1.1   thorpej 	if (pi == NULL)
    172        1.7   thorpej 		goto out;
    173       1.20  christos 
    174        1.1   thorpej 	ctx->poec_depth++;
    175        1.1   thorpej 	_PROP_ASSERT(ctx->poec_depth != 0);
    176        1.1   thorpej 
    177       1.18      yamt 	while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
    178        1.9   thorpej 		if ((*po->po_type->pot_extern)(ctx, po) == false) {
    179        1.1   thorpej 			prop_object_iterator_release(pi);
    180        1.7   thorpej 			goto out;
    181        1.1   thorpej 		}
    182        1.1   thorpej 	}
    183        1.1   thorpej 
    184        1.1   thorpej 	prop_object_iterator_release(pi);
    185        1.1   thorpej 
    186        1.1   thorpej 	ctx->poec_depth--;
    187        1.1   thorpej 	for (i = 0; i < ctx->poec_depth; i++) {
    188        1.9   thorpej 		if (_prop_object_externalize_append_char(ctx, '\t') == false)
    189        1.7   thorpej 			goto out;
    190        1.1   thorpej 	}
    191        1.9   thorpej 	if (_prop_object_externalize_end_tag(ctx, "array") == false)
    192        1.7   thorpej 		goto out;
    193        1.7   thorpej 
    194        1.9   thorpej 	rv = true;
    195       1.20  christos 
    196        1.7   thorpej  out:
    197       1.20  christos 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    198        1.7   thorpej 	return (rv);
    199        1.1   thorpej }
    200        1.1   thorpej 
    201       1.11     joerg /* ARGSUSED */
    202       1.19   thorpej static _prop_object_equals_rv_t
    203       1.11     joerg _prop_array_equals(prop_object_t v1, prop_object_t v2,
    204       1.11     joerg     void **stored_pointer1, void **stored_pointer2,
    205       1.11     joerg     prop_object_t *next_obj1, prop_object_t *next_obj2)
    206        1.2   thorpej {
    207        1.2   thorpej 	prop_array_t array1 = v1;
    208        1.2   thorpej 	prop_array_t array2 = v2;
    209       1.11     joerg 	uintptr_t idx;
    210       1.19   thorpej 	_prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
    211        1.2   thorpej 
    212       1.11     joerg 	if (array1 == array2)
    213       1.11     joerg 		return (_PROP_OBJECT_EQUALS_TRUE);
    214        1.2   thorpej 
    215       1.11     joerg 	_PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
    216       1.11     joerg 	idx = (uintptr_t)*stored_pointer1;
    217        1.7   thorpej 
    218       1.11     joerg 	/* For the first iteration, lock the objects. */
    219       1.11     joerg 	if (idx == 0) {
    220       1.11     joerg 		if ((uintptr_t)array1 < (uintptr_t)array2) {
    221       1.11     joerg 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
    222       1.11     joerg 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
    223       1.11     joerg 		} else {
    224       1.11     joerg 			_PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
    225       1.11     joerg 			_PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
    226       1.11     joerg 		}
    227        1.7   thorpej 	}
    228        1.7   thorpej 
    229        1.2   thorpej 	if (array1->pa_count != array2->pa_count)
    230        1.7   thorpej 		goto out;
    231       1.11     joerg 	if (idx == array1->pa_count) {
    232       1.19   thorpej 		rv = _PROP_OBJECT_EQUALS_TRUE;
    233       1.11     joerg 		goto out;
    234       1.11     joerg 	}
    235       1.11     joerg 	_PROP_ASSERT(idx < array1->pa_count);
    236       1.11     joerg 
    237       1.11     joerg 	*stored_pointer1 = (void *)(idx + 1);
    238       1.11     joerg 	*stored_pointer2 = (void *)(idx + 1);
    239       1.20  christos 
    240       1.11     joerg 	*next_obj1 = array1->pa_array[idx];
    241       1.11     joerg 	*next_obj2 = array2->pa_array[idx];
    242        1.2   thorpej 
    243       1.11     joerg 	return (_PROP_OBJECT_EQUALS_RECURSE);
    244        1.7   thorpej 
    245        1.7   thorpej  out:
    246        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
    247        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
    248        1.7   thorpej 	return (rv);
    249        1.2   thorpej }
    250        1.2   thorpej 
    251       1.11     joerg static void
    252       1.11     joerg _prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
    253       1.11     joerg {
    254       1.11     joerg 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
    255       1.11     joerg 	_PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
    256       1.11     joerg }
    257       1.11     joerg 
    258        1.1   thorpej static prop_array_t
    259        1.1   thorpej _prop_array_alloc(unsigned int capacity)
    260        1.1   thorpej {
    261        1.1   thorpej 	prop_array_t pa;
    262        1.1   thorpej 	prop_object_t *array;
    263        1.1   thorpej 
    264        1.1   thorpej 	if (capacity != 0) {
    265        1.1   thorpej 		array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
    266        1.1   thorpej 				     M_PROP_ARRAY);
    267        1.1   thorpej 		if (array == NULL)
    268        1.1   thorpej 			return (NULL);
    269        1.1   thorpej 	} else
    270        1.1   thorpej 		array = NULL;
    271        1.1   thorpej 
    272        1.1   thorpej 	pa = _PROP_POOL_GET(_prop_array_pool);
    273        1.1   thorpej 	if (pa != NULL) {
    274        1.2   thorpej 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
    275        1.2   thorpej 		pa->pa_obj.po_type = &_prop_object_type_array;
    276        1.1   thorpej 
    277        1.7   thorpej 		_PROP_RWLOCK_INIT(pa->pa_rwlock);
    278        1.1   thorpej 		pa->pa_array = array;
    279        1.1   thorpej 		pa->pa_capacity = capacity;
    280        1.1   thorpej 		pa->pa_count = 0;
    281        1.1   thorpej 		pa->pa_flags = 0;
    282        1.1   thorpej 
    283        1.1   thorpej 		pa->pa_version = 0;
    284        1.1   thorpej 	} else if (array != NULL)
    285        1.1   thorpej 		_PROP_FREE(array, M_PROP_ARRAY);
    286        1.1   thorpej 
    287        1.1   thorpej 	return (pa);
    288        1.1   thorpej }
    289        1.1   thorpej 
    290        1.9   thorpej static bool
    291        1.1   thorpej _prop_array_expand(prop_array_t pa, unsigned int capacity)
    292        1.1   thorpej {
    293        1.1   thorpej 	prop_object_t *array, *oarray;
    294        1.1   thorpej 
    295        1.7   thorpej 	/*
    296        1.7   thorpej 	 * Array must be WRITE-LOCKED.
    297        1.7   thorpej 	 */
    298        1.7   thorpej 
    299        1.1   thorpej 	oarray = pa->pa_array;
    300        1.1   thorpej 
    301        1.3   thorpej 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
    302        1.1   thorpej 	if (array == NULL)
    303        1.9   thorpej 		return (false);
    304        1.1   thorpej 	if (oarray != NULL)
    305        1.3   thorpej 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
    306        1.1   thorpej 	pa->pa_array = array;
    307        1.1   thorpej 	pa->pa_capacity = capacity;
    308        1.1   thorpej 
    309        1.1   thorpej 	if (oarray != NULL)
    310        1.1   thorpej 		_PROP_FREE(oarray, M_PROP_ARRAY);
    311        1.1   thorpej 
    312        1.9   thorpej 	return (true);
    313        1.1   thorpej }
    314        1.1   thorpej 
    315        1.1   thorpej static prop_object_t
    316       1.18      yamt _prop_array_iterator_next_object_locked(void *v)
    317        1.1   thorpej {
    318        1.1   thorpej 	struct _prop_array_iterator *pai = v;
    319        1.1   thorpej 	prop_array_t pa = pai->pai_base.pi_obj;
    320        1.7   thorpej 	prop_object_t po = NULL;
    321        1.1   thorpej 
    322        1.1   thorpej 	_PROP_ASSERT(prop_object_is_array(pa));
    323       1.17      yamt 
    324        1.1   thorpej 	if (pa->pa_version != pai->pai_base.pi_version)
    325        1.7   thorpej 		goto out;	/* array changed during iteration */
    326       1.20  christos 
    327        1.1   thorpej 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
    328        1.1   thorpej 
    329        1.1   thorpej 	if (pai->pai_index == pa->pa_count)
    330        1.7   thorpej 		goto out;	/* we've iterated all objects */
    331       1.20  christos 
    332        1.1   thorpej 	po = pa->pa_array[pai->pai_index];
    333        1.1   thorpej 	pai->pai_index++;
    334        1.1   thorpej 
    335        1.7   thorpej  out:
    336       1.18      yamt 	return (po);
    337       1.18      yamt }
    338       1.18      yamt 
    339       1.18      yamt static prop_object_t
    340       1.18      yamt _prop_array_iterator_next_object(void *v)
    341       1.18      yamt {
    342       1.18      yamt 	struct _prop_array_iterator *pai = v;
    343       1.21     pooka 	prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
    344       1.18      yamt 	prop_object_t po;
    345       1.18      yamt 
    346       1.18      yamt 	_PROP_ASSERT(prop_object_is_array(pa));
    347       1.18      yamt 
    348       1.18      yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    349       1.18      yamt 	po = _prop_array_iterator_next_object_locked(pai);
    350       1.17      yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    351        1.1   thorpej 	return (po);
    352        1.1   thorpej }
    353        1.1   thorpej 
    354        1.1   thorpej static void
    355       1.18      yamt _prop_array_iterator_reset_locked(void *v)
    356        1.1   thorpej {
    357        1.1   thorpej 	struct _prop_array_iterator *pai = v;
    358        1.1   thorpej 	prop_array_t pa = pai->pai_base.pi_obj;
    359        1.1   thorpej 
    360        1.1   thorpej 	_PROP_ASSERT(prop_object_is_array(pa));
    361       1.17      yamt 
    362        1.1   thorpej 	pai->pai_index = 0;
    363        1.1   thorpej 	pai->pai_base.pi_version = pa->pa_version;
    364       1.18      yamt }
    365       1.18      yamt 
    366       1.18      yamt static void
    367       1.18      yamt _prop_array_iterator_reset(void *v)
    368       1.18      yamt {
    369       1.18      yamt 	struct _prop_array_iterator *pai = v;
    370       1.21     pooka 	prop_array_t pa _PROP_ARG_UNUSED = pai->pai_base.pi_obj;
    371       1.14   xtraeme 
    372       1.18      yamt 	_PROP_ASSERT(prop_object_is_array(pa));
    373       1.18      yamt 
    374       1.18      yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    375       1.18      yamt 	_prop_array_iterator_reset_locked(pai);
    376       1.17      yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    377        1.1   thorpej }
    378        1.1   thorpej 
    379        1.1   thorpej /*
    380        1.1   thorpej  * prop_array_create --
    381        1.1   thorpej  *	Create an empty array.
    382        1.1   thorpej  */
    383        1.1   thorpej prop_array_t
    384        1.1   thorpej prop_array_create(void)
    385        1.1   thorpej {
    386        1.1   thorpej 
    387        1.1   thorpej 	return (_prop_array_alloc(0));
    388        1.1   thorpej }
    389        1.1   thorpej 
    390        1.1   thorpej /*
    391        1.1   thorpej  * prop_array_create_with_capacity --
    392        1.1   thorpej  *	Create an array with the capacity to store N objects.
    393        1.1   thorpej  */
    394        1.1   thorpej prop_array_t
    395        1.1   thorpej prop_array_create_with_capacity(unsigned int capacity)
    396        1.1   thorpej {
    397        1.1   thorpej 
    398        1.1   thorpej 	return (_prop_array_alloc(capacity));
    399        1.1   thorpej }
    400        1.1   thorpej 
    401        1.1   thorpej /*
    402        1.1   thorpej  * prop_array_copy --
    403       1.20  christos  *	Copy an array.	The new array has an initial capacity equal to
    404        1.1   thorpej  *	the number of objects stored in the original array.  The new
    405        1.1   thorpej  *	array contains references to the original array's objects, not
    406        1.1   thorpej  *	copies of those objects (i.e. a shallow copy).
    407        1.1   thorpej  */
    408        1.1   thorpej prop_array_t
    409        1.1   thorpej prop_array_copy(prop_array_t opa)
    410        1.1   thorpej {
    411        1.1   thorpej 	prop_array_t pa;
    412        1.1   thorpej 	prop_object_t po;
    413        1.1   thorpej 	unsigned int idx;
    414        1.1   thorpej 
    415        1.4   thorpej 	if (! prop_object_is_array(opa))
    416        1.4   thorpej 		return (NULL);
    417        1.1   thorpej 
    418        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
    419        1.7   thorpej 
    420        1.1   thorpej 	pa = _prop_array_alloc(opa->pa_count);
    421        1.1   thorpej 	if (pa != NULL) {
    422        1.1   thorpej 		for (idx = 0; idx < opa->pa_count; idx++) {
    423        1.1   thorpej 			po = opa->pa_array[idx];
    424        1.1   thorpej 			prop_object_retain(po);
    425        1.1   thorpej 			pa->pa_array[idx] = po;
    426        1.1   thorpej 		}
    427        1.1   thorpej 		pa->pa_count = opa->pa_count;
    428        1.1   thorpej 		pa->pa_flags = opa->pa_flags;
    429        1.1   thorpej 	}
    430        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
    431        1.1   thorpej 	return (pa);
    432        1.1   thorpej }
    433        1.1   thorpej 
    434        1.1   thorpej /*
    435        1.1   thorpej  * prop_array_copy_mutable --
    436        1.1   thorpej  *	Like prop_array_copy(), but the resulting array is mutable.
    437        1.1   thorpej  */
    438        1.1   thorpej prop_array_t
    439        1.1   thorpej prop_array_copy_mutable(prop_array_t opa)
    440        1.1   thorpej {
    441        1.1   thorpej 	prop_array_t pa;
    442        1.1   thorpej 
    443        1.1   thorpej 	pa = prop_array_copy(opa);
    444        1.1   thorpej 	if (pa != NULL)
    445        1.1   thorpej 		pa->pa_flags &= ~PA_F_IMMUTABLE;
    446       1.20  christos 
    447        1.1   thorpej 	return (pa);
    448        1.1   thorpej }
    449        1.1   thorpej 
    450        1.1   thorpej /*
    451        1.1   thorpej  * prop_array_capacity --
    452        1.1   thorpej  *	Return the capacity of the array.
    453        1.1   thorpej  */
    454        1.1   thorpej unsigned int
    455        1.1   thorpej prop_array_capacity(prop_array_t pa)
    456        1.1   thorpej {
    457        1.7   thorpej 	unsigned int rv;
    458        1.1   thorpej 
    459        1.4   thorpej 	if (! prop_object_is_array(pa))
    460        1.4   thorpej 		return (0);
    461        1.4   thorpej 
    462        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    463        1.7   thorpej 	rv = pa->pa_capacity;
    464        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    465        1.7   thorpej 
    466        1.7   thorpej 	return (rv);
    467        1.1   thorpej }
    468        1.1   thorpej 
    469        1.1   thorpej /*
    470        1.1   thorpej  * prop_array_count --
    471        1.1   thorpej  *	Return the number of objects stored in the array.
    472        1.1   thorpej  */
    473        1.1   thorpej unsigned int
    474        1.1   thorpej prop_array_count(prop_array_t pa)
    475        1.1   thorpej {
    476        1.7   thorpej 	unsigned int rv;
    477        1.1   thorpej 
    478        1.4   thorpej 	if (! prop_object_is_array(pa))
    479        1.4   thorpej 		return (0);
    480        1.4   thorpej 
    481        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    482        1.7   thorpej 	rv = pa->pa_count;
    483        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    484        1.7   thorpej 
    485        1.7   thorpej 	return (rv);
    486        1.1   thorpej }
    487        1.1   thorpej 
    488        1.1   thorpej /*
    489        1.1   thorpej  * prop_array_ensure_capacity --
    490        1.1   thorpej  *	Ensure that the array has the capacity to store the specified
    491        1.1   thorpej  *	total number of objects (inluding the objects already stored
    492        1.1   thorpej  *	in the array).
    493        1.1   thorpej  */
    494        1.9   thorpej bool
    495        1.1   thorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
    496        1.1   thorpej {
    497        1.9   thorpej 	bool rv;
    498        1.1   thorpej 
    499        1.4   thorpej 	if (! prop_object_is_array(pa))
    500        1.9   thorpej 		return (false);
    501        1.4   thorpej 
    502        1.7   thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    503        1.1   thorpej 	if (capacity > pa->pa_capacity)
    504        1.7   thorpej 		rv = _prop_array_expand(pa, capacity);
    505        1.7   thorpej 	else
    506        1.9   thorpej 		rv = true;
    507        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    508        1.7   thorpej 
    509        1.7   thorpej 	return (rv);
    510        1.1   thorpej }
    511        1.1   thorpej 
    512       1.18      yamt static prop_object_iterator_t
    513       1.18      yamt _prop_array_iterator_locked(prop_array_t pa)
    514        1.1   thorpej {
    515        1.1   thorpej 	struct _prop_array_iterator *pai;
    516        1.1   thorpej 
    517        1.4   thorpej 	if (! prop_object_is_array(pa))
    518        1.4   thorpej 		return (NULL);
    519        1.1   thorpej 
    520        1.1   thorpej 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
    521        1.1   thorpej 	if (pai == NULL)
    522        1.1   thorpej 		return (NULL);
    523        1.1   thorpej 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
    524        1.1   thorpej 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
    525        1.1   thorpej 	prop_object_retain(pa);
    526        1.1   thorpej 	pai->pai_base.pi_obj = pa;
    527       1.18      yamt 	_prop_array_iterator_reset_locked(pai);
    528        1.1   thorpej 
    529        1.1   thorpej 	return (&pai->pai_base);
    530        1.1   thorpej }
    531        1.1   thorpej 
    532        1.1   thorpej /*
    533       1.18      yamt  * prop_array_iterator --
    534       1.18      yamt  *	Return an iterator for the array.  The array is retained by
    535       1.18      yamt  *	the iterator.
    536       1.18      yamt  */
    537       1.18      yamt prop_object_iterator_t
    538       1.18      yamt prop_array_iterator(prop_array_t pa)
    539       1.18      yamt {
    540       1.18      yamt 	prop_object_iterator_t pi;
    541       1.18      yamt 
    542       1.18      yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    543       1.18      yamt 	pi = _prop_array_iterator_locked(pa);
    544       1.18      yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    545       1.18      yamt 	return (pi);
    546       1.18      yamt }
    547       1.18      yamt 
    548       1.18      yamt /*
    549        1.1   thorpej  * prop_array_make_immutable --
    550        1.1   thorpej  *	Make the array immutable.
    551        1.1   thorpej  */
    552        1.1   thorpej void
    553        1.1   thorpej prop_array_make_immutable(prop_array_t pa)
    554        1.1   thorpej {
    555        1.1   thorpej 
    556        1.7   thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    557        1.9   thorpej 	if (prop_array_is_immutable(pa) == false)
    558        1.1   thorpej 		pa->pa_flags |= PA_F_IMMUTABLE;
    559        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    560        1.1   thorpej }
    561        1.1   thorpej 
    562        1.1   thorpej /*
    563        1.1   thorpej  * prop_array_mutable --
    564        1.9   thorpej  *	Returns true if the array is mutable.
    565        1.1   thorpej  */
    566        1.9   thorpej bool
    567        1.1   thorpej prop_array_mutable(prop_array_t pa)
    568        1.1   thorpej {
    569        1.9   thorpej 	bool rv;
    570        1.1   thorpej 
    571        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    572        1.9   thorpej 	rv = prop_array_is_immutable(pa) == false;
    573        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    574        1.7   thorpej 
    575        1.7   thorpej 	return (rv);
    576        1.1   thorpej }
    577        1.1   thorpej 
    578        1.1   thorpej /*
    579        1.1   thorpej  * prop_array_get --
    580        1.1   thorpej  *	Return the object stored at the specified array index.
    581        1.1   thorpej  */
    582        1.1   thorpej prop_object_t
    583        1.1   thorpej prop_array_get(prop_array_t pa, unsigned int idx)
    584        1.1   thorpej {
    585        1.7   thorpej 	prop_object_t po = NULL;
    586        1.1   thorpej 
    587        1.4   thorpej 	if (! prop_object_is_array(pa))
    588        1.4   thorpej 		return (NULL);
    589        1.4   thorpej 
    590        1.7   thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    591        1.1   thorpej 	if (idx >= pa->pa_count)
    592        1.7   thorpej 		goto out;
    593        1.1   thorpej 	po = pa->pa_array[idx];
    594        1.1   thorpej 	_PROP_ASSERT(po != NULL);
    595        1.7   thorpej  out:
    596        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    597        1.1   thorpej 	return (po);
    598        1.1   thorpej }
    599        1.1   thorpej 
    600        1.9   thorpej static bool
    601        1.7   thorpej _prop_array_add(prop_array_t pa, prop_object_t po)
    602        1.7   thorpej {
    603        1.7   thorpej 
    604        1.7   thorpej 	/*
    605        1.7   thorpej 	 * Array must be WRITE-LOCKED.
    606        1.7   thorpej 	 */
    607        1.7   thorpej 
    608        1.7   thorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
    609        1.7   thorpej 
    610        1.7   thorpej 	if (prop_array_is_immutable(pa) ||
    611        1.7   thorpej 	    (pa->pa_count == pa->pa_capacity &&
    612        1.9   thorpej 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
    613        1.9   thorpej 		return (false);
    614        1.7   thorpej 
    615        1.7   thorpej 	prop_object_retain(po);
    616        1.7   thorpej 	pa->pa_array[pa->pa_count++] = po;
    617        1.7   thorpej 	pa->pa_version++;
    618        1.7   thorpej 
    619        1.9   thorpej 	return (true);
    620        1.7   thorpej }
    621        1.7   thorpej 
    622        1.1   thorpej /*
    623        1.1   thorpej  * prop_array_set --
    624        1.1   thorpej  *	Store a reference to an object at the specified array index.
    625        1.1   thorpej  *	This method is not allowed to create holes in the array; the
    626        1.1   thorpej  *	caller must either be setting the object just beyond the existing
    627        1.1   thorpej  *	count or replacing an already existing object reference.
    628        1.1   thorpej  */
    629        1.9   thorpej bool
    630        1.1   thorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
    631        1.1   thorpej {
    632        1.1   thorpej 	prop_object_t opo;
    633        1.9   thorpej 	bool rv = false;
    634        1.1   thorpej 
    635        1.4   thorpej 	if (! prop_object_is_array(pa))
    636        1.9   thorpej 		return (false);
    637        1.1   thorpej 
    638        1.7   thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    639        1.7   thorpej 
    640        1.1   thorpej 	if (prop_array_is_immutable(pa))
    641        1.7   thorpej 		goto out;
    642       1.20  christos 
    643        1.7   thorpej 	if (idx == pa->pa_count) {
    644        1.7   thorpej 		rv = _prop_array_add(pa, po);
    645        1.7   thorpej 		goto out;
    646        1.7   thorpej 	}
    647       1.20  christos 
    648        1.1   thorpej 	_PROP_ASSERT(idx < pa->pa_count);
    649        1.1   thorpej 
    650        1.1   thorpej 	opo = pa->pa_array[idx];
    651        1.1   thorpej 	_PROP_ASSERT(opo != NULL);
    652       1.20  christos 
    653        1.1   thorpej 	prop_object_retain(po);
    654        1.1   thorpej 	pa->pa_array[idx] = po;
    655        1.1   thorpej 	pa->pa_version++;
    656        1.1   thorpej 
    657        1.1   thorpej 	prop_object_release(opo);
    658        1.1   thorpej 
    659        1.9   thorpej 	rv = true;
    660        1.7   thorpej 
    661        1.7   thorpej  out:
    662        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    663        1.7   thorpej 	return (rv);
    664        1.1   thorpej }
    665        1.1   thorpej 
    666        1.1   thorpej /*
    667        1.1   thorpej  * prop_array_add --
    668       1.20  christos  *	Add a reference to an object to the specified array, appending
    669        1.1   thorpej  *	to the end and growing the array's capacity, if necessary.
    670        1.1   thorpej  */
    671        1.9   thorpej bool
    672        1.1   thorpej prop_array_add(prop_array_t pa, prop_object_t po)
    673        1.1   thorpej {
    674        1.9   thorpej 	bool rv;
    675        1.1   thorpej 
    676        1.4   thorpej 	if (! prop_object_is_array(pa))
    677        1.9   thorpej 		return (false);
    678        1.4   thorpej 
    679        1.7   thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    680        1.7   thorpej 	rv = _prop_array_add(pa, po);
    681        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    682        1.1   thorpej 
    683        1.7   thorpej 	return (rv);
    684        1.1   thorpej }
    685        1.1   thorpej 
    686        1.1   thorpej /*
    687        1.1   thorpej  * prop_array_remove --
    688        1.1   thorpej  *	Remove the reference to an object from an array at the specified
    689       1.20  christos  *	index.	The array will be compacted following the removal.
    690        1.1   thorpej  */
    691        1.1   thorpej void
    692        1.1   thorpej prop_array_remove(prop_array_t pa, unsigned int idx)
    693        1.1   thorpej {
    694        1.1   thorpej 	prop_object_t po;
    695        1.1   thorpej 
    696        1.4   thorpej 	if (! prop_object_is_array(pa))
    697        1.4   thorpej 		return;
    698        1.4   thorpej 
    699        1.7   thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    700        1.7   thorpej 
    701        1.1   thorpej 	_PROP_ASSERT(idx < pa->pa_count);
    702        1.1   thorpej 
    703        1.1   thorpej 	/* XXX Should this be a _PROP_ASSERT()? */
    704        1.7   thorpej 	if (prop_array_is_immutable(pa)) {
    705        1.7   thorpej 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    706        1.1   thorpej 		return;
    707        1.7   thorpej 	}
    708        1.1   thorpej 
    709        1.1   thorpej 	po = pa->pa_array[idx];
    710        1.1   thorpej 	_PROP_ASSERT(po != NULL);
    711        1.1   thorpej 
    712        1.1   thorpej 	for (++idx; idx < pa->pa_count; idx++)
    713        1.1   thorpej 		pa->pa_array[idx - 1] = pa->pa_array[idx];
    714        1.1   thorpej 	pa->pa_count--;
    715        1.1   thorpej 	pa->pa_version++;
    716        1.7   thorpej 
    717        1.7   thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    718       1.20  christos 
    719        1.1   thorpej 	prop_object_release(po);
    720        1.1   thorpej }
    721        1.1   thorpej 
    722        1.1   thorpej /*
    723        1.2   thorpej  * prop_array_equals --
    724        1.9   thorpej  *	Return true if the two arrays are equivalent.  Note we do a
    725        1.2   thorpej  *	by-value comparison of the objects in the array.
    726        1.2   thorpej  */
    727        1.9   thorpej bool
    728        1.2   thorpej prop_array_equals(prop_array_t array1, prop_array_t array2)
    729        1.2   thorpej {
    730       1.11     joerg 	if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
    731       1.11     joerg 		return (false);
    732        1.2   thorpej 
    733       1.11     joerg 	return (prop_object_equals(array1, array2));
    734        1.2   thorpej }
    735        1.2   thorpej 
    736        1.2   thorpej /*
    737        1.4   thorpej  * prop_array_externalize --
    738        1.4   thorpej  *	Externalize an array, return a NUL-terminated buffer
    739        1.4   thorpej  *	containing the XML-style representation.  The buffer is allocated
    740       1.20  christos  *	with the M_TEMP memory type.
    741        1.4   thorpej  */
    742        1.4   thorpej char *
    743        1.4   thorpej prop_array_externalize(prop_array_t pa)
    744        1.4   thorpej {
    745        1.4   thorpej 	struct _prop_object_externalize_context *ctx;
    746        1.4   thorpej 	char *cp;
    747        1.4   thorpej 
    748        1.4   thorpej 	ctx = _prop_object_externalize_context_alloc();
    749        1.4   thorpej 	if (ctx == NULL)
    750        1.4   thorpej 		return (NULL);
    751       1.20  christos 
    752        1.9   thorpej 	if (_prop_object_externalize_header(ctx) == false ||
    753        1.9   thorpej 	    (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
    754        1.9   thorpej 	    _prop_object_externalize_footer(ctx) == false) {
    755        1.4   thorpej 		/* We are responsible for releasing the buffer. */
    756        1.4   thorpej 		_PROP_FREE(ctx->poec_buf, M_TEMP);
    757        1.4   thorpej 		_prop_object_externalize_context_free(ctx);
    758        1.4   thorpej 		return (NULL);
    759        1.4   thorpej 	}
    760        1.4   thorpej 
    761        1.4   thorpej 	cp = ctx->poec_buf;
    762        1.4   thorpej 	_prop_object_externalize_context_free(ctx);
    763        1.4   thorpej 
    764        1.4   thorpej 	return (cp);
    765        1.4   thorpej }
    766        1.4   thorpej 
    767        1.4   thorpej /*
    768        1.1   thorpej  * _prop_array_internalize --
    769        1.1   thorpej  *	Parse an <array>...</array> and return the object created from the
    770        1.1   thorpej  *	external representation.
    771        1.1   thorpej  */
    772       1.10     joerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
    773       1.10     joerg     struct _prop_object_internalize_context *);
    774       1.10     joerg 
    775       1.10     joerg bool
    776       1.10     joerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
    777       1.10     joerg     struct _prop_object_internalize_context *ctx)
    778        1.1   thorpej {
    779        1.1   thorpej 	/* We don't currently understand any attributes. */
    780        1.1   thorpej 	if (ctx->poic_tagattr != NULL)
    781       1.10     joerg 		return (true);
    782       1.20  christos 
    783       1.10     joerg 	*obj = prop_array_create();
    784       1.10     joerg 	/*
    785       1.10     joerg 	 * We are done if the create failed or no child elements exist.
    786       1.10     joerg 	 */
    787       1.10     joerg 	if (*obj == NULL || ctx->poic_is_empty_element)
    788       1.10     joerg 		return (true);
    789       1.10     joerg 
    790       1.10     joerg 	/*
    791       1.10     joerg 	 * Opening tag is found, now continue to the first element.
    792       1.10     joerg 	 */
    793       1.10     joerg 	return (_prop_array_internalize_body(stack, obj, ctx));
    794       1.10     joerg }
    795       1.10     joerg 
    796       1.10     joerg static bool
    797       1.10     joerg _prop_array_internalize_continue(prop_stack_t stack,
    798       1.10     joerg     prop_object_t *obj,
    799       1.10     joerg     struct _prop_object_internalize_context *ctx,
    800       1.10     joerg     void *data, prop_object_t child)
    801       1.10     joerg {
    802       1.10     joerg 	prop_array_t array;
    803       1.10     joerg 
    804       1.10     joerg 	_PROP_ASSERT(data == NULL);
    805       1.10     joerg 
    806       1.10     joerg 	if (child == NULL)
    807       1.10     joerg 		goto bad; /* Element could not be parsed. */
    808       1.10     joerg 
    809       1.10     joerg 	array = *obj;
    810       1.10     joerg 
    811       1.10     joerg 	if (prop_array_add(array, child) == false) {
    812       1.10     joerg 		prop_object_release(child);
    813       1.10     joerg 		goto bad;
    814       1.10     joerg 	}
    815       1.10     joerg 	prop_object_release(child);
    816       1.10     joerg 
    817       1.10     joerg 	/*
    818       1.10     joerg 	 * Current element is processed and added, look for next.
    819       1.10     joerg 	 */
    820       1.10     joerg 	return (_prop_array_internalize_body(stack, obj, ctx));
    821       1.10     joerg 
    822       1.10     joerg  bad:
    823       1.10     joerg 	prop_object_release(*obj);
    824       1.10     joerg 	*obj = NULL;
    825       1.10     joerg 	return (true);
    826       1.10     joerg }
    827       1.10     joerg 
    828       1.10     joerg static bool
    829       1.10     joerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
    830       1.10     joerg     struct _prop_object_internalize_context *ctx)
    831       1.10     joerg {
    832       1.10     joerg 	prop_array_t array = *obj;
    833       1.10     joerg 
    834       1.10     joerg 	_PROP_ASSERT(array != NULL);
    835       1.10     joerg 
    836       1.10     joerg 	/* Fetch the next tag. */
    837       1.10     joerg 	if (_prop_object_internalize_find_tag(ctx, NULL,
    838       1.10     joerg 				_PROP_TAG_TYPE_EITHER) == false)
    839       1.10     joerg 		goto bad;
    840       1.10     joerg 
    841       1.10     joerg 	/* Check to see if this is the end of the array. */
    842       1.10     joerg 	if (_PROP_TAG_MATCH(ctx, "array") &&
    843       1.10     joerg 	    ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
    844       1.10     joerg 		/* It is, so don't iterate any further. */
    845       1.10     joerg 		return (true);
    846        1.1   thorpej 	}
    847        1.1   thorpej 
    848       1.11     joerg 	if (_prop_stack_push(stack, array,
    849       1.11     joerg 			     _prop_array_internalize_continue, NULL, NULL))
    850       1.10     joerg 		return (false);
    851        1.1   thorpej 
    852        1.1   thorpej  bad:
    853        1.1   thorpej 	prop_object_release(array);
    854       1.10     joerg 	*obj = NULL;
    855       1.10     joerg 	return (true);
    856        1.1   thorpej }
    857        1.4   thorpej 
    858        1.4   thorpej /*
    859        1.4   thorpej  * prop_array_internalize --
    860        1.4   thorpej  *	Create an array by parsing the XML-style representation.
    861        1.4   thorpej  */
    862        1.4   thorpej prop_array_t
    863        1.4   thorpej prop_array_internalize(const char *xml)
    864        1.4   thorpej {
    865        1.8     joerg 	return _prop_generic_internalize(xml, "array");
    866        1.4   thorpej }
    867        1.4   thorpej 
    868        1.4   thorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
    869        1.4   thorpej /*
    870        1.4   thorpej  * prop_array_externalize_to_file --
    871        1.4   thorpej  *	Externalize an array to the specified file.
    872        1.4   thorpej  */
    873        1.9   thorpej bool
    874        1.4   thorpej prop_array_externalize_to_file(prop_array_t array, const char *fname)
    875        1.4   thorpej {
    876        1.4   thorpej 	char *xml;
    877        1.9   thorpej 	bool rv;
    878        1.5        he 	int save_errno = 0;	/* XXXGCC -Wuninitialized [mips, ...] */
    879        1.4   thorpej 
    880        1.4   thorpej 	xml = prop_array_externalize(array);
    881        1.4   thorpej 	if (xml == NULL)
    882        1.9   thorpej 		return (false);
    883        1.4   thorpej 	rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
    884        1.9   thorpej 	if (rv == false)
    885        1.4   thorpej 		save_errno = errno;
    886        1.4   thorpej 	_PROP_FREE(xml, M_TEMP);
    887        1.9   thorpej 	if (rv == false)
    888        1.4   thorpej 		errno = save_errno;
    889        1.4   thorpej 
    890        1.4   thorpej 	return (rv);
    891        1.4   thorpej }
    892        1.4   thorpej 
    893        1.4   thorpej /*
    894        1.4   thorpej  * prop_array_internalize_from_file --
    895        1.4   thorpej  *	Internalize an array from a file.
    896        1.4   thorpej  */
    897        1.4   thorpej prop_array_t
    898        1.4   thorpej prop_array_internalize_from_file(const char *fname)
    899        1.4   thorpej {
    900        1.4   thorpej 	struct _prop_object_internalize_mapped_file *mf;
    901        1.4   thorpej 	prop_array_t array;
    902        1.4   thorpej 
    903        1.4   thorpej 	mf = _prop_object_internalize_map_file(fname);
    904        1.4   thorpej 	if (mf == NULL)
    905        1.4   thorpej 		return (NULL);
    906        1.4   thorpej 	array = prop_array_internalize(mf->poimf_xml);
    907        1.4   thorpej 	_prop_object_internalize_unmap_file(mf);
    908        1.4   thorpej 
    909        1.4   thorpej 	return (array);
    910        1.4   thorpej }
    911        1.4   thorpej #endif /* _KERNEL && !_STANDALONE */
    912