Home | History | Annotate | Line # | Download | only in libprop
prop_array.c revision 1.19
      1  1.19  thorpej /*	$NetBSD: prop_array.c,v 1.19 2008/08/03 04:00:12 thorpej 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.1  thorpej #include <prop/prop_array.h>
     33   1.1  thorpej #include "prop_object_impl.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.1  thorpej #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.2  thorpej #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.1  thorpej #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.1  thorpej #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.1  thorpej 
    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.1  thorpej 
    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.1  thorpej 
    196   1.7  thorpej  out:
    197   1.7  thorpej  	_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.2  thorpej 
    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 
    273   1.1  thorpej 	pa = _PROP_POOL_GET(_prop_array_pool);
    274   1.1  thorpej 	if (pa != NULL) {
    275   1.2  thorpej 		_prop_object_init(&pa->pa_obj, &_prop_object_type_array);
    276   1.2  thorpej 		pa->pa_obj.po_type = &_prop_object_type_array;
    277   1.1  thorpej 
    278   1.7  thorpej 		_PROP_RWLOCK_INIT(pa->pa_rwlock);
    279   1.1  thorpej 		pa->pa_array = array;
    280   1.1  thorpej 		pa->pa_capacity = capacity;
    281   1.1  thorpej 		pa->pa_count = 0;
    282   1.1  thorpej 		pa->pa_flags = 0;
    283   1.1  thorpej 
    284   1.1  thorpej 		pa->pa_version = 0;
    285   1.1  thorpej 	} else if (array != NULL)
    286   1.1  thorpej 		_PROP_FREE(array, M_PROP_ARRAY);
    287   1.1  thorpej 
    288   1.1  thorpej 	return (pa);
    289   1.1  thorpej }
    290   1.1  thorpej 
    291   1.9  thorpej static bool
    292   1.1  thorpej _prop_array_expand(prop_array_t pa, unsigned int capacity)
    293   1.1  thorpej {
    294   1.1  thorpej 	prop_object_t *array, *oarray;
    295   1.1  thorpej 
    296   1.7  thorpej 	/*
    297   1.7  thorpej 	 * Array must be WRITE-LOCKED.
    298   1.7  thorpej 	 */
    299   1.7  thorpej 
    300   1.1  thorpej 	oarray = pa->pa_array;
    301   1.1  thorpej 
    302   1.3  thorpej 	array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
    303   1.1  thorpej 	if (array == NULL)
    304   1.9  thorpej 		return (false);
    305   1.1  thorpej 	if (oarray != NULL)
    306   1.3  thorpej 		memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
    307   1.1  thorpej 	pa->pa_array = array;
    308   1.1  thorpej 	pa->pa_capacity = capacity;
    309   1.1  thorpej 
    310   1.1  thorpej 	if (oarray != NULL)
    311   1.1  thorpej 		_PROP_FREE(oarray, M_PROP_ARRAY);
    312   1.1  thorpej 
    313   1.9  thorpej 	return (true);
    314   1.1  thorpej }
    315   1.1  thorpej 
    316   1.1  thorpej static prop_object_t
    317  1.18     yamt _prop_array_iterator_next_object_locked(void *v)
    318   1.1  thorpej {
    319   1.1  thorpej 	struct _prop_array_iterator *pai = v;
    320   1.1  thorpej 	prop_array_t pa = pai->pai_base.pi_obj;
    321   1.7  thorpej 	prop_object_t po = NULL;
    322   1.1  thorpej 
    323   1.1  thorpej 	_PROP_ASSERT(prop_object_is_array(pa));
    324  1.17     yamt 
    325   1.1  thorpej 	if (pa->pa_version != pai->pai_base.pi_version)
    326   1.7  thorpej 		goto out;	/* array changed during iteration */
    327   1.1  thorpej 
    328   1.1  thorpej 	_PROP_ASSERT(pai->pai_index <= pa->pa_count);
    329   1.1  thorpej 
    330   1.1  thorpej 	if (pai->pai_index == pa->pa_count)
    331   1.7  thorpej 		goto out;	/* we've iterated all objects */
    332   1.1  thorpej 
    333   1.1  thorpej 	po = pa->pa_array[pai->pai_index];
    334   1.1  thorpej 	pai->pai_index++;
    335   1.1  thorpej 
    336   1.7  thorpej  out:
    337  1.18     yamt 	return (po);
    338  1.18     yamt }
    339  1.18     yamt 
    340  1.18     yamt static prop_object_t
    341  1.18     yamt _prop_array_iterator_next_object(void *v)
    342  1.18     yamt {
    343  1.18     yamt 	struct _prop_array_iterator *pai = v;
    344  1.18     yamt 	prop_array_t pa __unused = pai->pai_base.pi_obj;
    345  1.18     yamt 	prop_object_t po;
    346  1.18     yamt 
    347  1.18     yamt 	_PROP_ASSERT(prop_object_is_array(pa));
    348  1.18     yamt 
    349  1.18     yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    350  1.18     yamt 	po = _prop_array_iterator_next_object_locked(pai);
    351  1.17     yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    352   1.1  thorpej 	return (po);
    353   1.1  thorpej }
    354   1.1  thorpej 
    355   1.1  thorpej static void
    356  1.18     yamt _prop_array_iterator_reset_locked(void *v)
    357   1.1  thorpej {
    358   1.1  thorpej 	struct _prop_array_iterator *pai = v;
    359   1.1  thorpej 	prop_array_t pa = pai->pai_base.pi_obj;
    360   1.1  thorpej 
    361   1.1  thorpej 	_PROP_ASSERT(prop_object_is_array(pa));
    362  1.17     yamt 
    363   1.1  thorpej 	pai->pai_index = 0;
    364   1.1  thorpej 	pai->pai_base.pi_version = pa->pa_version;
    365  1.18     yamt }
    366  1.18     yamt 
    367  1.18     yamt static void
    368  1.18     yamt _prop_array_iterator_reset(void *v)
    369  1.18     yamt {
    370  1.18     yamt 	struct _prop_array_iterator *pai = v;
    371  1.18     yamt 	prop_array_t pa __unused = pai->pai_base.pi_obj;
    372  1.14  xtraeme 
    373  1.18     yamt 	_PROP_ASSERT(prop_object_is_array(pa));
    374  1.18     yamt 
    375  1.18     yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    376  1.18     yamt 	_prop_array_iterator_reset_locked(pai);
    377  1.17     yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    378   1.1  thorpej }
    379   1.1  thorpej 
    380   1.1  thorpej /*
    381   1.1  thorpej  * prop_array_create --
    382   1.1  thorpej  *	Create an empty array.
    383   1.1  thorpej  */
    384   1.1  thorpej prop_array_t
    385   1.1  thorpej prop_array_create(void)
    386   1.1  thorpej {
    387   1.1  thorpej 
    388   1.1  thorpej 	return (_prop_array_alloc(0));
    389   1.1  thorpej }
    390   1.1  thorpej 
    391   1.1  thorpej /*
    392   1.1  thorpej  * prop_array_create_with_capacity --
    393   1.1  thorpej  *	Create an array with the capacity to store N objects.
    394   1.1  thorpej  */
    395   1.1  thorpej prop_array_t
    396   1.1  thorpej prop_array_create_with_capacity(unsigned int capacity)
    397   1.1  thorpej {
    398   1.1  thorpej 
    399   1.1  thorpej 	return (_prop_array_alloc(capacity));
    400   1.1  thorpej }
    401   1.1  thorpej 
    402   1.1  thorpej /*
    403   1.1  thorpej  * prop_array_copy --
    404   1.1  thorpej  *	Copy an array.  The new array has an initial capacity equal to
    405   1.1  thorpej  *	the number of objects stored in the original array.  The new
    406   1.1  thorpej  *	array contains references to the original array's objects, not
    407   1.1  thorpej  *	copies of those objects (i.e. a shallow copy).
    408   1.1  thorpej  */
    409   1.1  thorpej prop_array_t
    410   1.1  thorpej prop_array_copy(prop_array_t opa)
    411   1.1  thorpej {
    412   1.1  thorpej 	prop_array_t pa;
    413   1.1  thorpej 	prop_object_t po;
    414   1.1  thorpej 	unsigned int idx;
    415   1.1  thorpej 
    416   1.4  thorpej 	if (! prop_object_is_array(opa))
    417   1.4  thorpej 		return (NULL);
    418   1.1  thorpej 
    419   1.7  thorpej 	_PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
    420   1.7  thorpej 
    421   1.1  thorpej 	pa = _prop_array_alloc(opa->pa_count);
    422   1.1  thorpej 	if (pa != NULL) {
    423   1.1  thorpej 		for (idx = 0; idx < opa->pa_count; idx++) {
    424   1.1  thorpej 			po = opa->pa_array[idx];
    425   1.1  thorpej 			prop_object_retain(po);
    426   1.1  thorpej 			pa->pa_array[idx] = po;
    427   1.1  thorpej 		}
    428   1.1  thorpej 		pa->pa_count = opa->pa_count;
    429   1.1  thorpej 		pa->pa_flags = opa->pa_flags;
    430   1.1  thorpej 	}
    431   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
    432   1.1  thorpej 	return (pa);
    433   1.1  thorpej }
    434   1.1  thorpej 
    435   1.1  thorpej /*
    436   1.1  thorpej  * prop_array_copy_mutable --
    437   1.1  thorpej  *	Like prop_array_copy(), but the resulting array is mutable.
    438   1.1  thorpej  */
    439   1.1  thorpej prop_array_t
    440   1.1  thorpej prop_array_copy_mutable(prop_array_t opa)
    441   1.1  thorpej {
    442   1.1  thorpej 	prop_array_t pa;
    443   1.1  thorpej 
    444   1.1  thorpej 	pa = prop_array_copy(opa);
    445   1.1  thorpej 	if (pa != NULL)
    446   1.1  thorpej 		pa->pa_flags &= ~PA_F_IMMUTABLE;
    447   1.1  thorpej 
    448   1.1  thorpej 	return (pa);
    449   1.1  thorpej }
    450   1.1  thorpej 
    451   1.1  thorpej /*
    452   1.1  thorpej  * prop_array_capacity --
    453   1.1  thorpej  *	Return the capacity of the array.
    454   1.1  thorpej  */
    455   1.1  thorpej unsigned int
    456   1.1  thorpej prop_array_capacity(prop_array_t pa)
    457   1.1  thorpej {
    458   1.7  thorpej 	unsigned int rv;
    459   1.1  thorpej 
    460   1.4  thorpej 	if (! prop_object_is_array(pa))
    461   1.4  thorpej 		return (0);
    462   1.4  thorpej 
    463   1.7  thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    464   1.7  thorpej 	rv = pa->pa_capacity;
    465   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    466   1.7  thorpej 
    467   1.7  thorpej 	return (rv);
    468   1.1  thorpej }
    469   1.1  thorpej 
    470   1.1  thorpej /*
    471   1.1  thorpej  * prop_array_count --
    472   1.1  thorpej  *	Return the number of objects stored in the array.
    473   1.1  thorpej  */
    474   1.1  thorpej unsigned int
    475   1.1  thorpej prop_array_count(prop_array_t pa)
    476   1.1  thorpej {
    477   1.7  thorpej 	unsigned int rv;
    478   1.1  thorpej 
    479   1.4  thorpej 	if (! prop_object_is_array(pa))
    480   1.4  thorpej 		return (0);
    481   1.4  thorpej 
    482   1.7  thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    483   1.7  thorpej 	rv = pa->pa_count;
    484   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    485   1.7  thorpej 
    486   1.7  thorpej 	return (rv);
    487   1.1  thorpej }
    488   1.1  thorpej 
    489   1.1  thorpej /*
    490   1.1  thorpej  * prop_array_ensure_capacity --
    491   1.1  thorpej  *	Ensure that the array has the capacity to store the specified
    492   1.1  thorpej  *	total number of objects (inluding the objects already stored
    493   1.1  thorpej  *	in the array).
    494   1.1  thorpej  */
    495   1.9  thorpej bool
    496   1.1  thorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
    497   1.1  thorpej {
    498   1.9  thorpej 	bool rv;
    499   1.1  thorpej 
    500   1.4  thorpej 	if (! prop_object_is_array(pa))
    501   1.9  thorpej 		return (false);
    502   1.4  thorpej 
    503   1.7  thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    504   1.1  thorpej 	if (capacity > pa->pa_capacity)
    505   1.7  thorpej 		rv = _prop_array_expand(pa, capacity);
    506   1.7  thorpej 	else
    507   1.9  thorpej 		rv = true;
    508   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    509   1.7  thorpej 
    510   1.7  thorpej 	return (rv);
    511   1.1  thorpej }
    512   1.1  thorpej 
    513  1.18     yamt static prop_object_iterator_t
    514  1.18     yamt _prop_array_iterator_locked(prop_array_t pa)
    515   1.1  thorpej {
    516   1.1  thorpej 	struct _prop_array_iterator *pai;
    517   1.1  thorpej 
    518   1.4  thorpej 	if (! prop_object_is_array(pa))
    519   1.4  thorpej 		return (NULL);
    520   1.1  thorpej 
    521   1.1  thorpej 	pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
    522   1.1  thorpej 	if (pai == NULL)
    523   1.1  thorpej 		return (NULL);
    524   1.1  thorpej 	pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
    525   1.1  thorpej 	pai->pai_base.pi_reset = _prop_array_iterator_reset;
    526   1.1  thorpej 	prop_object_retain(pa);
    527   1.1  thorpej 	pai->pai_base.pi_obj = pa;
    528  1.18     yamt 	_prop_array_iterator_reset_locked(pai);
    529   1.1  thorpej 
    530   1.1  thorpej 	return (&pai->pai_base);
    531   1.1  thorpej }
    532   1.1  thorpej 
    533   1.1  thorpej /*
    534  1.18     yamt  * prop_array_iterator --
    535  1.18     yamt  *	Return an iterator for the array.  The array is retained by
    536  1.18     yamt  *	the iterator.
    537  1.18     yamt  */
    538  1.18     yamt prop_object_iterator_t
    539  1.18     yamt prop_array_iterator(prop_array_t pa)
    540  1.18     yamt {
    541  1.18     yamt 	prop_object_iterator_t pi;
    542  1.18     yamt 
    543  1.18     yamt 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    544  1.18     yamt 	pi = _prop_array_iterator_locked(pa);
    545  1.18     yamt 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    546  1.18     yamt 	return (pi);
    547  1.18     yamt }
    548  1.18     yamt 
    549  1.18     yamt /*
    550   1.1  thorpej  * prop_array_make_immutable --
    551   1.1  thorpej  *	Make the array immutable.
    552   1.1  thorpej  */
    553   1.1  thorpej void
    554   1.1  thorpej prop_array_make_immutable(prop_array_t pa)
    555   1.1  thorpej {
    556   1.1  thorpej 
    557   1.7  thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    558   1.9  thorpej 	if (prop_array_is_immutable(pa) == false)
    559   1.1  thorpej 		pa->pa_flags |= PA_F_IMMUTABLE;
    560   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    561   1.1  thorpej }
    562   1.1  thorpej 
    563   1.1  thorpej /*
    564   1.1  thorpej  * prop_array_mutable --
    565   1.9  thorpej  *	Returns true if the array is mutable.
    566   1.1  thorpej  */
    567   1.9  thorpej bool
    568   1.1  thorpej prop_array_mutable(prop_array_t pa)
    569   1.1  thorpej {
    570   1.9  thorpej 	bool rv;
    571   1.1  thorpej 
    572   1.7  thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    573   1.9  thorpej 	rv = prop_array_is_immutable(pa) == false;
    574   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    575   1.7  thorpej 
    576   1.7  thorpej 	return (rv);
    577   1.1  thorpej }
    578   1.1  thorpej 
    579   1.1  thorpej /*
    580   1.1  thorpej  * prop_array_get --
    581   1.1  thorpej  *	Return the object stored at the specified array index.
    582   1.1  thorpej  */
    583   1.1  thorpej prop_object_t
    584   1.1  thorpej prop_array_get(prop_array_t pa, unsigned int idx)
    585   1.1  thorpej {
    586   1.7  thorpej 	prop_object_t po = NULL;
    587   1.1  thorpej 
    588   1.4  thorpej 	if (! prop_object_is_array(pa))
    589   1.4  thorpej 		return (NULL);
    590   1.4  thorpej 
    591   1.7  thorpej 	_PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
    592   1.1  thorpej 	if (idx >= pa->pa_count)
    593   1.7  thorpej 		goto out;
    594   1.1  thorpej 	po = pa->pa_array[idx];
    595   1.1  thorpej 	_PROP_ASSERT(po != NULL);
    596   1.7  thorpej  out:
    597   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    598   1.1  thorpej 	return (po);
    599   1.1  thorpej }
    600   1.1  thorpej 
    601   1.9  thorpej static bool
    602   1.7  thorpej _prop_array_add(prop_array_t pa, prop_object_t po)
    603   1.7  thorpej {
    604   1.7  thorpej 
    605   1.7  thorpej 	/*
    606   1.7  thorpej 	 * Array must be WRITE-LOCKED.
    607   1.7  thorpej 	 */
    608   1.7  thorpej 
    609   1.7  thorpej 	_PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
    610   1.7  thorpej 
    611   1.7  thorpej 	if (prop_array_is_immutable(pa) ||
    612   1.7  thorpej 	    (pa->pa_count == pa->pa_capacity &&
    613   1.9  thorpej 	    _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
    614   1.9  thorpej 		return (false);
    615   1.7  thorpej 
    616   1.7  thorpej 	prop_object_retain(po);
    617   1.7  thorpej 	pa->pa_array[pa->pa_count++] = po;
    618   1.7  thorpej 	pa->pa_version++;
    619   1.7  thorpej 
    620   1.9  thorpej 	return (true);
    621   1.7  thorpej }
    622   1.7  thorpej 
    623   1.1  thorpej /*
    624   1.1  thorpej  * prop_array_set --
    625   1.1  thorpej  *	Store a reference to an object at the specified array index.
    626   1.1  thorpej  *	This method is not allowed to create holes in the array; the
    627   1.1  thorpej  *	caller must either be setting the object just beyond the existing
    628   1.1  thorpej  *	count or replacing an already existing object reference.
    629   1.1  thorpej  */
    630   1.9  thorpej bool
    631   1.1  thorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
    632   1.1  thorpej {
    633   1.1  thorpej 	prop_object_t opo;
    634   1.9  thorpej 	bool rv = false;
    635   1.1  thorpej 
    636   1.4  thorpej 	if (! prop_object_is_array(pa))
    637   1.9  thorpej 		return (false);
    638   1.1  thorpej 
    639   1.7  thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    640   1.7  thorpej 
    641   1.1  thorpej 	if (prop_array_is_immutable(pa))
    642   1.7  thorpej 		goto out;
    643   1.1  thorpej 
    644   1.7  thorpej 	if (idx == pa->pa_count) {
    645   1.7  thorpej 		rv = _prop_array_add(pa, po);
    646   1.7  thorpej 		goto out;
    647   1.7  thorpej 	}
    648   1.1  thorpej 
    649   1.1  thorpej 	_PROP_ASSERT(idx < pa->pa_count);
    650   1.1  thorpej 
    651   1.1  thorpej 	opo = pa->pa_array[idx];
    652   1.1  thorpej 	_PROP_ASSERT(opo != NULL);
    653   1.1  thorpej 
    654   1.1  thorpej 	prop_object_retain(po);
    655   1.1  thorpej 	pa->pa_array[idx] = po;
    656   1.1  thorpej 	pa->pa_version++;
    657   1.1  thorpej 
    658   1.1  thorpej 	prop_object_release(opo);
    659   1.1  thorpej 
    660   1.9  thorpej 	rv = true;
    661   1.7  thorpej 
    662   1.7  thorpej  out:
    663   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    664   1.7  thorpej 	return (rv);
    665   1.1  thorpej }
    666   1.1  thorpej 
    667   1.1  thorpej /*
    668   1.1  thorpej  * prop_array_add --
    669   1.1  thorpej  *	Add a refrerence to an object to the specified array, appending
    670   1.1  thorpej  *	to the end and growing the array's capacity, if necessary.
    671   1.1  thorpej  */
    672   1.9  thorpej bool
    673   1.1  thorpej prop_array_add(prop_array_t pa, prop_object_t po)
    674   1.1  thorpej {
    675   1.9  thorpej 	bool rv;
    676   1.1  thorpej 
    677   1.4  thorpej 	if (! prop_object_is_array(pa))
    678   1.9  thorpej 		return (false);
    679   1.4  thorpej 
    680   1.7  thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    681   1.7  thorpej 	rv = _prop_array_add(pa, po);
    682   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    683   1.1  thorpej 
    684   1.7  thorpej 	return (rv);
    685   1.1  thorpej }
    686   1.1  thorpej 
    687   1.1  thorpej /*
    688   1.1  thorpej  * prop_array_remove --
    689   1.1  thorpej  *	Remove the reference to an object from an array at the specified
    690   1.1  thorpej  *	index.  The array will be compacted following the removal.
    691   1.1  thorpej  */
    692   1.1  thorpej void
    693   1.1  thorpej prop_array_remove(prop_array_t pa, unsigned int idx)
    694   1.1  thorpej {
    695   1.1  thorpej 	prop_object_t po;
    696   1.1  thorpej 
    697   1.4  thorpej 	if (! prop_object_is_array(pa))
    698   1.4  thorpej 		return;
    699   1.4  thorpej 
    700   1.7  thorpej 	_PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
    701   1.7  thorpej 
    702   1.1  thorpej 	_PROP_ASSERT(idx < pa->pa_count);
    703   1.1  thorpej 
    704   1.1  thorpej 	/* XXX Should this be a _PROP_ASSERT()? */
    705   1.7  thorpej 	if (prop_array_is_immutable(pa)) {
    706   1.7  thorpej 		_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    707   1.1  thorpej 		return;
    708   1.7  thorpej 	}
    709   1.1  thorpej 
    710   1.1  thorpej 	po = pa->pa_array[idx];
    711   1.1  thorpej 	_PROP_ASSERT(po != NULL);
    712   1.1  thorpej 
    713   1.1  thorpej 	for (++idx; idx < pa->pa_count; idx++)
    714   1.1  thorpej 		pa->pa_array[idx - 1] = pa->pa_array[idx];
    715   1.1  thorpej 	pa->pa_count--;
    716   1.1  thorpej 	pa->pa_version++;
    717   1.7  thorpej 
    718   1.7  thorpej 	_PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
    719   1.1  thorpej 
    720   1.1  thorpej 	prop_object_release(po);
    721   1.1  thorpej }
    722   1.1  thorpej 
    723   1.1  thorpej /*
    724   1.2  thorpej  * prop_array_equals --
    725   1.9  thorpej  *	Return true if the two arrays are equivalent.  Note we do a
    726   1.2  thorpej  *	by-value comparison of the objects in the array.
    727   1.2  thorpej  */
    728   1.9  thorpej bool
    729   1.2  thorpej prop_array_equals(prop_array_t array1, prop_array_t array2)
    730   1.2  thorpej {
    731  1.11    joerg 	if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
    732  1.11    joerg 		return (false);
    733   1.2  thorpej 
    734  1.11    joerg 	return (prop_object_equals(array1, array2));
    735   1.2  thorpej }
    736   1.2  thorpej 
    737   1.2  thorpej /*
    738   1.4  thorpej  * prop_array_externalize --
    739   1.4  thorpej  *	Externalize an array, return a NUL-terminated buffer
    740   1.4  thorpej  *	containing the XML-style representation.  The buffer is allocated
    741   1.4  thorpej  * 	with the M_TEMP memory type.
    742   1.4  thorpej  */
    743   1.4  thorpej char *
    744   1.4  thorpej prop_array_externalize(prop_array_t pa)
    745   1.4  thorpej {
    746   1.4  thorpej 	struct _prop_object_externalize_context *ctx;
    747   1.4  thorpej 	char *cp;
    748   1.4  thorpej 
    749   1.4  thorpej 	ctx = _prop_object_externalize_context_alloc();
    750   1.4  thorpej 	if (ctx == NULL)
    751   1.4  thorpej 		return (NULL);
    752   1.4  thorpej 
    753   1.9  thorpej 	if (_prop_object_externalize_header(ctx) == false ||
    754   1.9  thorpej 	    (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
    755   1.9  thorpej 	    _prop_object_externalize_footer(ctx) == false) {
    756   1.4  thorpej 		/* We are responsible for releasing the buffer. */
    757   1.4  thorpej 		_PROP_FREE(ctx->poec_buf, M_TEMP);
    758   1.4  thorpej 		_prop_object_externalize_context_free(ctx);
    759   1.4  thorpej 		return (NULL);
    760   1.4  thorpej 	}
    761   1.4  thorpej 
    762   1.4  thorpej 	cp = ctx->poec_buf;
    763   1.4  thorpej 	_prop_object_externalize_context_free(ctx);
    764   1.4  thorpej 
    765   1.4  thorpej 	return (cp);
    766   1.4  thorpej }
    767   1.4  thorpej 
    768   1.4  thorpej /*
    769   1.1  thorpej  * _prop_array_internalize --
    770   1.1  thorpej  *	Parse an <array>...</array> and return the object created from the
    771   1.1  thorpej  *	external representation.
    772   1.1  thorpej  */
    773  1.10    joerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
    774  1.10    joerg     struct _prop_object_internalize_context *);
    775  1.10    joerg 
    776  1.10    joerg bool
    777  1.10    joerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
    778  1.10    joerg     struct _prop_object_internalize_context *ctx)
    779   1.1  thorpej {
    780   1.1  thorpej 	/* We don't currently understand any attributes. */
    781   1.1  thorpej 	if (ctx->poic_tagattr != NULL)
    782  1.10    joerg 		return (true);
    783   1.1  thorpej 
    784  1.10    joerg 	*obj = prop_array_create();
    785  1.10    joerg 	/*
    786  1.10    joerg 	 * We are done if the create failed or no child elements exist.
    787  1.10    joerg 	 */
    788  1.10    joerg 	if (*obj == NULL || ctx->poic_is_empty_element)
    789  1.10    joerg 		return (true);
    790  1.10    joerg 
    791  1.10    joerg 	/*
    792  1.10    joerg 	 * Opening tag is found, now continue to the first element.
    793  1.10    joerg 	 */
    794  1.10    joerg 	return (_prop_array_internalize_body(stack, obj, ctx));
    795  1.10    joerg }
    796  1.10    joerg 
    797  1.10    joerg static bool
    798  1.10    joerg _prop_array_internalize_continue(prop_stack_t stack,
    799  1.10    joerg     prop_object_t *obj,
    800  1.10    joerg     struct _prop_object_internalize_context *ctx,
    801  1.10    joerg     void *data, prop_object_t child)
    802  1.10    joerg {
    803  1.10    joerg 	prop_array_t array;
    804  1.10    joerg 
    805  1.10    joerg 	_PROP_ASSERT(data == NULL);
    806  1.10    joerg 
    807  1.10    joerg 	if (child == NULL)
    808  1.10    joerg 		goto bad; /* Element could not be parsed. */
    809  1.10    joerg 
    810  1.10    joerg 	array = *obj;
    811  1.10    joerg 
    812  1.10    joerg 	if (prop_array_add(array, child) == false) {
    813  1.10    joerg 		prop_object_release(child);
    814  1.10    joerg 		goto bad;
    815  1.10    joerg 	}
    816  1.10    joerg 	prop_object_release(child);
    817  1.10    joerg 
    818  1.10    joerg 	/*
    819  1.10    joerg 	 * Current element is processed and added, look for next.
    820  1.10    joerg 	 */
    821  1.10    joerg 	return (_prop_array_internalize_body(stack, obj, ctx));
    822  1.10    joerg 
    823  1.10    joerg  bad:
    824  1.10    joerg 	prop_object_release(*obj);
    825  1.10    joerg 	*obj = NULL;
    826  1.10    joerg 	return (true);
    827  1.10    joerg }
    828  1.10    joerg 
    829  1.10    joerg static bool
    830  1.10    joerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
    831  1.10    joerg     struct _prop_object_internalize_context *ctx)
    832  1.10    joerg {
    833  1.10    joerg 	prop_array_t array = *obj;
    834  1.10    joerg 
    835  1.10    joerg 	_PROP_ASSERT(array != NULL);
    836  1.10    joerg 
    837  1.10    joerg 	/* Fetch the next tag. */
    838  1.10    joerg 	if (_prop_object_internalize_find_tag(ctx, NULL,
    839  1.10    joerg 				_PROP_TAG_TYPE_EITHER) == false)
    840  1.10    joerg 		goto bad;
    841  1.10    joerg 
    842  1.10    joerg 	/* Check to see if this is the end of the array. */
    843  1.10    joerg 	if (_PROP_TAG_MATCH(ctx, "array") &&
    844  1.10    joerg 	    ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
    845  1.10    joerg 		/* It is, so don't iterate any further. */
    846  1.10    joerg 		return (true);
    847   1.1  thorpej 	}
    848   1.1  thorpej 
    849  1.11    joerg 	if (_prop_stack_push(stack, array,
    850  1.11    joerg 			     _prop_array_internalize_continue, NULL, NULL))
    851  1.10    joerg 		return (false);
    852   1.1  thorpej 
    853   1.1  thorpej  bad:
    854   1.1  thorpej 	prop_object_release(array);
    855  1.10    joerg 	*obj = NULL;
    856  1.10    joerg 	return (true);
    857   1.1  thorpej }
    858   1.4  thorpej 
    859   1.4  thorpej /*
    860   1.4  thorpej  * prop_array_internalize --
    861   1.4  thorpej  *	Create an array by parsing the XML-style representation.
    862   1.4  thorpej  */
    863   1.4  thorpej prop_array_t
    864   1.4  thorpej prop_array_internalize(const char *xml)
    865   1.4  thorpej {
    866   1.8    joerg 	return _prop_generic_internalize(xml, "array");
    867   1.4  thorpej }
    868   1.4  thorpej 
    869   1.4  thorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
    870   1.4  thorpej /*
    871   1.4  thorpej  * prop_array_externalize_to_file --
    872   1.4  thorpej  *	Externalize an array to the specified file.
    873   1.4  thorpej  */
    874   1.9  thorpej bool
    875   1.4  thorpej prop_array_externalize_to_file(prop_array_t array, const char *fname)
    876   1.4  thorpej {
    877   1.4  thorpej 	char *xml;
    878   1.9  thorpej 	bool rv;
    879   1.5       he 	int save_errno = 0;	/* XXXGCC -Wuninitialized [mips, ...] */
    880   1.4  thorpej 
    881   1.4  thorpej 	xml = prop_array_externalize(array);
    882   1.4  thorpej 	if (xml == NULL)
    883   1.9  thorpej 		return (false);
    884   1.4  thorpej 	rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
    885   1.9  thorpej 	if (rv == false)
    886   1.4  thorpej 		save_errno = errno;
    887   1.4  thorpej 	_PROP_FREE(xml, M_TEMP);
    888   1.9  thorpej 	if (rv == false)
    889   1.4  thorpej 		errno = save_errno;
    890   1.4  thorpej 
    891   1.4  thorpej 	return (rv);
    892   1.4  thorpej }
    893   1.4  thorpej 
    894   1.4  thorpej /*
    895   1.4  thorpej  * prop_array_internalize_from_file --
    896   1.4  thorpej  *	Internalize an array from a file.
    897   1.4  thorpej  */
    898   1.4  thorpej prop_array_t
    899   1.4  thorpej prop_array_internalize_from_file(const char *fname)
    900   1.4  thorpej {
    901   1.4  thorpej 	struct _prop_object_internalize_mapped_file *mf;
    902   1.4  thorpej 	prop_array_t array;
    903   1.4  thorpej 
    904   1.4  thorpej 	mf = _prop_object_internalize_map_file(fname);
    905   1.4  thorpej 	if (mf == NULL)
    906   1.4  thorpej 		return (NULL);
    907   1.4  thorpej 	array = prop_array_internalize(mf->poimf_xml);
    908   1.4  thorpej 	_prop_object_internalize_unmap_file(mf);
    909   1.4  thorpej 
    910   1.4  thorpej 	return (array);
    911   1.4  thorpej }
    912   1.4  thorpej #endif /* _KERNEL && !_STANDALONE */
    913