1*75b1a2ecSyamt /* $NetBSD: prop_array.c,v 1.18 2008/05/24 14:32:48 yamt 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 56e835604cSjoerg static int _prop_array_free(prop_stack_t, prop_object_t *); 57e835604cSjoerg static void _prop_array_emergency_free(prop_object_t); 5804377267Sthorpej static bool _prop_array_externalize( 593e69f1b2Sthorpej struct _prop_object_externalize_context *, 603e69f1b2Sthorpej void *); 614deb5931Sjoerg static bool _prop_array_equals(prop_object_t, prop_object_t, 624deb5931Sjoerg void **, void **, 634deb5931Sjoerg prop_object_t *, prop_object_t *); 644deb5931Sjoerg static void _prop_array_equals_finish(prop_object_t, prop_object_t); 65*75b1a2ecSyamt static prop_object_iterator_t _prop_array_iterator_locked(prop_array_t); 66*75b1a2ecSyamt static prop_object_t _prop_array_iterator_next_object_locked(void *); 67*75b1a2ecSyamt static void _prop_array_iterator_reset_locked(void *); 683e69f1b2Sthorpej 693e69f1b2Sthorpej static const struct _prop_object_type _prop_object_type_array = { 703e69f1b2Sthorpej .pot_type = PROP_TYPE_ARRAY, 713e69f1b2Sthorpej .pot_free = _prop_array_free, 72e835604cSjoerg .pot_emergency_free = _prop_array_emergency_free, 733e69f1b2Sthorpej .pot_extern = _prop_array_externalize, 743e69f1b2Sthorpej .pot_equals = _prop_array_equals, 754deb5931Sjoerg .pot_equals_finish = _prop_array_equals_finish, 763e69f1b2Sthorpej }; 773e69f1b2Sthorpej 783e69f1b2Sthorpej #define prop_object_is_array(x) \ 79beabdd9bSthorpej ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array) 80774eb1a3Sthorpej 81774eb1a3Sthorpej #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0) 82774eb1a3Sthorpej 83774eb1a3Sthorpej struct _prop_array_iterator { 84774eb1a3Sthorpej struct _prop_object_iterator pai_base; 85774eb1a3Sthorpej unsigned int pai_index; 86774eb1a3Sthorpej }; 87774eb1a3Sthorpej 88774eb1a3Sthorpej #define EXPAND_STEP 16 89774eb1a3Sthorpej 90e835604cSjoerg static int 91e835604cSjoerg _prop_array_free(prop_stack_t stack, prop_object_t *obj) 92774eb1a3Sthorpej { 93e835604cSjoerg prop_array_t pa = *obj; 94774eb1a3Sthorpej prop_object_t po; 95774eb1a3Sthorpej 96774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 97774eb1a3Sthorpej _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) || 98774eb1a3Sthorpej (pa->pa_capacity != 0 && pa->pa_array != NULL)); 99774eb1a3Sthorpej 100e835604cSjoerg /* The easy case is an empty array, just free and return. */ 101e835604cSjoerg if (pa->pa_count == 0) { 102774eb1a3Sthorpej if (pa->pa_array != NULL) 103774eb1a3Sthorpej _PROP_FREE(pa->pa_array, M_PROP_ARRAY); 104774eb1a3Sthorpej 105eb2acb85Sthorpej _PROP_RWLOCK_DESTROY(pa->pa_rwlock); 106eb2acb85Sthorpej 107774eb1a3Sthorpej _PROP_POOL_PUT(_prop_array_pool, pa); 108e835604cSjoerg 109e835604cSjoerg return (_PROP_OBJECT_FREE_DONE); 110e835604cSjoerg } 111e835604cSjoerg 112e835604cSjoerg po = pa->pa_array[pa->pa_count - 1]; 113e835604cSjoerg _PROP_ASSERT(po != NULL); 114e835604cSjoerg 115e835604cSjoerg if (stack == NULL) { 116e835604cSjoerg /* 117e835604cSjoerg * If we are in emergency release mode, 118e835604cSjoerg * just let caller recurse down. 119e835604cSjoerg */ 120e835604cSjoerg *obj = po; 121e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED); 122e835604cSjoerg } 123e835604cSjoerg 124e835604cSjoerg /* Otherwise, try to push the current object on the stack. */ 1254deb5931Sjoerg if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) { 126e835604cSjoerg /* Push failed, entering emergency release mode. */ 127e835604cSjoerg return (_PROP_OBJECT_FREE_FAILED); 128e835604cSjoerg } 129e835604cSjoerg /* Object pushed on stack, caller will release it. */ 130e835604cSjoerg --pa->pa_count; 131e835604cSjoerg *obj = po; 132e835604cSjoerg return (_PROP_OBJECT_FREE_RECURSE); 133e835604cSjoerg } 134e835604cSjoerg 135e835604cSjoerg static void 136e835604cSjoerg _prop_array_emergency_free(prop_object_t obj) 137e835604cSjoerg { 138e835604cSjoerg prop_array_t pa = obj; 139e835604cSjoerg 140e835604cSjoerg _PROP_ASSERT(pa->pa_count != 0); 141e835604cSjoerg --pa->pa_count; 142774eb1a3Sthorpej } 143774eb1a3Sthorpej 14404377267Sthorpej static bool 145774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx, 146774eb1a3Sthorpej void *v) 147774eb1a3Sthorpej { 148774eb1a3Sthorpej prop_array_t pa = v; 149774eb1a3Sthorpej struct _prop_object *po; 150774eb1a3Sthorpej prop_object_iterator_t pi; 151774eb1a3Sthorpej unsigned int i; 15204377267Sthorpej bool rv = false; 153774eb1a3Sthorpej 154eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 155eb2acb85Sthorpej 156eb2acb85Sthorpej if (pa->pa_count == 0) { 157eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 158774eb1a3Sthorpej return (_prop_object_externalize_empty_tag(ctx, "array")); 159eb2acb85Sthorpej } 160774eb1a3Sthorpej 161774eb1a3Sthorpej /* XXXJRT Hint "count" for the internalize step? */ 16204377267Sthorpej if (_prop_object_externalize_start_tag(ctx, "array") == false || 16304377267Sthorpej _prop_object_externalize_append_char(ctx, '\n') == false) 164eb2acb85Sthorpej goto out; 165774eb1a3Sthorpej 166*75b1a2ecSyamt pi = _prop_array_iterator_locked(pa); 167774eb1a3Sthorpej if (pi == NULL) 168eb2acb85Sthorpej goto out; 169774eb1a3Sthorpej 170774eb1a3Sthorpej ctx->poec_depth++; 171774eb1a3Sthorpej _PROP_ASSERT(ctx->poec_depth != 0); 172774eb1a3Sthorpej 173*75b1a2ecSyamt while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) { 17404377267Sthorpej if ((*po->po_type->pot_extern)(ctx, po) == false) { 175774eb1a3Sthorpej prop_object_iterator_release(pi); 176eb2acb85Sthorpej goto out; 177774eb1a3Sthorpej } 178774eb1a3Sthorpej } 179774eb1a3Sthorpej 180774eb1a3Sthorpej prop_object_iterator_release(pi); 181774eb1a3Sthorpej 182774eb1a3Sthorpej ctx->poec_depth--; 183774eb1a3Sthorpej for (i = 0; i < ctx->poec_depth; i++) { 18404377267Sthorpej if (_prop_object_externalize_append_char(ctx, '\t') == false) 185eb2acb85Sthorpej goto out; 186774eb1a3Sthorpej } 18704377267Sthorpej if (_prop_object_externalize_end_tag(ctx, "array") == false) 188eb2acb85Sthorpej goto out; 189774eb1a3Sthorpej 19004377267Sthorpej rv = true; 191eb2acb85Sthorpej 192eb2acb85Sthorpej out: 193eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 194eb2acb85Sthorpej return (rv); 195774eb1a3Sthorpej } 196774eb1a3Sthorpej 1974deb5931Sjoerg /* ARGSUSED */ 19804377267Sthorpej static bool 1994deb5931Sjoerg _prop_array_equals(prop_object_t v1, prop_object_t v2, 2004deb5931Sjoerg void **stored_pointer1, void **stored_pointer2, 2014deb5931Sjoerg prop_object_t *next_obj1, prop_object_t *next_obj2) 2023e69f1b2Sthorpej { 2033e69f1b2Sthorpej prop_array_t array1 = v1; 2043e69f1b2Sthorpej prop_array_t array2 = v2; 2054deb5931Sjoerg uintptr_t idx; 2064deb5931Sjoerg bool rv = _PROP_OBJECT_EQUALS_FALSE; 2073e69f1b2Sthorpej 2083e69f1b2Sthorpej if (array1 == array2) 2094deb5931Sjoerg return (_PROP_OBJECT_EQUALS_TRUE); 210eb2acb85Sthorpej 2114deb5931Sjoerg _PROP_ASSERT(*stored_pointer1 == *stored_pointer2); 2124deb5931Sjoerg idx = (uintptr_t)*stored_pointer1; 2134deb5931Sjoerg 2144deb5931Sjoerg /* For the first iteration, lock the objects. */ 2154deb5931Sjoerg if (idx == 0) { 216eb2acb85Sthorpej if ((uintptr_t)array1 < (uintptr_t)array2) { 217eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 218eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 219eb2acb85Sthorpej } else { 220eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 221eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 222eb2acb85Sthorpej } 2234deb5931Sjoerg } 224eb2acb85Sthorpej 2253e69f1b2Sthorpej if (array1->pa_count != array2->pa_count) 226eb2acb85Sthorpej goto out; 2274deb5931Sjoerg if (idx == array1->pa_count) { 2284deb5931Sjoerg rv = true; 229eb2acb85Sthorpej goto out; 2303e69f1b2Sthorpej } 2314deb5931Sjoerg _PROP_ASSERT(idx < array1->pa_count); 2323e69f1b2Sthorpej 2334deb5931Sjoerg *stored_pointer1 = (void *)(idx + 1); 2344deb5931Sjoerg *stored_pointer2 = (void *)(idx + 1); 2354deb5931Sjoerg 2364deb5931Sjoerg *next_obj1 = array1->pa_array[idx]; 2374deb5931Sjoerg *next_obj2 = array2->pa_array[idx]; 2384deb5931Sjoerg 2394deb5931Sjoerg return (_PROP_OBJECT_EQUALS_RECURSE); 240eb2acb85Sthorpej 241eb2acb85Sthorpej out: 242eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array1->pa_rwlock); 243eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array2->pa_rwlock); 244eb2acb85Sthorpej return (rv); 2453e69f1b2Sthorpej } 2463e69f1b2Sthorpej 2474deb5931Sjoerg static void 2484deb5931Sjoerg _prop_array_equals_finish(prop_object_t v1, prop_object_t v2) 2494deb5931Sjoerg { 2504deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock); 2514deb5931Sjoerg _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock); 2524deb5931Sjoerg } 2534deb5931Sjoerg 254774eb1a3Sthorpej static prop_array_t 255774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity) 256774eb1a3Sthorpej { 257774eb1a3Sthorpej prop_array_t pa; 258774eb1a3Sthorpej prop_object_t *array; 259774eb1a3Sthorpej 260774eb1a3Sthorpej if (capacity != 0) { 261774eb1a3Sthorpej array = _PROP_CALLOC(capacity * sizeof(prop_object_t), 262774eb1a3Sthorpej M_PROP_ARRAY); 263774eb1a3Sthorpej if (array == NULL) 264774eb1a3Sthorpej return (NULL); 265774eb1a3Sthorpej } else 266774eb1a3Sthorpej array = NULL; 267774eb1a3Sthorpej 268774eb1a3Sthorpej 269774eb1a3Sthorpej pa = _PROP_POOL_GET(_prop_array_pool); 270774eb1a3Sthorpej if (pa != NULL) { 2713e69f1b2Sthorpej _prop_object_init(&pa->pa_obj, &_prop_object_type_array); 2723e69f1b2Sthorpej pa->pa_obj.po_type = &_prop_object_type_array; 273774eb1a3Sthorpej 274eb2acb85Sthorpej _PROP_RWLOCK_INIT(pa->pa_rwlock); 275774eb1a3Sthorpej pa->pa_array = array; 276774eb1a3Sthorpej pa->pa_capacity = capacity; 277774eb1a3Sthorpej pa->pa_count = 0; 278774eb1a3Sthorpej pa->pa_flags = 0; 279774eb1a3Sthorpej 280774eb1a3Sthorpej pa->pa_version = 0; 281774eb1a3Sthorpej } else if (array != NULL) 282774eb1a3Sthorpej _PROP_FREE(array, M_PROP_ARRAY); 283774eb1a3Sthorpej 284774eb1a3Sthorpej return (pa); 285774eb1a3Sthorpej } 286774eb1a3Sthorpej 28704377267Sthorpej static bool 288774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity) 289774eb1a3Sthorpej { 290774eb1a3Sthorpej prop_object_t *array, *oarray; 291774eb1a3Sthorpej 292eb2acb85Sthorpej /* 293eb2acb85Sthorpej * Array must be WRITE-LOCKED. 294eb2acb85Sthorpej */ 295eb2acb85Sthorpej 296774eb1a3Sthorpej oarray = pa->pa_array; 297774eb1a3Sthorpej 29842e8dee3Sthorpej array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY); 299774eb1a3Sthorpej if (array == NULL) 30004377267Sthorpej return (false); 301774eb1a3Sthorpej if (oarray != NULL) 30242e8dee3Sthorpej memcpy(array, oarray, pa->pa_capacity * sizeof(*array)); 303774eb1a3Sthorpej pa->pa_array = array; 304774eb1a3Sthorpej pa->pa_capacity = capacity; 305774eb1a3Sthorpej 306774eb1a3Sthorpej if (oarray != NULL) 307774eb1a3Sthorpej _PROP_FREE(oarray, M_PROP_ARRAY); 308774eb1a3Sthorpej 30904377267Sthorpej return (true); 310774eb1a3Sthorpej } 311774eb1a3Sthorpej 312774eb1a3Sthorpej static prop_object_t 313*75b1a2ecSyamt _prop_array_iterator_next_object_locked(void *v) 314774eb1a3Sthorpej { 315774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 316774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 317eb2acb85Sthorpej prop_object_t po = NULL; 318774eb1a3Sthorpej 319774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 3206787eedeSyamt 321774eb1a3Sthorpej if (pa->pa_version != pai->pai_base.pi_version) 322eb2acb85Sthorpej goto out; /* array changed during iteration */ 323774eb1a3Sthorpej 324774eb1a3Sthorpej _PROP_ASSERT(pai->pai_index <= pa->pa_count); 325774eb1a3Sthorpej 326774eb1a3Sthorpej if (pai->pai_index == pa->pa_count) 327eb2acb85Sthorpej goto out; /* we've iterated all objects */ 328774eb1a3Sthorpej 329774eb1a3Sthorpej po = pa->pa_array[pai->pai_index]; 330774eb1a3Sthorpej pai->pai_index++; 331774eb1a3Sthorpej 332eb2acb85Sthorpej out: 333*75b1a2ecSyamt return (po); 334*75b1a2ecSyamt } 335*75b1a2ecSyamt 336*75b1a2ecSyamt static prop_object_t 337*75b1a2ecSyamt _prop_array_iterator_next_object(void *v) 338*75b1a2ecSyamt { 339*75b1a2ecSyamt struct _prop_array_iterator *pai = v; 340*75b1a2ecSyamt prop_array_t pa __unused = pai->pai_base.pi_obj; 341*75b1a2ecSyamt prop_object_t po; 342*75b1a2ecSyamt 343*75b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa)); 344*75b1a2ecSyamt 345*75b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 346*75b1a2ecSyamt po = _prop_array_iterator_next_object_locked(pai); 347eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 348774eb1a3Sthorpej return (po); 349774eb1a3Sthorpej } 350774eb1a3Sthorpej 351774eb1a3Sthorpej static void 352*75b1a2ecSyamt _prop_array_iterator_reset_locked(void *v) 353774eb1a3Sthorpej { 354774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 355774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 356774eb1a3Sthorpej 357774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 3586787eedeSyamt 359774eb1a3Sthorpej pai->pai_index = 0; 360774eb1a3Sthorpej pai->pai_base.pi_version = pa->pa_version; 361*75b1a2ecSyamt } 36235fe7cdcSxtraeme 363*75b1a2ecSyamt static void 364*75b1a2ecSyamt _prop_array_iterator_reset(void *v) 365*75b1a2ecSyamt { 366*75b1a2ecSyamt struct _prop_array_iterator *pai = v; 367*75b1a2ecSyamt prop_array_t pa __unused = pai->pai_base.pi_obj; 368*75b1a2ecSyamt 369*75b1a2ecSyamt _PROP_ASSERT(prop_object_is_array(pa)); 370*75b1a2ecSyamt 371*75b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 372*75b1a2ecSyamt _prop_array_iterator_reset_locked(pai); 37335fe7cdcSxtraeme _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 37435fe7cdcSxtraeme } 375774eb1a3Sthorpej 376774eb1a3Sthorpej /* 377774eb1a3Sthorpej * prop_array_create -- 378774eb1a3Sthorpej * Create an empty array. 379774eb1a3Sthorpej */ 380774eb1a3Sthorpej prop_array_t 381774eb1a3Sthorpej prop_array_create(void) 382774eb1a3Sthorpej { 383774eb1a3Sthorpej 384774eb1a3Sthorpej return (_prop_array_alloc(0)); 385774eb1a3Sthorpej } 386774eb1a3Sthorpej 387774eb1a3Sthorpej /* 388774eb1a3Sthorpej * prop_array_create_with_capacity -- 389774eb1a3Sthorpej * Create an array with the capacity to store N objects. 390774eb1a3Sthorpej */ 391774eb1a3Sthorpej prop_array_t 392774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity) 393774eb1a3Sthorpej { 394774eb1a3Sthorpej 395774eb1a3Sthorpej return (_prop_array_alloc(capacity)); 396774eb1a3Sthorpej } 397774eb1a3Sthorpej 398774eb1a3Sthorpej /* 399774eb1a3Sthorpej * prop_array_copy -- 400774eb1a3Sthorpej * Copy an array. The new array has an initial capacity equal to 401774eb1a3Sthorpej * the number of objects stored in the original array. The new 402774eb1a3Sthorpej * array contains references to the original array's objects, not 403774eb1a3Sthorpej * copies of those objects (i.e. a shallow copy). 404774eb1a3Sthorpej */ 405774eb1a3Sthorpej prop_array_t 406774eb1a3Sthorpej prop_array_copy(prop_array_t opa) 407774eb1a3Sthorpej { 408774eb1a3Sthorpej prop_array_t pa; 409774eb1a3Sthorpej prop_object_t po; 410774eb1a3Sthorpej unsigned int idx; 411774eb1a3Sthorpej 412d21620b2Sthorpej if (! prop_object_is_array(opa)) 413d21620b2Sthorpej return (NULL); 414774eb1a3Sthorpej 415eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(opa->pa_rwlock); 416eb2acb85Sthorpej 417774eb1a3Sthorpej pa = _prop_array_alloc(opa->pa_count); 418774eb1a3Sthorpej if (pa != NULL) { 419774eb1a3Sthorpej for (idx = 0; idx < opa->pa_count; idx++) { 420774eb1a3Sthorpej po = opa->pa_array[idx]; 421774eb1a3Sthorpej prop_object_retain(po); 422774eb1a3Sthorpej pa->pa_array[idx] = po; 423774eb1a3Sthorpej } 424774eb1a3Sthorpej pa->pa_count = opa->pa_count; 425774eb1a3Sthorpej pa->pa_flags = opa->pa_flags; 426774eb1a3Sthorpej } 427eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(opa->pa_rwlock); 428774eb1a3Sthorpej return (pa); 429774eb1a3Sthorpej } 430774eb1a3Sthorpej 431774eb1a3Sthorpej /* 432774eb1a3Sthorpej * prop_array_copy_mutable -- 433774eb1a3Sthorpej * Like prop_array_copy(), but the resulting array is mutable. 434774eb1a3Sthorpej */ 435774eb1a3Sthorpej prop_array_t 436774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa) 437774eb1a3Sthorpej { 438774eb1a3Sthorpej prop_array_t pa; 439774eb1a3Sthorpej 440774eb1a3Sthorpej pa = prop_array_copy(opa); 441774eb1a3Sthorpej if (pa != NULL) 442774eb1a3Sthorpej pa->pa_flags &= ~PA_F_IMMUTABLE; 443774eb1a3Sthorpej 444774eb1a3Sthorpej return (pa); 445774eb1a3Sthorpej } 446774eb1a3Sthorpej 447774eb1a3Sthorpej /* 448774eb1a3Sthorpej * prop_array_capacity -- 449774eb1a3Sthorpej * Return the capacity of the array. 450774eb1a3Sthorpej */ 451774eb1a3Sthorpej unsigned int 452774eb1a3Sthorpej prop_array_capacity(prop_array_t pa) 453774eb1a3Sthorpej { 454eb2acb85Sthorpej unsigned int rv; 455774eb1a3Sthorpej 456d21620b2Sthorpej if (! prop_object_is_array(pa)) 457d21620b2Sthorpej return (0); 458d21620b2Sthorpej 459eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 460eb2acb85Sthorpej rv = pa->pa_capacity; 461eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 462eb2acb85Sthorpej 463eb2acb85Sthorpej return (rv); 464774eb1a3Sthorpej } 465774eb1a3Sthorpej 466774eb1a3Sthorpej /* 467774eb1a3Sthorpej * prop_array_count -- 468774eb1a3Sthorpej * Return the number of objects stored in the array. 469774eb1a3Sthorpej */ 470774eb1a3Sthorpej unsigned int 471774eb1a3Sthorpej prop_array_count(prop_array_t pa) 472774eb1a3Sthorpej { 473eb2acb85Sthorpej unsigned int rv; 474774eb1a3Sthorpej 475d21620b2Sthorpej if (! prop_object_is_array(pa)) 476d21620b2Sthorpej return (0); 477d21620b2Sthorpej 478eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 479eb2acb85Sthorpej rv = pa->pa_count; 480eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 481eb2acb85Sthorpej 482eb2acb85Sthorpej return (rv); 483774eb1a3Sthorpej } 484774eb1a3Sthorpej 485774eb1a3Sthorpej /* 486774eb1a3Sthorpej * prop_array_ensure_capacity -- 487774eb1a3Sthorpej * Ensure that the array has the capacity to store the specified 488774eb1a3Sthorpej * total number of objects (inluding the objects already stored 489774eb1a3Sthorpej * in the array). 490774eb1a3Sthorpej */ 49104377267Sthorpej bool 492774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity) 493774eb1a3Sthorpej { 49404377267Sthorpej bool rv; 495774eb1a3Sthorpej 496d21620b2Sthorpej if (! prop_object_is_array(pa)) 49704377267Sthorpej return (false); 498d21620b2Sthorpej 499eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 500774eb1a3Sthorpej if (capacity > pa->pa_capacity) 501eb2acb85Sthorpej rv = _prop_array_expand(pa, capacity); 502eb2acb85Sthorpej else 50304377267Sthorpej rv = true; 504eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 505eb2acb85Sthorpej 506eb2acb85Sthorpej return (rv); 507774eb1a3Sthorpej } 508774eb1a3Sthorpej 509*75b1a2ecSyamt static prop_object_iterator_t 510*75b1a2ecSyamt _prop_array_iterator_locked(prop_array_t pa) 511774eb1a3Sthorpej { 512774eb1a3Sthorpej struct _prop_array_iterator *pai; 513774eb1a3Sthorpej 514d21620b2Sthorpej if (! prop_object_is_array(pa)) 515d21620b2Sthorpej return (NULL); 516774eb1a3Sthorpej 517774eb1a3Sthorpej pai = _PROP_CALLOC(sizeof(*pai), M_TEMP); 518774eb1a3Sthorpej if (pai == NULL) 519774eb1a3Sthorpej return (NULL); 520774eb1a3Sthorpej pai->pai_base.pi_next_object = _prop_array_iterator_next_object; 521774eb1a3Sthorpej pai->pai_base.pi_reset = _prop_array_iterator_reset; 522774eb1a3Sthorpej prop_object_retain(pa); 523774eb1a3Sthorpej pai->pai_base.pi_obj = pa; 524*75b1a2ecSyamt _prop_array_iterator_reset_locked(pai); 525774eb1a3Sthorpej 526774eb1a3Sthorpej return (&pai->pai_base); 527774eb1a3Sthorpej } 528774eb1a3Sthorpej 529774eb1a3Sthorpej /* 530*75b1a2ecSyamt * prop_array_iterator -- 531*75b1a2ecSyamt * Return an iterator for the array. The array is retained by 532*75b1a2ecSyamt * the iterator. 533*75b1a2ecSyamt */ 534*75b1a2ecSyamt prop_object_iterator_t 535*75b1a2ecSyamt prop_array_iterator(prop_array_t pa) 536*75b1a2ecSyamt { 537*75b1a2ecSyamt prop_object_iterator_t pi; 538*75b1a2ecSyamt 539*75b1a2ecSyamt _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 540*75b1a2ecSyamt pi = _prop_array_iterator_locked(pa); 541*75b1a2ecSyamt _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 542*75b1a2ecSyamt return (pi); 543*75b1a2ecSyamt } 544*75b1a2ecSyamt 545*75b1a2ecSyamt /* 546774eb1a3Sthorpej * prop_array_make_immutable -- 547774eb1a3Sthorpej * Make the array immutable. 548774eb1a3Sthorpej */ 549774eb1a3Sthorpej void 550774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa) 551774eb1a3Sthorpej { 552774eb1a3Sthorpej 553eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 55404377267Sthorpej if (prop_array_is_immutable(pa) == false) 555774eb1a3Sthorpej pa->pa_flags |= PA_F_IMMUTABLE; 556eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 557774eb1a3Sthorpej } 558774eb1a3Sthorpej 559774eb1a3Sthorpej /* 560774eb1a3Sthorpej * prop_array_mutable -- 56104377267Sthorpej * Returns true if the array is mutable. 562774eb1a3Sthorpej */ 56304377267Sthorpej bool 564774eb1a3Sthorpej prop_array_mutable(prop_array_t pa) 565774eb1a3Sthorpej { 56604377267Sthorpej bool rv; 567774eb1a3Sthorpej 568eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 56904377267Sthorpej rv = prop_array_is_immutable(pa) == false; 570eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 571eb2acb85Sthorpej 572eb2acb85Sthorpej return (rv); 573774eb1a3Sthorpej } 574774eb1a3Sthorpej 575774eb1a3Sthorpej /* 576774eb1a3Sthorpej * prop_array_get -- 577774eb1a3Sthorpej * Return the object stored at the specified array index. 578774eb1a3Sthorpej */ 579774eb1a3Sthorpej prop_object_t 580774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx) 581774eb1a3Sthorpej { 582eb2acb85Sthorpej prop_object_t po = NULL; 583774eb1a3Sthorpej 584d21620b2Sthorpej if (! prop_object_is_array(pa)) 585d21620b2Sthorpej return (NULL); 586d21620b2Sthorpej 587eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 588774eb1a3Sthorpej if (idx >= pa->pa_count) 589eb2acb85Sthorpej goto out; 590774eb1a3Sthorpej po = pa->pa_array[idx]; 591774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 592eb2acb85Sthorpej out: 593eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 594774eb1a3Sthorpej return (po); 595774eb1a3Sthorpej } 596774eb1a3Sthorpej 59704377267Sthorpej static bool 598eb2acb85Sthorpej _prop_array_add(prop_array_t pa, prop_object_t po) 599774eb1a3Sthorpej { 600774eb1a3Sthorpej 601eb2acb85Sthorpej /* 602eb2acb85Sthorpej * Array must be WRITE-LOCKED. 603eb2acb85Sthorpej */ 604d21620b2Sthorpej 605774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 606774eb1a3Sthorpej 607774eb1a3Sthorpej if (prop_array_is_immutable(pa) || 608774eb1a3Sthorpej (pa->pa_count == pa->pa_capacity && 60904377267Sthorpej _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false)) 61004377267Sthorpej return (false); 611774eb1a3Sthorpej 612774eb1a3Sthorpej prop_object_retain(po); 613774eb1a3Sthorpej pa->pa_array[pa->pa_count++] = po; 614774eb1a3Sthorpej pa->pa_version++; 615774eb1a3Sthorpej 61604377267Sthorpej return (true); 617774eb1a3Sthorpej } 618774eb1a3Sthorpej 619774eb1a3Sthorpej /* 620eb2acb85Sthorpej * prop_array_set -- 621eb2acb85Sthorpej * Store a reference to an object at the specified array index. 622eb2acb85Sthorpej * This method is not allowed to create holes in the array; the 623eb2acb85Sthorpej * caller must either be setting the object just beyond the existing 624eb2acb85Sthorpej * count or replacing an already existing object reference. 625eb2acb85Sthorpej */ 62604377267Sthorpej bool 627eb2acb85Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po) 628eb2acb85Sthorpej { 629eb2acb85Sthorpej prop_object_t opo; 63004377267Sthorpej bool rv = false; 631eb2acb85Sthorpej 632eb2acb85Sthorpej if (! prop_object_is_array(pa)) 63304377267Sthorpej return (false); 634eb2acb85Sthorpej 635eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 636eb2acb85Sthorpej 637eb2acb85Sthorpej if (prop_array_is_immutable(pa)) 638eb2acb85Sthorpej goto out; 639eb2acb85Sthorpej 640eb2acb85Sthorpej if (idx == pa->pa_count) { 641eb2acb85Sthorpej rv = _prop_array_add(pa, po); 642eb2acb85Sthorpej goto out; 643eb2acb85Sthorpej } 644eb2acb85Sthorpej 645eb2acb85Sthorpej _PROP_ASSERT(idx < pa->pa_count); 646eb2acb85Sthorpej 647eb2acb85Sthorpej opo = pa->pa_array[idx]; 648eb2acb85Sthorpej _PROP_ASSERT(opo != NULL); 649eb2acb85Sthorpej 650eb2acb85Sthorpej prop_object_retain(po); 651eb2acb85Sthorpej pa->pa_array[idx] = po; 652eb2acb85Sthorpej pa->pa_version++; 653eb2acb85Sthorpej 654eb2acb85Sthorpej prop_object_release(opo); 655eb2acb85Sthorpej 65604377267Sthorpej rv = true; 657eb2acb85Sthorpej 658eb2acb85Sthorpej out: 659eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 660eb2acb85Sthorpej return (rv); 661eb2acb85Sthorpej } 662eb2acb85Sthorpej 663eb2acb85Sthorpej /* 664eb2acb85Sthorpej * prop_array_add -- 665eb2acb85Sthorpej * Add a refrerence to an object to the specified array, appending 666eb2acb85Sthorpej * to the end and growing the array's capacity, if necessary. 667eb2acb85Sthorpej */ 66804377267Sthorpej bool 669eb2acb85Sthorpej prop_array_add(prop_array_t pa, prop_object_t po) 670eb2acb85Sthorpej { 67104377267Sthorpej bool rv; 672eb2acb85Sthorpej 673eb2acb85Sthorpej if (! prop_object_is_array(pa)) 67404377267Sthorpej return (false); 675eb2acb85Sthorpej 676eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 677eb2acb85Sthorpej rv = _prop_array_add(pa, po); 678eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 679eb2acb85Sthorpej 680eb2acb85Sthorpej return (rv); 681eb2acb85Sthorpej } 682eb2acb85Sthorpej 683eb2acb85Sthorpej /* 684774eb1a3Sthorpej * prop_array_remove -- 685774eb1a3Sthorpej * Remove the reference to an object from an array at the specified 686774eb1a3Sthorpej * index. The array will be compacted following the removal. 687774eb1a3Sthorpej */ 688774eb1a3Sthorpej void 689774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx) 690774eb1a3Sthorpej { 691774eb1a3Sthorpej prop_object_t po; 692774eb1a3Sthorpej 693d21620b2Sthorpej if (! prop_object_is_array(pa)) 694d21620b2Sthorpej return; 695d21620b2Sthorpej 696eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 697eb2acb85Sthorpej 698774eb1a3Sthorpej _PROP_ASSERT(idx < pa->pa_count); 699774eb1a3Sthorpej 700774eb1a3Sthorpej /* XXX Should this be a _PROP_ASSERT()? */ 701eb2acb85Sthorpej if (prop_array_is_immutable(pa)) { 702eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 703774eb1a3Sthorpej return; 704eb2acb85Sthorpej } 705774eb1a3Sthorpej 706774eb1a3Sthorpej po = pa->pa_array[idx]; 707774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 708774eb1a3Sthorpej 709774eb1a3Sthorpej for (++idx; idx < pa->pa_count; idx++) 710774eb1a3Sthorpej pa->pa_array[idx - 1] = pa->pa_array[idx]; 711774eb1a3Sthorpej pa->pa_count--; 712774eb1a3Sthorpej pa->pa_version++; 713774eb1a3Sthorpej 714eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 715eb2acb85Sthorpej 716774eb1a3Sthorpej prop_object_release(po); 717774eb1a3Sthorpej } 718774eb1a3Sthorpej 719774eb1a3Sthorpej /* 7203e69f1b2Sthorpej * prop_array_equals -- 72104377267Sthorpej * Return true if the two arrays are equivalent. Note we do a 7223e69f1b2Sthorpej * by-value comparison of the objects in the array. 7233e69f1b2Sthorpej */ 72404377267Sthorpej bool 7253e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2) 7263e69f1b2Sthorpej { 7274deb5931Sjoerg if (!prop_object_is_array(array1) || !prop_object_is_array(array2)) 7284deb5931Sjoerg return (false); 7293e69f1b2Sthorpej 7304deb5931Sjoerg return (prop_object_equals(array1, array2)); 7313e69f1b2Sthorpej } 7323e69f1b2Sthorpej 7333e69f1b2Sthorpej /* 734d21620b2Sthorpej * prop_array_externalize -- 735d21620b2Sthorpej * Externalize an array, return a NUL-terminated buffer 736d21620b2Sthorpej * containing the XML-style representation. The buffer is allocated 737d21620b2Sthorpej * with the M_TEMP memory type. 738d21620b2Sthorpej */ 739d21620b2Sthorpej char * 740d21620b2Sthorpej prop_array_externalize(prop_array_t pa) 741d21620b2Sthorpej { 742d21620b2Sthorpej struct _prop_object_externalize_context *ctx; 743d21620b2Sthorpej char *cp; 744d21620b2Sthorpej 745d21620b2Sthorpej ctx = _prop_object_externalize_context_alloc(); 746d21620b2Sthorpej if (ctx == NULL) 747d21620b2Sthorpej return (NULL); 748d21620b2Sthorpej 74904377267Sthorpej if (_prop_object_externalize_header(ctx) == false || 75004377267Sthorpej (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false || 75104377267Sthorpej _prop_object_externalize_footer(ctx) == false) { 752d21620b2Sthorpej /* We are responsible for releasing the buffer. */ 753d21620b2Sthorpej _PROP_FREE(ctx->poec_buf, M_TEMP); 754d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 755d21620b2Sthorpej return (NULL); 756d21620b2Sthorpej } 757d21620b2Sthorpej 758d21620b2Sthorpej cp = ctx->poec_buf; 759d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 760d21620b2Sthorpej 761d21620b2Sthorpej return (cp); 762d21620b2Sthorpej } 763d21620b2Sthorpej 764d21620b2Sthorpej /* 765774eb1a3Sthorpej * _prop_array_internalize -- 766774eb1a3Sthorpej * Parse an <array>...</array> and return the object created from the 767774eb1a3Sthorpej * external representation. 768774eb1a3Sthorpej */ 769e835604cSjoerg static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *, 770e835604cSjoerg struct _prop_object_internalize_context *); 771774eb1a3Sthorpej 772e835604cSjoerg bool 773e835604cSjoerg _prop_array_internalize(prop_stack_t stack, prop_object_t *obj, 774e835604cSjoerg struct _prop_object_internalize_context *ctx) 775e835604cSjoerg { 776774eb1a3Sthorpej /* We don't currently understand any attributes. */ 777774eb1a3Sthorpej if (ctx->poic_tagattr != NULL) 778e835604cSjoerg return (true); 779774eb1a3Sthorpej 780e835604cSjoerg *obj = prop_array_create(); 781e835604cSjoerg /* 782e835604cSjoerg * We are done if the create failed or no child elements exist. 783e835604cSjoerg */ 784e835604cSjoerg if (*obj == NULL || ctx->poic_is_empty_element) 785e835604cSjoerg return (true); 786774eb1a3Sthorpej 787e835604cSjoerg /* 788e835604cSjoerg * Opening tag is found, now continue to the first element. 789e835604cSjoerg */ 790e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx)); 791e835604cSjoerg } 792774eb1a3Sthorpej 793e835604cSjoerg static bool 794e835604cSjoerg _prop_array_internalize_continue(prop_stack_t stack, 795e835604cSjoerg prop_object_t *obj, 796e835604cSjoerg struct _prop_object_internalize_context *ctx, 797e835604cSjoerg void *data, prop_object_t child) 798e835604cSjoerg { 799e835604cSjoerg prop_array_t array; 800e835604cSjoerg 801e835604cSjoerg _PROP_ASSERT(data == NULL); 802e835604cSjoerg 803e835604cSjoerg if (child == NULL) 804e835604cSjoerg goto bad; /* Element could not be parsed. */ 805e835604cSjoerg 806e835604cSjoerg array = *obj; 807e835604cSjoerg 808e835604cSjoerg if (prop_array_add(array, child) == false) { 809e835604cSjoerg prop_object_release(child); 810e835604cSjoerg goto bad; 811e835604cSjoerg } 812e835604cSjoerg prop_object_release(child); 813e835604cSjoerg 814e835604cSjoerg /* 815e835604cSjoerg * Current element is processed and added, look for next. 816e835604cSjoerg */ 817e835604cSjoerg return (_prop_array_internalize_body(stack, obj, ctx)); 818e835604cSjoerg 819e835604cSjoerg bad: 820e835604cSjoerg prop_object_release(*obj); 821e835604cSjoerg *obj = NULL; 822e835604cSjoerg return (true); 823e835604cSjoerg } 824e835604cSjoerg 825e835604cSjoerg static bool 826e835604cSjoerg _prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj, 827e835604cSjoerg struct _prop_object_internalize_context *ctx) 828e835604cSjoerg { 829e835604cSjoerg prop_array_t array = *obj; 830e835604cSjoerg 831e835604cSjoerg _PROP_ASSERT(array != NULL); 832e835604cSjoerg 833774eb1a3Sthorpej /* Fetch the next tag. */ 834774eb1a3Sthorpej if (_prop_object_internalize_find_tag(ctx, NULL, 83504377267Sthorpej _PROP_TAG_TYPE_EITHER) == false) 836774eb1a3Sthorpej goto bad; 837774eb1a3Sthorpej 838774eb1a3Sthorpej /* Check to see if this is the end of the array. */ 839774eb1a3Sthorpej if (_PROP_TAG_MATCH(ctx, "array") && 840e835604cSjoerg ctx->poic_tag_type == _PROP_TAG_TYPE_END) { 841e835604cSjoerg /* It is, so don't iterate any further. */ 842e835604cSjoerg return (true); 843774eb1a3Sthorpej } 844774eb1a3Sthorpej 8454deb5931Sjoerg if (_prop_stack_push(stack, array, 8464deb5931Sjoerg _prop_array_internalize_continue, NULL, NULL)) 847e835604cSjoerg return (false); 848774eb1a3Sthorpej 849774eb1a3Sthorpej bad: 850774eb1a3Sthorpej prop_object_release(array); 851e835604cSjoerg *obj = NULL; 852e835604cSjoerg return (true); 853774eb1a3Sthorpej } 854d21620b2Sthorpej 855d21620b2Sthorpej /* 856d21620b2Sthorpej * prop_array_internalize -- 857d21620b2Sthorpej * Create an array by parsing the XML-style representation. 858d21620b2Sthorpej */ 859d21620b2Sthorpej prop_array_t 860d21620b2Sthorpej prop_array_internalize(const char *xml) 861d21620b2Sthorpej { 86239dccbf2Sjoerg return _prop_generic_internalize(xml, "array"); 863d21620b2Sthorpej } 864d21620b2Sthorpej 865d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE) 866d21620b2Sthorpej /* 867d21620b2Sthorpej * prop_array_externalize_to_file -- 868d21620b2Sthorpej * Externalize an array to the specified file. 869d21620b2Sthorpej */ 87004377267Sthorpej bool 871d21620b2Sthorpej prop_array_externalize_to_file(prop_array_t array, const char *fname) 872d21620b2Sthorpej { 873d21620b2Sthorpej char *xml; 87404377267Sthorpej bool rv; 8751a119b51She int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ 876d21620b2Sthorpej 877d21620b2Sthorpej xml = prop_array_externalize(array); 878d21620b2Sthorpej if (xml == NULL) 87904377267Sthorpej return (false); 880d21620b2Sthorpej rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); 88104377267Sthorpej if (rv == false) 882d21620b2Sthorpej save_errno = errno; 883d21620b2Sthorpej _PROP_FREE(xml, M_TEMP); 88404377267Sthorpej if (rv == false) 885d21620b2Sthorpej errno = save_errno; 886d21620b2Sthorpej 887d21620b2Sthorpej return (rv); 888d21620b2Sthorpej } 889d21620b2Sthorpej 890d21620b2Sthorpej /* 891d21620b2Sthorpej * prop_array_internalize_from_file -- 892d21620b2Sthorpej * Internalize an array from a file. 893d21620b2Sthorpej */ 894d21620b2Sthorpej prop_array_t 895d21620b2Sthorpej prop_array_internalize_from_file(const char *fname) 896d21620b2Sthorpej { 897d21620b2Sthorpej struct _prop_object_internalize_mapped_file *mf; 898d21620b2Sthorpej prop_array_t array; 899d21620b2Sthorpej 900d21620b2Sthorpej mf = _prop_object_internalize_map_file(fname); 901d21620b2Sthorpej if (mf == NULL) 902d21620b2Sthorpej return (NULL); 903d21620b2Sthorpej array = prop_array_internalize(mf->poimf_xml); 904d21620b2Sthorpej _prop_object_internalize_unmap_file(mf); 905d21620b2Sthorpej 906d21620b2Sthorpej return (array); 907d21620b2Sthorpej } 908d21620b2Sthorpej #endif /* _KERNEL && !_STANDALONE */ 909