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