1*ecd6bc70Schristos /* $NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $ */ 2774eb1a3Sthorpej 3774eb1a3Sthorpej /*- 4e835604cSjoerg * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc. 5774eb1a3Sthorpej * All rights reserved. 6774eb1a3Sthorpej * 7774eb1a3Sthorpej * This code is derived from software contributed to The NetBSD Foundation 8774eb1a3Sthorpej * by Jason R. Thorpe. 9774eb1a3Sthorpej * 10774eb1a3Sthorpej * Redistribution and use in source and binary forms, with or without 11774eb1a3Sthorpej * modification, are permitted provided that the following conditions 12774eb1a3Sthorpej * are met: 13774eb1a3Sthorpej * 1. Redistributions of source code must retain the above copyright 14774eb1a3Sthorpej * notice, this list of conditions and the following disclaimer. 15774eb1a3Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 16774eb1a3Sthorpej * notice, this list of conditions and the following disclaimer in the 17774eb1a3Sthorpej * documentation and/or other materials provided with the distribution. 18774eb1a3Sthorpej * 19774eb1a3Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20774eb1a3Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21774eb1a3Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22774eb1a3Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23774eb1a3Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24774eb1a3Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25774eb1a3Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26774eb1a3Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27774eb1a3Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28774eb1a3Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29774eb1a3Sthorpej * POSSIBILITY OF SUCH DAMAGE. 30774eb1a3Sthorpej */ 31774eb1a3Sthorpej 32774eb1a3Sthorpej #include <prop/prop_array.h> 33774eb1a3Sthorpej #include "prop_object_impl.h" 34774eb1a3Sthorpej 35d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE) 36d21620b2Sthorpej #include <errno.h> 37d21620b2Sthorpej #endif 38d21620b2Sthorpej 39774eb1a3Sthorpej struct _prop_array { 40774eb1a3Sthorpej struct _prop_object pa_obj; 41eb2acb85Sthorpej _PROP_RWLOCK_DECL(pa_rwlock) 42774eb1a3Sthorpej prop_object_t * pa_array; 43774eb1a3Sthorpej unsigned int pa_capacity; 44774eb1a3Sthorpej unsigned int pa_count; 45774eb1a3Sthorpej int pa_flags; 46774eb1a3Sthorpej 47774eb1a3Sthorpej uint32_t pa_version; 48774eb1a3Sthorpej }; 49774eb1a3Sthorpej 50774eb1a3Sthorpej #define PA_F_IMMUTABLE 0x01 /* array is immutable */ 51774eb1a3Sthorpej 52774eb1a3Sthorpej _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay") 53774eb1a3Sthorpej _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array", 54774eb1a3Sthorpej "property array container object") 55774eb1a3Sthorpej 564ce0dc3aSthorpej static _prop_object_free_rv_t 574ce0dc3aSthorpej _prop_array_free(prop_stack_t, prop_object_t *); 58e835604cSjoerg static void _prop_array_emergency_free(prop_object_t); 5904377267Sthorpej static bool _prop_array_externalize( 603e69f1b2Sthorpej struct _prop_object_externalize_context *, 613e69f1b2Sthorpej void *); 624ce0dc3aSthorpej static _prop_object_equals_rv_t 634ce0dc3aSthorpej _prop_array_equals(prop_object_t, prop_object_t, 644deb5931Sjoerg void **, void **, 654deb5931Sjoerg prop_object_t *, prop_object_t *); 664deb5931Sjoerg static void _prop_array_equals_finish(prop_object_t, prop_object_t); 674ce0dc3aSthorpej static prop_object_iterator_t 684ce0dc3aSthorpej _prop_array_iterator_locked(prop_array_t); 694ce0dc3aSthorpej static prop_object_t 704ce0dc3aSthorpej _prop_array_iterator_next_object_locked(void *); 7175b1a2ecSyamt static void _prop_array_iterator_reset_locked(void *); 723e69f1b2Sthorpej 733e69f1b2Sthorpej static const struct _prop_object_type _prop_object_type_array = { 743e69f1b2Sthorpej .pot_type = PROP_TYPE_ARRAY, 753e69f1b2Sthorpej .pot_free = _prop_array_free, 76e835604cSjoerg .pot_emergency_free = _prop_array_emergency_free, 773e69f1b2Sthorpej .pot_extern = _prop_array_externalize, 783e69f1b2Sthorpej .pot_equals = _prop_array_equals, 794deb5931Sjoerg .pot_equals_finish = _prop_array_equals_finish, 803e69f1b2Sthorpej }; 813e69f1b2Sthorpej 823e69f1b2Sthorpej #define prop_object_is_array(x) \ 83beabdd9bSthorpej ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array) 84774eb1a3Sthorpej 85774eb1a3Sthorpej #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0) 86774eb1a3Sthorpej 87774eb1a3Sthorpej struct _prop_array_iterator { 88774eb1a3Sthorpej struct _prop_object_iterator pai_base; 89774eb1a3Sthorpej unsigned int pai_index; 90774eb1a3Sthorpej }; 91774eb1a3Sthorpej 92774eb1a3Sthorpej #define EXPAND_STEP 16 93774eb1a3Sthorpej 944ce0dc3aSthorpej static _prop_object_free_rv_t 95e835604cSjoerg _prop_array_free(prop_stack_t stack, prop_object_t *obj) 96774eb1a3Sthorpej { 97e835604cSjoerg prop_array_t pa = *obj; 98774eb1a3Sthorpej prop_object_t po; 99774eb1a3Sthorpej 100774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 101774eb1a3Sthorpej _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) || 102774eb1a3Sthorpej (pa->pa_capacity != 0 && pa->pa_array != NULL)); 103774eb1a3Sthorpej 104e835604cSjoerg /* The easy case is an empty array, just free and return. */ 105e835604cSjoerg if (pa->pa_count == 0) { 106774eb1a3Sthorpej if (pa->pa_array != NULL) 107774eb1a3Sthorpej _PROP_FREE(pa->pa_array, M_PROP_ARRAY); 108774eb1a3Sthorpej 109eb2acb85Sthorpej _PROP_RWLOCK_DESTROY(pa->pa_rwlock); 110eb2acb85Sthorpej 111774eb1a3Sthorpej _PROP_POOL_PUT(_prop_array_pool, pa); 112e835604cSjoerg 113e835604cSjoerg return (_PROP_OBJECT_FREE_DONE); 114e835604cSjoerg } 115e835604cSjoerg 116e835604cSjoerg po = pa->pa_array[pa->pa_count - 1]; 117e835604cSjoerg _PROP_ASSERT(po != NULL); 118e835604cSjoerg 119e835604cSjoerg if (stack == NULL) { 120e835604cSjoerg /* 121e835604cSjoerg * If we are in emergency release mode, 122e835604cSjoerg * just let caller recurse down. 123e835604cSjoerg */ 124e835604cSjoerg *obj = po; 125e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED); 126e835604cSjoerg } 127e835604cSjoerg 128e835604cSjoerg /* Otherwise, try to push the current object on the stack. */ 1294deb5931Sjoerg if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) { 130e835604cSjoerg /* Push failed, entering emergency release mode. */ 131e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED); 132e835604cSjoerg } 133e835604cSjoerg /* Object pushed on stack, caller will release it. */ 134e835604cSjoerg --pa->pa_count; 135e835604cSjoerg *obj = po; 136e835604cSjoerg return (_PROP_OBJECT_FREE_RECURSE); 137e835604cSjoerg } 138e835604cSjoerg 139e835604cSjoerg static void 140e835604cSjoerg _prop_array_emergency_free(prop_object_t obj) 141e835604cSjoerg { 142e835604cSjoerg prop_array_t pa = obj; 143e835604cSjoerg 144e835604cSjoerg _PROP_ASSERT(pa->pa_count != 0); 145e835604cSjoerg --pa->pa_count; 146774eb1a3Sthorpej } 147774eb1a3Sthorpej 14804377267Sthorpej static bool 149774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx, 150774eb1a3Sthorpej void *v) 151774eb1a3Sthorpej { 152774eb1a3Sthorpej prop_array_t pa = v; 153774eb1a3Sthorpej struct _prop_object *po; 154774eb1a3Sthorpej prop_object_iterator_t pi; 155774eb1a3Sthorpej unsigned int i; 15604377267Sthorpej bool rv = false; 157774eb1a3Sthorpej 158eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 159eb2acb85Sthorpej 160eb2acb85Sthorpej if (pa->pa_count == 0) { 161eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 162774eb1a3Sthorpej return (_prop_object_externalize_empty_tag(ctx, "array")); 163eb2acb85Sthorpej } 164774eb1a3Sthorpej 165774eb1a3Sthorpej /* XXXJRT Hint "count" for the internalize step? */ 16604377267Sthorpej if (_prop_object_externalize_start_tag(ctx, "array") == false || 16704377267Sthorpej _prop_object_externalize_append_char(ctx, '\n') == false) 168eb2acb85Sthorpej goto out; 169774eb1a3Sthorpej 17075b1a2ecSyamt pi = _prop_array_iterator_locked(pa); 171774eb1a3Sthorpej if (pi == NULL) 172eb2acb85Sthorpej goto out; 173774eb1a3Sthorpej 174774eb1a3Sthorpej ctx->poec_depth++; 175774eb1a3Sthorpej _PROP_ASSERT(ctx->poec_depth != 0); 176774eb1a3Sthorpej 17775b1a2ecSyamt while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) { 17804377267Sthorpej if ((*po->po_type->pot_extern)(ctx, po) == false) { 179774eb1a3Sthorpej prop_object_iterator_release(pi); 180eb2acb85Sthorpej goto out; 181774eb1a3Sthorpej } 182774eb1a3Sthorpej } 183774eb1a3Sthorpej 184774eb1a3Sthorpej prop_object_iterator_release(pi); 185774eb1a3Sthorpej 186774eb1a3Sthorpej ctx->poec_depth--; 187774eb1a3Sthorpej for (i = 0; i < ctx->poec_depth; i++) { 18804377267Sthorpej if (_prop_object_externalize_append_char(ctx, '\t') == false) 189eb2acb85Sthorpej goto out; 190774eb1a3Sthorpej } 19104377267Sthorpej if (_prop_object_externalize_end_tag(ctx, "array") == false) 192eb2acb85Sthorpej goto out; 193774eb1a3Sthorpej 19404377267Sthorpej rv = true; 195eb2acb85Sthorpej 196eb2acb85Sthorpej out: 197eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 198eb2acb85Sthorpej return (rv); 199774eb1a3Sthorpej } 200774eb1a3Sthorpej 2014deb5931Sjoerg /* ARGSUSED */ 2024ce0dc3aSthorpej static _prop_object_equals_rv_t 2034deb5931Sjoerg _prop_array_equals(prop_object_t v1, prop_object_t v2, 2044deb5931Sjoerg void **stored_pointer1, void **stored_pointer2, 2054deb5931Sjoerg prop_object_t *next_obj1, prop_object_t *next_obj2) 2063e69f1b2Sthorpej { 2073e69f1b2Sthorpej prop_array_t array1 = v1; 2083e69f1b2Sthorpej prop_array_t array2 = v2; 2094deb5931Sjoerg uintptr_t idx; 2104ce0dc3aSthorpej _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE; 2113e69f1b2Sthorpej 2123e69f1b2Sthorpej if (array1 == array2) 2134deb5931Sjoerg return (_PROP_OBJECT_EQUALS_TRUE); 214eb2acb85Sthorpej 2154deb5931Sjoerg _PROP_ASSERT(*stored_pointer1 == *stored_pointer2); 2164deb5931Sjoerg idx = (uintptr_t)*stored_pointer1; 2174deb5931Sjoerg 2184deb5931Sjoerg /* For the first iteration, lock the objects. */ 2194deb5931Sjoerg if (idx == 0) { 220eb2acb85Sthorpej if ((uintptr_t)array1 < (uintptr_t)array2) { 221eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 222eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 223eb2acb85Sthorpej } else { 224eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 225eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 226eb2acb85Sthorpej } 2274deb5931Sjoerg } 228eb2acb85Sthorpej 2293e69f1b2Sthorpej if (array1->pa_count != array2->pa_count) 230eb2acb85Sthorpej goto out; 2314deb5931Sjoerg if (idx == array1->pa_count) { 2324ce0dc3aSthorpej rv = _PROP_OBJECT_EQUALS_TRUE; 233eb2acb85Sthorpej goto out; 2343e69f1b2Sthorpej } 2354deb5931Sjoerg _PROP_ASSERT(idx < array1->pa_count); 2363e69f1b2Sthorpej 2374deb5931Sjoerg *stored_pointer1 = (void *)(idx + 1); 2384deb5931Sjoerg *stored_pointer2 = (void *)(idx + 1); 2394deb5931Sjoerg 2404deb5931Sjoerg *next_obj1 = array1->pa_array[idx]; 2414deb5931Sjoerg *next_obj2 = array2->pa_array[idx]; 2424deb5931Sjoerg 2434deb5931Sjoerg return (_PROP_OBJECT_EQUALS_RECURSE); 244eb2acb85Sthorpej 245eb2acb85Sthorpej out: 246eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array1->pa_rwlock); 247eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array2->pa_rwlock); 248eb2acb85Sthorpej return (rv); 2493e69f1b2Sthorpej } 2503e69f1b2Sthorpej 2514deb5931Sjoerg static void 2524deb5931Sjoerg _prop_array_equals_finish(prop_object_t v1, prop_object_t v2) 2534deb5931Sjoerg { 2544deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock); 2554deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock); 2564deb5931Sjoerg } 2574deb5931Sjoerg 258774eb1a3Sthorpej static prop_array_t 259774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity) 260774eb1a3Sthorpej { 261774eb1a3Sthorpej prop_array_t pa; 262774eb1a3Sthorpej prop_object_t *array; 263774eb1a3Sthorpej 264774eb1a3Sthorpej if (capacity != 0) { 265774eb1a3Sthorpej array = _PROP_CALLOC(capacity * sizeof(prop_object_t), 266774eb1a3Sthorpej M_PROP_ARRAY); 267774eb1a3Sthorpej if (array == NULL) 268774eb1a3Sthorpej return (NULL); 269774eb1a3Sthorpej } else 270774eb1a3Sthorpej array = NULL; 271774eb1a3Sthorpej 272774eb1a3Sthorpej pa = _PROP_POOL_GET(_prop_array_pool); 273774eb1a3Sthorpej if (pa != NULL) { 2743e69f1b2Sthorpej _prop_object_init(&pa->pa_obj, &_prop_object_type_array); 2753e69f1b2Sthorpej pa->pa_obj.po_type = &_prop_object_type_array; 276774eb1a3Sthorpej 277eb2acb85Sthorpej _PROP_RWLOCK_INIT(pa->pa_rwlock); 278774eb1a3Sthorpej pa->pa_array = array; 279774eb1a3Sthorpej pa->pa_capacity = capacity; 280774eb1a3Sthorpej pa->pa_count = 0; 281774eb1a3Sthorpej pa->pa_flags = 0; 282774eb1a3Sthorpej 283774eb1a3Sthorpej pa->pa_version = 0; 284774eb1a3Sthorpej } else if (array != NULL) 285774eb1a3Sthorpej _PROP_FREE(array, M_PROP_ARRAY); 286774eb1a3Sthorpej 287774eb1a3Sthorpej return (pa); 288774eb1a3Sthorpej } 289774eb1a3Sthorpej 29004377267Sthorpej static bool 291774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity) 292774eb1a3Sthorpej { 293774eb1a3Sthorpej prop_object_t *array, *oarray; 294774eb1a3Sthorpej 295eb2acb85Sthorpej /* 296eb2acb85Sthorpej * Array must be WRITE-LOCKED. 297eb2acb85Sthorpej */ 298eb2acb85Sthorpej 299774eb1a3Sthorpej oarray = pa->pa_array; 300774eb1a3Sthorpej 30142e8dee3Sthorpej array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY); 302774eb1a3Sthorpej if (array == NULL) 30304377267Sthorpej return (false); 304774eb1a3Sthorpej if (oarray != NULL) 30542e8dee3Sthorpej memcpy(array, oarray, pa->pa_capacity * sizeof(*array)); 306774eb1a3Sthorpej pa->pa_array = array; 307774eb1a3Sthorpej pa->pa_capacity = capacity; 308774eb1a3Sthorpej 309774eb1a3Sthorpej if (oarray != NULL) 310774eb1a3Sthorpej _PROP_FREE(oarray, M_PROP_ARRAY); 311774eb1a3Sthorpej 31204377267Sthorpej return (true); 313774eb1a3Sthorpej } 314774eb1a3Sthorpej 315774eb1a3Sthorpej static prop_object_t 31675b1a2ecSyamt _prop_array_iterator_next_object_locked(void *v) 317774eb1a3Sthorpej { 318774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 319774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 320eb2acb85Sthorpej prop_object_t po = NULL; 321774eb1a3Sthorpej 322774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 3236787eedeSyamt 324774eb1a3Sthorpej if (pa->pa_version != pai->pai_base.pi_version) 325eb2acb85Sthorpej goto out; /* array changed during iteration */ 326774eb1a3Sthorpej 327774eb1a3Sthorpej _PROP_ASSERT(pai->pai_index <= pa->pa_count); 328774eb1a3Sthorpej 329774eb1a3Sthorpej if (pai->pai_index == pa->pa_count) 330eb2acb85Sthorpej goto out; /* we've iterated all objects */ 331774eb1a3Sthorpej 332774eb1a3Sthorpej po = pa->pa_array[pai->pai_index]; 333774eb1a3Sthorpej pai->pai_index++; 334774eb1a3Sthorpej 335eb2acb85Sthorpej out: 33675b1a2ecSyamt return (po); 33775b1a2ecSyamt } 33875b1a2ecSyamt 33975b1a2ecSyamt static prop_object_t 34075b1a2ecSyamt _prop_array_iterator_next_object(void *v) 34175b1a2ecSyamt { 34275b1a2ecSyamt struct _prop_array_iterator *pai = v; 34375b1a2ecSyamt prop_array_t pa __unused = pai->pai_base.pi_obj; 34475b1a2ecSyamt prop_object_t po; 34575b1a2ecSyamt 34675b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa)); 34775b1a2ecSyamt 34875b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 34975b1a2ecSyamt po = _prop_array_iterator_next_object_locked(pai); 350eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 351774eb1a3Sthorpej return (po); 352774eb1a3Sthorpej } 353774eb1a3Sthorpej 354774eb1a3Sthorpej static void 35575b1a2ecSyamt _prop_array_iterator_reset_locked(void *v) 356774eb1a3Sthorpej { 357774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 358774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 359774eb1a3Sthorpej 360774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 3616787eedeSyamt 362774eb1a3Sthorpej pai->pai_index = 0; 363774eb1a3Sthorpej pai->pai_base.pi_version = pa->pa_version; 36475b1a2ecSyamt } 36535fe7cdcSxtraeme 36675b1a2ecSyamt static void 36775b1a2ecSyamt _prop_array_iterator_reset(void *v) 36875b1a2ecSyamt { 36975b1a2ecSyamt struct _prop_array_iterator *pai = v; 37075b1a2ecSyamt prop_array_t pa __unused = pai->pai_base.pi_obj; 37175b1a2ecSyamt 37275b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa)); 37375b1a2ecSyamt 37475b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 37575b1a2ecSyamt _prop_array_iterator_reset_locked(pai); 37635fe7cdcSxtraeme _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 37735fe7cdcSxtraeme } 378774eb1a3Sthorpej 379774eb1a3Sthorpej /* 380774eb1a3Sthorpej * prop_array_create -- 381774eb1a3Sthorpej * Create an empty array. 382774eb1a3Sthorpej */ 383774eb1a3Sthorpej prop_array_t 384774eb1a3Sthorpej prop_array_create(void) 385774eb1a3Sthorpej { 386774eb1a3Sthorpej 387774eb1a3Sthorpej return (_prop_array_alloc(0)); 388774eb1a3Sthorpej } 389774eb1a3Sthorpej 390774eb1a3Sthorpej /* 391774eb1a3Sthorpej * prop_array_create_with_capacity -- 392774eb1a3Sthorpej * Create an array with the capacity to store N objects. 393774eb1a3Sthorpej */ 394774eb1a3Sthorpej prop_array_t 395774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity) 396774eb1a3Sthorpej { 397774eb1a3Sthorpej 398774eb1a3Sthorpej return (_prop_array_alloc(capacity)); 399774eb1a3Sthorpej } 400774eb1a3Sthorpej 401774eb1a3Sthorpej /* 402774eb1a3Sthorpej * prop_array_copy -- 403774eb1a3Sthorpej * Copy an array. The new array has an initial capacity equal to 404774eb1a3Sthorpej * the number of objects stored in the original array. The new 405774eb1a3Sthorpej * array contains references to the original array's objects, not 406774eb1a3Sthorpej * copies of those objects (i.e. a shallow copy). 407774eb1a3Sthorpej */ 408774eb1a3Sthorpej prop_array_t 409774eb1a3Sthorpej prop_array_copy(prop_array_t opa) 410774eb1a3Sthorpej { 411774eb1a3Sthorpej prop_array_t pa; 412774eb1a3Sthorpej prop_object_t po; 413774eb1a3Sthorpej unsigned int idx; 414774eb1a3Sthorpej 415d21620b2Sthorpej if (! prop_object_is_array(opa)) 416d21620b2Sthorpej return (NULL); 417774eb1a3Sthorpej 418eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(opa->pa_rwlock); 419eb2acb85Sthorpej 420774eb1a3Sthorpej pa = _prop_array_alloc(opa->pa_count); 421774eb1a3Sthorpej if (pa != NULL) { 422774eb1a3Sthorpej for (idx = 0; idx < opa->pa_count; idx++) { 423774eb1a3Sthorpej po = opa->pa_array[idx]; 424774eb1a3Sthorpej prop_object_retain(po); 425774eb1a3Sthorpej pa->pa_array[idx] = po; 426774eb1a3Sthorpej } 427774eb1a3Sthorpej pa->pa_count = opa->pa_count; 428774eb1a3Sthorpej pa->pa_flags = opa->pa_flags; 429774eb1a3Sthorpej } 430eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(opa->pa_rwlock); 431774eb1a3Sthorpej return (pa); 432774eb1a3Sthorpej } 433774eb1a3Sthorpej 434774eb1a3Sthorpej /* 435774eb1a3Sthorpej * prop_array_copy_mutable -- 436774eb1a3Sthorpej * Like prop_array_copy(), but the resulting array is mutable. 437774eb1a3Sthorpej */ 438774eb1a3Sthorpej prop_array_t 439774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa) 440774eb1a3Sthorpej { 441774eb1a3Sthorpej prop_array_t pa; 442774eb1a3Sthorpej 443774eb1a3Sthorpej pa = prop_array_copy(opa); 444774eb1a3Sthorpej if (pa != NULL) 445774eb1a3Sthorpej pa->pa_flags &= ~PA_F_IMMUTABLE; 446774eb1a3Sthorpej 447774eb1a3Sthorpej return (pa); 448774eb1a3Sthorpej } 449774eb1a3Sthorpej 450774eb1a3Sthorpej /* 451774eb1a3Sthorpej * prop_array_capacity -- 452774eb1a3Sthorpej * Return the capacity of the array. 453774eb1a3Sthorpej */ 454774eb1a3Sthorpej unsigned int 455774eb1a3Sthorpej prop_array_capacity(prop_array_t pa) 456774eb1a3Sthorpej { 457eb2acb85Sthorpej unsigned int rv; 458774eb1a3Sthorpej 459d21620b2Sthorpej if (! prop_object_is_array(pa)) 460d21620b2Sthorpej return (0); 461d21620b2Sthorpej 462eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 463eb2acb85Sthorpej rv = pa->pa_capacity; 464eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 465eb2acb85Sthorpej 466eb2acb85Sthorpej return (rv); 467774eb1a3Sthorpej } 468774eb1a3Sthorpej 469774eb1a3Sthorpej /* 470774eb1a3Sthorpej * prop_array_count -- 471774eb1a3Sthorpej * Return the number of objects stored in the array. 472774eb1a3Sthorpej */ 473774eb1a3Sthorpej unsigned int 474774eb1a3Sthorpej prop_array_count(prop_array_t pa) 475774eb1a3Sthorpej { 476eb2acb85Sthorpej unsigned int rv; 477774eb1a3Sthorpej 478d21620b2Sthorpej if (! prop_object_is_array(pa)) 479d21620b2Sthorpej return (0); 480d21620b2Sthorpej 481eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 482eb2acb85Sthorpej rv = pa->pa_count; 483eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 484eb2acb85Sthorpej 485eb2acb85Sthorpej return (rv); 486774eb1a3Sthorpej } 487774eb1a3Sthorpej 488774eb1a3Sthorpej /* 489774eb1a3Sthorpej * prop_array_ensure_capacity -- 490774eb1a3Sthorpej * Ensure that the array has the capacity to store the specified 491774eb1a3Sthorpej * total number of objects (inluding the objects already stored 492774eb1a3Sthorpej * in the array). 493774eb1a3Sthorpej */ 49404377267Sthorpej bool 495774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity) 496774eb1a3Sthorpej { 49704377267Sthorpej bool rv; 498774eb1a3Sthorpej 499d21620b2Sthorpej if (! prop_object_is_array(pa)) 50004377267Sthorpej return (false); 501d21620b2Sthorpej 502eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 503774eb1a3Sthorpej if (capacity > pa->pa_capacity) 504eb2acb85Sthorpej rv = _prop_array_expand(pa, capacity); 505eb2acb85Sthorpej else 50604377267Sthorpej rv = true; 507eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 508eb2acb85Sthorpej 509eb2acb85Sthorpej return (rv); 510774eb1a3Sthorpej } 511774eb1a3Sthorpej 51275b1a2ecSyamt static prop_object_iterator_t 51375b1a2ecSyamt _prop_array_iterator_locked(prop_array_t pa) 514774eb1a3Sthorpej { 515774eb1a3Sthorpej struct _prop_array_iterator *pai; 516774eb1a3Sthorpej 517d21620b2Sthorpej if (! prop_object_is_array(pa)) 518d21620b2Sthorpej return (NULL); 519774eb1a3Sthorpej 520774eb1a3Sthorpej pai = _PROP_CALLOC(sizeof(*pai), M_TEMP); 521774eb1a3Sthorpej if (pai == NULL) 522774eb1a3Sthorpej return (NULL); 523774eb1a3Sthorpej pai->pai_base.pi_next_object = _prop_array_iterator_next_object; 524774eb1a3Sthorpej pai->pai_base.pi_reset = _prop_array_iterator_reset; 525774eb1a3Sthorpej prop_object_retain(pa); 526774eb1a3Sthorpej pai->pai_base.pi_obj = pa; 52775b1a2ecSyamt _prop_array_iterator_reset_locked(pai); 528774eb1a3Sthorpej 529774eb1a3Sthorpej return (&pai->pai_base); 530774eb1a3Sthorpej } 531774eb1a3Sthorpej 532774eb1a3Sthorpej /* 53375b1a2ecSyamt * prop_array_iterator -- 53475b1a2ecSyamt * Return an iterator for the array. The array is retained by 53575b1a2ecSyamt * the iterator. 53675b1a2ecSyamt */ 53775b1a2ecSyamt prop_object_iterator_t 53875b1a2ecSyamt prop_array_iterator(prop_array_t pa) 53975b1a2ecSyamt { 54075b1a2ecSyamt prop_object_iterator_t pi; 54175b1a2ecSyamt 54275b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 54375b1a2ecSyamt pi = _prop_array_iterator_locked(pa); 54475b1a2ecSyamt _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 54575b1a2ecSyamt return (pi); 54675b1a2ecSyamt } 54775b1a2ecSyamt 54875b1a2ecSyamt /* 549774eb1a3Sthorpej * prop_array_make_immutable -- 550774eb1a3Sthorpej * Make the array immutable. 551774eb1a3Sthorpej */ 552774eb1a3Sthorpej void 553774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa) 554774eb1a3Sthorpej { 555774eb1a3Sthorpej 556eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 55704377267Sthorpej if (prop_array_is_immutable(pa) == false) 558774eb1a3Sthorpej pa->pa_flags |= PA_F_IMMUTABLE; 559eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 560774eb1a3Sthorpej } 561774eb1a3Sthorpej 562774eb1a3Sthorpej /* 563774eb1a3Sthorpej * prop_array_mutable -- 56404377267Sthorpej * Returns true if the array is mutable. 565774eb1a3Sthorpej */ 56604377267Sthorpej bool 567774eb1a3Sthorpej prop_array_mutable(prop_array_t pa) 568774eb1a3Sthorpej { 56904377267Sthorpej bool rv; 570774eb1a3Sthorpej 571eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 57204377267Sthorpej rv = prop_array_is_immutable(pa) == false; 573eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 574eb2acb85Sthorpej 575eb2acb85Sthorpej return (rv); 576774eb1a3Sthorpej } 577774eb1a3Sthorpej 578774eb1a3Sthorpej /* 579774eb1a3Sthorpej * prop_array_get -- 580774eb1a3Sthorpej * Return the object stored at the specified array index. 581774eb1a3Sthorpej */ 582774eb1a3Sthorpej prop_object_t 583774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx) 584774eb1a3Sthorpej { 585eb2acb85Sthorpej prop_object_t po = NULL; 586774eb1a3Sthorpej 587d21620b2Sthorpej if (! prop_object_is_array(pa)) 588d21620b2Sthorpej return (NULL); 589d21620b2Sthorpej 590eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 591774eb1a3Sthorpej if (idx >= pa->pa_count) 592eb2acb85Sthorpej goto out; 593774eb1a3Sthorpej po = pa->pa_array[idx]; 594774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 595eb2acb85Sthorpej out: 596eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 597774eb1a3Sthorpej return (po); 598774eb1a3Sthorpej } 599774eb1a3Sthorpej 60004377267Sthorpej static bool 601eb2acb85Sthorpej _prop_array_add(prop_array_t pa, prop_object_t po) 602774eb1a3Sthorpej { 603774eb1a3Sthorpej 604eb2acb85Sthorpej /* 605eb2acb85Sthorpej * Array must be WRITE-LOCKED. 606eb2acb85Sthorpej */ 607d21620b2Sthorpej 608774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 609774eb1a3Sthorpej 610774eb1a3Sthorpej if (prop_array_is_immutable(pa) || 611774eb1a3Sthorpej (pa->pa_count == pa->pa_capacity && 61204377267Sthorpej _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false)) 61304377267Sthorpej return (false); 614774eb1a3Sthorpej 615774eb1a3Sthorpej prop_object_retain(po); 616774eb1a3Sthorpej pa->pa_array[pa->pa_count++] = po; 617774eb1a3Sthorpej pa->pa_version++; 618774eb1a3Sthorpej 61904377267Sthorpej return (true); 620774eb1a3Sthorpej } 621774eb1a3Sthorpej 622774eb1a3Sthorpej /* 623eb2acb85Sthorpej * prop_array_set -- 624eb2acb85Sthorpej * Store a reference to an object at the specified array index. 625eb2acb85Sthorpej * This method is not allowed to create holes in the array; the 626eb2acb85Sthorpej * caller must either be setting the object just beyond the existing 627eb2acb85Sthorpej * count or replacing an already existing object reference. 628eb2acb85Sthorpej */ 62904377267Sthorpej bool 630eb2acb85Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po) 631eb2acb85Sthorpej { 632eb2acb85Sthorpej prop_object_t opo; 63304377267Sthorpej bool rv = false; 634eb2acb85Sthorpej 635eb2acb85Sthorpej if (! prop_object_is_array(pa)) 63604377267Sthorpej return (false); 637eb2acb85Sthorpej 638eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 639eb2acb85Sthorpej 640eb2acb85Sthorpej if (prop_array_is_immutable(pa)) 641eb2acb85Sthorpej goto out; 642eb2acb85Sthorpej 643eb2acb85Sthorpej if (idx == pa->pa_count) { 644eb2acb85Sthorpej rv = _prop_array_add(pa, po); 645eb2acb85Sthorpej goto out; 646eb2acb85Sthorpej } 647eb2acb85Sthorpej 648eb2acb85Sthorpej _PROP_ASSERT(idx < pa->pa_count); 649eb2acb85Sthorpej 650eb2acb85Sthorpej opo = pa->pa_array[idx]; 651eb2acb85Sthorpej _PROP_ASSERT(opo != NULL); 652eb2acb85Sthorpej 653eb2acb85Sthorpej prop_object_retain(po); 654eb2acb85Sthorpej pa->pa_array[idx] = po; 655eb2acb85Sthorpej pa->pa_version++; 656eb2acb85Sthorpej 657eb2acb85Sthorpej prop_object_release(opo); 658eb2acb85Sthorpej 65904377267Sthorpej rv = true; 660eb2acb85Sthorpej 661eb2acb85Sthorpej out: 662eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 663eb2acb85Sthorpej return (rv); 664eb2acb85Sthorpej } 665eb2acb85Sthorpej 666eb2acb85Sthorpej /* 667eb2acb85Sthorpej * prop_array_add -- 668*ecd6bc70Schristos * Add a reference to an object to the specified array, appending 669eb2acb85Sthorpej * to the end and growing the array's capacity, if necessary. 670eb2acb85Sthorpej */ 67104377267Sthorpej bool 672eb2acb85Sthorpej prop_array_add(prop_array_t pa, prop_object_t po) 673eb2acb85Sthorpej { 67404377267Sthorpej bool rv; 675eb2acb85Sthorpej 676eb2acb85Sthorpej if (! prop_object_is_array(pa)) 67704377267Sthorpej return (false); 678eb2acb85Sthorpej 679eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 680eb2acb85Sthorpej rv = _prop_array_add(pa, po); 681eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 682eb2acb85Sthorpej 683eb2acb85Sthorpej return (rv); 684eb2acb85Sthorpej } 685eb2acb85Sthorpej 686eb2acb85Sthorpej /* 687774eb1a3Sthorpej * prop_array_remove -- 688774eb1a3Sthorpej * Remove the reference to an object from an array at the specified 689774eb1a3Sthorpej * index. The array will be compacted following the removal. 690774eb1a3Sthorpej */ 691774eb1a3Sthorpej void 692774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx) 693774eb1a3Sthorpej { 694774eb1a3Sthorpej prop_object_t po; 695774eb1a3Sthorpej 696d21620b2Sthorpej if (! prop_object_is_array(pa)) 697d21620b2Sthorpej return; 698d21620b2Sthorpej 699eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 700eb2acb85Sthorpej 701774eb1a3Sthorpej _PROP_ASSERT(idx < pa->pa_count); 702774eb1a3Sthorpej 703774eb1a3Sthorpej /* XXX Should this be a _PROP_ASSERT()? */ 704eb2acb85Sthorpej if (prop_array_is_immutable(pa)) { 705eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 706774eb1a3Sthorpej return; 707eb2acb85Sthorpej } 708774eb1a3Sthorpej 709774eb1a3Sthorpej po = pa->pa_array[idx]; 710774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 711774eb1a3Sthorpej 712774eb1a3Sthorpej for (++idx; idx < pa->pa_count; idx++) 713774eb1a3Sthorpej pa->pa_array[idx - 1] = pa->pa_array[idx]; 714774eb1a3Sthorpej pa->pa_count--; 715774eb1a3Sthorpej pa->pa_version++; 716774eb1a3Sthorpej 717eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 718eb2acb85Sthorpej 719774eb1a3Sthorpej prop_object_release(po); 720774eb1a3Sthorpej } 721774eb1a3Sthorpej 722774eb1a3Sthorpej /* 7233e69f1b2Sthorpej * prop_array_equals -- 72404377267Sthorpej * Return true if the two arrays are equivalent. Note we do a 7253e69f1b2Sthorpej * by-value comparison of the objects in the array. 7263e69f1b2Sthorpej */ 72704377267Sthorpej bool 7283e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2) 7293e69f1b2Sthorpej { 7304deb5931Sjoerg if (!prop_object_is_array(array1) || !prop_object_is_array(array2)) 7314deb5931Sjoerg return (false); 7323e69f1b2Sthorpej 7334deb5931Sjoerg return (prop_object_equals(array1, array2)); 7343e69f1b2Sthorpej } 7353e69f1b2Sthorpej 7363e69f1b2Sthorpej /* 737d21620b2Sthorpej * prop_array_externalize -- 738d21620b2Sthorpej * Externalize an array, return a NUL-terminated buffer 739d21620b2Sthorpej * containing the XML-style representation. The buffer is allocated 740d21620b2Sthorpej * with the M_TEMP memory type. 741d21620b2Sthorpej */ 742d21620b2Sthorpej char * 743d21620b2Sthorpej prop_array_externalize(prop_array_t pa) 744d21620b2Sthorpej { 745d21620b2Sthorpej struct _prop_object_externalize_context *ctx; 746d21620b2Sthorpej char *cp; 747d21620b2Sthorpej 748d21620b2Sthorpej ctx = _prop_object_externalize_context_alloc(); 749d21620b2Sthorpej if (ctx == NULL) 750d21620b2Sthorpej return (NULL); 751d21620b2Sthorpej 75204377267Sthorpej if (_prop_object_externalize_header(ctx) == false || 75304377267Sthorpej (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false || 75404377267Sthorpej _prop_object_externalize_footer(ctx) == false) { 755d21620b2Sthorpej /* We are responsible for releasing the buffer. */ 756d21620b2Sthorpej _PROP_FREE(ctx->poec_buf, M_TEMP); 757d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 758d21620b2Sthorpej return (NULL); 759d21620b2Sthorpej } 760d21620b2Sthorpej 761d21620b2Sthorpej cp = ctx->poec_buf; 762d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 763d21620b2Sthorpej 764d21620b2Sthorpej return (cp); 765d21620b2Sthorpej } 766d21620b2Sthorpej 767d21620b2Sthorpej /* 768774eb1a3Sthorpej * _prop_array_internalize -- 769774eb1a3Sthorpej * Parse an <array>...</array> and return the object created from the 770774eb1a3Sthorpej * external representation. 771774eb1a3Sthorpej */ 772e835604cSjoerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *, 773e835604cSjoerg struct _prop_object_internalize_context *); 774774eb1a3Sthorpej 775e835604cSjoerg bool 776e835604cSjoerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj, 777e835604cSjoerg struct _prop_object_internalize_context *ctx) 778e835604cSjoerg { 779774eb1a3Sthorpej /* We don't currently understand any attributes. */ 780774eb1a3Sthorpej if (ctx->poic_tagattr != NULL) 781e835604cSjoerg return (true); 782774eb1a3Sthorpej 783e835604cSjoerg *obj = prop_array_create(); 784e835604cSjoerg /* 785e835604cSjoerg * We are done if the create failed or no child elements exist. 786e835604cSjoerg */ 787e835604cSjoerg if (*obj == NULL || ctx->poic_is_empty_element) 788e835604cSjoerg return (true); 789774eb1a3Sthorpej 790e835604cSjoerg /* 791e835604cSjoerg * Opening tag is found, now continue to the first element. 792e835604cSjoerg */ 793e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx)); 794e835604cSjoerg } 795774eb1a3Sthorpej 796e835604cSjoerg static bool 797e835604cSjoerg _prop_array_internalize_continue(prop_stack_t stack, 798e835604cSjoerg prop_object_t *obj, 799e835604cSjoerg struct _prop_object_internalize_context *ctx, 800e835604cSjoerg void *data, prop_object_t child) 801e835604cSjoerg { 802e835604cSjoerg prop_array_t array; 803e835604cSjoerg 804e835604cSjoerg _PROP_ASSERT(data == NULL); 805e835604cSjoerg 806e835604cSjoerg if (child == NULL) 807e835604cSjoerg goto bad; /* Element could not be parsed. */ 808e835604cSjoerg 809e835604cSjoerg array = *obj; 810e835604cSjoerg 811e835604cSjoerg if (prop_array_add(array, child) == false) { 812e835604cSjoerg prop_object_release(child); 813e835604cSjoerg goto bad; 814e835604cSjoerg } 815e835604cSjoerg prop_object_release(child); 816e835604cSjoerg 817e835604cSjoerg /* 818e835604cSjoerg * Current element is processed and added, look for next. 819e835604cSjoerg */ 820e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx)); 821e835604cSjoerg 822e835604cSjoerg bad: 823e835604cSjoerg prop_object_release(*obj); 824e835604cSjoerg *obj = NULL; 825e835604cSjoerg return (true); 826e835604cSjoerg } 827e835604cSjoerg 828e835604cSjoerg static bool 829e835604cSjoerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj, 830e835604cSjoerg struct _prop_object_internalize_context *ctx) 831e835604cSjoerg { 832e835604cSjoerg prop_array_t array = *obj; 833e835604cSjoerg 834e835604cSjoerg _PROP_ASSERT(array != NULL); 835e835604cSjoerg 836774eb1a3Sthorpej /* Fetch the next tag. */ 837774eb1a3Sthorpej if (_prop_object_internalize_find_tag(ctx, NULL, 83804377267Sthorpej _PROP_TAG_TYPE_EITHER) == false) 839774eb1a3Sthorpej goto bad; 840774eb1a3Sthorpej 841774eb1a3Sthorpej /* Check to see if this is the end of the array. */ 842774eb1a3Sthorpej if (_PROP_TAG_MATCH(ctx, "array") && 843e835604cSjoerg ctx->poic_tag_type == _PROP_TAG_TYPE_END) { 844e835604cSjoerg /* It is, so don't iterate any further. */ 845e835604cSjoerg return (true); 846774eb1a3Sthorpej } 847774eb1a3Sthorpej 8484deb5931Sjoerg if (_prop_stack_push(stack, array, 8494deb5931Sjoerg _prop_array_internalize_continue, NULL, NULL)) 850e835604cSjoerg return (false); 851774eb1a3Sthorpej 852774eb1a3Sthorpej bad: 853774eb1a3Sthorpej prop_object_release(array); 854e835604cSjoerg *obj = NULL; 855e835604cSjoerg return (true); 856774eb1a3Sthorpej } 857d21620b2Sthorpej 858d21620b2Sthorpej /* 859d21620b2Sthorpej * prop_array_internalize -- 860d21620b2Sthorpej * Create an array by parsing the XML-style representation. 861d21620b2Sthorpej */ 862d21620b2Sthorpej prop_array_t 863d21620b2Sthorpej prop_array_internalize(const char *xml) 864d21620b2Sthorpej { 86539dccbf2Sjoerg return _prop_generic_internalize(xml, "array"); 866d21620b2Sthorpej } 867d21620b2Sthorpej 868d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE) 869d21620b2Sthorpej /* 870d21620b2Sthorpej * prop_array_externalize_to_file -- 871d21620b2Sthorpej * Externalize an array to the specified file. 872d21620b2Sthorpej */ 87304377267Sthorpej bool 874d21620b2Sthorpej prop_array_externalize_to_file(prop_array_t array, const char *fname) 875d21620b2Sthorpej { 876d21620b2Sthorpej char *xml; 87704377267Sthorpej bool rv; 8781a119b51She int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ 879d21620b2Sthorpej 880d21620b2Sthorpej xml = prop_array_externalize(array); 881d21620b2Sthorpej if (xml == NULL) 88204377267Sthorpej return (false); 883d21620b2Sthorpej rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); 88404377267Sthorpej if (rv == false) 885d21620b2Sthorpej save_errno = errno; 886d21620b2Sthorpej _PROP_FREE(xml, M_TEMP); 88704377267Sthorpej if (rv == false) 888d21620b2Sthorpej errno = save_errno; 889d21620b2Sthorpej 890d21620b2Sthorpej return (rv); 891d21620b2Sthorpej } 892d21620b2Sthorpej 893d21620b2Sthorpej /* 894d21620b2Sthorpej * prop_array_internalize_from_file -- 895d21620b2Sthorpej * Internalize an array from a file. 896d21620b2Sthorpej */ 897d21620b2Sthorpej prop_array_t 898d21620b2Sthorpej prop_array_internalize_from_file(const char *fname) 899d21620b2Sthorpej { 900d21620b2Sthorpej struct _prop_object_internalize_mapped_file *mf; 901d21620b2Sthorpej prop_array_t array; 902d21620b2Sthorpej 903d21620b2Sthorpej mf = _prop_object_internalize_map_file(fname); 904d21620b2Sthorpej if (mf == NULL) 905d21620b2Sthorpej return (NULL); 906d21620b2Sthorpej array = prop_array_internalize(mf->poimf_xml); 907d21620b2Sthorpej _prop_object_internalize_unmap_file(mf); 908d21620b2Sthorpej 909d21620b2Sthorpej return (array); 910d21620b2Sthorpej } 911d21620b2Sthorpej #endif /* _KERNEL && !_STANDALONE */ 912