1*04377267Sthorpej /* $NetBSD: prop_array.c,v 1.9 2007/08/16 16:28:17 thorpej Exp $ */ 2774eb1a3Sthorpej 3774eb1a3Sthorpej /*- 4774eb1a3Sthorpej * Copyright (c) 2006 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 * 3. All advertising materials mentioning features or use of this software 19774eb1a3Sthorpej * must display the following acknowledgement: 20774eb1a3Sthorpej * This product includes software developed by the NetBSD 21774eb1a3Sthorpej * Foundation, Inc. and its contributors. 22774eb1a3Sthorpej * 4. Neither the name of The NetBSD Foundation nor the names of its 23774eb1a3Sthorpej * contributors may be used to endorse or promote products derived 24774eb1a3Sthorpej * from this software without specific prior written permission. 25774eb1a3Sthorpej * 26774eb1a3Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27774eb1a3Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28774eb1a3Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29774eb1a3Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30774eb1a3Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31774eb1a3Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32774eb1a3Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33774eb1a3Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34774eb1a3Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35774eb1a3Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36774eb1a3Sthorpej * POSSIBILITY OF SUCH DAMAGE. 37774eb1a3Sthorpej */ 38774eb1a3Sthorpej 39774eb1a3Sthorpej #include <prop/prop_array.h> 40774eb1a3Sthorpej #include "prop_object_impl.h" 41774eb1a3Sthorpej 42d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE) 43d21620b2Sthorpej #include <errno.h> 44d21620b2Sthorpej #endif 45d21620b2Sthorpej 46774eb1a3Sthorpej struct _prop_array { 47774eb1a3Sthorpej struct _prop_object pa_obj; 48eb2acb85Sthorpej _PROP_RWLOCK_DECL(pa_rwlock) 49774eb1a3Sthorpej prop_object_t * pa_array; 50774eb1a3Sthorpej unsigned int pa_capacity; 51774eb1a3Sthorpej unsigned int pa_count; 52774eb1a3Sthorpej int pa_flags; 53774eb1a3Sthorpej 54774eb1a3Sthorpej uint32_t pa_version; 55774eb1a3Sthorpej }; 56774eb1a3Sthorpej 57774eb1a3Sthorpej #define PA_F_IMMUTABLE 0x01 /* array is immutable */ 58774eb1a3Sthorpej 59774eb1a3Sthorpej _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay") 60774eb1a3Sthorpej _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array", 61774eb1a3Sthorpej "property array container object") 62774eb1a3Sthorpej 633e69f1b2Sthorpej static void _prop_array_free(void *); 64*04377267Sthorpej static bool _prop_array_externalize( 653e69f1b2Sthorpej struct _prop_object_externalize_context *, 663e69f1b2Sthorpej void *); 67*04377267Sthorpej static bool _prop_array_equals(void *, 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, 723e69f1b2Sthorpej .pot_extern = _prop_array_externalize, 733e69f1b2Sthorpej .pot_equals = _prop_array_equals, 743e69f1b2Sthorpej }; 753e69f1b2Sthorpej 763e69f1b2Sthorpej #define prop_object_is_array(x) \ 77beabdd9bSthorpej ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array) 78774eb1a3Sthorpej 79774eb1a3Sthorpej #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0) 80774eb1a3Sthorpej 81774eb1a3Sthorpej struct _prop_array_iterator { 82774eb1a3Sthorpej struct _prop_object_iterator pai_base; 83774eb1a3Sthorpej unsigned int pai_index; 84774eb1a3Sthorpej }; 85774eb1a3Sthorpej 86774eb1a3Sthorpej #define EXPAND_STEP 16 87774eb1a3Sthorpej 88774eb1a3Sthorpej static void 89774eb1a3Sthorpej _prop_array_free(void *v) 90774eb1a3Sthorpej { 91774eb1a3Sthorpej prop_array_t pa = v; 92774eb1a3Sthorpej prop_object_t po; 93774eb1a3Sthorpej unsigned int idx; 94774eb1a3Sthorpej 95774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 96774eb1a3Sthorpej _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) || 97774eb1a3Sthorpej (pa->pa_capacity != 0 && pa->pa_array != NULL)); 98774eb1a3Sthorpej 99774eb1a3Sthorpej for (idx = 0; idx < pa->pa_count; idx++) { 100774eb1a3Sthorpej po = pa->pa_array[idx]; 101774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 102774eb1a3Sthorpej prop_object_release(po); 103774eb1a3Sthorpej } 104774eb1a3Sthorpej 105774eb1a3Sthorpej if (pa->pa_array != NULL) 106774eb1a3Sthorpej _PROP_FREE(pa->pa_array, M_PROP_ARRAY); 107774eb1a3Sthorpej 108eb2acb85Sthorpej _PROP_RWLOCK_DESTROY(pa->pa_rwlock); 109eb2acb85Sthorpej 110774eb1a3Sthorpej _PROP_POOL_PUT(_prop_array_pool, pa); 111774eb1a3Sthorpej } 112774eb1a3Sthorpej 113*04377267Sthorpej static bool 114774eb1a3Sthorpej _prop_array_externalize(struct _prop_object_externalize_context *ctx, 115774eb1a3Sthorpej void *v) 116774eb1a3Sthorpej { 117774eb1a3Sthorpej prop_array_t pa = v; 118774eb1a3Sthorpej struct _prop_object *po; 119774eb1a3Sthorpej prop_object_iterator_t pi; 120774eb1a3Sthorpej unsigned int i; 121*04377267Sthorpej bool rv = false; 122774eb1a3Sthorpej 123eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 124eb2acb85Sthorpej 125eb2acb85Sthorpej if (pa->pa_count == 0) { 126eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 127774eb1a3Sthorpej return (_prop_object_externalize_empty_tag(ctx, "array")); 128eb2acb85Sthorpej } 129774eb1a3Sthorpej 130774eb1a3Sthorpej /* XXXJRT Hint "count" for the internalize step? */ 131*04377267Sthorpej if (_prop_object_externalize_start_tag(ctx, "array") == false || 132*04377267Sthorpej _prop_object_externalize_append_char(ctx, '\n') == false) 133eb2acb85Sthorpej goto out; 134774eb1a3Sthorpej 135774eb1a3Sthorpej pi = prop_array_iterator(pa); 136774eb1a3Sthorpej if (pi == NULL) 137eb2acb85Sthorpej goto out; 138774eb1a3Sthorpej 139774eb1a3Sthorpej ctx->poec_depth++; 140774eb1a3Sthorpej _PROP_ASSERT(ctx->poec_depth != 0); 141774eb1a3Sthorpej 142774eb1a3Sthorpej while ((po = prop_object_iterator_next(pi)) != NULL) { 143*04377267Sthorpej if ((*po->po_type->pot_extern)(ctx, po) == false) { 144774eb1a3Sthorpej prop_object_iterator_release(pi); 145eb2acb85Sthorpej goto out; 146774eb1a3Sthorpej } 147774eb1a3Sthorpej } 148774eb1a3Sthorpej 149774eb1a3Sthorpej prop_object_iterator_release(pi); 150774eb1a3Sthorpej 151774eb1a3Sthorpej ctx->poec_depth--; 152774eb1a3Sthorpej for (i = 0; i < ctx->poec_depth; i++) { 153*04377267Sthorpej if (_prop_object_externalize_append_char(ctx, '\t') == false) 154eb2acb85Sthorpej goto out; 155774eb1a3Sthorpej } 156*04377267Sthorpej if (_prop_object_externalize_end_tag(ctx, "array") == false) 157eb2acb85Sthorpej goto out; 158774eb1a3Sthorpej 159*04377267Sthorpej rv = true; 160eb2acb85Sthorpej 161eb2acb85Sthorpej out: 162eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 163eb2acb85Sthorpej return (rv); 164774eb1a3Sthorpej } 165774eb1a3Sthorpej 166*04377267Sthorpej static bool 1673e69f1b2Sthorpej _prop_array_equals(void *v1, void *v2) 1683e69f1b2Sthorpej { 1693e69f1b2Sthorpej prop_array_t array1 = v1; 1703e69f1b2Sthorpej prop_array_t array2 = v2; 1713e69f1b2Sthorpej unsigned int idx; 172*04377267Sthorpej bool rv = false; 1733e69f1b2Sthorpej 174d21620b2Sthorpej if (! (prop_object_is_array(array1) && 175d21620b2Sthorpej prop_object_is_array(array2))) 176*04377267Sthorpej return (false); 1773e69f1b2Sthorpej 1783e69f1b2Sthorpej if (array1 == array2) 179*04377267Sthorpej return (true); 180eb2acb85Sthorpej 181eb2acb85Sthorpej if ((uintptr_t)array1 < (uintptr_t)array2) { 182eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 183eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 184eb2acb85Sthorpej } else { 185eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 186eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 187eb2acb85Sthorpej } 188eb2acb85Sthorpej 1893e69f1b2Sthorpej if (array1->pa_count != array2->pa_count) 190eb2acb85Sthorpej goto out; 1913e69f1b2Sthorpej 1923e69f1b2Sthorpej for (idx = 0; idx < array1->pa_count; idx++) { 1933e69f1b2Sthorpej if (prop_object_equals(array1->pa_array[idx], 194*04377267Sthorpej array2->pa_array[idx]) == false) 195eb2acb85Sthorpej goto out; 1963e69f1b2Sthorpej } 1973e69f1b2Sthorpej 198*04377267Sthorpej rv = true; 199eb2acb85Sthorpej 200eb2acb85Sthorpej out: 201eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array1->pa_rwlock); 202eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(array2->pa_rwlock); 203eb2acb85Sthorpej return (rv); 2043e69f1b2Sthorpej } 2053e69f1b2Sthorpej 206774eb1a3Sthorpej static prop_array_t 207774eb1a3Sthorpej _prop_array_alloc(unsigned int capacity) 208774eb1a3Sthorpej { 209774eb1a3Sthorpej prop_array_t pa; 210774eb1a3Sthorpej prop_object_t *array; 211774eb1a3Sthorpej 212774eb1a3Sthorpej if (capacity != 0) { 213774eb1a3Sthorpej array = _PROP_CALLOC(capacity * sizeof(prop_object_t), 214774eb1a3Sthorpej M_PROP_ARRAY); 215774eb1a3Sthorpej if (array == NULL) 216774eb1a3Sthorpej return (NULL); 217774eb1a3Sthorpej } else 218774eb1a3Sthorpej array = NULL; 219774eb1a3Sthorpej 220774eb1a3Sthorpej 221774eb1a3Sthorpej pa = _PROP_POOL_GET(_prop_array_pool); 222774eb1a3Sthorpej if (pa != NULL) { 2233e69f1b2Sthorpej _prop_object_init(&pa->pa_obj, &_prop_object_type_array); 2243e69f1b2Sthorpej pa->pa_obj.po_type = &_prop_object_type_array; 225774eb1a3Sthorpej 226eb2acb85Sthorpej _PROP_RWLOCK_INIT(pa->pa_rwlock); 227774eb1a3Sthorpej pa->pa_array = array; 228774eb1a3Sthorpej pa->pa_capacity = capacity; 229774eb1a3Sthorpej pa->pa_count = 0; 230774eb1a3Sthorpej pa->pa_flags = 0; 231774eb1a3Sthorpej 232774eb1a3Sthorpej pa->pa_version = 0; 233774eb1a3Sthorpej } else if (array != NULL) 234774eb1a3Sthorpej _PROP_FREE(array, M_PROP_ARRAY); 235774eb1a3Sthorpej 236774eb1a3Sthorpej return (pa); 237774eb1a3Sthorpej } 238774eb1a3Sthorpej 239*04377267Sthorpej static bool 240774eb1a3Sthorpej _prop_array_expand(prop_array_t pa, unsigned int capacity) 241774eb1a3Sthorpej { 242774eb1a3Sthorpej prop_object_t *array, *oarray; 243774eb1a3Sthorpej 244eb2acb85Sthorpej /* 245eb2acb85Sthorpej * Array must be WRITE-LOCKED. 246eb2acb85Sthorpej */ 247eb2acb85Sthorpej 248774eb1a3Sthorpej oarray = pa->pa_array; 249774eb1a3Sthorpej 25042e8dee3Sthorpej array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY); 251774eb1a3Sthorpej if (array == NULL) 252*04377267Sthorpej return (false); 253774eb1a3Sthorpej if (oarray != NULL) 25442e8dee3Sthorpej memcpy(array, oarray, pa->pa_capacity * sizeof(*array)); 255774eb1a3Sthorpej pa->pa_array = array; 256774eb1a3Sthorpej pa->pa_capacity = capacity; 257774eb1a3Sthorpej 258774eb1a3Sthorpej if (oarray != NULL) 259774eb1a3Sthorpej _PROP_FREE(oarray, M_PROP_ARRAY); 260774eb1a3Sthorpej 261*04377267Sthorpej return (true); 262774eb1a3Sthorpej } 263774eb1a3Sthorpej 264774eb1a3Sthorpej static prop_object_t 265774eb1a3Sthorpej _prop_array_iterator_next_object(void *v) 266774eb1a3Sthorpej { 267774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 268774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 269eb2acb85Sthorpej prop_object_t po = NULL; 270774eb1a3Sthorpej 271774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 272774eb1a3Sthorpej 273eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 274eb2acb85Sthorpej 275774eb1a3Sthorpej if (pa->pa_version != pai->pai_base.pi_version) 276eb2acb85Sthorpej goto out; /* array changed during iteration */ 277774eb1a3Sthorpej 278774eb1a3Sthorpej _PROP_ASSERT(pai->pai_index <= pa->pa_count); 279774eb1a3Sthorpej 280774eb1a3Sthorpej if (pai->pai_index == pa->pa_count) 281eb2acb85Sthorpej goto out; /* we've iterated all objects */ 282774eb1a3Sthorpej 283774eb1a3Sthorpej po = pa->pa_array[pai->pai_index]; 284774eb1a3Sthorpej pai->pai_index++; 285774eb1a3Sthorpej 286eb2acb85Sthorpej out: 287eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 288774eb1a3Sthorpej return (po); 289774eb1a3Sthorpej } 290774eb1a3Sthorpej 291774eb1a3Sthorpej static void 292774eb1a3Sthorpej _prop_array_iterator_reset(void *v) 293774eb1a3Sthorpej { 294774eb1a3Sthorpej struct _prop_array_iterator *pai = v; 295774eb1a3Sthorpej prop_array_t pa = pai->pai_base.pi_obj; 296774eb1a3Sthorpej 297774eb1a3Sthorpej _PROP_ASSERT(prop_object_is_array(pa)); 298774eb1a3Sthorpej 299eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 300eb2acb85Sthorpej 301774eb1a3Sthorpej pai->pai_index = 0; 302774eb1a3Sthorpej pai->pai_base.pi_version = pa->pa_version; 303eb2acb85Sthorpej 304eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 305774eb1a3Sthorpej } 306774eb1a3Sthorpej 307774eb1a3Sthorpej /* 308774eb1a3Sthorpej * prop_array_create -- 309774eb1a3Sthorpej * Create an empty array. 310774eb1a3Sthorpej */ 311774eb1a3Sthorpej prop_array_t 312774eb1a3Sthorpej prop_array_create(void) 313774eb1a3Sthorpej { 314774eb1a3Sthorpej 315774eb1a3Sthorpej return (_prop_array_alloc(0)); 316774eb1a3Sthorpej } 317774eb1a3Sthorpej 318774eb1a3Sthorpej /* 319774eb1a3Sthorpej * prop_array_create_with_capacity -- 320774eb1a3Sthorpej * Create an array with the capacity to store N objects. 321774eb1a3Sthorpej */ 322774eb1a3Sthorpej prop_array_t 323774eb1a3Sthorpej prop_array_create_with_capacity(unsigned int capacity) 324774eb1a3Sthorpej { 325774eb1a3Sthorpej 326774eb1a3Sthorpej return (_prop_array_alloc(capacity)); 327774eb1a3Sthorpej } 328774eb1a3Sthorpej 329774eb1a3Sthorpej /* 330774eb1a3Sthorpej * prop_array_copy -- 331774eb1a3Sthorpej * Copy an array. The new array has an initial capacity equal to 332774eb1a3Sthorpej * the number of objects stored in the original array. The new 333774eb1a3Sthorpej * array contains references to the original array's objects, not 334774eb1a3Sthorpej * copies of those objects (i.e. a shallow copy). 335774eb1a3Sthorpej */ 336774eb1a3Sthorpej prop_array_t 337774eb1a3Sthorpej prop_array_copy(prop_array_t opa) 338774eb1a3Sthorpej { 339774eb1a3Sthorpej prop_array_t pa; 340774eb1a3Sthorpej prop_object_t po; 341774eb1a3Sthorpej unsigned int idx; 342774eb1a3Sthorpej 343d21620b2Sthorpej if (! prop_object_is_array(opa)) 344d21620b2Sthorpej return (NULL); 345774eb1a3Sthorpej 346eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(opa->pa_rwlock); 347eb2acb85Sthorpej 348774eb1a3Sthorpej pa = _prop_array_alloc(opa->pa_count); 349774eb1a3Sthorpej if (pa != NULL) { 350774eb1a3Sthorpej for (idx = 0; idx < opa->pa_count; idx++) { 351774eb1a3Sthorpej po = opa->pa_array[idx]; 352774eb1a3Sthorpej prop_object_retain(po); 353774eb1a3Sthorpej pa->pa_array[idx] = po; 354774eb1a3Sthorpej } 355774eb1a3Sthorpej pa->pa_count = opa->pa_count; 356774eb1a3Sthorpej pa->pa_flags = opa->pa_flags; 357774eb1a3Sthorpej } 358eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(opa->pa_rwlock); 359774eb1a3Sthorpej return (pa); 360774eb1a3Sthorpej } 361774eb1a3Sthorpej 362774eb1a3Sthorpej /* 363774eb1a3Sthorpej * prop_array_copy_mutable -- 364774eb1a3Sthorpej * Like prop_array_copy(), but the resulting array is mutable. 365774eb1a3Sthorpej */ 366774eb1a3Sthorpej prop_array_t 367774eb1a3Sthorpej prop_array_copy_mutable(prop_array_t opa) 368774eb1a3Sthorpej { 369774eb1a3Sthorpej prop_array_t pa; 370774eb1a3Sthorpej 371774eb1a3Sthorpej pa = prop_array_copy(opa); 372774eb1a3Sthorpej if (pa != NULL) 373774eb1a3Sthorpej pa->pa_flags &= ~PA_F_IMMUTABLE; 374774eb1a3Sthorpej 375774eb1a3Sthorpej return (pa); 376774eb1a3Sthorpej } 377774eb1a3Sthorpej 378774eb1a3Sthorpej /* 379774eb1a3Sthorpej * prop_array_capacity -- 380774eb1a3Sthorpej * Return the capacity of the array. 381774eb1a3Sthorpej */ 382774eb1a3Sthorpej unsigned int 383774eb1a3Sthorpej prop_array_capacity(prop_array_t pa) 384774eb1a3Sthorpej { 385eb2acb85Sthorpej unsigned int rv; 386774eb1a3Sthorpej 387d21620b2Sthorpej if (! prop_object_is_array(pa)) 388d21620b2Sthorpej return (0); 389d21620b2Sthorpej 390eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 391eb2acb85Sthorpej rv = pa->pa_capacity; 392eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 393eb2acb85Sthorpej 394eb2acb85Sthorpej return (rv); 395774eb1a3Sthorpej } 396774eb1a3Sthorpej 397774eb1a3Sthorpej /* 398774eb1a3Sthorpej * prop_array_count -- 399774eb1a3Sthorpej * Return the number of objects stored in the array. 400774eb1a3Sthorpej */ 401774eb1a3Sthorpej unsigned int 402774eb1a3Sthorpej prop_array_count(prop_array_t pa) 403774eb1a3Sthorpej { 404eb2acb85Sthorpej unsigned int rv; 405774eb1a3Sthorpej 406d21620b2Sthorpej if (! prop_object_is_array(pa)) 407d21620b2Sthorpej return (0); 408d21620b2Sthorpej 409eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 410eb2acb85Sthorpej rv = pa->pa_count; 411eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 412eb2acb85Sthorpej 413eb2acb85Sthorpej return (rv); 414774eb1a3Sthorpej } 415774eb1a3Sthorpej 416774eb1a3Sthorpej /* 417774eb1a3Sthorpej * prop_array_ensure_capacity -- 418774eb1a3Sthorpej * Ensure that the array has the capacity to store the specified 419774eb1a3Sthorpej * total number of objects (inluding the objects already stored 420774eb1a3Sthorpej * in the array). 421774eb1a3Sthorpej */ 422*04377267Sthorpej bool 423774eb1a3Sthorpej prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity) 424774eb1a3Sthorpej { 425*04377267Sthorpej bool rv; 426774eb1a3Sthorpej 427d21620b2Sthorpej if (! prop_object_is_array(pa)) 428*04377267Sthorpej return (false); 429d21620b2Sthorpej 430eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 431774eb1a3Sthorpej if (capacity > pa->pa_capacity) 432eb2acb85Sthorpej rv = _prop_array_expand(pa, capacity); 433eb2acb85Sthorpej else 434*04377267Sthorpej rv = true; 435eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 436eb2acb85Sthorpej 437eb2acb85Sthorpej return (rv); 438774eb1a3Sthorpej } 439774eb1a3Sthorpej 440774eb1a3Sthorpej /* 441774eb1a3Sthorpej * prop_array_iterator -- 442774eb1a3Sthorpej * Return an iterator for the array. The array is retained by 443774eb1a3Sthorpej * the iterator. 444774eb1a3Sthorpej */ 445774eb1a3Sthorpej prop_object_iterator_t 446774eb1a3Sthorpej prop_array_iterator(prop_array_t pa) 447774eb1a3Sthorpej { 448774eb1a3Sthorpej struct _prop_array_iterator *pai; 449774eb1a3Sthorpej 450d21620b2Sthorpej if (! prop_object_is_array(pa)) 451d21620b2Sthorpej return (NULL); 452774eb1a3Sthorpej 453774eb1a3Sthorpej pai = _PROP_CALLOC(sizeof(*pai), M_TEMP); 454774eb1a3Sthorpej if (pai == NULL) 455774eb1a3Sthorpej return (NULL); 456774eb1a3Sthorpej pai->pai_base.pi_next_object = _prop_array_iterator_next_object; 457774eb1a3Sthorpej pai->pai_base.pi_reset = _prop_array_iterator_reset; 458774eb1a3Sthorpej prop_object_retain(pa); 459774eb1a3Sthorpej pai->pai_base.pi_obj = pa; 460774eb1a3Sthorpej _prop_array_iterator_reset(pai); 461774eb1a3Sthorpej 462774eb1a3Sthorpej return (&pai->pai_base); 463774eb1a3Sthorpej } 464774eb1a3Sthorpej 465774eb1a3Sthorpej /* 466774eb1a3Sthorpej * prop_array_make_immutable -- 467774eb1a3Sthorpej * Make the array immutable. 468774eb1a3Sthorpej */ 469774eb1a3Sthorpej void 470774eb1a3Sthorpej prop_array_make_immutable(prop_array_t pa) 471774eb1a3Sthorpej { 472774eb1a3Sthorpej 473eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 474*04377267Sthorpej if (prop_array_is_immutable(pa) == false) 475774eb1a3Sthorpej pa->pa_flags |= PA_F_IMMUTABLE; 476eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 477774eb1a3Sthorpej } 478774eb1a3Sthorpej 479774eb1a3Sthorpej /* 480774eb1a3Sthorpej * prop_array_mutable -- 481*04377267Sthorpej * Returns true if the array is mutable. 482774eb1a3Sthorpej */ 483*04377267Sthorpej bool 484774eb1a3Sthorpej prop_array_mutable(prop_array_t pa) 485774eb1a3Sthorpej { 486*04377267Sthorpej bool rv; 487774eb1a3Sthorpej 488eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 489*04377267Sthorpej rv = prop_array_is_immutable(pa) == false; 490eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 491eb2acb85Sthorpej 492eb2acb85Sthorpej return (rv); 493774eb1a3Sthorpej } 494774eb1a3Sthorpej 495774eb1a3Sthorpej /* 496774eb1a3Sthorpej * prop_array_get -- 497774eb1a3Sthorpej * Return the object stored at the specified array index. 498774eb1a3Sthorpej */ 499774eb1a3Sthorpej prop_object_t 500774eb1a3Sthorpej prop_array_get(prop_array_t pa, unsigned int idx) 501774eb1a3Sthorpej { 502eb2acb85Sthorpej prop_object_t po = NULL; 503774eb1a3Sthorpej 504d21620b2Sthorpej if (! prop_object_is_array(pa)) 505d21620b2Sthorpej return (NULL); 506d21620b2Sthorpej 507eb2acb85Sthorpej _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 508774eb1a3Sthorpej if (idx >= pa->pa_count) 509eb2acb85Sthorpej goto out; 510774eb1a3Sthorpej po = pa->pa_array[idx]; 511774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 512eb2acb85Sthorpej out: 513eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 514774eb1a3Sthorpej return (po); 515774eb1a3Sthorpej } 516774eb1a3Sthorpej 517*04377267Sthorpej static bool 518eb2acb85Sthorpej _prop_array_add(prop_array_t pa, prop_object_t po) 519774eb1a3Sthorpej { 520774eb1a3Sthorpej 521eb2acb85Sthorpej /* 522eb2acb85Sthorpej * Array must be WRITE-LOCKED. 523eb2acb85Sthorpej */ 524d21620b2Sthorpej 525774eb1a3Sthorpej _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 526774eb1a3Sthorpej 527774eb1a3Sthorpej if (prop_array_is_immutable(pa) || 528774eb1a3Sthorpej (pa->pa_count == pa->pa_capacity && 529*04377267Sthorpej _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false)) 530*04377267Sthorpej return (false); 531774eb1a3Sthorpej 532774eb1a3Sthorpej prop_object_retain(po); 533774eb1a3Sthorpej pa->pa_array[pa->pa_count++] = po; 534774eb1a3Sthorpej pa->pa_version++; 535774eb1a3Sthorpej 536*04377267Sthorpej return (true); 537774eb1a3Sthorpej } 538774eb1a3Sthorpej 539774eb1a3Sthorpej /* 540eb2acb85Sthorpej * prop_array_set -- 541eb2acb85Sthorpej * Store a reference to an object at the specified array index. 542eb2acb85Sthorpej * This method is not allowed to create holes in the array; the 543eb2acb85Sthorpej * caller must either be setting the object just beyond the existing 544eb2acb85Sthorpej * count or replacing an already existing object reference. 545eb2acb85Sthorpej */ 546*04377267Sthorpej bool 547eb2acb85Sthorpej prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po) 548eb2acb85Sthorpej { 549eb2acb85Sthorpej prop_object_t opo; 550*04377267Sthorpej bool rv = false; 551eb2acb85Sthorpej 552eb2acb85Sthorpej if (! prop_object_is_array(pa)) 553*04377267Sthorpej return (false); 554eb2acb85Sthorpej 555eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 556eb2acb85Sthorpej 557eb2acb85Sthorpej if (prop_array_is_immutable(pa)) 558eb2acb85Sthorpej goto out; 559eb2acb85Sthorpej 560eb2acb85Sthorpej if (idx == pa->pa_count) { 561eb2acb85Sthorpej rv = _prop_array_add(pa, po); 562eb2acb85Sthorpej goto out; 563eb2acb85Sthorpej } 564eb2acb85Sthorpej 565eb2acb85Sthorpej _PROP_ASSERT(idx < pa->pa_count); 566eb2acb85Sthorpej 567eb2acb85Sthorpej opo = pa->pa_array[idx]; 568eb2acb85Sthorpej _PROP_ASSERT(opo != NULL); 569eb2acb85Sthorpej 570eb2acb85Sthorpej prop_object_retain(po); 571eb2acb85Sthorpej pa->pa_array[idx] = po; 572eb2acb85Sthorpej pa->pa_version++; 573eb2acb85Sthorpej 574eb2acb85Sthorpej prop_object_release(opo); 575eb2acb85Sthorpej 576*04377267Sthorpej rv = true; 577eb2acb85Sthorpej 578eb2acb85Sthorpej out: 579eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 580eb2acb85Sthorpej return (rv); 581eb2acb85Sthorpej } 582eb2acb85Sthorpej 583eb2acb85Sthorpej /* 584eb2acb85Sthorpej * prop_array_add -- 585eb2acb85Sthorpej * Add a refrerence to an object to the specified array, appending 586eb2acb85Sthorpej * to the end and growing the array's capacity, if necessary. 587eb2acb85Sthorpej */ 588*04377267Sthorpej bool 589eb2acb85Sthorpej prop_array_add(prop_array_t pa, prop_object_t po) 590eb2acb85Sthorpej { 591*04377267Sthorpej bool rv; 592eb2acb85Sthorpej 593eb2acb85Sthorpej if (! prop_object_is_array(pa)) 594*04377267Sthorpej return (false); 595eb2acb85Sthorpej 596eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 597eb2acb85Sthorpej rv = _prop_array_add(pa, po); 598eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 599eb2acb85Sthorpej 600eb2acb85Sthorpej return (rv); 601eb2acb85Sthorpej } 602eb2acb85Sthorpej 603eb2acb85Sthorpej /* 604774eb1a3Sthorpej * prop_array_remove -- 605774eb1a3Sthorpej * Remove the reference to an object from an array at the specified 606774eb1a3Sthorpej * index. The array will be compacted following the removal. 607774eb1a3Sthorpej */ 608774eb1a3Sthorpej void 609774eb1a3Sthorpej prop_array_remove(prop_array_t pa, unsigned int idx) 610774eb1a3Sthorpej { 611774eb1a3Sthorpej prop_object_t po; 612774eb1a3Sthorpej 613d21620b2Sthorpej if (! prop_object_is_array(pa)) 614d21620b2Sthorpej return; 615d21620b2Sthorpej 616eb2acb85Sthorpej _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 617eb2acb85Sthorpej 618774eb1a3Sthorpej _PROP_ASSERT(idx < pa->pa_count); 619774eb1a3Sthorpej 620774eb1a3Sthorpej /* XXX Should this be a _PROP_ASSERT()? */ 621eb2acb85Sthorpej if (prop_array_is_immutable(pa)) { 622eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 623774eb1a3Sthorpej return; 624eb2acb85Sthorpej } 625774eb1a3Sthorpej 626774eb1a3Sthorpej po = pa->pa_array[idx]; 627774eb1a3Sthorpej _PROP_ASSERT(po != NULL); 628774eb1a3Sthorpej 629774eb1a3Sthorpej for (++idx; idx < pa->pa_count; idx++) 630774eb1a3Sthorpej pa->pa_array[idx - 1] = pa->pa_array[idx]; 631774eb1a3Sthorpej pa->pa_count--; 632774eb1a3Sthorpej pa->pa_version++; 633774eb1a3Sthorpej 634eb2acb85Sthorpej _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 635eb2acb85Sthorpej 636774eb1a3Sthorpej prop_object_release(po); 637774eb1a3Sthorpej } 638774eb1a3Sthorpej 639774eb1a3Sthorpej /* 6403e69f1b2Sthorpej * prop_array_equals -- 641*04377267Sthorpej * Return true if the two arrays are equivalent. Note we do a 6423e69f1b2Sthorpej * by-value comparison of the objects in the array. 6433e69f1b2Sthorpej */ 644*04377267Sthorpej bool 6453e69f1b2Sthorpej prop_array_equals(prop_array_t array1, prop_array_t array2) 6463e69f1b2Sthorpej { 6473e69f1b2Sthorpej 6483e69f1b2Sthorpej return (_prop_array_equals(array1, array2)); 6493e69f1b2Sthorpej } 6503e69f1b2Sthorpej 6513e69f1b2Sthorpej /* 652d21620b2Sthorpej * prop_array_externalize -- 653d21620b2Sthorpej * Externalize an array, return a NUL-terminated buffer 654d21620b2Sthorpej * containing the XML-style representation. The buffer is allocated 655d21620b2Sthorpej * with the M_TEMP memory type. 656d21620b2Sthorpej */ 657d21620b2Sthorpej char * 658d21620b2Sthorpej prop_array_externalize(prop_array_t pa) 659d21620b2Sthorpej { 660d21620b2Sthorpej struct _prop_object_externalize_context *ctx; 661d21620b2Sthorpej char *cp; 662d21620b2Sthorpej 663d21620b2Sthorpej ctx = _prop_object_externalize_context_alloc(); 664d21620b2Sthorpej if (ctx == NULL) 665d21620b2Sthorpej return (NULL); 666d21620b2Sthorpej 667*04377267Sthorpej if (_prop_object_externalize_header(ctx) == false || 668*04377267Sthorpej (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false || 669*04377267Sthorpej _prop_object_externalize_footer(ctx) == false) { 670d21620b2Sthorpej /* We are responsible for releasing the buffer. */ 671d21620b2Sthorpej _PROP_FREE(ctx->poec_buf, M_TEMP); 672d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 673d21620b2Sthorpej return (NULL); 674d21620b2Sthorpej } 675d21620b2Sthorpej 676d21620b2Sthorpej cp = ctx->poec_buf; 677d21620b2Sthorpej _prop_object_externalize_context_free(ctx); 678d21620b2Sthorpej 679d21620b2Sthorpej return (cp); 680d21620b2Sthorpej } 681d21620b2Sthorpej 682d21620b2Sthorpej /* 683774eb1a3Sthorpej * _prop_array_internalize -- 684774eb1a3Sthorpej * Parse an <array>...</array> and return the object created from the 685774eb1a3Sthorpej * external representation. 686774eb1a3Sthorpej */ 687774eb1a3Sthorpej prop_object_t 688774eb1a3Sthorpej _prop_array_internalize(struct _prop_object_internalize_context *ctx) 689774eb1a3Sthorpej { 690774eb1a3Sthorpej prop_array_t array; 691774eb1a3Sthorpej prop_object_t obj; 692774eb1a3Sthorpej 693774eb1a3Sthorpej /* We don't currently understand any attributes. */ 694774eb1a3Sthorpej if (ctx->poic_tagattr != NULL) 695774eb1a3Sthorpej return (NULL); 696774eb1a3Sthorpej 697774eb1a3Sthorpej array = prop_array_create(); 698774eb1a3Sthorpej if (array == NULL) 699774eb1a3Sthorpej return (NULL); 700774eb1a3Sthorpej 701774eb1a3Sthorpej if (ctx->poic_is_empty_element) 702774eb1a3Sthorpej return (array); 703774eb1a3Sthorpej 704774eb1a3Sthorpej for (;;) { 705774eb1a3Sthorpej /* Fetch the next tag. */ 706774eb1a3Sthorpej if (_prop_object_internalize_find_tag(ctx, NULL, 707*04377267Sthorpej _PROP_TAG_TYPE_EITHER) == false) 708774eb1a3Sthorpej goto bad; 709774eb1a3Sthorpej 710774eb1a3Sthorpej /* Check to see if this is the end of the array. */ 711774eb1a3Sthorpej if (_PROP_TAG_MATCH(ctx, "array") && 712774eb1a3Sthorpej ctx->poic_tag_type == _PROP_TAG_TYPE_END) 713774eb1a3Sthorpej break; 714774eb1a3Sthorpej 715774eb1a3Sthorpej /* Fetch the object. */ 716774eb1a3Sthorpej obj = _prop_object_internalize_by_tag(ctx); 717774eb1a3Sthorpej if (obj == NULL) 718774eb1a3Sthorpej goto bad; 719774eb1a3Sthorpej 720*04377267Sthorpej if (prop_array_add(array, obj) == false) { 721774eb1a3Sthorpej prop_object_release(obj); 722774eb1a3Sthorpej goto bad; 723774eb1a3Sthorpej } 724774eb1a3Sthorpej prop_object_release(obj); 725774eb1a3Sthorpej } 726774eb1a3Sthorpej 727774eb1a3Sthorpej return (array); 728774eb1a3Sthorpej 729774eb1a3Sthorpej bad: 730774eb1a3Sthorpej prop_object_release(array); 731774eb1a3Sthorpej return (NULL); 732774eb1a3Sthorpej } 733d21620b2Sthorpej 734d21620b2Sthorpej /* 735d21620b2Sthorpej * prop_array_internalize -- 736d21620b2Sthorpej * Create an array by parsing the XML-style representation. 737d21620b2Sthorpej */ 738d21620b2Sthorpej prop_array_t 739d21620b2Sthorpej prop_array_internalize(const char *xml) 740d21620b2Sthorpej { 74139dccbf2Sjoerg return _prop_generic_internalize(xml, "array"); 742d21620b2Sthorpej } 743d21620b2Sthorpej 744d21620b2Sthorpej #if !defined(_KERNEL) && !defined(_STANDALONE) 745d21620b2Sthorpej /* 746d21620b2Sthorpej * prop_array_externalize_to_file -- 747d21620b2Sthorpej * Externalize an array to the specified file. 748d21620b2Sthorpej */ 749*04377267Sthorpej bool 750d21620b2Sthorpej prop_array_externalize_to_file(prop_array_t array, const char *fname) 751d21620b2Sthorpej { 752d21620b2Sthorpej char *xml; 753*04377267Sthorpej bool rv; 7541a119b51She int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ 755d21620b2Sthorpej 756d21620b2Sthorpej xml = prop_array_externalize(array); 757d21620b2Sthorpej if (xml == NULL) 758*04377267Sthorpej return (false); 759d21620b2Sthorpej rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); 760*04377267Sthorpej if (rv == false) 761d21620b2Sthorpej save_errno = errno; 762d21620b2Sthorpej _PROP_FREE(xml, M_TEMP); 763*04377267Sthorpej if (rv == false) 764d21620b2Sthorpej errno = save_errno; 765d21620b2Sthorpej 766d21620b2Sthorpej return (rv); 767d21620b2Sthorpej } 768d21620b2Sthorpej 769d21620b2Sthorpej /* 770d21620b2Sthorpej * prop_array_internalize_from_file -- 771d21620b2Sthorpej * Internalize an array from a file. 772d21620b2Sthorpej */ 773d21620b2Sthorpej prop_array_t 774d21620b2Sthorpej prop_array_internalize_from_file(const char *fname) 775d21620b2Sthorpej { 776d21620b2Sthorpej struct _prop_object_internalize_mapped_file *mf; 777d21620b2Sthorpej prop_array_t array; 778d21620b2Sthorpej 779d21620b2Sthorpej mf = _prop_object_internalize_map_file(fname); 780d21620b2Sthorpej if (mf == NULL) 781d21620b2Sthorpej return (NULL); 782d21620b2Sthorpej array = prop_array_internalize(mf->poimf_xml); 783d21620b2Sthorpej _prop_object_internalize_unmap_file(mf); 784d21620b2Sthorpej 785d21620b2Sthorpej return (array); 786d21620b2Sthorpej } 787d21620b2Sthorpej #endif /* _KERNEL && !_STANDALONE */ 788