--- /dev/null
+# $NetBSD: Makefile.inc,v 1.8 2008/06/30 20:14:09 matt Exp $
+
+.PATH: ${.PARSEDIR}
+
+SRCS+= prop_array.c prop_array_util.c prop_bool.c prop_data.c \
+ prop_dictionary.c prop_dictionary_util.c prop_ingest.c \
+ prop_kern.c prop_number.c prop_object.c prop_stack.c prop_string.c
+
+#SRCS+= prop_rb.c
--- /dev/null
+.\" $NetBSD: prop_array.3,v 1.13 2011/09/30 22:08:18 jym Exp $
+.\"
+.\" Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd October 10, 2009
+.Dt PROP_ARRAY 3
+.Os
+.Sh NAME
+.Nm prop_array ,
+.Nm prop_array_create ,
+.Nm prop_array_create_with_capacity ,
+.Nm prop_array_copy ,
+.Nm prop_array_copy_mutable ,
+.Nm prop_array_capacity ,
+.Nm prop_array_count ,
+.Nm prop_array_ensure_capacity ,
+.Nm prop_array_iterator ,
+.Nm prop_array_make_immutable ,
+.Nm prop_array_mutable ,
+.Nm prop_array_get ,
+.Nm prop_array_set ,
+.Nm prop_array_add ,
+.Nm prop_array_remove ,
+.Nm prop_array_externalize ,
+.Nm prop_array_internalize ,
+.Nm prop_array_externalize_to_file ,
+.Nm prop_array_internalize_from_file ,
+.Nm prop_array_externalize_to_pref ,
+.Nm prop_array_internalize_from_pref ,
+.Nm prop_array_equals
+.Nd array property collection object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_array_t
+.Fn prop_array_create "void"
+.Ft prop_array_t
+.Fn prop_array_create_with_capacity "unsigned int capacity"
+.\"
+.Ft prop_array_t
+.Fn prop_array_copy "prop_array_t array"
+.Ft prop_array_t
+.Fn prop_array_copy_mutable "prop_array_t array"
+.\"
+.Ft unsigned int
+.Fn prop_array_capacity "prop_array_t array"
+.Ft unsigned int
+.Fn prop_array_count "prop_array_t array"
+.Ft bool
+.Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity"
+.\"
+.Ft prop_object_iterator_t
+.Fn prop_array_iterator "prop_array_t array"
+.\"
+.Ft void
+.Fn prop_array_make_immutable "prop_array_t array"
+.Ft bool
+.Fn prop_array_mutable "prop_array_t array"
+.\"
+.Ft prop_object_t
+.Fn prop_array_get "prop_array_t array" "unsigned int index"
+.Ft bool
+.Fn prop_array_set "prop_array_t array" "unsigned int index" "prop_object_t obj"
+.Ft bool
+.Fn prop_array_add "prop_array_t array" "prop_object_t obj"
+.Ft void
+.Fn prop_array_remove "prop_array_t array" "unsigned int index"
+.\"
+.Ft char *
+.Fn prop_array_externalize "prop_array_t array"
+.Ft prop_array_t
+.Fn prop_array_internalize "const char *xml"
+.\"
+.Ft bool
+.Fn prop_array_externalize_to_file "prop_array_t array" "const char *path"
+.Ft prop_array_t
+.Fn prop_array_internalize_from_file "const char *path"
+.\"
+.Ft bool
+.Fn prop_array_externalize_to_pref "prop_array_t array" "struct plistref *pref"
+.Ft bool
+.Fn prop_array_internalize_from_pref "const struct plistref *pref" \
+ "prop_array_t *arrayp"
+.\"
+.Ft bool
+.Fn prop_array_equals "prop_array_t array1" "prop_array_t array2"
+.Sh DESCRIPTION
+The
+.Nm prop_array
+family of functions operate on the array property collection object type.
+An array is an ordered set; an iterated array will return objects in the
+same order with which they were stored.
+.Bl -tag -width "xxxxx"
+.It Fn prop_array_create "void"
+Create an empty array.
+The array initially has no capacity.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_create_with_capacity "unsigned int capacity"
+Create an array with the capacity to store
+.Fa capacity
+objects.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_copy "prop_array_t array"
+Copy an array.
+The new array has an initial capacity equal to the number of objects stored
+in the array being copied.
+The new array contains references to the original array's objects, not
+copies of those objects
+.Pq i.e. a shallow copy is made .
+If the original array is immutable, the resulting array is also immutable.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_copy_mutable "prop_array_t array"
+Like
+.Fn prop_array_copy ,
+except the resulting array is always mutable.
+.It Fn prop_array_capacity "prop_array_t array"
+Returns the total capacity of the array, including objects already stored
+in the array.
+If the supplied object isn't an array, zero is returned.
+.It Fn prop_array_count "prop_array_t array"
+Returns the number of objects stored in the array.
+If the supplied object isn't an array, zero is returned.
+.It Fn prop_array_ensure_capacity "prop_array_t array" "unsigned int capacity"
+Ensure that the array has a total capacity of
+.Fa capacity ,
+including objects already stored in the array.
+Returns
+.Dv true
+if the capacity of the array is greater or equal to
+.Fa capacity
+or if expansion of the array's capacity was successful
+and
+.Dv false
+otherwise.
+.It Fn prop_array_iterator "prop_array_t array"
+Create an iterator for the array.
+The array is retained by the iterator.
+An array iterator returns the object references stored in the array.
+Storing to or removing from the array invalidates any active iterators for
+the array.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_make_immutable "prop_array_t array"
+Make
+.Fa array
+immutable.
+.It Fn prop_array_mutable "prop_array_t array"
+Returns
+.Dv true
+if the array is mutable.
+.It Fn prop_array_get "prop_array_t array" "unsigned int index"
+Return the object stored at the array index
+.Fa index .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_set "prop_array_t array" "unsigned int index" \
+ "prop_object_t obj"
+Store a reference to the object
+.Fa obj
+at the array index
+.Fa index .
+This function is not allowed to create holes in the array;
+the caller must either be setting the object just beyond the existing
+count or replacing an already existing object reference.
+The object will be retained by the array.
+If an existing object reference is being replaced, that object will be
+released.
+Returns
+.Dv true
+if storing the object was successful and
+.Dv false
+otherwise.
+.It Fn prop_array_add "prop_array_t array" "prop_object_t obj"
+Add a reference to the object
+.Fa obj
+to the array, appending to the end and growing the array's capacity if
+necessary.
+The object will be retained by the array.
+Returns
+.Dv true
+if storing the object was successful and
+.Dv false
+otherwise.
+.Pp
+During expansion, array's capacity is augmented by the
+.Dv EXPAND_STEP
+constant, as defined in
+.Pa libprop/prop_array.c
+file, e.g.
+.Pp
+.Dl #define EXPAND_STEP 16
+.It Fn prop_array_remove "prop_array_t array" "unsigned int index"
+Remove the reference to the object stored at array index
+.Fa index .
+The object will be released and the array compacted following
+the removal.
+.It Fn prop_array_externalize "prop_array_t array"
+Externalizes an array, returning a NUL-terminated buffer containing
+the XML representation of the array.
+The caller is responsible for freeing the returned buffer.
+If converting to the external representation fails for any reason,
+.Dv NULL
+is returned.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.It Fn prop_array_internalize "const char *xml"
+Parse the XML representation of a property list in the NUL-terminated
+buffer
+.Fa xml
+and return the corresponding array.
+Returns
+.Dv NULL
+if parsing fails for any reason.
+.It Fn prop_array_externalize_to_file "prop_array_t array" "const char *path"
+Externalizes an array and writes it to the file specified by
+.Fa path .
+The file is saved with the mode
+.Dv 0666
+as modified by the process's file creation mask
+.Pq see Xr umask 2
+and is written atomically.
+Returns
+.Dv false
+if externalizing or writing the array fails for any reason.
+.It Fn prop_array_internalize_from_file "const char *path"
+Reads the XML property list contained in the file specified by
+.Fa path ,
+internalizes it, and returns the corresponding array.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_array_externalize_to_pref "prop_array_t array" \
+ "struct plistref *pref"
+Externalizes an array and packs it into the plistref specified by
+.Fa pref .
+Returns
+.Dv false
+if externalizing the array fails for any reason.
+.It Fn prop_array_internalize_from_pref "const struct plistref *pref" \
+ "prop_array_t *arrayp"
+Reads the plistref specified by
+.Fa pref ,
+internalizes it, and returns the corresponding array.
+Returns
+.Dv false
+if internalizing or writing the array fails for any reason.
+.It Fn prop_array_equals "prop_array_t array1" "prop_array_t array2"
+Returns
+.Dv true
+if the two arrays are equivalent.
+If at least one of the supplied objects isn't an array,
+.Dv false
+is returned.
+Note: Objects contained in the array are compared by value, not by reference.
+.El
+.Sh SEE ALSO
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_array.h>
+#include "prop_object_impl.h"
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <errno.h>
+#endif
+
+struct _prop_array {
+ struct _prop_object pa_obj;
+ _PROP_RWLOCK_DECL(pa_rwlock)
+ prop_object_t * pa_array;
+ unsigned int pa_capacity;
+ unsigned int pa_count;
+ int pa_flags;
+
+ uint32_t pa_version;
+};
+
+#define PA_F_IMMUTABLE 0x01 /* array is immutable */
+
+_PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay")
+_PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array",
+ "property array container object")
+
+static _prop_object_free_rv_t
+ _prop_array_free(prop_stack_t, prop_object_t *);
+static void _prop_array_emergency_free(prop_object_t);
+static bool _prop_array_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_array_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+static void _prop_array_equals_finish(prop_object_t, prop_object_t);
+static prop_object_iterator_t
+ _prop_array_iterator_locked(prop_array_t);
+static prop_object_t
+ _prop_array_iterator_next_object_locked(void *);
+static void _prop_array_iterator_reset_locked(void *);
+
+static const struct _prop_object_type _prop_object_type_array = {
+ .pot_type = PROP_TYPE_ARRAY,
+ .pot_free = _prop_array_free,
+ .pot_emergency_free = _prop_array_emergency_free,
+ .pot_extern = _prop_array_externalize,
+ .pot_equals = _prop_array_equals,
+ .pot_equals_finish = _prop_array_equals_finish,
+};
+
+#define prop_object_is_array(x) \
+ ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
+
+#define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
+
+struct _prop_array_iterator {
+ struct _prop_object_iterator pai_base;
+ unsigned int pai_index;
+};
+
+#define EXPAND_STEP 16
+
+static _prop_object_free_rv_t
+_prop_array_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_array_t pa = *obj;
+ prop_object_t po;
+
+ _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
+ _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) ||
+ (pa->pa_capacity != 0 && pa->pa_array != NULL));
+
+ /* The easy case is an empty array, just free and return. */
+ if (pa->pa_count == 0) {
+ if (pa->pa_array != NULL)
+ _PROP_FREE(pa->pa_array, M_PROP_ARRAY);
+
+ _PROP_RWLOCK_DESTROY(pa->pa_rwlock);
+
+ _PROP_POOL_PUT(_prop_array_pool, pa);
+
+ return (_PROP_OBJECT_FREE_DONE);
+ }
+
+ po = pa->pa_array[pa->pa_count - 1];
+ _PROP_ASSERT(po != NULL);
+
+ if (stack == NULL) {
+ /*
+ * If we are in emergency release mode,
+ * just let caller recurse down.
+ */
+ *obj = po;
+ return (_PROP_OBJECT_FREE_FAILED);
+ }
+
+ /* Otherwise, try to push the current object on the stack. */
+ if (!_prop_stack_push(stack, pa, NULL, NULL, NULL)) {
+ /* Push failed, entering emergency release mode. */
+ return (_PROP_OBJECT_FREE_FAILED);
+ }
+ /* Object pushed on stack, caller will release it. */
+ --pa->pa_count;
+ *obj = po;
+ return (_PROP_OBJECT_FREE_RECURSE);
+}
+
+static void
+_prop_array_emergency_free(prop_object_t obj)
+{
+ prop_array_t pa = obj;
+
+ _PROP_ASSERT(pa->pa_count != 0);
+ --pa->pa_count;
+}
+
+static bool
+_prop_array_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_array_t pa = v;
+ struct _prop_object *po;
+ prop_object_iterator_t pi;
+ unsigned int i;
+ bool rv = false;
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+
+ if (pa->pa_count == 0) {
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (_prop_object_externalize_empty_tag(ctx, "array"));
+ }
+
+ /* XXXJRT Hint "count" for the internalize step? */
+ if (_prop_object_externalize_start_tag(ctx, "array") == false ||
+ _prop_object_externalize_append_char(ctx, '\n') == false)
+ goto out;
+
+ pi = _prop_array_iterator_locked(pa);
+ if (pi == NULL)
+ goto out;
+
+ ctx->poec_depth++;
+ _PROP_ASSERT(ctx->poec_depth != 0);
+
+ while ((po = _prop_array_iterator_next_object_locked(pi)) != NULL) {
+ if ((*po->po_type->pot_extern)(ctx, po) == false) {
+ prop_object_iterator_release(pi);
+ goto out;
+ }
+ }
+
+ prop_object_iterator_release(pi);
+
+ ctx->poec_depth--;
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == false)
+ goto out;
+ }
+ if (_prop_object_externalize_end_tag(ctx, "array") == false)
+ goto out;
+
+ rv = true;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (rv);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_array_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_array_t array1 = v1;
+ prop_array_t array2 = v2;
+ uintptr_t idx;
+ _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
+
+ if (array1 == array2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+
+ _PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
+ idx = (uintptr_t)*stored_pointer1;
+
+ /* For the first iteration, lock the objects. */
+ if (idx == 0) {
+ if ((uintptr_t)array1 < (uintptr_t)array2) {
+ _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
+ _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
+ } else {
+ _PROP_RWLOCK_RDLOCK(array2->pa_rwlock);
+ _PROP_RWLOCK_RDLOCK(array1->pa_rwlock);
+ }
+ }
+
+ if (array1->pa_count != array2->pa_count)
+ goto out;
+ if (idx == array1->pa_count) {
+ rv = _PROP_OBJECT_EQUALS_TRUE;
+ goto out;
+ }
+ _PROP_ASSERT(idx < array1->pa_count);
+
+ *stored_pointer1 = (void *)(idx + 1);
+ *stored_pointer2 = (void *)(idx + 1);
+
+ *next_obj1 = array1->pa_array[idx];
+ *next_obj2 = array2->pa_array[idx];
+
+ return (_PROP_OBJECT_EQUALS_RECURSE);
+
+ out:
+ _PROP_RWLOCK_UNLOCK(array1->pa_rwlock);
+ _PROP_RWLOCK_UNLOCK(array2->pa_rwlock);
+ return (rv);
+}
+
+static void
+_prop_array_equals_finish(prop_object_t v1, prop_object_t v2)
+{
+ _PROP_RWLOCK_UNLOCK(((prop_array_t)v1)->pa_rwlock);
+ _PROP_RWLOCK_UNLOCK(((prop_array_t)v2)->pa_rwlock);
+}
+
+static prop_array_t
+_prop_array_alloc(unsigned int capacity)
+{
+ prop_array_t pa;
+ prop_object_t *array;
+
+ if (capacity != 0) {
+ array = _PROP_CALLOC(capacity * sizeof(prop_object_t),
+ M_PROP_ARRAY);
+ if (array == NULL)
+ return (NULL);
+ } else
+ array = NULL;
+
+ pa = _PROP_POOL_GET(_prop_array_pool);
+ if (pa != NULL) {
+ _prop_object_init(&pa->pa_obj, &_prop_object_type_array);
+ pa->pa_obj.po_type = &_prop_object_type_array;
+
+ _PROP_RWLOCK_INIT(pa->pa_rwlock);
+ pa->pa_array = array;
+ pa->pa_capacity = capacity;
+ pa->pa_count = 0;
+ pa->pa_flags = 0;
+
+ pa->pa_version = 0;
+ } else if (array != NULL)
+ _PROP_FREE(array, M_PROP_ARRAY);
+
+ return (pa);
+}
+
+static bool
+_prop_array_expand(prop_array_t pa, unsigned int capacity)
+{
+ prop_object_t *array, *oarray;
+
+ /*
+ * Array must be WRITE-LOCKED.
+ */
+
+ oarray = pa->pa_array;
+
+ array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY);
+ if (array == NULL)
+ return (false);
+ if (oarray != NULL)
+ memcpy(array, oarray, pa->pa_capacity * sizeof(*array));
+ pa->pa_array = array;
+ pa->pa_capacity = capacity;
+
+ if (oarray != NULL)
+ _PROP_FREE(oarray, M_PROP_ARRAY);
+
+ return (true);
+}
+
+static prop_object_t
+_prop_array_iterator_next_object_locked(void *v)
+{
+ struct _prop_array_iterator *pai = v;
+ prop_array_t pa = pai->pai_base.pi_obj;
+ prop_object_t po = NULL;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+
+ if (pa->pa_version != pai->pai_base.pi_version)
+ goto out; /* array changed during iteration */
+
+ _PROP_ASSERT(pai->pai_index <= pa->pa_count);
+
+ if (pai->pai_index == pa->pa_count)
+ goto out; /* we've iterated all objects */
+
+ po = pa->pa_array[pai->pai_index];
+ pai->pai_index++;
+
+ out:
+ return (po);
+}
+
+static prop_object_t
+_prop_array_iterator_next_object(void *v)
+{
+ struct _prop_array_iterator *pai = v;
+ prop_array_t pa __unused = pai->pai_base.pi_obj;
+ prop_object_t po;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ po = _prop_array_iterator_next_object_locked(pai);
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (po);
+}
+
+static void
+_prop_array_iterator_reset_locked(void *v)
+{
+ struct _prop_array_iterator *pai = v;
+ prop_array_t pa = pai->pai_base.pi_obj;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+
+ pai->pai_index = 0;
+ pai->pai_base.pi_version = pa->pa_version;
+}
+
+static void
+_prop_array_iterator_reset(void *v)
+{
+ struct _prop_array_iterator *pai = v;
+ prop_array_t pa __unused = pai->pai_base.pi_obj;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ _prop_array_iterator_reset_locked(pai);
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+}
+
+/*
+ * prop_array_create --
+ * Create an empty array.
+ */
+prop_array_t
+prop_array_create(void)
+{
+
+ return (_prop_array_alloc(0));
+}
+
+/*
+ * prop_array_create_with_capacity --
+ * Create an array with the capacity to store N objects.
+ */
+prop_array_t
+prop_array_create_with_capacity(unsigned int capacity)
+{
+
+ return (_prop_array_alloc(capacity));
+}
+
+/*
+ * prop_array_copy --
+ * Copy an array. The new array has an initial capacity equal to
+ * the number of objects stored in the original array. The new
+ * array contains references to the original array's objects, not
+ * copies of those objects (i.e. a shallow copy).
+ */
+prop_array_t
+prop_array_copy(prop_array_t opa)
+{
+ prop_array_t pa;
+ prop_object_t po;
+ unsigned int idx;
+
+ if (! prop_object_is_array(opa))
+ return (NULL);
+
+ _PROP_RWLOCK_RDLOCK(opa->pa_rwlock);
+
+ pa = _prop_array_alloc(opa->pa_count);
+ if (pa != NULL) {
+ for (idx = 0; idx < opa->pa_count; idx++) {
+ po = opa->pa_array[idx];
+ prop_object_retain(po);
+ pa->pa_array[idx] = po;
+ }
+ pa->pa_count = opa->pa_count;
+ pa->pa_flags = opa->pa_flags;
+ }
+ _PROP_RWLOCK_UNLOCK(opa->pa_rwlock);
+ return (pa);
+}
+
+/*
+ * prop_array_copy_mutable --
+ * Like prop_array_copy(), but the resulting array is mutable.
+ */
+prop_array_t
+prop_array_copy_mutable(prop_array_t opa)
+{
+ prop_array_t pa;
+
+ pa = prop_array_copy(opa);
+ if (pa != NULL)
+ pa->pa_flags &= ~PA_F_IMMUTABLE;
+
+ return (pa);
+}
+
+/*
+ * prop_array_capacity --
+ * Return the capacity of the array.
+ */
+unsigned int
+prop_array_capacity(prop_array_t pa)
+{
+ unsigned int rv;
+
+ if (! prop_object_is_array(pa))
+ return (0);
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ rv = pa->pa_capacity;
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ return (rv);
+}
+
+/*
+ * prop_array_count --
+ * Return the number of objects stored in the array.
+ */
+unsigned int
+prop_array_count(prop_array_t pa)
+{
+ unsigned int rv;
+
+ if (! prop_object_is_array(pa))
+ return (0);
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ rv = pa->pa_count;
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ return (rv);
+}
+
+/*
+ * prop_array_ensure_capacity --
+ * Ensure that the array has the capacity to store the specified
+ * total number of objects (inluding the objects already stored
+ * in the array).
+ */
+bool
+prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity)
+{
+ bool rv;
+
+ if (! prop_object_is_array(pa))
+ return (false);
+
+ _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
+ if (capacity > pa->pa_capacity)
+ rv = _prop_array_expand(pa, capacity);
+ else
+ rv = true;
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ return (rv);
+}
+
+static prop_object_iterator_t
+_prop_array_iterator_locked(prop_array_t pa)
+{
+ struct _prop_array_iterator *pai;
+
+ if (! prop_object_is_array(pa))
+ return (NULL);
+
+ pai = _PROP_CALLOC(sizeof(*pai), M_TEMP);
+ if (pai == NULL)
+ return (NULL);
+ pai->pai_base.pi_next_object = _prop_array_iterator_next_object;
+ pai->pai_base.pi_reset = _prop_array_iterator_reset;
+ prop_object_retain(pa);
+ pai->pai_base.pi_obj = pa;
+ _prop_array_iterator_reset_locked(pai);
+
+ return (&pai->pai_base);
+}
+
+/*
+ * prop_array_iterator --
+ * Return an iterator for the array. The array is retained by
+ * the iterator.
+ */
+prop_object_iterator_t
+prop_array_iterator(prop_array_t pa)
+{
+ prop_object_iterator_t pi;
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ pi = _prop_array_iterator_locked(pa);
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (pi);
+}
+
+/*
+ * prop_array_make_immutable --
+ * Make the array immutable.
+ */
+void
+prop_array_make_immutable(prop_array_t pa)
+{
+
+ _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
+ if (prop_array_is_immutable(pa) == false)
+ pa->pa_flags |= PA_F_IMMUTABLE;
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+}
+
+/*
+ * prop_array_mutable --
+ * Returns true if the array is mutable.
+ */
+bool
+prop_array_mutable(prop_array_t pa)
+{
+ bool rv;
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ rv = prop_array_is_immutable(pa) == false;
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ return (rv);
+}
+
+/*
+ * prop_array_get --
+ * Return the object stored at the specified array index.
+ */
+prop_object_t
+prop_array_get(prop_array_t pa, unsigned int idx)
+{
+ prop_object_t po = NULL;
+
+ if (! prop_object_is_array(pa))
+ return (NULL);
+
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+ if (idx >= pa->pa_count)
+ goto out;
+ po = pa->pa_array[idx];
+ _PROP_ASSERT(po != NULL);
+ out:
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (po);
+}
+
+static bool
+_prop_array_add(prop_array_t pa, prop_object_t po)
+{
+
+ /*
+ * Array must be WRITE-LOCKED.
+ */
+
+ _PROP_ASSERT(pa->pa_count <= pa->pa_capacity);
+
+ if (prop_array_is_immutable(pa) ||
+ (pa->pa_count == pa->pa_capacity &&
+ _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == false))
+ return (false);
+
+ prop_object_retain(po);
+ pa->pa_array[pa->pa_count++] = po;
+ pa->pa_version++;
+
+ return (true);
+}
+
+/*
+ * prop_array_set --
+ * Store a reference to an object at the specified array index.
+ * This method is not allowed to create holes in the array; the
+ * caller must either be setting the object just beyond the existing
+ * count or replacing an already existing object reference.
+ */
+bool
+prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po)
+{
+ prop_object_t opo;
+ bool rv = false;
+
+ if (! prop_object_is_array(pa))
+ return (false);
+
+ _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
+
+ if (prop_array_is_immutable(pa))
+ goto out;
+
+ if (idx == pa->pa_count) {
+ rv = _prop_array_add(pa, po);
+ goto out;
+ }
+
+ _PROP_ASSERT(idx < pa->pa_count);
+
+ opo = pa->pa_array[idx];
+ _PROP_ASSERT(opo != NULL);
+
+ prop_object_retain(po);
+ pa->pa_array[idx] = po;
+ pa->pa_version++;
+
+ prop_object_release(opo);
+
+ rv = true;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return (rv);
+}
+
+/*
+ * prop_array_add --
+ * Add a reference to an object to the specified array, appending
+ * to the end and growing the array's capacity, if necessary.
+ */
+bool
+prop_array_add(prop_array_t pa, prop_object_t po)
+{
+ bool rv;
+
+ if (! prop_object_is_array(pa))
+ return (false);
+
+ _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
+ rv = _prop_array_add(pa, po);
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ return (rv);
+}
+
+/*
+ * prop_array_remove --
+ * Remove the reference to an object from an array at the specified
+ * index. The array will be compacted following the removal.
+ */
+void
+prop_array_remove(prop_array_t pa, unsigned int idx)
+{
+ prop_object_t po;
+
+ if (! prop_object_is_array(pa))
+ return;
+
+ _PROP_RWLOCK_WRLOCK(pa->pa_rwlock);
+
+ _PROP_ASSERT(idx < pa->pa_count);
+
+ /* XXX Should this be a _PROP_ASSERT()? */
+ if (prop_array_is_immutable(pa)) {
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+ return;
+ }
+
+ po = pa->pa_array[idx];
+ _PROP_ASSERT(po != NULL);
+
+ for (++idx; idx < pa->pa_count; idx++)
+ pa->pa_array[idx - 1] = pa->pa_array[idx];
+ pa->pa_count--;
+ pa->pa_version++;
+
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+
+ prop_object_release(po);
+}
+
+/*
+ * prop_array_equals --
+ * Return true if the two arrays are equivalent. Note we do a
+ * by-value comparison of the objects in the array.
+ */
+bool
+prop_array_equals(prop_array_t array1, prop_array_t array2)
+{
+ if (!prop_object_is_array(array1) || !prop_object_is_array(array2))
+ return (false);
+
+ return (prop_object_equals(array1, array2));
+}
+
+/*
+ * prop_array_externalize --
+ * Externalize an array, return a NUL-terminated buffer
+ * containing the XML-style representation. The buffer is allocated
+ * with the M_TEMP memory type.
+ */
+char *
+prop_array_externalize(prop_array_t pa)
+{
+ struct _prop_object_externalize_context *ctx;
+ char *cp;
+
+ ctx = _prop_object_externalize_context_alloc();
+ if (ctx == NULL)
+ return (NULL);
+
+ if (_prop_object_externalize_header(ctx) == false ||
+ (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false ||
+ _prop_object_externalize_footer(ctx) == false) {
+ /* We are responsible for releasing the buffer. */
+ _PROP_FREE(ctx->poec_buf, M_TEMP);
+ _prop_object_externalize_context_free(ctx);
+ return (NULL);
+ }
+
+ cp = ctx->poec_buf;
+ _prop_object_externalize_context_free(ctx);
+
+ return (cp);
+}
+
+/*
+ * _prop_array_internalize --
+ * Parse an <array>...</array> and return the object created from the
+ * external representation.
+ */
+static bool _prop_array_internalize_body(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+
+bool
+_prop_array_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ /* We don't currently understand any attributes. */
+ if (ctx->poic_tagattr != NULL)
+ return (true);
+
+ *obj = prop_array_create();
+ /*
+ * We are done if the create failed or no child elements exist.
+ */
+ if (*obj == NULL || ctx->poic_is_empty_element)
+ return (true);
+
+ /*
+ * Opening tag is found, now continue to the first element.
+ */
+ return (_prop_array_internalize_body(stack, obj, ctx));
+}
+
+static bool
+_prop_array_internalize_continue(prop_stack_t stack,
+ prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx,
+ void *data, prop_object_t child)
+{
+ prop_array_t array;
+
+ _PROP_ASSERT(data == NULL);
+
+ if (child == NULL)
+ goto bad; /* Element could not be parsed. */
+
+ array = *obj;
+
+ if (prop_array_add(array, child) == false) {
+ prop_object_release(child);
+ goto bad;
+ }
+ prop_object_release(child);
+
+ /*
+ * Current element is processed and added, look for next.
+ */
+ return (_prop_array_internalize_body(stack, obj, ctx));
+
+ bad:
+ prop_object_release(*obj);
+ *obj = NULL;
+ return (true);
+}
+
+static bool
+_prop_array_internalize_body(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ prop_array_t array = *obj;
+
+ _PROP_ASSERT(array != NULL);
+
+ /* Fetch the next tag. */
+ if (_prop_object_internalize_find_tag(ctx, NULL,
+ _PROP_TAG_TYPE_EITHER) == false)
+ goto bad;
+
+ /* Check to see if this is the end of the array. */
+ if (_PROP_TAG_MATCH(ctx, "array") &&
+ ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
+ /* It is, so don't iterate any further. */
+ return (true);
+ }
+
+ if (_prop_stack_push(stack, array,
+ _prop_array_internalize_continue, NULL, NULL))
+ return (false);
+
+ bad:
+ prop_object_release(array);
+ *obj = NULL;
+ return (true);
+}
+
+/*
+ * prop_array_internalize --
+ * Create an array by parsing the XML-style representation.
+ */
+prop_array_t
+prop_array_internalize(const char *xml)
+{
+ return _prop_generic_internalize(xml, "array");
+}
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+/*
+ * prop_array_externalize_to_file --
+ * Externalize an array to the specified file.
+ */
+bool
+prop_array_externalize_to_file(prop_array_t array, const char *fname)
+{
+ char *xml;
+ bool rv;
+ int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */
+
+ xml = prop_array_externalize(array);
+ if (xml == NULL)
+ return (false);
+ rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
+ if (rv == false)
+ save_errno = errno;
+ _PROP_FREE(xml, M_TEMP);
+ if (rv == false)
+ errno = save_errno;
+
+ return (rv);
+}
+
+/*
+ * prop_array_internalize_from_file --
+ * Internalize an array from a file.
+ */
+prop_array_t
+prop_array_internalize_from_file(const char *fname)
+{
+ struct _prop_object_internalize_mapped_file *mf;
+ prop_array_t array;
+
+ mf = _prop_object_internalize_map_file(fname);
+ if (mf == NULL)
+ return (NULL);
+ array = prop_array_internalize(mf->poimf_xml);
+ _prop_object_internalize_unmap_file(mf);
+
+ return (array);
+}
+#endif /* _KERNEL && !_STANDALONE */
--- /dev/null
+.\" $NetBSD: prop_array_util.3,v 1.7 2011/10/17 09:24:54 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd March 12, 2011
+.Dt PROP_ARRAY_UTIL 3
+.Os
+.Sh NAME
+.Nm prop_array_util ,
+.Nm prop_array_get_bool ,
+.Nm prop_array_set_bool ,
+.Nm prop_array_get_int8 ,
+.Nm prop_array_get_uint8 ,
+.Nm prop_array_set_int8 ,
+.Nm prop_array_set_uint8 ,
+.Nm prop_array_get_int16 ,
+.Nm prop_array_get_uint16 ,
+.Nm prop_array_set_int16 ,
+.Nm prop_array_set_uint16 ,
+.Nm prop_array_get_int32 ,
+.Nm prop_array_get_uint32 ,
+.Nm prop_array_set_int32 ,
+.Nm prop_array_set_uint32 ,
+.Nm prop_array_get_int64 ,
+.Nm prop_array_get_uint64 ,
+.Nm prop_array_set_int64 ,
+.Nm prop_array_set_uint64 ,
+.Nm prop_array_add_int8 ,
+.Nm prop_array_add_uint8 ,
+.Nm prop_array_add_int16 ,
+.Nm prop_array_add_uint16 ,
+.Nm prop_array_add_int32 ,
+.Nm prop_array_add_uint32 ,
+.Nm prop_array_add_int64 ,
+.Nm prop_array_add_uint64 ,
+.Nm prop_array_get_cstring ,
+.Nm prop_array_set_cstring ,
+.Nm prop_array_get_cstring_nocopy ,
+.Nm prop_array_set_cstring_nocopy ,
+.Nm prop_array_add_and_rel
+.Nd array property collection object utility functions
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft bool
+.Fn prop_array_get_bool "prop_array_t dict" "unsigned int indx" \
+ "bool *valp"
+.Ft bool
+.Fn prop_array_set_bool "prop_array_t dict" "unsigned int indx" \
+ "bool val"
+.\"
+.Ft bool
+.Fn prop_array_get_int8 "prop_array_t dict" "unsigned int indx" \
+ "int8_t *valp"
+.Ft bool
+.Fn prop_array_get_uint8 "prop_array_t dict" "unsigned int indx" \
+ "uint8_t *valp"
+.Ft bool
+.Fn prop_array_set_int8 "prop_array_t dict" "unsigned int indx" \
+ "int8_t val"
+.Ft bool
+.Fn prop_array_set_uint8 "prop_array_t dict" "unsigned int indx" \
+ "uint8_t val"
+.\"
+.Ft bool
+.Fn prop_array_get_int16 "prop_array_t dict" "unsigned int indx" \
+ "int16_t *valp"
+.Ft bool
+.Fn prop_array_get_uint16 "prop_array_t dict" "unsigned int indx" \
+ "uint16_t *valp"
+.Ft bool
+.Fn prop_array_set_int16 "prop_array_t dict" "unsigned int indx" \
+ "int16_t val"
+.Ft bool
+.Fn prop_array_set_uint16 "prop_array_t dict" "unsigned int indx" \
+ "uint16_t val"
+.\"
+.Ft bool
+.Fn prop_array_get_int32 "prop_array_t dict" "unsigned int indx" \
+ "int32_t *valp"
+.Ft bool
+.Fn prop_array_get_uint32 "prop_array_t dict" "unsigned int indx" \
+ "uint32_t *valp"
+.Ft bool
+.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \
+ "int32_t val"
+.Ft bool
+.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \
+ "uint32_t val"
+.\"
+.Ft bool
+.Fn prop_array_get_int64 "prop_array_t dict" "unsigned int indx" \
+ "int64_t *valp"
+.Ft bool
+.Fn prop_array_get_uint64 "prop_array_t dict" "unsigned int indx" \
+ "uint64_t *valp"
+.Ft bool
+.Fn prop_array_set_int64 "prop_array_t dict" "unsigned int indx" \
+ "int64_t val"
+.Ft bool
+.Fn prop_array_set_uint64 "prop_array_t dict" "unsigned int indx" \
+ "uint64_t val"
+.\"
+.Ft bool
+.Fn prop_array_set_int32 "prop_array_t dict" "unsigned int indx" \
+ "int32_t val"
+.Ft bool
+.Fn prop_array_set_uint32 "prop_array_t dict" "unsigned int indx" \
+ "uint32_t val"
+.\"
+.Ft bool
+.Fn prop_array_add_int8 "prop_array_t dict" "int8_t val"
+.Ft bool
+.Fn prop_array_add_uint8 "prop_array_t dict" "uint8_t val"
+.Ft bool
+.Fn prop_array_add_int16 "prop_array_t dict" "int16_t val"
+.Ft bool
+.Fn prop_array_add_uint16 "prop_array_t dict" "uint16_t val"
+.Ft bool
+.Fn prop_array_add_int32 "prop_array_t dict" "int32_t val"
+.Ft bool
+.Fn prop_array_add_uint32 "prop_array_t dict" "uint32_t val"
+.Ft bool
+.Fn prop_array_add_int64 "prop_array_t dict" "int64_t val"
+.Ft bool
+.Fn prop_array_add_uint64 "prop_array_t dict" "uint64_t val"
+.\"
+.Ft bool
+.Fn prop_array_get_cstring "prop_array_t dict" "unsigned int indx" \
+ "char **strp"
+.Ft bool
+.Fn prop_array_set_cstring "prop_array_t dict" "unsigned int indx" \
+ "const char *str"
+.\"
+.Ft bool
+.Fn prop_array_get_cstring_nocopy "prop_array_t dict" \
+ "unsigned int indx" "const char **strp"
+.Ft bool
+.Fn prop_array_set_cstring_nocopy "prop_array_t dict" \
+ "unsigned int indx" "const char *strp"
+.Ft bool
+.Fn prop_array_add_and_rel "prop_array_t dict" \
+ "prop_object_t obj"
+.Sh DESCRIPTION
+The
+.Nm prop_array_util
+family of functions are provided to make getting and setting values in
+arrays more convenient in some applications.
+.Pp
+The getters check the type of the returned object and, in some cases, also
+ensure that the returned value is within the range implied by the getter's
+value type.
+.Pp
+The setters handle object creation and release for the caller.
+.Pp
+The
+.Fn prop_array_get_cstring
+function returns dynamically allocated memory.
+See
+.Xr prop_string 3
+for more information.
+.Pp
+The
+.Fn prop_array_get_cstring_nocopy
+and
+.Fn prop_array_set_cstring_nocopy
+functions do not copy the string that is set or returned.
+See
+.Xr prop_string 3
+for more information.
+.Pp
+The
+.Fn prop_array_add_and_rel
+function adds the object to the end of the array and releases it.
+The object is also released on failure.
+.Sh RETURN VALUES
+The
+.Nm prop_array_util
+getter functions return
+.Dv true
+if the object exists in the array and the value is in-range, or
+.Dv false
+otherwise.
+.Pp
+The
+.Nm prop_array_util
+setter functions return
+.Dv true
+if creating the object and storing it in the array is successful, or
+.Dv false
+otherwise.
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_number 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_array_util.c,v 1.3 2011/03/24 17:05:39 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Utility routines to make it more convenient to work with values
+ * stored in array.
+ *
+ * Note: There is no special magic going on here. We use the standard
+ * proplib(3) APIs to do all of this work. Any application could do
+ * exactly what we're doing here.
+ */
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h" /* hide kernel vs. not-kernel vs. standalone */
+
+bool
+prop_array_get_bool(prop_array_t array,
+ unsigned int indx,
+ bool *valp)
+{
+ prop_bool_t b;
+
+ b = prop_array_get(array, indx);
+ if (prop_object_type(b) != PROP_TYPE_BOOL)
+ return (false);
+
+ *valp = prop_bool_true(b);
+
+ return (true);
+}
+
+bool
+prop_array_set_bool(prop_array_t array,
+ unsigned int indx,
+ bool val)
+{
+ prop_bool_t b;
+ int rv;
+
+ b = prop_bool_create(val);
+ if (b == NULL)
+ return (false);
+ rv = prop_array_set(array, indx, b);
+ prop_object_release(b);
+
+ return (rv);
+}
+
+#define TEMPLATE(size) \
+bool \
+prop_array_get_int ## size (prop_array_t array, \
+ unsigned int indx, \
+ int ## size ## _t *valp) \
+{ \
+ prop_number_t num; \
+ \
+ num = prop_array_get(array, indx); \
+ if (prop_object_type(num) != PROP_TYPE_NUMBER) \
+ return (false); \
+ \
+ if (prop_number_unsigned(num) && \
+ prop_number_unsigned_integer_value(num) > \
+ /*CONSTCOND*/((size) == 8 ? INT8_MAX : \
+ (size) == 16 ? INT16_MAX : \
+ (size) == 32 ? INT32_MAX : INT64_MAX)) { \
+ return (false); \
+ } \
+ \
+ if (prop_number_size(num) > (size)) \
+ return (false); \
+ \
+ *valp = (int ## size ## _t) prop_number_integer_value(num); \
+ \
+ return (true); \
+} \
+ \
+bool \
+prop_array_get_uint ## size (prop_array_t array, \
+ unsigned int indx, \
+ uint ## size ## _t *valp) \
+{ \
+ prop_number_t num; \
+ \
+ num = prop_array_get(array, indx); \
+ if (prop_object_type(num) != PROP_TYPE_NUMBER) \
+ return (false); \
+ \
+ if (prop_number_unsigned(num) == false && \
+ prop_number_integer_value(num) < 0) { \
+ return (false); \
+ } \
+ \
+ if (prop_number_size(num) > (size)) \
+ return (false); \
+ \
+ *valp = (uint ## size ## _t) \
+ prop_number_unsigned_integer_value(num); \
+ \
+ return (true); \
+} \
+ \
+bool \
+ prop_array_set_int ## size (prop_array_t array, \
+ unsigned int indx, \
+ int ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_integer((int64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_array_set(array, indx, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+} \
+ \
+bool \
+prop_array_set_uint ## size (prop_array_t array, \
+ unsigned int indx, \
+ uint ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_unsigned_integer((uint64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_array_set(array, indx, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+} \
+ \
+bool \
+prop_array_add_int ## size (prop_array_t array, \
+ int ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_integer((int64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_array_add(array, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+} \
+ \
+bool \
+prop_array_add_uint ## size (prop_array_t array, \
+ uint ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_integer((int64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_array_add(array, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+}
+
+TEMPLATE(8)
+TEMPLATE(16)
+TEMPLATE(32)
+TEMPLATE(64)
+
+#undef TEMPLATE
+
+#define TEMPLATE(variant, qualifier) \
+bool \
+prop_array_get_cstring ## variant (prop_array_t array, \
+ unsigned int indx, \
+ qualifier char **cpp) \
+{ \
+ prop_string_t str; \
+ \
+ str = prop_array_get(array, indx); \
+ if (prop_object_type(str) != PROP_TYPE_STRING) \
+ return (false); \
+ \
+ *cpp = prop_string_cstring ## variant (str); \
+ \
+ return (*cpp == NULL ? false : true); \
+} \
+ \
+bool \
+prop_array_set_cstring ## variant (prop_array_t array, \
+ unsigned int indx, \
+ const char *cp) \
+{ \
+ prop_string_t str; \
+ int rv; \
+ \
+ str = prop_string_create_cstring ## variant (cp); \
+ if (str == NULL) \
+ return (false); \
+ rv = prop_array_set(array, indx, str); \
+ prop_object_release(str); \
+ \
+ return (rv); \
+}
+
+TEMPLATE(,)
+TEMPLATE(_nocopy,const)
+
+#undef TEMPLATE
+
+bool
+prop_array_add_and_rel(prop_array_t array, prop_object_t po)
+{
+ bool ret;
+ if (po == NULL)
+ return false;
+ ret = prop_array_add(array, po);
+ prop_object_release(po);
+ return ret;
+}
--- /dev/null
+.\" $NetBSD: prop_bool.3,v 1.6 2008/08/03 03:11:28 thorpej Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd April 22, 2006
+.Dt PROP_BOOL 3
+.Os
+.Sh NAME
+.Nm prop_bool ,
+.Nm prop_bool_create ,
+.Nm prop_bool_copy ,
+.Nm prop_bool_true
+.Nd boolean value property object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_bool_t
+.Fn prop_bool_create "bool val"
+.Ft prop_bool_t
+.Fn prop_bool_copy "prop_bool_t bool"
+.\"
+.Ft bool
+.Fn prop_bool_true "prop_bool_t bool"
+.Sh DESCRIPTION
+The
+.Nm prop_bool
+family of functions operate on a boolean value property object type.
+.Bl -tag -width "xxxxx"
+.It Fn prop_bool_create "bool val"
+Create a boolean value object with the value
+.Fa val .
+.It Fn prop_bool_copy "prop_bool_t bool"
+Copy a boolean value object.
+If the supplied object isn't a boolean,
+.Dv NULL
+is returned.
+.It Fn prop_bool_true "prop_bool_t bool"
+Returns the value of the boolean value object.
+If the supplied object isn't a boolean,
+.Dv false
+is returned.
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_bool.c,v 1.17 2009/01/03 18:31:33 pooka Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_bool.h>
+#include "prop_object_impl.h"
+
+struct _prop_bool {
+ struct _prop_object pb_obj;
+ bool pb_value;
+};
+
+static struct _prop_bool _prop_bool_true;
+static struct _prop_bool _prop_bool_false;
+
+static _prop_object_free_rv_t
+ _prop_bool_free(prop_stack_t, prop_object_t *);
+static bool _prop_bool_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_bool_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+
+static const struct _prop_object_type _prop_object_type_bool = {
+ .pot_type = PROP_TYPE_BOOL,
+ .pot_free = _prop_bool_free,
+ .pot_extern = _prop_bool_externalize,
+ .pot_equals = _prop_bool_equals,
+};
+
+#define prop_object_is_bool(x) \
+ ((x) != NULL && (x)->pb_obj.po_type == &_prop_object_type_bool)
+
+/* ARGSUSED */
+static _prop_object_free_rv_t
+_prop_bool_free(prop_stack_t stack, prop_object_t *obj)
+{
+ /*
+ * This should never happen as we "leak" our initial reference
+ * count.
+ */
+
+ /* XXX forced assertion failure? */
+ return (_PROP_OBJECT_FREE_DONE);
+}
+
+static bool
+_prop_bool_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_bool_t pb = v;
+
+ return (_prop_object_externalize_empty_tag(ctx,
+ pb->pb_value ? "true" : "false"));
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_bool_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_bool_t b1 = v1;
+ prop_bool_t b2 = v2;
+
+ if (! (prop_object_is_bool(b1) &&
+ prop_object_is_bool(b2)))
+ return (_PROP_OBJECT_EQUALS_FALSE);
+
+ /*
+ * Since we only ever allocate one true and one false,
+ * save ourselves a couple of memory operations.
+ */
+ if (b1 == b2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+ else
+ return (_PROP_OBJECT_EQUALS_FALSE);
+}
+
+_PROP_ONCE_DECL(_prop_bool_init_once)
+
+static int
+_prop_bool_init(void)
+{
+
+ _prop_object_init(&_prop_bool_true.pb_obj,
+ &_prop_object_type_bool);
+ _prop_bool_true.pb_value = true;
+
+ _prop_object_init(&_prop_bool_false.pb_obj,
+ &_prop_object_type_bool);
+ _prop_bool_false.pb_value = false;
+
+ return 0;
+}
+
+static prop_bool_t
+_prop_bool_alloc(bool val)
+{
+ prop_bool_t pb;
+
+ _PROP_ONCE_RUN(_prop_bool_init_once, _prop_bool_init);
+ pb = val ? &_prop_bool_true : &_prop_bool_false;
+ prop_object_retain(pb);
+
+ return (pb);
+}
+
+/*
+ * prop_bool_create --
+ * Create a prop_bool_t and initialize it with the
+ * provided boolean value.
+ */
+prop_bool_t
+prop_bool_create(bool val)
+{
+
+ return (_prop_bool_alloc(val));
+}
+
+/*
+ * prop_bool_copy --
+ * Copy a prop_bool_t.
+ */
+prop_bool_t
+prop_bool_copy(prop_bool_t opb)
+{
+
+ if (! prop_object_is_bool(opb))
+ return (NULL);
+
+ /*
+ * Because we only ever allocate one true and one false, this
+ * can be reduced to a simple retain operation.
+ */
+ prop_object_retain(opb);
+ return (opb);
+}
+
+/*
+ * prop_bool_true --
+ * Get the value of a prop_bool_t.
+ */
+bool
+prop_bool_true(prop_bool_t pb)
+{
+
+ if (! prop_object_is_bool(pb))
+ return (false);
+
+ return (pb->pb_value);
+}
+
+/*
+ * prop_bool_equals --
+ * Return true if the boolean values are equivalent.
+ */
+bool
+prop_bool_equals(prop_bool_t b1, prop_bool_t b2)
+{
+ if (!prop_object_is_bool(b1) || !prop_object_is_bool(b2))
+ return (false);
+
+ return (prop_object_equals(b1, b2));
+}
+
+/*
+ * _prop_bool_internalize --
+ * Parse a <true/> or <false/> and return the object created from
+ * the external representation.
+ */
+
+/* ARGSUSED */
+bool
+_prop_bool_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ bool val;
+
+ /* No attributes, and it must be an empty element. */
+ if (ctx->poic_tagattr != NULL ||
+ ctx->poic_is_empty_element == false)
+ return (true);
+
+ if (_PROP_TAG_MATCH(ctx, "true"))
+ val = true;
+ else {
+ _PROP_ASSERT(_PROP_TAG_MATCH(ctx, "false"));
+ val = false;
+ }
+ *obj = prop_bool_create(val);
+ return (true);
+}
--- /dev/null
+.\" $NetBSD: prop_copyin_ioctl.9,v 1.9 2011/01/20 10:47:33 wiz Exp $
+.\"
+.\" Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 17, 2011
+.Dt PROP_COPYIN_IOCTL 9
+.Os
+.Sh NAME
+.Nm prop_array_copyin_ioctl ,
+.Nm prop_array_copyout_ioctl ,
+.Nm prop_array_copyin ,
+.Nm prop_array_copyout ,
+.Nm prop_dictionary_copyin_ioctl ,
+.Nm prop_dictionary_copyout_ioctl ,
+.Nm prop_dictionary_copyin ,
+.Nm prop_dictionary_copyout
+.Nd Copy property lists to and from kernel space
+.Sh SYNOPSIS
+.In prop/proplib.h
+.Ft int
+.Fn prop_array_copyin_ioctl "const struct plistref *pref" \
+ "const u_long cmd" "prop_array_t *arrayp"
+.Ft int
+.Fn prop_array_copyin "const struct plistref *pref" \
+ "prop_array_t *arrayp"
+.Ft int
+.Fn prop_array_copyout_ioctl "struct plistref *pref" \
+ "const u_long cmd" "prop_array_t array"
+.Ft int
+.Fn prop_array_copyout "struct plistref *pref" \
+ "prop_array_t array"
+.Ft int
+.Fn prop_dictionary_copyin_ioctl "const struct plistref *pref" \
+ "const u_long cmd" "prop_dictionary_t *dictp"
+.Ft int
+.Fn prop_dictionary_copyin "const struct plistref *pref" \
+ "prop_dictionary_t *dictp"
+.Ft int
+.Fn prop_dictionary_copyout_ioctl "struct plistref *pref" \
+ "const u_long cmd" "prop_dictionary_t dict"
+.Ft int
+.Fn prop_dictionary_copyout "struct plistref *pref" \
+ "prop_dictionary_t dict"
+.Sh DESCRIPTION
+The
+.Nm prop_array_copyin_ioctl ,
+.Nm prop_array_copyout_ioctl ,
+.Nm prop_dictionary_copyin_ioctl ,
+and
+.Nm prop_dictionary_copyout_ioctl
+functions implement the kernel side of a protocol for copying property lists
+to and from the kernel using
+.Xr ioctl 2 .
+The functions
+.Nm prop_array_copyin ,
+.Nm prop_array_copyout ,
+.Nm prop_dictionary_copyin ,
+and
+.Nm prop_dictionary_copyout
+implement the kernel side of a protocol for copying property lists to the
+kernel as arguments of normal system calls.
+.Pp
+A kernel routine receiving or returning a property list will be passed a
+pointer to a
+.Vt struct plistref .
+This structure encapsulates the reference to the property list in externalized
+form.
+.Sh RETURN VALUES
+If successful, functions return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh EXAMPLES
+The following
+.Pq simplified
+example demonstrates using
+.Fn prop_dictionary_copyin_ioctl
+and
+.Fn prop_dictionary_copyout_ioctl
+in an ioctl routine:
+.Bd -literal
+extern prop_dictionary_t fooprops;
+
+int
+fooioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
+{
+ prop_dictionary_t dict, odict;
+ int error;
+
+ switch (cmd) {
+ case FOOSETPROPS: {
+ const struct plistref *pref = (const struct plistref *) data;
+ error = prop_dictionary_copyin_ioctl(pref, cmd, \*[Am]dict);
+ if (error)
+ return (error);
+ odict = fooprops;
+ fooprops = dict;
+ prop_object_release(odict);
+ break;
+ }
+
+ case FOOGETPROPS: {
+ struct plistref *pref = (struct plistref *) data;
+ error = prop_dictionary_copyout_ioctl(pref, cmd, fooprops);
+ break;
+ }
+
+ default:
+ return (EPASSTHROUGH);
+ }
+ return (error);
+}
+.Ed
+.Pp
+The following
+.Pq simplified
+example demonstrates using
+.Fn prop_array_copyin
+in a routine:
+.Bd -literal
+int
+foocopyin(const struct plistref *pref))
+{
+ prop_array_t array;
+ int error;
+
+ error = prop_array_copyin(pref, \*[Am]array);
+ if (error)
+ return (error);
+ ...
+}
+.Ed
+.Sh ERRORS
+.Fn prop_array_copyin_ioctl
+and
+.Fn prop_dictionary_copyin_ioctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Bad address
+.It Bq Er EIO
+Input/output error
+.It Bq Er ENOMEM
+Cannot allocate memory
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Pp
+.Fn prop_array_copyout_ioctl
+and
+.Fn prop_dictionary_copyout_ioctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EFAULT
+Bad address
+.It Bq Er ENOMEM
+Cannot allocate memory
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_send_ioctl 3 ,
+.Xr prop_send_syscall 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+.\" $NetBSD: prop_data.3,v 1.7 2009/12/14 06:03:23 dholland Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd April 22, 2006
+.Dt PROP_DATA 3
+.Os
+.Sh NAME
+.Nm prop_data ,
+.Nm prop_data_create_data ,
+.Nm prop_data_create_data_nocopy ,
+.Nm prop_data_copy ,
+.Nm prop_data_size ,
+.Nm prop_data_data ,
+.Nm prop_data_data_nocopy ,
+.Nm prop_data_equals ,
+.Nm prop_data_equals_data
+.Nd opaque data value property object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_data_t
+.Fn prop_data_create_data "const void *blob" "size_t len"
+.Ft prop_data_t
+.Fn prop_data_create_data_nocopy "const void *blob" "size_t len"
+.\"
+.Ft prop_data_t
+.Fn prop_data_copy "prop_data_t data"
+.\"
+.Ft size_t
+.Fn prop_data_size "prop_data_t data"
+.Ft void *
+.Fn prop_data_data "prop_data_t data"
+.Ft const void *
+.Fn prop_data_data_nocopy "prop_data_t data"
+.\"
+.Ft bool
+.Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2"
+.Ft bool
+.Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len"
+.Sh DESCRIPTION
+The
+.Nm prop_data
+family of functions operate on an opaque data value property object type.
+.Bl -tag -width "xxxxx"
+.It Fn prop_data_create_data "const void *blob" "size_t len"
+Create a data object that contains a copy of
+.Fa blob
+with size
+.Fa len .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_data_create_data_nocopy "const void *blob" "size_t len"
+Create a data object that contains a reference to
+.Fa blob
+with size
+.Fa len .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_data_copy "prop_data_t data"
+Copy a data object.
+If the data object being copied is an external data reference,
+then the copy also references the same external data.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_data_size "prop_data_t data"
+Returns the size of the data object.
+If the supplied object isn't a data object, zero is returned.
+.It Fn prop_data_data "prop_data_t data"
+Returns a copy of the data object's contents.
+The caller is responsible for freeing the returned buffer.
+If the supplied object isn't a data object or
+if the data container is empty,
+.Dv NULL
+is returned.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.It Fn prop_data_data_nocopy "prop_data_t data"
+Returns an immutable reference to the contents of the data object.
+If the supplied object isn't a data object,
+.Dv NULL
+is returned.
+.It Fn prop_data_equals "prop_data_t dat1" "prop_data_t dat2"
+Returns
+.Dv true
+if the two data objects are equivalent.
+If at least one of the supplied objects isn't a data object,
+.Dv false
+is returned.
+.It Fn prop_data_equals_data "prop_data_t data" "const void *blob" "size_t len"
+Returns
+.Dv true
+if the data object's value is equivalent to
+.Fa blob
+with size
+.Fa len .
+If the supplied object isn't a data object,
+.Dv false
+is returned.
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_data.c,v 1.14 2009/01/25 06:59:35 cyber Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_data.h>
+#include "prop_object_impl.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#elif defined(_STANDALONE)
+#include <sys/param.h>
+#include <lib/libkern/libkern.h>
+#else
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#endif
+
+struct _prop_data {
+ struct _prop_object pd_obj;
+ union {
+ void * pdu_mutable;
+ const void * pdu_immutable;
+ } pd_un;
+#define pd_mutable pd_un.pdu_mutable
+#define pd_immutable pd_un.pdu_immutable
+ size_t pd_size;
+ int pd_flags;
+};
+
+#define PD_F_NOCOPY 0x01
+
+_PROP_POOL_INIT(_prop_data_pool, sizeof(struct _prop_data), "propdata")
+
+_PROP_MALLOC_DEFINE(M_PROP_DATA, "prop data",
+ "property data container object")
+
+static _prop_object_free_rv_t
+ _prop_data_free(prop_stack_t, prop_object_t *);
+static bool _prop_data_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_data_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+
+static const struct _prop_object_type _prop_object_type_data = {
+ .pot_type = PROP_TYPE_DATA,
+ .pot_free = _prop_data_free,
+ .pot_extern = _prop_data_externalize,
+ .pot_equals = _prop_data_equals,
+};
+
+#define prop_object_is_data(x) \
+ ((x) != NULL && (x)->pd_obj.po_type == &_prop_object_type_data)
+
+/* ARGSUSED */
+static _prop_object_free_rv_t
+_prop_data_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_data_t pd = *obj;
+
+ if ((pd->pd_flags & PD_F_NOCOPY) == 0 && pd->pd_mutable != NULL)
+ _PROP_FREE(pd->pd_mutable, M_PROP_DATA);
+ _PROP_POOL_PUT(_prop_data_pool, pd);
+
+ return (_PROP_OBJECT_FREE_DONE);
+}
+
+static const char _prop_data_base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char _prop_data_pad64 = '=';
+
+static bool
+_prop_data_externalize(struct _prop_object_externalize_context *ctx, void *v)
+{
+ prop_data_t pd = v;
+ size_t i, srclen;
+ const uint8_t *src;
+ uint8_t output[4];
+ uint8_t input[3];
+
+ if (pd->pd_size == 0)
+ return (_prop_object_externalize_empty_tag(ctx, "data"));
+
+ if (_prop_object_externalize_start_tag(ctx, "data") == false)
+ return (false);
+
+ for (src = pd->pd_immutable, srclen = pd->pd_size;
+ srclen > 2; srclen -= 3) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+
+ output[0] = (uint32_t)input[0] >> 2;
+ output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
+ ((uint32_t)input[1] >> 4);
+ output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
+ ((uint32_t)input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ _PROP_ASSERT(output[0] < 64);
+ _PROP_ASSERT(output[1] < 64);
+ _PROP_ASSERT(output[2] < 64);
+ _PROP_ASSERT(output[3] < 64);
+
+ if (_prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[0]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[1]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[2]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[3]]) == false)
+ return (false);
+ }
+
+ if (srclen != 0) {
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclen; i++)
+ input[i] = *src++;
+
+ output[0] = (uint32_t)input[0] >> 2;
+ output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
+ ((uint32_t)input[1] >> 4);
+ output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
+ ((uint32_t)input[2] >> 6);
+ _PROP_ASSERT(output[0] < 64);
+ _PROP_ASSERT(output[1] < 64);
+ _PROP_ASSERT(output[2] < 64);
+
+ if (_prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[0]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_base64[output[1]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ srclen == 1 ? _prop_data_pad64
+ : _prop_data_base64[output[2]]) == false ||
+ _prop_object_externalize_append_char(ctx,
+ _prop_data_pad64) == false)
+ return (false);
+ }
+
+ if (_prop_object_externalize_end_tag(ctx, "data") == false)
+ return (false);
+
+ return (true);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_data_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_data_t pd1 = v1;
+ prop_data_t pd2 = v2;
+
+ if (pd1 == pd2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+ if (pd1->pd_size != pd2->pd_size)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ if (pd1->pd_size == 0) {
+ _PROP_ASSERT(pd1->pd_immutable == NULL);
+ _PROP_ASSERT(pd2->pd_immutable == NULL);
+ return (_PROP_OBJECT_EQUALS_TRUE);
+ }
+ if (memcmp(pd1->pd_immutable, pd2->pd_immutable, pd1->pd_size) == 0)
+ return _PROP_OBJECT_EQUALS_TRUE;
+ else
+ return _PROP_OBJECT_EQUALS_FALSE;
+}
+
+static prop_data_t
+_prop_data_alloc(void)
+{
+ prop_data_t pd;
+
+ pd = _PROP_POOL_GET(_prop_data_pool);
+ if (pd != NULL) {
+ _prop_object_init(&pd->pd_obj, &_prop_object_type_data);
+
+ pd->pd_mutable = NULL;
+ pd->pd_size = 0;
+ pd->pd_flags = 0;
+ }
+
+ return (pd);
+}
+
+/*
+ * prop_data_create_data --
+ * Create a data container that contains a copy of the data.
+ */
+prop_data_t
+prop_data_create_data(const void *v, size_t size)
+{
+ prop_data_t pd;
+ void *nv;
+
+ pd = _prop_data_alloc();
+ if (pd != NULL && size != 0) {
+ nv = _PROP_MALLOC(size, M_PROP_DATA);
+ if (nv == NULL) {
+ prop_object_release(pd);
+ return (NULL);
+ }
+ memcpy(nv, v, size);
+ pd->pd_mutable = nv;
+ pd->pd_size = size;
+ }
+ return (pd);
+}
+
+/*
+ * prop_data_create_data_nocopy --
+ * Create an immutable data container that contains a refrence to the
+ * provided external data.
+ */
+prop_data_t
+prop_data_create_data_nocopy(const void *v, size_t size)
+{
+ prop_data_t pd;
+
+ pd = _prop_data_alloc();
+ if (pd != NULL) {
+ pd->pd_immutable = v;
+ pd->pd_size = size;
+ pd->pd_flags |= PD_F_NOCOPY;
+ }
+ return (pd);
+}
+
+/*
+ * prop_data_copy --
+ * Copy a data container. If the original data is external, then
+ * the copy is also references the same external data.
+ */
+prop_data_t
+prop_data_copy(prop_data_t opd)
+{
+ prop_data_t pd;
+
+ if (! prop_object_is_data(opd))
+ return (NULL);
+
+ pd = _prop_data_alloc();
+ if (pd != NULL) {
+ pd->pd_size = opd->pd_size;
+ pd->pd_flags = opd->pd_flags;
+ if (opd->pd_flags & PD_F_NOCOPY)
+ pd->pd_immutable = opd->pd_immutable;
+ else if (opd->pd_size != 0) {
+ void *nv = _PROP_MALLOC(pd->pd_size, M_PROP_DATA);
+ if (nv == NULL) {
+ prop_object_release(pd);
+ return (NULL);
+ }
+ memcpy(nv, opd->pd_immutable, opd->pd_size);
+ pd->pd_mutable = nv;
+ }
+ }
+ return (pd);
+}
+
+/*
+ * prop_data_size --
+ * Return the size of the data.
+ */
+size_t
+prop_data_size(prop_data_t pd)
+{
+
+ if (! prop_object_is_data(pd))
+ return (0);
+
+ return (pd->pd_size);
+}
+
+/*
+ * prop_data_data --
+ * Return a copy of the contents of the data container.
+ * The data is allocated with the M_TEMP malloc type.
+ * If the data container is empty, NULL is returned.
+ */
+void *
+prop_data_data(prop_data_t pd)
+{
+ void *v;
+
+ if (! prop_object_is_data(pd))
+ return (NULL);
+
+ if (pd->pd_size == 0) {
+ _PROP_ASSERT(pd->pd_immutable == NULL);
+ return (NULL);
+ }
+
+ _PROP_ASSERT(pd->pd_immutable != NULL);
+
+ v = _PROP_MALLOC(pd->pd_size, M_TEMP);
+ if (v != NULL)
+ memcpy(v, pd->pd_immutable, pd->pd_size);
+
+ return (v);
+}
+
+/*
+ * prop_data_data_nocopy --
+ * Return an immutable reference to the contents of the data
+ * container.
+ */
+const void *
+prop_data_data_nocopy(prop_data_t pd)
+{
+
+ if (! prop_object_is_data(pd))
+ return (NULL);
+
+ _PROP_ASSERT((pd->pd_size == 0 && pd->pd_immutable == NULL) ||
+ (pd->pd_size != 0 && pd->pd_immutable != NULL));
+
+ return (pd->pd_immutable);
+}
+
+/*
+ * prop_data_equals --
+ * Return true if two strings are equivalent.
+ */
+bool
+prop_data_equals(prop_data_t pd1, prop_data_t pd2)
+{
+ if (!prop_object_is_data(pd1) || !prop_object_is_data(pd2))
+ return (false);
+
+ return (prop_object_equals(pd1, pd2));
+}
+
+/*
+ * prop_data_equals_data --
+ * Return true if the contained data is equivalent to the specified
+ * external data.
+ */
+bool
+prop_data_equals_data(prop_data_t pd, const void *v, size_t size)
+{
+
+ if (! prop_object_is_data(pd))
+ return (false);
+
+ if (pd->pd_size != size)
+ return (false);
+ return (memcmp(pd->pd_immutable, v, size) == 0);
+}
+
+static bool
+_prop_data_internalize_decode(struct _prop_object_internalize_context *ctx,
+ uint8_t *target, size_t targsize, size_t *sizep,
+ const char **cpp)
+{
+ const char *src;
+ size_t tarindex;
+ int state, ch;
+ const char *pos;
+
+ state = 0;
+ tarindex = 0;
+ src = ctx->poic_cp;
+
+ for (;;) {
+ ch = (unsigned char) *src++;
+ if (_PROP_EOF(ch))
+ return (false);
+ if (_PROP_ISSPACE(ch))
+ continue;
+ if (ch == '<') {
+ src--;
+ break;
+ }
+ if (ch == _prop_data_pad64)
+ break;
+
+ pos = strchr(_prop_data_base64, ch);
+ if (pos == NULL)
+ return (false);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if (tarindex >= targsize)
+ return (false);
+ target[tarindex] =
+ (uint8_t)((pos - _prop_data_base64) << 2);
+ }
+ state = 1;
+ break;
+
+ case 1:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (false);
+ target[tarindex] |=
+ (uint32_t)(pos - _prop_data_base64) >> 4;
+ target[tarindex + 1] =
+ (uint8_t)(((pos - _prop_data_base64) & 0xf)
+ << 4);
+ }
+ tarindex++;
+ state = 2;
+ break;
+
+ case 2:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (false);
+ target[tarindex] |=
+ (uint32_t)(pos - _prop_data_base64) >> 2;
+ target[tarindex + 1] =
+ (uint8_t)(((pos - _prop_data_base64)
+ & 0x3) << 6);
+ }
+ tarindex++;
+ state = 3;
+ break;
+
+ case 3:
+ if (target) {
+ if (tarindex >= targsize)
+ return (false);
+ target[tarindex] |= (uint8_t)
+ (pos - _prop_data_base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+
+ default:
+ _PROP_ASSERT(/*CONSTCOND*/0);
+ }
+ }
+
+ /*
+ * We are done decoding the Base64 characters. Let's see if we
+ * ended up on a byte boundary and/or with unrecognized trailing
+ * characters.
+ */
+ if (ch == _prop_data_pad64) {
+ ch = (unsigned char) *src; /* src already advanced */
+ if (_PROP_EOF(ch))
+ return (false);
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (false);
+
+ case 2: /* Valid, one byte of info */
+ /* Skip whitespace */
+ for (ch = (unsigned char) *src++;
+ ch != '<'; ch = (unsigned char) *src++) {
+ if (_PROP_EOF(ch))
+ return (false);
+ if (!_PROP_ISSPACE(ch))
+ break;
+ }
+ /* Make sure there is another trailing = */
+ if (ch != _prop_data_pad64)
+ return (false);
+ ch = (unsigned char) *src;
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, two bytes of info */
+ /*
+ * We know this char is a =. Is there anything but
+ * whitespace after it?
+ */
+ for (ch = (unsigned char) *src++;
+ ch != '<'; ch = (unsigned char) *src++) {
+ if (_PROP_EOF(ch))
+ return (false);
+ if (!_PROP_ISSPACE(ch))
+ return (false);
+ }
+ /* back up to '<' */
+ src--;
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the Base64 string. Make
+ * sure there are no partial bytes lying around.
+ */
+ if (state != 0)
+ return (false);
+ }
+
+ _PROP_ASSERT(*src == '<');
+ if (sizep != NULL)
+ *sizep = tarindex;
+ if (cpp != NULL)
+ *cpp = src;
+
+ return (true);
+}
+
+/*
+ * _prop_data_internalize --
+ * Parse a <data>...</data> and return the object created from the
+ * external representation.
+ */
+
+/* strtoul is used for parsing, enforce. */
+typedef int PROP_DATA_ASSERT[/* CONSTCOND */sizeof(size_t) == sizeof(unsigned long) ? 1 : -1];
+
+/* ARGSUSED */
+bool
+_prop_data_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ prop_data_t data;
+ uint8_t *buf;
+ size_t len, alen;
+
+ /*
+ * We don't accept empty elements.
+ * This actually only checks for the node to be <data/>
+ * (Which actually causes another error if found.)
+ */
+ if (ctx->poic_is_empty_element)
+ return (true);
+
+ /*
+ * If we got a "size" attribute, get the size of the data blob
+ * from that. Otherwise, we have to figure it out from the base64.
+ */
+ if (ctx->poic_tagattr != NULL) {
+ char *cp;
+
+ if (!_PROP_TAGATTR_MATCH(ctx, "size") ||
+ ctx->poic_tagattrval_len == 0)
+ return (true);
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ len = strtoul(ctx->poic_tagattrval, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if (len == ULONG_MAX && errno == ERANGE)
+ return (true);
+#endif
+ if (cp != ctx->poic_tagattrval + ctx->poic_tagattrval_len)
+ return (true);
+ _PROP_ASSERT(*cp == '\"');
+ } else if (_prop_data_internalize_decode(ctx, NULL, 0, &len,
+ NULL) == false)
+ return (true);
+
+ /*
+ * Always allocate one extra in case we don't land on an even byte
+ * boundary during the decode.
+ */
+ buf = _PROP_MALLOC(len + 1, M_PROP_DATA);
+ if (buf == NULL)
+ return (true);
+
+ if (_prop_data_internalize_decode(ctx, buf, len + 1, &alen,
+ &ctx->poic_cp) == false) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (true);
+ }
+ if (alen != len) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (true);
+ }
+
+ if (_prop_object_internalize_find_tag(ctx, "data",
+ _PROP_TAG_TYPE_END) == false) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (true);
+ }
+
+ data = _prop_data_alloc();
+ if (data == NULL) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ return (true);
+ }
+
+ /*
+ * Handle alternate type of empty node.
+ * XML document could contain open/close tags, yet still be empty.
+ */
+ if (alen == 0) {
+ _PROP_FREE(buf, M_PROP_DATA);
+ data->pd_mutable = NULL;
+ } else {
+ data->pd_mutable = buf;
+ }
+ data->pd_size = len;
+
+ *obj = data;
+ return (true);
+}
--- /dev/null
+.\" $NetBSD: prop_dictionary.3,v 1.18 2011/09/30 22:08:18 jym Exp $
+.\"
+.\" Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd December 5, 2009
+.Dt PROP_DICTIONARY 3
+.Os
+.Sh NAME
+.Nm prop_dictionary ,
+.Nm prop_dictionary_create ,
+.Nm prop_dictionary_create_with_capacity ,
+.Nm prop_dictionary_copy ,
+.Nm prop_dictionary_copy_mutable ,
+.Nm prop_dictionary_count ,
+.Nm prop_dictionary_ensure_capacity ,
+.Nm prop_dictionary_iterator ,
+.Nm prop_dictionary_all_keys ,
+.Nm prop_dictionary_make_immutable ,
+.Nm prop_dictionary_mutable ,
+.Nm prop_dictionary_get ,
+.Nm prop_dictionary_set ,
+.Nm prop_dictionary_remove ,
+.Nm prop_dictionary_get_keysym ,
+.Nm prop_dictionary_set_keysym ,
+.Nm prop_dictionary_remove_keysym ,
+.Nm prop_dictionary_externalize ,
+.Nm prop_dictionary_internalize ,
+.Nm prop_dictionary_externalize_to_file ,
+.Nm prop_dictionary_internalize_from_file ,
+.Nm prop_dictionary_externalize_to_pref ,
+.Nm prop_dictionary_internalize_from_pref ,
+.Nm prop_dictionary_equals ,
+.Nm prop_dictionary_keysym_cstring_nocopy ,
+.Nm prop_dictionary_keysym_equals
+.Nd dictionary property collection object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_create "void"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_create_with_capacity "unsigned int capacity"
+.\"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_copy "prop_dictionary_t dict"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_copy_mutable "prop_dictionary_t dict"
+.\"
+.Ft unsigned int
+.Fn prop_dictionary_count "prop_dictionary_t dict"
+.Ft bool
+.Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" \
+ "unsigned int capacity"
+.\"
+.Ft prop_object_iterator_t
+.Fn prop_dictionary_iterator "prop_dictionary_t dict"
+.Ft prop_array_t
+.Fn prop_dictionary_all_keys "prop_dictionary_t dict"
+.\"
+.Ft void
+.Fn prop_dictionary_make_immutable "prop_dictionary_t dict"
+.Ft bool
+.Fn prop_dictionary_mutable "prop_dictionary_t dict"
+.\"
+.Ft prop_object_t
+.Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key"
+.Ft bool
+.Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \
+ "prop_object_t obj"
+.Ft void
+.Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key"
+.\"
+.Ft prop_object_t
+.Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t keysym"
+.Ft bool
+.Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t keysym" "prop_object_t obj"
+.Ft void
+.Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t keysym"
+.\"
+.Ft bool
+.Fn prop_dictionary_equals "prop_dictionary_t dict1" "prop_dictionary_t dict2"
+.\"
+.Ft const char *
+.Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t sym"
+.\"
+.Ft bool
+.Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \
+ "prop_dictionary_keysym_t keysym2"
+.\"
+.Ft char *
+.Fn prop_dictionary_externalize "prop_dictionary_t dict"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_internalize "const char *xml"
+.\"
+.Ft bool
+.Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \
+ "const char *path"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_internalize_from_file "const char *path"
+.\"
+.Ft bool
+.Fn prop_dictionary_externalize_to_pref "prop_dictionary_t dict" \
+ "struct plistref *pref"
+.Ft bool
+.Fn prop_dictionary_internalize_from_pref "const struct plistref *pref" \
+ "prop_dictionary_t *dictp"
+.\"
+.Sh DESCRIPTION
+The
+.Nm prop_dictionary
+family of functions operate on the dictionary property collection object type.
+A dictionary is an unordered set of objects stored as key-value pairs.
+.Bl -tag -width "xxxxx"
+.It Fn prop_dictionary_create "void"
+Create an empty dictionary.
+The dictionary initially has no capacity.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_dictionary_create_with_capacity "unsigned int capacity"
+Create a dictionary with the capacity to store
+.Fa capacity
+objects.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_dictionary_copy "prop_dictionary_t dict"
+Copy a dictionary.
+The new dictionary has an initial capacity equal to the number of objects
+stored in the dictionary being copied.
+The new dictionary contains references to the original dictionary's objects,
+not copies of those objects
+.Pq i.e. a shallow copy is made .
+If the original dictionary is immutable, the resulting dictionary is also
+immutable.
+.It Fn prop_dictionary_copy_mutable "prop_dictionary_t dict"
+Like
+.Fn prop_dictionary_copy ,
+except the resulting dictionary is always mutable.
+.It Fn prop_dictionary_count "prop_dictionary_t dict"
+Returns the number of objects stored in the dictionary.
+.It Fn prop_dictionary_ensure_capacity "prop_dictionary_t dict" \
+ "unsigned int capacity"
+Ensure that the dictionary has a total capacity of
+.Fa capacity ,
+including objects already stored in the dictionary.
+Returns
+.Dv true
+if the capacity of the dictionary is greater or equal to
+.Fa capacity
+or if the expansion of the dictionary's capacity was successful
+and
+.Dv false
+otherwise.
+If the supplied object isn't a dictionary,
+.Dv false
+is returned.
+.It Fn prop_dictionary_iterator "prop_dictionary_t dict"
+Create an iterator for the dictionary.
+The dictionary is retained by the iterator.
+A dictionary iterator returns the key symbols used to look up objects stored
+in the dictionary; to get the object itself, a dictionary lookup using this
+key symbol must be performed.
+Storing to or removing from the dictionary invalidates any active iterators for
+the dictionary.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_dictionary_all_keys "prop_dictionary_t dict"
+Return an array of all of the dictionary key symbols
+.Pq prop_dictionary_keysym_t
+in the dictionary.
+This provides a way to iterate over the items in the dictionary while
+retaining the ability to mutate the dictionary; instead of iterating
+over the dictionary itself, iterate over the array of keys.
+The caller is responsible for releasing the array.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_dictionary_make_immutable "prop_dictionary_t dict"
+Make
+.Fa dict
+immutable.
+.It Fn prop_dictionary_mutable "prop_dictionary_t dict"
+Returns
+.Dv true
+if the dictionary is mutable.
+.It Fn prop_dictionary_get "prop_dictionary_t dict" "const char *key"
+Return the object stored in the dictionary with the key
+.Fa key .
+If no object is stored with the specified key,
+.Dv NULL
+is returned.
+.It Fn prop_dictionary_set "prop_dictionary_t dict" "const char *key" \
+ "prop_object_t obj"
+Store a reference to the object
+.Fa obj
+with the key
+.Fa key .
+The object will be retained by the dictionary.
+If the key already exists in the dictionary, the object associated with
+that key will be released and replaced with the new object.
+Returns
+.Dv true
+if storing the object was successful and
+.Dv false
+otherwise.
+.It Fn prop_dictionary_remove "prop_dictionary_t dict" "const char *key"
+Remove the reference to the object stored in the dictionary with the key
+.Fa key .
+The object will be released.
+.It Fn prop_dictionary_get_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t sym"
+Like
+.Fn prop_dictionary_get ,
+but the lookup is performed using a key symbol returned by a dictionary
+iterator.
+The results are undefined if the iterator used to obtain the key symbol
+is not associated with
+.Fa dict .
+.It Fn prop_dictionary_set_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t sym" "prop_object_t obj"
+Like
+.Fn prop_dictionary_set ,
+but the lookup of the object to replace is performed using a key symbol
+returned by a dictionary iterator.
+The results are undefined if the iterator used to obtain the key symbol
+is not associated with
+.Fa dict .
+.It Fn prop_dictionary_remove_keysym "prop_dictionary_t dict" \
+ "prop_dictionary_keysym_t sym"
+Like
+.Fn prop_dictionary_remove ,
+but the lookup of the object to remove is performed using a key symbol
+returned by a dictionary iterator.
+The results are undefined if the iterator used to obtain the key symbol
+is not associated with
+.Fa dict .
+.It Fn prop_dictionary_equals "prop_dictionary_t dict1" \
+ "prop_dictionary_t dict2"
+Returns
+.Dv true
+if the two dictionaries are equivalent.
+Note: Objects contained in the dictionary are compared by value, not by
+reference.
+.It Fn prop_dictionary_keysym_cstring_nocopy "prop_dictionary_keysym_t keysym"
+Returns an immutable reference to the dictionary key symbol's string value.
+.It Fn prop_dictionary_keysym_equals "prop_dictionary_keysym_t keysym1" \
+ "prop_dictionary_keysym_t keysym2"
+Returns
+.Dv true
+if the two dictionary key symbols are equivalent.
+.It Fn prop_dictionary_externalize "prop_dictionary_t dict"
+Externalizes a dictionary, returning a NUL-terminated buffer containing
+the XML representation of the dictionary.
+The caller is responsible for freeing the returned buffer.
+If converting to the external representation fails for any reason,
+.Dv NULL
+is returned.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.It Fn prop_dictionary_internalize "const char *xml"
+Parse the XML representation of a property list in the NUL-terminated
+buffer
+.Fa xml
+and return the corresponding dictionary.
+Returns
+.Dv NULL
+if parsing fails for any reason.
+.It Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \
+ "const char *path"
+Externalizes a dictionary and writes it to the file specified by
+.Fa path .
+The file is saved with the mode
+.Dv 0666
+as modified by the process's file creation mask
+.Pq see Xr umask 2
+and is written atomically.
+Returns
+.Dv false
+if externalizing or writing the dictionary fails for any reason.
+.It Fn prop_dictionary_internalize_from_file "const char *path"
+Reads the XML property list contained in the file specified by
+.Fa path ,
+internalizes it, and returns the corresponding dictionary.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_dictionary_externalize_to_pref "prop_dictionary_t dict" \
+ "struct plistref *pref"
+Externalizes a dictionary and packs it into the plistref specified by
+.Fa pref .
+Returns
+.Dv false
+if externalizing the dictionary fails for any reason.
+.It Fn prop_dictionary_internalize_from_pref "const struct plistref *pref" \
+ "prop_dictionary_t *dictp"
+Reads the plistref specified by
+.Fa pref ,
+internalizes it, and returns the corresponding dictionary.
+Returns
+.Dv false
+if internalizing or writing the dictionary fails for any reason.
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary_util 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_dictionary.c,v 1.37 2011/04/20 19:40:00 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_array.h>
+#include <prop/prop_dictionary.h>
+#include <prop/prop_string.h>
+#include "prop_object_impl.h"
+#include "prop_rb_impl.h"
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <errno.h>
+#endif
+
+/*
+ * We implement these like arrays, but we keep them sorted by key.
+ * This allows us to binary-search as well as keep externalized output
+ * sane-looking for human eyes.
+ */
+
+#define EXPAND_STEP 16
+
+/*
+ * prop_dictionary_keysym_t is allocated with space at the end to hold the
+ * key. This must be a regular object so that we can maintain sane iterator
+ * semantics -- we don't want to require that the caller release the result
+ * of prop_object_iterator_next().
+ *
+ * We'd like to have some small'ish keysym objects for up-to-16 characters
+ * in a key, some for up-to-32 characters in a key, and then a final bucket
+ * for up-to-128 characters in a key (not including NUL). Keys longer than
+ * 128 characters are not allowed.
+ */
+struct _prop_dictionary_keysym {
+ struct _prop_object pdk_obj;
+ size_t pdk_size;
+ struct rb_node pdk_link;
+ char pdk_key[1];
+ /* actually variable length */
+};
+
+ /* pdk_key[1] takes care of the NUL */
+#define PDK_SIZE_16 (sizeof(struct _prop_dictionary_keysym) + 16)
+#define PDK_SIZE_32 (sizeof(struct _prop_dictionary_keysym) + 32)
+#define PDK_SIZE_128 (sizeof(struct _prop_dictionary_keysym) + 128)
+
+#define PDK_MAXKEY 128
+
+_PROP_POOL_INIT(_prop_dictionary_keysym16_pool, PDK_SIZE_16, "pdict16")
+_PROP_POOL_INIT(_prop_dictionary_keysym32_pool, PDK_SIZE_32, "pdict32")
+_PROP_POOL_INIT(_prop_dictionary_keysym128_pool, PDK_SIZE_128, "pdict128")
+
+struct _prop_dict_entry {
+ prop_dictionary_keysym_t pde_key;
+ prop_object_t pde_objref;
+};
+
+struct _prop_dictionary {
+ struct _prop_object pd_obj;
+ _PROP_RWLOCK_DECL(pd_rwlock)
+ struct _prop_dict_entry *pd_array;
+ unsigned int pd_capacity;
+ unsigned int pd_count;
+ int pd_flags;
+
+ uint32_t pd_version;
+};
+
+#define PD_F_IMMUTABLE 0x01 /* dictionary is immutable */
+
+_PROP_POOL_INIT(_prop_dictionary_pool, sizeof(struct _prop_dictionary),
+ "propdict")
+_PROP_MALLOC_DEFINE(M_PROP_DICT, "prop dictionary",
+ "property dictionary container object")
+
+static _prop_object_free_rv_t
+ _prop_dictionary_free(prop_stack_t, prop_object_t *);
+static void _prop_dictionary_emergency_free(prop_object_t);
+static bool _prop_dictionary_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_dictionary_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+static void _prop_dictionary_equals_finish(prop_object_t, prop_object_t);
+static prop_object_iterator_t
+ _prop_dictionary_iterator_locked(prop_dictionary_t);
+static prop_object_t
+ _prop_dictionary_iterator_next_object_locked(void *);
+static prop_object_t
+ _prop_dictionary_get_keysym(prop_dictionary_t,
+ prop_dictionary_keysym_t, bool);
+static prop_object_t
+ _prop_dictionary_get(prop_dictionary_t, const char *, bool);
+
+static void _prop_dictionary_lock(void);
+static void _prop_dictionary_unlock(void);
+
+static const struct _prop_object_type _prop_object_type_dictionary = {
+ .pot_type = PROP_TYPE_DICTIONARY,
+ .pot_free = _prop_dictionary_free,
+ .pot_emergency_free = _prop_dictionary_emergency_free,
+ .pot_extern = _prop_dictionary_externalize,
+ .pot_equals = _prop_dictionary_equals,
+ .pot_equals_finish = _prop_dictionary_equals_finish,
+ .pot_lock = _prop_dictionary_lock,
+ .pot_unlock = _prop_dictionary_unlock,
+};
+
+static _prop_object_free_rv_t
+ _prop_dict_keysym_free(prop_stack_t, prop_object_t *);
+static bool _prop_dict_keysym_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_dict_keysym_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+
+static const struct _prop_object_type _prop_object_type_dict_keysym = {
+ .pot_type = PROP_TYPE_DICT_KEYSYM,
+ .pot_free = _prop_dict_keysym_free,
+ .pot_extern = _prop_dict_keysym_externalize,
+ .pot_equals = _prop_dict_keysym_equals,
+};
+
+#define prop_object_is_dictionary(x) \
+ ((x) != NULL && (x)->pd_obj.po_type == &_prop_object_type_dictionary)
+#define prop_object_is_dictionary_keysym(x) \
+ ((x) != NULL && (x)->pdk_obj.po_type == &_prop_object_type_dict_keysym)
+
+#define prop_dictionary_is_immutable(x) \
+ (((x)->pd_flags & PD_F_IMMUTABLE) != 0)
+
+struct _prop_dictionary_iterator {
+ struct _prop_object_iterator pdi_base;
+ unsigned int pdi_index;
+};
+
+/*
+ * Dictionary key symbols are immutable, and we are likely to have many
+ * duplicated key symbols. So, to save memory, we unique'ify key symbols
+ * so we only have to have one copy of each string.
+ */
+
+static int
+/*ARGSUSED*/
+_prop_dict_keysym_rb_compare_nodes(void *ctx __unused,
+ const void *n1, const void *n2)
+{
+ const struct _prop_dictionary_keysym *pdk1 = n1;
+ const struct _prop_dictionary_keysym *pdk2 = n2;
+
+ return strcmp(pdk1->pdk_key, pdk2->pdk_key);
+}
+
+static int
+/*ARGSUSED*/
+_prop_dict_keysym_rb_compare_key(void *ctx __unused,
+ const void *n, const void *v)
+{
+ const struct _prop_dictionary_keysym *pdk = n;
+ const char *cp = v;
+
+ return strcmp(pdk->pdk_key, cp);
+}
+
+static const rb_tree_ops_t _prop_dict_keysym_rb_tree_ops = {
+ .rbto_compare_nodes = _prop_dict_keysym_rb_compare_nodes,
+ .rbto_compare_key = _prop_dict_keysym_rb_compare_key,
+ .rbto_node_offset = offsetof(struct _prop_dictionary_keysym, pdk_link),
+ .rbto_context = NULL
+};
+
+static struct rb_tree _prop_dict_keysym_tree;
+
+_PROP_ONCE_DECL(_prop_dict_init_once)
+_PROP_MUTEX_DECL_STATIC(_prop_dict_keysym_tree_mutex)
+
+static int
+_prop_dict_init(void)
+{
+
+ _PROP_MUTEX_INIT(_prop_dict_keysym_tree_mutex);
+ _prop_rb_tree_init(&_prop_dict_keysym_tree,
+ &_prop_dict_keysym_rb_tree_ops);
+ return 0;
+}
+
+static void
+_prop_dict_keysym_put(prop_dictionary_keysym_t pdk)
+{
+
+ if (pdk->pdk_size <= PDK_SIZE_16)
+ _PROP_POOL_PUT(_prop_dictionary_keysym16_pool, pdk);
+ else if (pdk->pdk_size <= PDK_SIZE_32)
+ _PROP_POOL_PUT(_prop_dictionary_keysym32_pool, pdk);
+ else {
+ _PROP_ASSERT(pdk->pdk_size <= PDK_SIZE_128);
+ _PROP_POOL_PUT(_prop_dictionary_keysym128_pool, pdk);
+ }
+}
+
+/* ARGSUSED */
+static _prop_object_free_rv_t
+_prop_dict_keysym_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_dictionary_keysym_t pdk = *obj;
+
+ _prop_rb_tree_remove_node(&_prop_dict_keysym_tree, pdk);
+ _prop_dict_keysym_put(pdk);
+
+ return _PROP_OBJECT_FREE_DONE;
+}
+
+static bool
+_prop_dict_keysym_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_dictionary_keysym_t pdk = v;
+
+ /* We externalize these as strings, and they're never empty. */
+
+ _PROP_ASSERT(pdk->pdk_key[0] != '\0');
+
+ if (_prop_object_externalize_start_tag(ctx, "string") == false ||
+ _prop_object_externalize_append_encoded_cstring(ctx,
+ pdk->pdk_key) == false ||
+ _prop_object_externalize_end_tag(ctx, "string") == false)
+ return (false);
+
+ return (true);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_dict_keysym_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_dictionary_keysym_t pdk1 = v1;
+ prop_dictionary_keysym_t pdk2 = v2;
+
+ /*
+ * There is only ever one copy of a keysym at any given time,
+ * so we can reduce this to a simple pointer equality check.
+ */
+ if (pdk1 == pdk2)
+ return _PROP_OBJECT_EQUALS_TRUE;
+ else
+ return _PROP_OBJECT_EQUALS_FALSE;
+}
+
+static prop_dictionary_keysym_t
+_prop_dict_keysym_alloc(const char *key)
+{
+ prop_dictionary_keysym_t opdk, pdk, rpdk;
+ size_t size;
+
+ _PROP_ONCE_RUN(_prop_dict_init_once, _prop_dict_init);
+
+ /*
+ * Check to see if this already exists in the tree. If it does,
+ * we just retain it and return it.
+ */
+ _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex);
+ opdk = _prop_rb_tree_find(&_prop_dict_keysym_tree, key);
+ if (opdk != NULL) {
+ prop_object_retain(opdk);
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+ return (opdk);
+ }
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+
+ /*
+ * Not in the tree. Create it now.
+ */
+
+ size = sizeof(*pdk) + strlen(key) /* pdk_key[1] covers the NUL */;
+
+ if (size <= PDK_SIZE_16)
+ pdk = _PROP_POOL_GET(_prop_dictionary_keysym16_pool);
+ else if (size <= PDK_SIZE_32)
+ pdk = _PROP_POOL_GET(_prop_dictionary_keysym32_pool);
+ else if (size <= PDK_SIZE_128)
+ pdk = _PROP_POOL_GET(_prop_dictionary_keysym128_pool);
+ else
+ pdk = NULL; /* key too long */
+
+ if (pdk == NULL)
+ return (NULL);
+
+ _prop_object_init(&pdk->pdk_obj, &_prop_object_type_dict_keysym);
+
+ strcpy(pdk->pdk_key, key);
+ pdk->pdk_size = size;
+
+ /*
+ * We dropped the mutex when we allocated the new object, so
+ * we have to check again if it is in the tree.
+ */
+ _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex);
+ opdk = _prop_rb_tree_find(&_prop_dict_keysym_tree, key);
+ if (opdk != NULL) {
+ prop_object_retain(opdk);
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+ _prop_dict_keysym_put(pdk);
+ return (opdk);
+ }
+ rpdk = _prop_rb_tree_insert_node(&_prop_dict_keysym_tree, pdk);
+ _PROP_ASSERT(rpdk == pdk);
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+ return (pdk);
+}
+
+static _prop_object_free_rv_t
+_prop_dictionary_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_dictionary_t pd = *obj;
+ prop_dictionary_keysym_t pdk;
+ prop_object_t po;
+
+ _PROP_ASSERT(pd->pd_count <= pd->pd_capacity);
+ _PROP_ASSERT((pd->pd_capacity == 0 && pd->pd_array == NULL) ||
+ (pd->pd_capacity != 0 && pd->pd_array != NULL));
+
+ /* The empty dictorinary is easy, handle that first. */
+ if (pd->pd_count == 0) {
+ if (pd->pd_array != NULL)
+ _PROP_FREE(pd->pd_array, M_PROP_DICT);
+
+ _PROP_RWLOCK_DESTROY(pd->pd_rwlock);
+
+ _PROP_POOL_PUT(_prop_dictionary_pool, pd);
+
+ return (_PROP_OBJECT_FREE_DONE);
+ }
+
+ po = pd->pd_array[pd->pd_count - 1].pde_objref;
+ _PROP_ASSERT(po != NULL);
+
+ if (stack == NULL) {
+ /*
+ * If we are in emergency release mode,
+ * just let caller recurse down.
+ */
+ *obj = po;
+ return (_PROP_OBJECT_FREE_FAILED);
+ }
+
+ /* Otherwise, try to push the current object on the stack. */
+ if (!_prop_stack_push(stack, pd, NULL, NULL, NULL)) {
+ /* Push failed, entering emergency release mode. */
+ return (_PROP_OBJECT_FREE_FAILED);
+ }
+ /* Object pushed on stack, caller will release it. */
+ --pd->pd_count;
+ pdk = pd->pd_array[pd->pd_count].pde_key;
+ _PROP_ASSERT(pdk != NULL);
+
+ prop_object_release(pdk);
+
+ *obj = po;
+ return (_PROP_OBJECT_FREE_RECURSE);
+}
+
+
+static void
+_prop_dictionary_lock(void)
+{
+
+ /* XXX: once necessary or paranoia? */
+ _PROP_ONCE_RUN(_prop_dict_init_once, _prop_dict_init);
+ _PROP_MUTEX_LOCK(_prop_dict_keysym_tree_mutex);
+}
+
+static void
+_prop_dictionary_unlock(void)
+{
+ _PROP_MUTEX_UNLOCK(_prop_dict_keysym_tree_mutex);
+}
+
+static void
+_prop_dictionary_emergency_free(prop_object_t obj)
+{
+ prop_dictionary_t pd = obj;
+ prop_dictionary_keysym_t pdk;
+
+ _PROP_ASSERT(pd->pd_count != 0);
+ --pd->pd_count;
+
+ pdk = pd->pd_array[pd->pd_count].pde_key;
+ _PROP_ASSERT(pdk != NULL);
+ prop_object_release(pdk);
+}
+
+static bool
+_prop_dictionary_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_dictionary_t pd = v;
+ prop_dictionary_keysym_t pdk;
+ struct _prop_object *po;
+ prop_object_iterator_t pi;
+ unsigned int i;
+ bool rv = false;
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+
+ if (pd->pd_count == 0) {
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (_prop_object_externalize_empty_tag(ctx, "dict"));
+ }
+
+ if (_prop_object_externalize_start_tag(ctx, "dict") == false ||
+ _prop_object_externalize_append_char(ctx, '\n') == false)
+ goto out;
+
+ pi = _prop_dictionary_iterator_locked(pd);
+ if (pi == NULL)
+ goto out;
+
+ ctx->poec_depth++;
+ _PROP_ASSERT(ctx->poec_depth != 0);
+
+ while ((pdk = _prop_dictionary_iterator_next_object_locked(pi))
+ != NULL) {
+ po = _prop_dictionary_get_keysym(pd, pdk, true);
+ if (po == NULL ||
+ _prop_object_externalize_start_tag(ctx, "key") == false ||
+ _prop_object_externalize_append_encoded_cstring(ctx,
+ pdk->pdk_key) == false ||
+ _prop_object_externalize_end_tag(ctx, "key") == false ||
+ (*po->po_type->pot_extern)(ctx, po) == false) {
+ prop_object_iterator_release(pi);
+ goto out;
+ }
+ }
+
+ prop_object_iterator_release(pi);
+
+ ctx->poec_depth--;
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == false)
+ goto out;
+ }
+ if (_prop_object_externalize_end_tag(ctx, "dict") == false)
+ goto out;
+
+ rv = true;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (rv);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_dictionary_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_dictionary_t dict1 = v1;
+ prop_dictionary_t dict2 = v2;
+ uintptr_t idx;
+ _prop_object_equals_rv_t rv = _PROP_OBJECT_EQUALS_FALSE;
+
+ if (dict1 == dict2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+
+ _PROP_ASSERT(*stored_pointer1 == *stored_pointer2);
+
+ idx = (uintptr_t)*stored_pointer1;
+
+ if (idx == 0) {
+ if ((uintptr_t)dict1 < (uintptr_t)dict2) {
+ _PROP_RWLOCK_RDLOCK(dict1->pd_rwlock);
+ _PROP_RWLOCK_RDLOCK(dict2->pd_rwlock);
+ } else {
+ _PROP_RWLOCK_RDLOCK(dict2->pd_rwlock);
+ _PROP_RWLOCK_RDLOCK(dict1->pd_rwlock);
+ }
+ }
+
+ if (dict1->pd_count != dict2->pd_count)
+ goto out;
+
+ if (idx == dict1->pd_count) {
+ rv = _PROP_OBJECT_EQUALS_TRUE;
+ goto out;
+ }
+
+ _PROP_ASSERT(idx < dict1->pd_count);
+
+ *stored_pointer1 = (void *)(idx + 1);
+ *stored_pointer2 = (void *)(idx + 1);
+
+ *next_obj1 = dict1->pd_array[idx].pde_objref;
+ *next_obj2 = dict2->pd_array[idx].pde_objref;
+
+ if (!prop_dictionary_keysym_equals(dict1->pd_array[idx].pde_key,
+ dict2->pd_array[idx].pde_key))
+ goto out;
+
+ return (_PROP_OBJECT_EQUALS_RECURSE);
+
+ out:
+ _PROP_RWLOCK_UNLOCK(dict1->pd_rwlock);
+ _PROP_RWLOCK_UNLOCK(dict2->pd_rwlock);
+ return (rv);
+}
+
+static void
+_prop_dictionary_equals_finish(prop_object_t v1, prop_object_t v2)
+{
+ _PROP_RWLOCK_UNLOCK(((prop_dictionary_t)v1)->pd_rwlock);
+ _PROP_RWLOCK_UNLOCK(((prop_dictionary_t)v2)->pd_rwlock);
+}
+
+static prop_dictionary_t
+_prop_dictionary_alloc(unsigned int capacity)
+{
+ prop_dictionary_t pd;
+ struct _prop_dict_entry *array;
+
+ if (capacity != 0) {
+ array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_DICT);
+ if (array == NULL)
+ return (NULL);
+ } else
+ array = NULL;
+
+ pd = _PROP_POOL_GET(_prop_dictionary_pool);
+ if (pd != NULL) {
+ _prop_object_init(&pd->pd_obj, &_prop_object_type_dictionary);
+
+ _PROP_RWLOCK_INIT(pd->pd_rwlock);
+ pd->pd_array = array;
+ pd->pd_capacity = capacity;
+ pd->pd_count = 0;
+ pd->pd_flags = 0;
+
+ pd->pd_version = 0;
+ } else if (array != NULL)
+ _PROP_FREE(array, M_PROP_DICT);
+
+ return (pd);
+}
+
+static bool
+_prop_dictionary_expand(prop_dictionary_t pd, unsigned int capacity)
+{
+ struct _prop_dict_entry *array, *oarray;
+
+ /*
+ * Dictionary must be WRITE-LOCKED.
+ */
+
+ oarray = pd->pd_array;
+
+ array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_DICT);
+ if (array == NULL)
+ return (false);
+ if (oarray != NULL)
+ memcpy(array, oarray, pd->pd_capacity * sizeof(*array));
+ pd->pd_array = array;
+ pd->pd_capacity = capacity;
+
+ if (oarray != NULL)
+ _PROP_FREE(oarray, M_PROP_DICT);
+
+ return (true);
+}
+
+static prop_object_t
+_prop_dictionary_iterator_next_object_locked(void *v)
+{
+ struct _prop_dictionary_iterator *pdi = v;
+ prop_dictionary_t pd = pdi->pdi_base.pi_obj;
+ prop_dictionary_keysym_t pdk = NULL;
+
+ _PROP_ASSERT(prop_object_is_dictionary(pd));
+
+ if (pd->pd_version != pdi->pdi_base.pi_version)
+ goto out; /* dictionary changed during iteration */
+
+ _PROP_ASSERT(pdi->pdi_index <= pd->pd_count);
+
+ if (pdi->pdi_index == pd->pd_count)
+ goto out; /* we've iterated all objects */
+
+ pdk = pd->pd_array[pdi->pdi_index].pde_key;
+ pdi->pdi_index++;
+
+ out:
+ return (pdk);
+}
+
+static prop_object_t
+_prop_dictionary_iterator_next_object(void *v)
+{
+ struct _prop_dictionary_iterator *pdi = v;
+ prop_dictionary_t pd __unused = pdi->pdi_base.pi_obj;
+ prop_dictionary_keysym_t pdk;
+
+ _PROP_ASSERT(prop_object_is_dictionary(pd));
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ pdk = _prop_dictionary_iterator_next_object_locked(pdi);
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (pdk);
+}
+
+static void
+_prop_dictionary_iterator_reset_locked(void *v)
+{
+ struct _prop_dictionary_iterator *pdi = v;
+ prop_dictionary_t pd = pdi->pdi_base.pi_obj;
+
+ _PROP_ASSERT(prop_object_is_dictionary(pd));
+
+ pdi->pdi_index = 0;
+ pdi->pdi_base.pi_version = pd->pd_version;
+}
+
+static void
+_prop_dictionary_iterator_reset(void *v)
+{
+ struct _prop_dictionary_iterator *pdi = v;
+ prop_dictionary_t pd __unused = pdi->pdi_base.pi_obj;
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ _prop_dictionary_iterator_reset_locked(pdi);
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+}
+
+/*
+ * prop_dictionary_create --
+ * Create a dictionary.
+ */
+prop_dictionary_t
+prop_dictionary_create(void)
+{
+
+ return (_prop_dictionary_alloc(0));
+}
+
+/*
+ * prop_dictionary_create_with_capacity --
+ * Create a dictionary with the capacity to store N objects.
+ */
+prop_dictionary_t
+prop_dictionary_create_with_capacity(unsigned int capacity)
+{
+
+ return (_prop_dictionary_alloc(capacity));
+}
+
+/*
+ * prop_dictionary_copy --
+ * Copy a dictionary. The new dictionary has an initial capacity equal
+ * to the number of objects stored int the original dictionary. The new
+ * dictionary contains refrences to the original dictionary's objects,
+ * not copies of those objects (i.e. a shallow copy).
+ */
+prop_dictionary_t
+prop_dictionary_copy(prop_dictionary_t opd)
+{
+ prop_dictionary_t pd;
+ prop_dictionary_keysym_t pdk;
+ prop_object_t po;
+ unsigned int idx;
+
+ if (! prop_object_is_dictionary(opd))
+ return (NULL);
+
+ _PROP_RWLOCK_RDLOCK(opd->pd_rwlock);
+
+ pd = _prop_dictionary_alloc(opd->pd_count);
+ if (pd != NULL) {
+ for (idx = 0; idx < opd->pd_count; idx++) {
+ pdk = opd->pd_array[idx].pde_key;
+ po = opd->pd_array[idx].pde_objref;
+
+ prop_object_retain(pdk);
+ prop_object_retain(po);
+
+ pd->pd_array[idx].pde_key = pdk;
+ pd->pd_array[idx].pde_objref = po;
+ }
+ pd->pd_count = opd->pd_count;
+ pd->pd_flags = opd->pd_flags;
+ }
+ _PROP_RWLOCK_UNLOCK(opd->pd_rwlock);
+ return (pd);
+}
+
+/*
+ * prop_dictionary_copy_mutable --
+ * Like prop_dictionary_copy(), but the resulting dictionary is
+ * mutable.
+ */
+prop_dictionary_t
+prop_dictionary_copy_mutable(prop_dictionary_t opd)
+{
+ prop_dictionary_t pd;
+
+ if (! prop_object_is_dictionary(opd))
+ return (NULL);
+
+ pd = prop_dictionary_copy(opd);
+ if (pd != NULL)
+ pd->pd_flags &= ~PD_F_IMMUTABLE;
+
+ return (pd);
+}
+
+/*
+ * prop_dictionary_make_immutable --
+ * Set the immutable flag on that dictionary.
+ */
+void
+prop_dictionary_make_immutable(prop_dictionary_t pd)
+{
+
+ _PROP_RWLOCK_WRLOCK(pd->pd_rwlock);
+ if (prop_dictionary_is_immutable(pd) == false)
+ pd->pd_flags |= PD_F_IMMUTABLE;
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+}
+
+/*
+ * prop_dictionary_count --
+ * Return the number of objects stored in the dictionary.
+ */
+unsigned int
+prop_dictionary_count(prop_dictionary_t pd)
+{
+ unsigned int rv;
+
+ if (! prop_object_is_dictionary(pd))
+ return (0);
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ rv = pd->pd_count;
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+
+ return (rv);
+}
+
+/*
+ * prop_dictionary_ensure_capacity --
+ * Ensure that the dictionary has the capacity to store the specified
+ * total number of objects (including the objects already stored in
+ * the dictionary).
+ */
+bool
+prop_dictionary_ensure_capacity(prop_dictionary_t pd, unsigned int capacity)
+{
+ bool rv;
+
+ if (! prop_object_is_dictionary(pd))
+ return (false);
+
+ _PROP_RWLOCK_WRLOCK(pd->pd_rwlock);
+ if (capacity > pd->pd_capacity)
+ rv = _prop_dictionary_expand(pd, capacity);
+ else
+ rv = true;
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (rv);
+}
+
+static prop_object_iterator_t
+_prop_dictionary_iterator_locked(prop_dictionary_t pd)
+{
+ struct _prop_dictionary_iterator *pdi;
+
+ if (! prop_object_is_dictionary(pd))
+ return (NULL);
+
+ pdi = _PROP_CALLOC(sizeof(*pdi), M_TEMP);
+ if (pdi == NULL)
+ return (NULL);
+ pdi->pdi_base.pi_next_object = _prop_dictionary_iterator_next_object;
+ pdi->pdi_base.pi_reset = _prop_dictionary_iterator_reset;
+ prop_object_retain(pd);
+ pdi->pdi_base.pi_obj = pd;
+ _prop_dictionary_iterator_reset_locked(pdi);
+
+ return (&pdi->pdi_base);
+}
+
+/*
+ * prop_dictionary_iterator --
+ * Return an iterator for the dictionary. The dictionary is retained by
+ * the iterator.
+ */
+prop_object_iterator_t
+prop_dictionary_iterator(prop_dictionary_t pd)
+{
+ prop_object_iterator_t pi;
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ pi = _prop_dictionary_iterator_locked(pd);
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (pi);
+}
+
+/*
+ * prop_dictionary_all_keys --
+ * Return an array containing a snapshot of all of the keys
+ * in the dictionary.
+ */
+prop_array_t
+prop_dictionary_all_keys(prop_dictionary_t pd)
+{
+ prop_array_t array;
+ unsigned int idx;
+ bool rv = true;
+
+ if (! prop_object_is_dictionary(pd))
+ return (NULL);
+
+ /* There is no pressing need to lock the dictionary for this. */
+ array = prop_array_create_with_capacity(pd->pd_count);
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+
+ for (idx = 0; idx < pd->pd_count; idx++) {
+ rv = prop_array_add(array, pd->pd_array[idx].pde_key);
+ if (rv == false)
+ break;
+ }
+
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+
+ if (rv == false) {
+ prop_object_release(array);
+ array = NULL;
+ }
+ return (array);
+}
+
+static struct _prop_dict_entry *
+_prop_dict_lookup(prop_dictionary_t pd, const char *key,
+ unsigned int *idxp)
+{
+ struct _prop_dict_entry *pde;
+ unsigned int base, idx, distance;
+ int res;
+
+ /*
+ * Dictionary must be READ-LOCKED or WRITE-LOCKED.
+ */
+
+ for (idx = 0, base = 0, distance = pd->pd_count; distance != 0;
+ distance >>= 1) {
+ idx = base + (distance >> 1);
+ pde = &pd->pd_array[idx];
+ _PROP_ASSERT(pde->pde_key != NULL);
+ res = strcmp(key, pde->pde_key->pdk_key);
+ if (res == 0) {
+ if (idxp != NULL)
+ *idxp = idx;
+ return (pde);
+ }
+ if (res > 0) { /* key > pdk_key: move right */
+ base = idx + 1;
+ distance--;
+ } /* else move left */
+ }
+
+ /* idx points to the slot we looked at last. */
+ if (idxp != NULL)
+ *idxp = idx;
+ return (NULL);
+}
+
+static prop_object_t
+_prop_dictionary_get(prop_dictionary_t pd, const char *key, bool locked)
+{
+ const struct _prop_dict_entry *pde;
+ prop_object_t po = NULL;
+
+ if (! prop_object_is_dictionary(pd))
+ return (NULL);
+
+ if (!locked)
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ pde = _prop_dict_lookup(pd, key, NULL);
+ if (pde != NULL) {
+ _PROP_ASSERT(pde->pde_objref != NULL);
+ po = pde->pde_objref;
+ }
+ if (!locked)
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (po);
+}
+/*
+ * prop_dictionary_get --
+ * Return the object stored with specified key.
+ */
+prop_object_t
+prop_dictionary_get(prop_dictionary_t pd, const char *key)
+{
+ prop_object_t po = NULL;
+
+ if (! prop_object_is_dictionary(pd))
+ return (NULL);
+
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+ po = _prop_dictionary_get(pd, key, true);
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (po);
+}
+
+static prop_object_t
+_prop_dictionary_get_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk,
+ bool locked)
+{
+
+ if (! (prop_object_is_dictionary(pd) &&
+ prop_object_is_dictionary_keysym(pdk)))
+ return (NULL);
+
+ return (_prop_dictionary_get(pd, pdk->pdk_key, locked));
+}
+
+/*
+ * prop_dictionary_get_keysym --
+ * Return the object stored at the location encoded by the keysym.
+ */
+prop_object_t
+prop_dictionary_get_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk)
+{
+
+ return (_prop_dictionary_get_keysym(pd, pdk, false));
+}
+
+/*
+ * prop_dictionary_set --
+ * Store a reference to an object at with the specified key.
+ * If the key already exisit, the original object is released.
+ */
+bool
+prop_dictionary_set(prop_dictionary_t pd, const char *key, prop_object_t po)
+{
+ struct _prop_dict_entry *pde;
+ prop_dictionary_keysym_t pdk;
+ unsigned int idx;
+ bool rv = false;
+
+ if (! prop_object_is_dictionary(pd))
+ return (false);
+
+ _PROP_ASSERT(pd->pd_count <= pd->pd_capacity);
+
+ if (prop_dictionary_is_immutable(pd))
+ return (false);
+
+ _PROP_RWLOCK_WRLOCK(pd->pd_rwlock);
+
+ pde = _prop_dict_lookup(pd, key, &idx);
+ if (pde != NULL) {
+ prop_object_t opo = pde->pde_objref;
+ prop_object_retain(po);
+ pde->pde_objref = po;
+ prop_object_release(opo);
+ rv = true;
+ goto out;
+ }
+
+ pdk = _prop_dict_keysym_alloc(key);
+ if (pdk == NULL)
+ goto out;
+
+ if (pd->pd_count == pd->pd_capacity &&
+ _prop_dictionary_expand(pd,
+ pd->pd_capacity + EXPAND_STEP) == false) {
+ prop_object_release(pdk);
+ goto out;
+ }
+
+ /* At this point, the store will succeed. */
+ prop_object_retain(po);
+
+ if (pd->pd_count == 0) {
+ pd->pd_array[0].pde_key = pdk;
+ pd->pd_array[0].pde_objref = po;
+ pd->pd_count++;
+ pd->pd_version++;
+ rv = true;
+ goto out;
+ }
+
+ pde = &pd->pd_array[idx];
+ _PROP_ASSERT(pde->pde_key != NULL);
+
+ if (strcmp(key, pde->pde_key->pdk_key) < 0) {
+ /*
+ * key < pdk_key: insert to the left. This is the same as
+ * inserting to the right, except we decrement the current
+ * index first.
+ *
+ * Because we're unsigned, we have to special case 0
+ * (grumble).
+ */
+ if (idx == 0) {
+ memmove(&pd->pd_array[1], &pd->pd_array[0],
+ pd->pd_count * sizeof(*pde));
+ pd->pd_array[0].pde_key = pdk;
+ pd->pd_array[0].pde_objref = po;
+ pd->pd_count++;
+ pd->pd_version++;
+ rv = true;
+ goto out;
+ }
+ idx--;
+ }
+
+ memmove(&pd->pd_array[idx + 2], &pd->pd_array[idx + 1],
+ (pd->pd_count - (idx + 1)) * sizeof(*pde));
+ pd->pd_array[idx + 1].pde_key = pdk;
+ pd->pd_array[idx + 1].pde_objref = po;
+ pd->pd_count++;
+
+ pd->pd_version++;
+
+ rv = true;
+
+ out:
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+ return (rv);
+}
+
+/*
+ * prop_dictionary_set_keysym --
+ * Replace the object in the dictionary at the location encoded by
+ * the keysym.
+ */
+bool
+prop_dictionary_set_keysym(prop_dictionary_t pd, prop_dictionary_keysym_t pdk,
+ prop_object_t po)
+{
+
+ if (! (prop_object_is_dictionary(pd) &&
+ prop_object_is_dictionary_keysym(pdk)))
+ return (false);
+
+ return (prop_dictionary_set(pd, pdk->pdk_key, po));
+}
+
+static void
+_prop_dictionary_remove(prop_dictionary_t pd, struct _prop_dict_entry *pde,
+ unsigned int idx)
+{
+ prop_dictionary_keysym_t pdk = pde->pde_key;
+ prop_object_t po = pde->pde_objref;
+
+ /*
+ * Dictionary must be WRITE-LOCKED.
+ */
+
+ _PROP_ASSERT(pd->pd_count != 0);
+ _PROP_ASSERT(idx < pd->pd_count);
+ _PROP_ASSERT(pde == &pd->pd_array[idx]);
+
+ idx++;
+ memmove(&pd->pd_array[idx - 1], &pd->pd_array[idx],
+ (pd->pd_count - idx) * sizeof(*pde));
+ pd->pd_count--;
+ pd->pd_version++;
+
+
+ prop_object_release(pdk);
+
+ prop_object_release(po);
+}
+
+/*
+ * prop_dictionary_remove --
+ * Remove the reference to an object with the specified key from
+ * the dictionary.
+ */
+void
+prop_dictionary_remove(prop_dictionary_t pd, const char *key)
+{
+ struct _prop_dict_entry *pde;
+ unsigned int idx;
+
+ if (! prop_object_is_dictionary(pd))
+ return;
+
+ _PROP_RWLOCK_WRLOCK(pd->pd_rwlock);
+
+ /* XXX Should this be a _PROP_ASSERT()? */
+ if (prop_dictionary_is_immutable(pd))
+ goto out;
+
+ pde = _prop_dict_lookup(pd, key, &idx);
+ /* XXX Should this be a _PROP_ASSERT()? */
+ if (pde == NULL)
+ goto out;
+
+ _prop_dictionary_remove(pd, pde, idx);
+ out:
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+}
+
+/*
+ * prop_dictionary_remove_keysym --
+ * Remove a reference to an object stored in the dictionary at the
+ * location encoded by the keysym.
+ */
+void
+prop_dictionary_remove_keysym(prop_dictionary_t pd,
+ prop_dictionary_keysym_t pdk)
+{
+
+ if (! (prop_object_is_dictionary(pd) &&
+ prop_object_is_dictionary_keysym(pdk)))
+ return;
+
+ prop_dictionary_remove(pd, pdk->pdk_key);
+}
+
+/*
+ * prop_dictionary_equals --
+ * Return true if the two dictionaries are equivalent. Note we do a
+ * by-value comparison of the objects in the dictionary.
+ */
+bool
+prop_dictionary_equals(prop_dictionary_t dict1, prop_dictionary_t dict2)
+{
+ if (!prop_object_is_dictionary(dict1) ||
+ !prop_object_is_dictionary(dict2))
+ return (false);
+
+ return (prop_object_equals(dict1, dict2));
+}
+
+/*
+ * prop_dictionary_keysym_cstring_nocopy --
+ * Return an immutable reference to the keysym's value.
+ */
+const char *
+prop_dictionary_keysym_cstring_nocopy(prop_dictionary_keysym_t pdk)
+{
+
+ if (! prop_object_is_dictionary_keysym(pdk))
+ return (NULL);
+
+ return (pdk->pdk_key);
+}
+
+/*
+ * prop_dictionary_keysym_equals --
+ * Return true if the two dictionary key symbols are equivalent.
+ * Note: We do not compare the object references.
+ */
+bool
+prop_dictionary_keysym_equals(prop_dictionary_keysym_t pdk1,
+ prop_dictionary_keysym_t pdk2)
+{
+ if (!prop_object_is_dictionary_keysym(pdk1) ||
+ !prop_object_is_dictionary_keysym(pdk2))
+ return (false);
+
+ return (prop_object_equals(pdk1, pdk2));
+}
+
+/*
+ * prop_dictionary_externalize --
+ * Externalize a dictionary, returning a NUL-terminated buffer
+ * containing the XML-style representation. The buffer is allocated
+ * with the M_TEMP memory type.
+ */
+char *
+prop_dictionary_externalize(prop_dictionary_t pd)
+{
+ struct _prop_object_externalize_context *ctx;
+ char *cp;
+
+ ctx = _prop_object_externalize_context_alloc();
+ if (ctx == NULL)
+ return (NULL);
+
+ if (_prop_object_externalize_header(ctx) == false ||
+ (*pd->pd_obj.po_type->pot_extern)(ctx, pd) == false ||
+ _prop_object_externalize_footer(ctx) == false) {
+ /* We are responsible for releasing the buffer. */
+ _PROP_FREE(ctx->poec_buf, M_TEMP);
+ _prop_object_externalize_context_free(ctx);
+ return (NULL);
+ }
+
+ cp = ctx->poec_buf;
+ _prop_object_externalize_context_free(ctx);
+
+ return (cp);
+}
+
+/*
+ * _prop_dictionary_internalize --
+ * Parse a <dict>...</dict> and return the object created from the
+ * external representation.
+ *
+ * Internal state in via rec_data is the storage area for the last processed
+ * key.
+ * _prop_dictionary_internalize_body is the upper half of the parse loop.
+ * It is responsible for parsing the key directly and storing it in the area
+ * referenced by rec_data.
+ * _prop_dictionary_internalize_cont is the lower half and called with the value
+ * associated with the key.
+ */
+static bool _prop_dictionary_internalize_body(prop_stack_t,
+ prop_object_t *, struct _prop_object_internalize_context *, char *);
+
+bool
+_prop_dictionary_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ prop_dictionary_t dict;
+ char *tmpkey;
+
+ /* We don't currently understand any attributes. */
+ if (ctx->poic_tagattr != NULL)
+ return (true);
+
+ dict = prop_dictionary_create();
+ if (dict == NULL)
+ return (true);
+
+ if (ctx->poic_is_empty_element) {
+ *obj = dict;
+ return (true);
+ }
+
+ tmpkey = _PROP_MALLOC(PDK_MAXKEY + 1, M_TEMP);
+ if (tmpkey == NULL) {
+ prop_object_release(dict);
+ return (true);
+ }
+
+ *obj = dict;
+ /*
+ * Opening tag is found, storage for key allocated and
+ * now continue to the first element.
+ */
+ return _prop_dictionary_internalize_body(stack, obj, ctx, tmpkey);
+}
+
+static bool
+_prop_dictionary_internalize_continue(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx, void *data, prop_object_t child)
+{
+ prop_dictionary_t dict = *obj;
+ char *tmpkey = data;
+
+ _PROP_ASSERT(tmpkey != NULL);
+
+ if (child == NULL ||
+ prop_dictionary_set(dict, tmpkey, child) == false) {
+ _PROP_FREE(tmpkey, M_TEMP);
+ if (child != NULL)
+ prop_object_release(child);
+ prop_object_release(dict);
+ *obj = NULL;
+ return (true);
+ }
+
+ prop_object_release(child);
+
+ /*
+ * key, value was added, now continue looking for the next key
+ * or the closing tag.
+ */
+ return _prop_dictionary_internalize_body(stack, obj, ctx, tmpkey);
+}
+
+static bool
+_prop_dictionary_internalize_body(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx, char *tmpkey)
+{
+ prop_dictionary_t dict = *obj;
+ size_t keylen;
+
+ /* Fetch the next tag. */
+ if (_prop_object_internalize_find_tag(ctx, NULL, _PROP_TAG_TYPE_EITHER) == false)
+ goto bad;
+
+ /* Check to see if this is the end of the dictionary. */
+ if (_PROP_TAG_MATCH(ctx, "dict") &&
+ ctx->poic_tag_type == _PROP_TAG_TYPE_END) {
+ _PROP_FREE(tmpkey, M_TEMP);
+ return (true);
+ }
+
+ /* Ok, it must be a non-empty key start tag. */
+ if (!_PROP_TAG_MATCH(ctx, "key") ||
+ ctx->poic_tag_type != _PROP_TAG_TYPE_START ||
+ ctx->poic_is_empty_element)
+ goto bad;
+
+ if (_prop_object_internalize_decode_string(ctx,
+ tmpkey, PDK_MAXKEY, &keylen,
+ &ctx->poic_cp) == false)
+ goto bad;
+
+ _PROP_ASSERT(keylen <= PDK_MAXKEY);
+ tmpkey[keylen] = '\0';
+
+ if (_prop_object_internalize_find_tag(ctx, "key",
+ _PROP_TAG_TYPE_END) == false)
+ goto bad;
+
+ /* ..and now the beginning of the value. */
+ if (_prop_object_internalize_find_tag(ctx, NULL,
+ _PROP_TAG_TYPE_START) == false)
+ goto bad;
+
+ /*
+ * Key is found, now wait for value to be parsed.
+ */
+ if (_prop_stack_push(stack, *obj,
+ _prop_dictionary_internalize_continue,
+ tmpkey, NULL))
+ return (false);
+
+ bad:
+ _PROP_FREE(tmpkey, M_TEMP);
+ prop_object_release(dict);
+ *obj = NULL;
+ return (true);
+}
+
+/*
+ * prop_dictionary_internalize --
+ * Create a dictionary by parsing the NUL-terminated XML-style
+ * representation.
+ */
+prop_dictionary_t
+prop_dictionary_internalize(const char *xml)
+{
+ return _prop_generic_internalize(xml, "dict");
+}
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+/*
+ * prop_dictionary_externalize_to_file --
+ * Externalize a dictionary to the specified file.
+ */
+bool
+prop_dictionary_externalize_to_file(prop_dictionary_t dict, const char *fname)
+{
+ char *xml;
+ bool rv;
+ int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */
+
+ xml = prop_dictionary_externalize(dict);
+ if (xml == NULL)
+ return (false);
+ rv = _prop_object_externalize_write_file(fname, xml, strlen(xml));
+ if (rv == false)
+ save_errno = errno;
+ _PROP_FREE(xml, M_TEMP);
+ if (rv == false)
+ errno = save_errno;
+
+ return (rv);
+}
+
+/*
+ * prop_dictionary_internalize_from_file --
+ * Internalize a dictionary from a file.
+ */
+prop_dictionary_t
+prop_dictionary_internalize_from_file(const char *fname)
+{
+ struct _prop_object_internalize_mapped_file *mf;
+ prop_dictionary_t dict;
+
+ mf = _prop_object_internalize_map_file(fname);
+ if (mf == NULL)
+ return (NULL);
+ dict = prop_dictionary_internalize(mf->poimf_xml);
+ _prop_object_internalize_unmap_file(mf);
+
+ return (dict);
+}
+#endif /* !_KERNEL && !_STANDALONE */
--- /dev/null
+.\" $NetBSD: prop_dictionary_util.3,v 1.8 2011/10/17 09:24:54 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 7, 2011
+.Dt PROP_DICTIONARY_UTIL 3
+.Os
+.Sh NAME
+.Nm prop_dictionary_util ,
+.Nm prop_dictionary_get_dict ,
+.Nm prop_dictionary_get_bool ,
+.Nm prop_dictionary_set_bool ,
+.Nm prop_dictionary_get_int8 ,
+.Nm prop_dictionary_get_uint8 ,
+.Nm prop_dictionary_set_int8 ,
+.Nm prop_dictionary_set_uint8 ,
+.Nm prop_dictionary_get_int16 ,
+.Nm prop_dictionary_get_uint16 ,
+.Nm prop_dictionary_set_int16 ,
+.Nm prop_dictionary_set_uint16 ,
+.Nm prop_dictionary_get_int32 ,
+.Nm prop_dictionary_get_uint32 ,
+.Nm prop_dictionary_set_int32 ,
+.Nm prop_dictionary_set_uint32 ,
+.Nm prop_dictionary_get_int64 ,
+.Nm prop_dictionary_get_uint64 ,
+.Nm prop_dictionary_set_int64 ,
+.Nm prop_dictionary_set_uint64 ,
+.Nm prop_dictionary_get_cstring ,
+.Nm prop_dictionary_set_cstring ,
+.Nm prop_dictionary_get_cstring_nocopy ,
+.Nm prop_dictionary_set_cstring_nocopy ,
+.Nm prop_dictionary_set_and_rel
+.Nd dictionary property collection object utility functions
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft bool
+.Fn prop_dictionary_get_dict "prop_dictionary_t dict" "const char *key" \
+ "prop_dictionary_t *dictp"
+.Ft bool
+.Fn prop_dictionary_get_bool "prop_dictionary_t dict" "const char *key" \
+ "bool *valp"
+.Ft bool
+.Fn prop_dictionary_set_bool "prop_dictionary_t dict" "const char *key" \
+ "bool val"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_int8 "prop_dictionary_t dict" "const char *key" \
+ "int8_t *valp"
+.Ft bool
+.Fn prop_dictionary_get_uint8 "prop_dictionary_t dict" "const char *key" \
+ "uint8_t *valp"
+.Ft bool
+.Fn prop_dictionary_set_int8 "prop_dictionary_t dict" "const char *key" \
+ "int8_t val"
+.Ft bool
+.Fn prop_dictionary_set_uint8 "prop_dictionary_t dict" "const char *key" \
+ "uint8_t val"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_int16 "prop_dictionary_t dict" "const char *key" \
+ "int16_t *valp"
+.Ft bool
+.Fn prop_dictionary_get_uint16 "prop_dictionary_t dict" "const char *key" \
+ "uint16_t *valp"
+.Ft bool
+.Fn prop_dictionary_set_int16 "prop_dictionary_t dict" "const char *key" \
+ "int16_t val"
+.Ft bool
+.Fn prop_dictionary_set_uint16 "prop_dictionary_t dict" "const char *key" \
+ "uint16_t val"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_int32 "prop_dictionary_t dict" "const char *key" \
+ "int32_t *valp"
+.Ft bool
+.Fn prop_dictionary_get_uint32 "prop_dictionary_t dict" "const char *key" \
+ "uint32_t *valp"
+.Ft bool
+.Fn prop_dictionary_set_int32 "prop_dictionary_t dict" "const char *key" \
+ "int32_t val"
+.Ft bool
+.Fn prop_dictionary_set_uint32 "prop_dictionary_t dict" "const char *key" \
+ "uint32_t val"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_int64 "prop_dictionary_t dict" "const char *key" \
+ "int64_t *valp"
+.Ft bool
+.Fn prop_dictionary_get_uint64 "prop_dictionary_t dict" "const char *key" \
+ "uint64_t *valp"
+.Ft bool
+.Fn prop_dictionary_set_int64 "prop_dictionary_t dict" "const char *key" \
+ "int64_t val"
+.Ft bool
+.Fn prop_dictionary_set_uint64 "prop_dictionary_t dict" "const char *key" \
+ "uint64_t val"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_cstring "prop_dictionary_t dict" "const char *key" \
+ "char **strp"
+.Ft bool
+.Fn prop_dictionary_set_cstring "prop_dictionary_t dict" "const char *key" \
+ "const char *str"
+.\"
+.Ft bool
+.Fn prop_dictionary_get_cstring_nocopy "prop_dictionary_t dict" \
+ "const char *key" "const char **strp"
+.Ft bool
+.Fn prop_dictionary_set_cstring_nocopy "prop_dictionary_t dict" \
+ "const char *key" "const char *strp"
+.Ft bool
+.Fn prop_dictionary_set_and_rel "prop_dictionary_t dict" \
+ "const char *key" "prop_object_t obj"
+.Sh DESCRIPTION
+The
+.Nm prop_dictionary_util
+family of functions are provided to make getting and setting values in
+dictionaries more convenient in some applications.
+.Pp
+The getters check the type of the returned object and, in some cases, also
+ensure that the returned value is within the range implied by the getter's
+value type.
+.Pp
+The setters handle object creation and release for the caller.
+.Pp
+The
+.Fn prop_dictionary_get_cstring
+function returns dynamically allocated memory.
+See
+.Xr prop_string 3
+for more information.
+.Pp
+The
+.Fn prop_dictionary_get_cstring_nocopy
+and
+.Fn prop_dictionary_set_cstring_nocopy
+functions do not copy the string that is set or returned.
+See
+.Xr prop_string 3
+for more information.
+.Pp
+The
+.Fn prop_dictionary_set_and_rel
+function adds the object to the dictionary and releases it.
+The object is also released on failure.
+.Sh RETURN VALUES
+The
+.Nm prop_dictionary_util
+getter functions return
+.Dv true
+if the object exists in the dictionary and the value is in-range, or
+.Dv false
+otherwise.
+.Pp
+The
+.Nm prop_dictionary_util
+setter functions return
+.Dv true
+if creating the object and storing it in the dictionary is successful, or
+.Dv false
+otherwise.
+.Sh SEE ALSO
+.Xr prop_bool 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_dictionary_util.c,v 1.4 2011/03/24 17:05:39 bouyer Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Utility routines to make it more convenient to work with values
+ * stored in dictionaries.
+ *
+ * Note: There is no special magic going on here. We use the standard
+ * proplib(3) APIs to do all of this work. Any application could do
+ * exactly what we're doing here.
+ */
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h" /* only to hide kernel vs. not-kernel */
+
+bool
+prop_dictionary_get_dict(prop_dictionary_t dict, const char *key, prop_dictionary_t *dp)
+{
+ prop_object_t o;
+ o = prop_dictionary_get(dict, key);
+ if (o == NULL || prop_object_type(o) != PROP_TYPE_DICTIONARY)
+ return false;
+ *dp = o;
+ return true;
+
+}
+
+bool
+prop_dictionary_get_bool(prop_dictionary_t dict,
+ const char *key,
+ bool *valp)
+{
+ prop_bool_t b;
+
+ b = prop_dictionary_get(dict, key);
+ if (prop_object_type(b) != PROP_TYPE_BOOL)
+ return (false);
+
+ *valp = prop_bool_true(b);
+
+ return (true);
+}
+
+bool
+prop_dictionary_set_bool(prop_dictionary_t dict,
+ const char *key,
+ bool val)
+{
+ prop_bool_t b;
+ int rv;
+
+ b = prop_bool_create(val);
+ if (b == NULL)
+ return (false);
+ rv = prop_dictionary_set(dict, key, b);
+ prop_object_release(b);
+
+ return (rv);
+}
+
+#define TEMPLATE(size) \
+bool \
+prop_dictionary_get_int ## size (prop_dictionary_t dict, \
+ const char *key, \
+ int ## size ## _t *valp) \
+{ \
+ prop_number_t num; \
+ \
+ num = prop_dictionary_get(dict, key); \
+ if (prop_object_type(num) != PROP_TYPE_NUMBER) \
+ return (false); \
+ \
+ if (prop_number_unsigned(num) && \
+ prop_number_unsigned_integer_value(num) > \
+ /*CONSTCOND*/((size) == 8 ? INT8_MAX : \
+ (size) == 16 ? INT16_MAX : \
+ (size) == 32 ? INT32_MAX : INT64_MAX)) { \
+ return (false); \
+ } \
+ \
+ if (prop_number_size(num) > (size)) \
+ return (false); \
+ \
+ *valp = (int ## size ## _t) prop_number_integer_value(num); \
+ \
+ return (true); \
+} \
+ \
+bool \
+prop_dictionary_get_uint ## size (prop_dictionary_t dict, \
+ const char *key, \
+ uint ## size ## _t *valp) \
+{ \
+ prop_number_t num; \
+ \
+ num = prop_dictionary_get(dict, key); \
+ if (prop_object_type(num) != PROP_TYPE_NUMBER) \
+ return (false); \
+ \
+ if (prop_number_unsigned(num) == false && \
+ prop_number_integer_value(num) < 0) { \
+ return (false); \
+ } \
+ \
+ if (prop_number_size(num) > (size)) \
+ return (false); \
+ \
+ *valp = (uint ## size ## _t) \
+ prop_number_unsigned_integer_value(num); \
+ \
+ return (true); \
+} \
+ \
+bool \
+prop_dictionary_set_int ## size (prop_dictionary_t dict, \
+ const char *key, \
+ int ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_integer((int64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_dictionary_set(dict, key, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+} \
+ \
+bool \
+prop_dictionary_set_uint ## size (prop_dictionary_t dict, \
+ const char *key, \
+ uint ## size ## _t val) \
+{ \
+ prop_number_t num; \
+ int rv; \
+ \
+ num = prop_number_create_unsigned_integer((uint64_t) val); \
+ if (num == NULL) \
+ return (false); \
+ rv = prop_dictionary_set(dict, key, num); \
+ prop_object_release(num); \
+ \
+ return (rv); \
+}
+
+TEMPLATE(8)
+TEMPLATE(16)
+TEMPLATE(32)
+TEMPLATE(64)
+
+#undef TEMPLATE
+
+#define TEMPLATE(variant, qualifier) \
+bool \
+prop_dictionary_get_cstring ## variant (prop_dictionary_t dict, \
+ const char *key, \
+ qualifier char **cpp) \
+{ \
+ prop_string_t str; \
+ \
+ str = prop_dictionary_get(dict, key); \
+ if (prop_object_type(str) != PROP_TYPE_STRING) \
+ return (false); \
+ \
+ *cpp = prop_string_cstring ## variant (str); \
+ \
+ return (*cpp == NULL ? false : true); \
+} \
+ \
+bool \
+prop_dictionary_set_cstring ## variant (prop_dictionary_t dict, \
+ const char *key, \
+ const char *cp) \
+{ \
+ prop_string_t str; \
+ int rv; \
+ \
+ str = prop_string_create_cstring ## variant (cp); \
+ if (str == NULL) \
+ return (false); \
+ rv = prop_dictionary_set(dict, key, str); \
+ prop_object_release(str); \
+ \
+ return (rv); \
+}
+
+TEMPLATE(,)
+TEMPLATE(_nocopy,const)
+
+#undef TEMPLATE
+
+bool
+prop_dictionary_set_and_rel(prop_dictionary_t dict, const char *key,
+ prop_object_t po)
+{
+ bool ret;
+ if (po == NULL)
+ return false;
+ ret = prop_dictionary_set(dict, key, po);
+ prop_object_release(po);
+ return ret;
+}
--- /dev/null
+.\" $NetBSD: prop_ingest.3,v 1.6 2010/02/18 14:00:39 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 21, 2008
+.Dt PROP_INGEST 3
+.Os
+.Sh NAME
+.Nm prop_ingest_context_alloc ,
+.Nm prop_ingest_context_free ,
+.Nm prop_ingest_context_error ,
+.Nm prop_ingest_context_type ,
+.Nm prop_ingest_context_key ,
+.Nm prop_ingest_context_private ,
+.Nm prop_dictionary_ingest
+.Nd Ingest a dictionary into an arbitrary binary format
+.Sh SYNOPSIS
+.In prop/proplib.h
+.Ft prop_ingest_context_t
+.Fn prop_ingest_context_alloc "void *private"
+.Ft void
+.Fn prop_ingest_context_free "prop_ingest_context_t ctx"
+.Ft prop_ingest_error_t
+.Fn prop_ingest_context_error "prop_ingest_context_t ctx"
+.Ft prop_type_t
+.Fn prop_ingest_context_type "prop_ingest_context_t ctx"
+.Ft const char *
+.Fn prop_ingest_context_key "prop_ingest_context_t ctx"
+.Ft void *
+.Fn prop_ingest_context_private "prop_ingest_context_t ctx"
+.Ft bool
+.Fn prop_dictionary_ingest "prop_dictionary_t dict" \
+ "const prop_ingest_table_entry rules[]" \
+ "prop_ingest_context_t ctx"
+.Pp
+.Ft typedef bool
+.Fn (*prop_ingest_handler_t) "prop_ingest_context_t" "prop_object_t"
+.Sh DESCRIPTION
+The
+.Nm prop_dictionary_ingest
+function provides a convenient way to convert a property list into
+an arbitrary binary format or to extract values from dictionaries in a
+way that is convenient to an application
+.Pq for configuration files, for example .
+.Pp
+.Nm prop_dictionary_ingest
+is driven by a table of rules provided by the application.
+Each rule consists of three items:
+.Bl -bullet
+.It
+A C string containing a key to be looked up in the dictionary.
+.It
+The expected property type of the object associated with the key
+(or
+.Dv PROP_TYPE_UNKNOWN
+to specify that any type is allowed).
+.It
+A callback function of type
+.Dv prop_ingest_handler_t
+that will perform the translation for the application.
+.El
+.Pp
+The table is constructed using a series of macros as follows:
+.Bd -literal
+static const prop_ingest_table_entry ingest_rules[] = {
+ PROP_INGEST("file-name", PROP_TYPE_STRING, ingest_filename),
+ PROP_INGEST("count", PROP_TYPE_NUMBER, ingest_count),
+ PROP_INGEST_OPTIONAL("required", PROP_TYPE_BOOL, ingest_required),
+ PROP_INGEST_OPTIONAL("extra", PROP_TYPE_UNKNOWN, ingest_extra),
+ PROP_INGEST_END
+};
+.Ed
+.Pp
+The
+.Dv PROP_INGEST
+macro specifies that the key is required to be present in the dictionary.
+The
+.Dv PROP_INGEST_OPTIONAL
+macro specifies that the presence of the key in the dictionary is optional.
+The
+.Dv PROP_INGEST_END
+macro marks the end of the rules table.
+.Pp
+In each case,
+.Nm prop_dictionary_ingest
+looks up the rule's key in the dictionary.
+If an object is present in the dictionary at that key, its type is checked
+against the type specified in the rule.
+A type specification of
+.Dv PROP_TYPE_UNKNOWN
+allows the object to be of any type.
+If the object does not exist and the rule is not marked as optional, then
+an error is returned.
+Otherwise, the handler specified in the rule is invoked with the ingest
+context and the object
+(or
+.Dv NULL
+if the key does not exist in the dictionary).
+The handler should return
+.Dv false
+if the value of the object is invalid to indicate failure and
+.Dv true
+otherwise.
+.Pp
+The ingest context contains several pieces of information that are
+useful during the ingest process.
+The context also provides specific error information should the ingest
+fail.
+.Bl -tag -width "xxxxx"
+.It Fn prop_ingest_context_alloc "void *private"
+Allocate an ingest context.
+The argument
+.Fa private
+may be used to pass application-specific context to the ingest handlers.
+Note that an ingest context can be re-used to perform multiple ingests.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_ingest_context_free "prop_ingest_context_t ctx"
+Free an ingest context.
+.It Fn prop_ingest_context_error "prop_ingest_context_t ctx"
+Returns the code indicating the error encountered during ingest.
+The following error codes are defined:
+.Pp
+.Bl -tag -width "PROP_INGEST_ERROR_HANDLER_FAILED" -compact
+.It Dv PROP_INGEST_ERROR_NO_ERROR
+No error was encountered during ingest.
+.It Dv PROP_INGEST_ERROR_NO_KEY
+A non-optional key was not found in the dictionary.
+.It Dv PROP_INGEST_ERROR_WRONG_TYPE
+An object in the dictionary was not the same type specified in the rules.
+.It Dv PROP_INGEST_ERROR_HANDLER_FAILED
+An object's handler returned
+.Dv false .
+.El
+.Pp
+.It Fn prop_ingest_context_type "prop_ingest_context_t ctx"
+Returns the type of the last object visited during an ingest.
+When called by an ingest handler, it returns the type of the object
+currently being processed.
+.It Fn prop_ingest_context_key "prop_ingest_context_t ctx"
+Returns the last dictionary key looked up during an ingest.
+When called by an ingest handler, it returns the dictionary key corresponding
+to the object currently being processed.
+.It Fn prop_ingest_context_private "prop_ingest_context_t ctx"
+Returns the private data set when the context was allocated with
+.Fn prop_ingest_context_alloc .
+.El
+.Sh SEE ALSO
+.Xr prop_dictionary 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_ingest.c,v 1.3 2008/04/28 20:22:53 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h"
+
+struct _prop_ingest_context {
+ prop_ingest_error_t pic_error;
+ prop_type_t pic_type;
+ const char * pic_key;
+ void * pic_private;
+};
+
+/*
+ * prop_ingest_context_alloc --
+ * Allocate and initialize an ingest context.
+ */
+prop_ingest_context_t
+prop_ingest_context_alloc(void *private)
+{
+ prop_ingest_context_t ctx;
+
+ ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP);
+ if (ctx != NULL) {
+ ctx->pic_error = PROP_INGEST_ERROR_NO_ERROR;
+ ctx->pic_type = PROP_TYPE_UNKNOWN;
+ ctx->pic_key = NULL;
+ ctx->pic_private = private;
+ }
+ return (ctx);
+}
+
+/*
+ * prop_ingest_context_free --
+ * Free an ingest context.
+ */
+void
+prop_ingest_context_free(prop_ingest_context_t ctx)
+{
+
+ _PROP_FREE(ctx, M_TEMP);
+}
+
+/*
+ * prop_ingest_context_error --
+ * Get the error code from an ingest context.
+ */
+prop_ingest_error_t
+prop_ingest_context_error(prop_ingest_context_t ctx)
+{
+
+ return (ctx->pic_error);
+}
+
+/*
+ * prop_ingest_context_type --
+ * Return the type of last object visisted by an ingest context.
+ */
+prop_type_t
+prop_ingest_context_type(prop_ingest_context_t ctx)
+{
+
+ return (ctx->pic_type);
+}
+
+/*
+ * prop_ingest_context_key --
+ * Return the last key looked up by an ingest context.
+ */
+const char *
+prop_ingest_context_key(prop_ingest_context_t ctx)
+{
+
+ return (ctx->pic_key);
+}
+
+/*
+ * prop_ingest_context_private --
+ * Return the caller-private data associated with an ingest context.
+ */
+void *
+prop_ingest_context_private(prop_ingest_context_t ctx)
+{
+
+ return (ctx->pic_private);
+}
+
+/*
+ * prop_dictionary_ingest --
+ * Ingest a dictionary using handlers for each object to translate
+ * into an arbitrary binary format.
+ */
+bool
+prop_dictionary_ingest(prop_dictionary_t dict,
+ const prop_ingest_table_entry rules[],
+ prop_ingest_context_t ctx)
+{
+ const prop_ingest_table_entry *pite;
+ prop_object_t obj;
+
+ ctx->pic_error = PROP_INGEST_ERROR_NO_ERROR;
+
+ for (pite = rules; pite->pite_key != NULL; pite++) {
+ ctx->pic_key = pite->pite_key;
+ obj = prop_dictionary_get(dict, pite->pite_key);
+ ctx->pic_type = prop_object_type(obj);
+ if (obj == NULL) {
+ if (pite->pite_flags & PROP_INGEST_FLAG_OPTIONAL) {
+ if ((*pite->pite_handler)(ctx, NULL) == false) {
+ ctx->pic_error =
+ PROP_INGEST_ERROR_HANDLER_FAILED;
+ return (false);
+ }
+ continue;
+ }
+ ctx->pic_error = PROP_INGEST_ERROR_NO_KEY;
+ return (false);
+ }
+ if (ctx->pic_type != pite->pite_type &&
+ pite->pite_type != PROP_TYPE_UNKNOWN) {
+ ctx->pic_error = PROP_INGEST_ERROR_WRONG_TYPE;
+ return (false);
+ }
+ if ((*pite->pite_handler)(ctx, obj) == false) {
+ ctx->pic_error = PROP_INGEST_ERROR_HANDLER_FAILED;
+ return (false);
+ }
+ }
+
+ return (true);
+}
--- /dev/null
+/* $NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__NetBSD__)
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <prop/proplib.h>
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef RUMP_ACTION
+#include <rump/rump_syscalls.h>
+#define ioctl(a,b,c) rump_sys_ioctl(a,b,c)
+#endif
+
+static int
+_prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
+ char **bufp)
+{
+ char *buf;
+
+ switch (prop_object_type(obj)) {
+ case PROP_TYPE_DICTIONARY:
+ buf = prop_dictionary_externalize(obj);
+ break;
+ case PROP_TYPE_ARRAY:
+ buf = prop_array_externalize(obj);
+ break;
+ default:
+ return (ENOTSUP);
+ }
+ if (buf == NULL) {
+ /* Assume we ran out of memory. */
+ return (ENOMEM);
+ }
+ pref->pref_plist = buf;
+ pref->pref_len = strlen(buf) + 1;
+
+ *bufp = buf;
+
+ return (0);
+}
+
+bool
+prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
+{
+ char *buf;
+ int rv;
+
+ rv = _prop_object_externalize_to_pref(array, prefp, &buf);
+ if (rv != 0)
+ errno = rv; /* pass up error value in errno */
+ return (rv == 0);
+}
+
+/*
+ * prop_array_externalize_to_pref --
+ * Externalize an array into a plistref for sending to the kernel.
+ */
+int
+prop_array_send_syscall(prop_array_t array, struct plistref *prefp)
+{
+ if (prop_array_externalize_to_pref(array, prefp))
+ return 0;
+ else
+ return errno;
+}
+
+bool
+prop_dictionary_externalize_to_pref(prop_dictionary_t dict,
+ struct plistref *prefp)
+{
+ char *buf;
+ int rv;
+
+ rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
+ if (rv != 0)
+ errno = rv; /* pass up error value in errno */
+ return (rv == 0);
+}
+
+/*
+ * prop_dictionary_externalize_to_pref --
+ * Externalize an dictionary into a plistref for sending to the kernel.
+ */
+int
+prop_dictionary_send_syscall(prop_dictionary_t dict,
+ struct plistref *prefp)
+{
+ if (prop_dictionary_externalize_to_pref(dict, prefp))
+ return 0;
+ else
+ return errno;
+}
+
+static int
+_prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
+{
+ struct plistref pref;
+ char *buf;
+ int error;
+
+ error = _prop_object_externalize_to_pref(obj, &pref, &buf);
+ if (error)
+ return (error);
+
+ if (ioctl(fd, cmd, &pref) == -1)
+ error = errno;
+ else
+ error = 0;
+
+ free(buf);
+
+ return (error);
+}
+
+/*
+ * prop_array_send_ioctl --
+ * Send an array to the kernel using the specified ioctl.
+ */
+int
+prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
+{
+ int rv;
+
+ rv = _prop_object_send_ioctl(array, fd, cmd);
+ if (rv != 0) {
+ errno = rv; /* pass up error value in errno */
+ return rv;
+ } else
+ return 0;
+}
+
+/*
+ * prop_dictionary_send_ioctl --
+ * Send a dictionary to the kernel using the specified ioctl.
+ */
+int
+prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
+{
+ int rv;
+
+ rv = _prop_object_send_ioctl(dict, fd, cmd);
+ if (rv != 0) {
+ errno = rv; /* pass up error value in errno */
+ return rv;
+ } else
+ return 0;
+}
+
+static int
+_prop_object_internalize_from_pref(const struct plistref *pref,
+ prop_type_t type, prop_object_t *objp)
+{
+ prop_object_t obj = NULL;
+ char *buf;
+ int error = 0;
+
+ if (pref->pref_len == 0) {
+ /*
+ * This should never happen; we should always get the XML
+ * for an empty dictionary if it's really empty.
+ */
+ error = EIO;
+ goto out;
+ } else {
+ buf = pref->pref_plist;
+ buf[pref->pref_len - 1] = '\0'; /* extra insurance */
+ switch (type) {
+ case PROP_TYPE_DICTIONARY:
+ obj = prop_dictionary_internalize(buf);
+ break;
+ case PROP_TYPE_ARRAY:
+ obj = prop_array_internalize(buf);
+ break;
+ default:
+ error = ENOTSUP;
+ }
+ (void) munmap(buf, pref->pref_len);
+ if (obj == NULL && error == 0)
+ error = EIO;
+ }
+
+ out:
+ if (error == 0)
+ *objp = obj;
+ return (error);
+}
+
+/*
+ * prop_array_internalize_from_pref --
+ * Internalize a pref into a prop_array_t object.
+ */
+bool
+prop_array_internalize_from_pref(const struct plistref *prefp,
+ prop_array_t *arrayp)
+{
+ int rv;
+
+ rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_ARRAY,
+ (prop_object_t *)arrayp);
+ if (rv != 0)
+ errno = rv; /* pass up error value in errno */
+ return (rv == 0);
+}
+
+/*
+ * prop_array_recv_syscall --
+ * Internalize an array received from the kernel as pref.
+ */
+int
+prop_array_recv_syscall(const struct plistref *prefp,
+ prop_array_t *arrayp)
+{
+ if (prop_array_internalize_from_pref(prefp, arrayp))
+ return 0;
+ else
+ return errno;
+}
+
+/*
+ * prop_dictionary_internalize_from_pref --
+ * Internalize a pref into a prop_dictionary_t object.
+ */
+bool
+prop_dictionary_internalize_from_pref(const struct plistref *prefp,
+ prop_dictionary_t *dictp)
+{
+ int rv;
+
+ rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_DICTIONARY,
+ (prop_object_t *)dictp);
+ if (rv != 0)
+ errno = rv; /* pass up error value in errno */
+ return (rv == 0);
+}
+
+/*
+ * prop_dictionary_recv_syscall --
+ * Internalize a dictionary received from the kernel as pref.
+ */
+int
+prop_dictionary_recv_syscall(const struct plistref *prefp,
+ prop_dictionary_t *dictp)
+{
+ if (prop_dictionary_internalize_from_pref(prefp, dictp))
+ return 0;
+ else
+ return errno;
+}
+
+
+/*
+ * prop_array_recv_ioctl --
+ * Receive an array from the kernel using the specified ioctl.
+ */
+int
+prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
+{
+ int rv;
+ struct plistref pref;
+
+ rv = ioctl(fd, cmd, &pref);
+ if (rv == -1)
+ return errno;
+
+ rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
+ (prop_object_t *)arrayp);
+ if (rv != 0) {
+ errno = rv; /* pass up error value in errno */
+ return rv;
+ } else
+ return 0;
+}
+
+/*
+ * prop_dictionary_recv_ioctl --
+ * Receive a dictionary from the kernel using the specified ioctl.
+ */
+int
+prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
+{
+ int rv;
+ struct plistref pref;
+
+ rv = ioctl(fd, cmd, &pref);
+ if (rv == -1)
+ return errno;
+
+ rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
+ (prop_object_t *)dictp);
+ if (rv != 0) {
+ errno = rv; /* pass up error value in errno */
+ return rv;
+ } else
+ return 0;
+}
+
+/*
+ * prop_dictionary_sendrecv_ioctl --
+ * Combination send/receive a dictionary to/from the kernel using
+ * the specified ioctl.
+ */
+int
+prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
+ unsigned long cmd, prop_dictionary_t *dictp)
+{
+ struct plistref pref;
+ char *buf;
+ int error;
+
+ error = _prop_object_externalize_to_pref(dict, &pref, &buf);
+ if (error != 0) {
+ errno = error;
+ return error;
+ }
+
+ if (ioctl(fd, cmd, &pref) == -1)
+ error = errno;
+ else
+ error = 0;
+
+ free(buf);
+
+ if (error != 0)
+ return error;
+
+ error = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
+ (prop_object_t *)dictp);
+ if (error != 0) {
+ errno = error; /* pass up error value in errno */
+ return error;
+ } else
+ return 0;
+}
+#endif /* !_KERNEL && !_STANDALONE */
+
+#if defined(_KERNEL)
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/errno.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/resource.h>
+#include <sys/pool.h>
+
+#include <uvm/uvm.h>
+
+#include "prop_object_impl.h"
+
+/* Arbitrary limit ioctl input to 64KB */
+unsigned int prop_object_copyin_limit = 65536;
+
+/* initialize proplib for use in the kernel */
+void
+prop_kern_init(void)
+{
+ __link_set_decl(prop_linkpools, struct prop_pool_init);
+ struct prop_pool_init * const *pi;
+
+ __link_set_foreach(pi, prop_linkpools)
+ pool_init((*pi)->pp, (*pi)->size, 0, 0, 0, (*pi)->wchan,
+ &pool_allocator_nointr, IPL_NONE);
+}
+
+static int
+_prop_object_copyin(const struct plistref *pref, const prop_type_t type,
+ prop_object_t *objp)
+{
+ prop_object_t obj = NULL;
+ char *buf;
+ int error;
+
+ /*
+ * Allocate an extra byte so we can guarantee NUL-termination.
+ *
+ * Allow malloc to fail in case pmap would be exhausted.
+ */
+ buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL);
+ if (buf == NULL)
+ return (ENOMEM);
+ error = copyin(pref->pref_plist, buf, pref->pref_len);
+ if (error) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+ buf[pref->pref_len] = '\0';
+
+ switch (type) {
+ case PROP_TYPE_ARRAY:
+ obj = prop_array_internalize(buf);
+ break;
+ case PROP_TYPE_DICTIONARY:
+ obj = prop_dictionary_internalize(buf);
+ break;
+ default:
+ error = ENOTSUP;
+ }
+
+ free(buf, M_TEMP);
+ if (obj == NULL) {
+ if (error == 0)
+ error = EIO;
+ } else {
+ *objp = obj;
+ }
+ return (error);
+}
+
+
+static int
+_prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
+ const u_long cmd, prop_object_t *objp)
+{
+ if ((cmd & IOC_IN) == 0)
+ return (EFAULT);
+
+ return _prop_object_copyin(pref, type, objp);
+}
+
+/*
+ * prop_array_copyin --
+ * Copy in an array passed as a syscall arg.
+ */
+int
+prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
+{
+ return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
+ (prop_object_t *)arrayp));
+}
+
+/*
+ * prop_dictionary_copyin --
+ * Copy in a dictionary passed as a syscall arg.
+ */
+int
+prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
+{
+ return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
+ (prop_object_t *)dictp));
+}
+
+
+/*
+ * prop_array_copyin_ioctl --
+ * Copy in an array send with an ioctl.
+ */
+int
+prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
+ prop_array_t *arrayp)
+{
+ return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
+ cmd, (prop_object_t *)arrayp));
+}
+
+/*
+ * prop_dictionary_copyin_ioctl --
+ * Copy in a dictionary sent with an ioctl.
+ */
+int
+prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
+ prop_dictionary_t *dictp)
+{
+ return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
+ cmd, (prop_object_t *)dictp));
+}
+
+static int
+_prop_object_copyout(struct plistref *pref, prop_object_t obj)
+{
+ struct lwp *l = curlwp; /* XXX */
+ struct proc *p = l->l_proc;
+ char *buf;
+ size_t len, rlen;
+ int error = 0;
+ vaddr_t uaddr;
+
+ switch (prop_object_type(obj)) {
+ case PROP_TYPE_ARRAY:
+ buf = prop_array_externalize(obj);
+ break;
+ case PROP_TYPE_DICTIONARY:
+ buf = prop_dictionary_externalize(obj);
+ break;
+ default:
+ return (ENOTSUP);
+ }
+ if (buf == NULL)
+ return (ENOMEM);
+
+ len = strlen(buf) + 1;
+ rlen = round_page(len);
+
+ /*
+ * See sys_mmap() in sys/uvm/uvm_mmap.c.
+ * Let's act as if we were calling mmap(0, ...)
+ */
+ uaddr = p->p_emul->e_vm_default_addr(p,
+ (vaddr_t)p->p_vmspace->vm_daddr, rlen);
+
+ error = uvm_mmap(&p->p_vmspace->vm_map,
+ &uaddr, rlen,
+ VM_PROT_READ|VM_PROT_WRITE,
+ VM_PROT_READ|VM_PROT_WRITE,
+ MAP_PRIVATE|MAP_ANON,
+ NULL, 0,
+ p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
+
+ if (error == 0) {
+ error = copyout(buf, (char *)uaddr, len);
+ if (error == 0) {
+ pref->pref_plist = (char *)uaddr;
+ pref->pref_len = len;
+ }
+ }
+
+ free(buf, M_TEMP);
+
+ return (error);
+}
+
+/*
+ * prop_array_copyout --
+ * Copy out an array to a syscall arg.
+ */
+int
+prop_array_copyout(struct plistref *pref, prop_array_t array)
+{
+ return (_prop_object_copyout(pref, array));
+}
+
+/*
+ * prop_dictionary_copyout --
+ * Copy out a dictionary to a syscall arg.
+ */
+int
+prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
+{
+ return (_prop_object_copyout(pref, dict));
+}
+
+static int
+_prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
+ prop_object_t obj)
+{
+ if ((cmd & IOC_OUT) == 0)
+ return (EFAULT);
+ return _prop_object_copyout(pref, obj);
+}
+
+
+/*
+ * prop_array_copyout_ioctl --
+ * Copy out an array being received with an ioctl.
+ */
+int
+prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
+ prop_array_t array)
+{
+ return (_prop_object_copyout_ioctl(pref, cmd, array));
+}
+
+/*
+ * prop_dictionary_copyout_ioctl --
+ * Copy out a dictionary being received with an ioctl.
+ */
+int
+prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
+ prop_dictionary_t dict)
+{
+ return (
+ _prop_object_copyout_ioctl(pref, cmd, dict));
+}
+#endif /* _KERNEL */
+
+#endif /* __NetBSD__ */
--- /dev/null
+.\" $NetBSD: prop_number.3,v 1.10 2011/01/20 10:44:42 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 21, 2008
+.Dt PROP_NUMBER 3
+.Os
+.Sh NAME
+.Nm prop_number ,
+.Nm prop_number_create_integer ,
+.Nm prop_number_create_unsigned_integer ,
+.Nm prop_number_copy ,
+.Nm prop_number_size ,
+.Nm prop_number_unsigned ,
+.Nm prop_number_integer_value ,
+.Nm prop_number_unsigned_integer_value ,
+.Nm prop_number_equals ,
+.Nm prop_number_equals_integer ,
+.Nm prop_number_equals_unsigned_integer
+.Nd numeric value property object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_number_t
+.Fn prop_number_create_integer "int64_t val"
+.Ft prop_number_t
+.Fn prop_number_create_unsigned_integer "uint64_t val"
+.Ft prop_number_t
+.Fn prop_number_copy "prop_number_t number"
+.\"
+.Ft int
+.Fn prop_number_size "prop_number_t number"
+.Ft bool
+.Fn prop_number_unsigned "prop_number_t number"
+.Ft int64_t
+.Fn prop_number_integer_value "prop_number_t number"
+.Ft uint64_t
+.Fn prop_number_unsigned_integer_value "prop_number_t number"
+.\"
+.Ft bool
+.Fn prop_number_equals "prop_number_t num1" "prop_number_t num2"
+.Ft bool
+.Fn prop_number_equals_integer "prop_number_t number" "int64_t val"
+.Ft bool
+.Fn prop_number_equals_unsigned_integer "prop_number_t number" "uint64_t val"
+.Sh DESCRIPTION
+The
+.Nm prop_number
+family of functions operate on a numeric value property object type.
+Values are either signed or unsigned, and promoted to a 64-bit type
+.Pq int64_t or uint64_t , respectively .
+.Pp
+It is possible to compare number objects that differ in sign.
+Such comparisons first test to see if each object is within the valid
+number range of the other:
+.Bl -bullet
+.It
+Signed numbers that are greater than or equal to 0 can be compared to
+unsigned numbers.
+.It
+Unsigned numbers that are less than or equal to the largest signed 64-bit
+value
+.Pq Dv INT64_MAX
+can be compared to signed numbers.
+.El
+.Pp
+Number objects have a different externalized representation depending
+on their sign:
+.Bl -bullet
+.It
+Signed numbers are externalized in base-10
+.Pq decimal .
+.It
+Unsigned numbers are externalized in base-16
+.Pq hexadecimal .
+.El
+.Pp
+When numbers are internalized, the sign of the resulting number object
+.Pq and thus its valid range
+is determined by a set of rules evaluated in the following order:
+.Bl -bullet
+.It
+If the first character of the number is a
+.Sq -
+then the number is signed.
+.It
+If the first two characters of the number are
+.Sq 0x
+then the number is unsigned.
+.It
+If the number value fits into the range of a signed number then the
+number is signed.
+.It
+In all other cases, the number is unsigned.
+.El
+.Bl -tag -width "xxxxx"
+.It Fn prop_number_create_integer "int64_t val"
+Create a numeric value object with the signed value
+.Fa val .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_number_create_unsigned_integer "uint64_t val"
+Create a numeric value object with the unsigned value
+.Fa val .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_number_copy "prop_number_t number"
+Copy a numeric value object.
+If the supplied object isn't a numeric value,
+.Dv NULL
+is returned.
+.It Fn prop_number_size "prop_number_t number"
+Returns 8, 16, 32, or 64, representing the number of bits required to
+hold the value of the object.
+If the supplied object isn't a numeric value,
+.Dv NULL
+is returned.
+.It Fn prop_number_unsigned "prop_number_t number"
+Returns
+.Dv true
+if the numeric value object has an unsigned value.
+.It Fn prop_number_integer_value "prop_number_t number"
+Returns the signed integer value of the numeric value object.
+If the supplied object isn't a numeric value, zero is returned.
+Thus,
+it is not possible to distinguish between
+.Dq not a prop_number_t
+and
+.Dq prop_number_t has a value of 0 .
+.It Fn prop_number_unsigned_integer_value "prop_number_t number"
+Returns the unsigned integer value of the numeric value object.
+If the supplied object isn't a numeric value, zero is returned.
+Thus,
+it is not possible to distinguish between
+.Dq not a prop_number_t
+and
+.Dq prop_number_t has a value of 0 .
+.It Fn prop_number_equals "prop_number_t num1" "prop_number_t num2"
+Returns
+.Dv true
+if the two numeric value objects are equivalent.
+If at least one of the supplied objects isn't a numeric value,
+.Dv false
+is returned.
+.It Fn prop_number_equals_integer "prop_number_t number" "int64_t val"
+Returns
+.Dv true
+if the object's value is equivalent to the signed value
+.Fa val .
+If the supplied object isn't a numerical value or if
+.Fa val
+exceeds
+.Dv INT64_MAX ,
+.Dv false
+is returned.
+.It Fn prop_number_equals_unsigned_integer "prop_number_t number" \
+ "uint64_t val"
+Returns
+.Dv true
+if the object's value is equivalent to the unsigned value
+.Fa val .
+If the supplied object isn't a numerical value or if
+.Fa val
+exceeds
+.Dv INT64_MAX ,
+.Dv false
+is returned.
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_object 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_number.c,v 1.23 2010/09/24 22:51:52 rmind Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_number.h>
+#include "prop_object_impl.h"
+#include "prop_rb_impl.h"
+
+#if defined(_KERNEL)
+#include <sys/systm.h>
+#elif defined(_STANDALONE)
+#include <sys/param.h>
+#include <lib/libkern/libkern.h>
+#else
+#include <errno.h>
+#include <stdlib.h>
+#endif
+
+struct _prop_number {
+ struct _prop_object pn_obj;
+ struct rb_node pn_link;
+ struct _prop_number_value {
+ union {
+ int64_t pnu_signed;
+ uint64_t pnu_unsigned;
+ } pnv_un;
+#define pnv_signed pnv_un.pnu_signed
+#define pnv_unsigned pnv_un.pnu_unsigned
+ unsigned int pnv_is_unsigned :1,
+ :31;
+ } pn_value;
+};
+
+_PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr")
+
+static _prop_object_free_rv_t
+ _prop_number_free(prop_stack_t, prop_object_t *);
+static bool _prop_number_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_number_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+
+static void _prop_number_lock(void);
+static void _prop_number_unlock(void);
+
+static const struct _prop_object_type _prop_object_type_number = {
+ .pot_type = PROP_TYPE_NUMBER,
+ .pot_free = _prop_number_free,
+ .pot_extern = _prop_number_externalize,
+ .pot_equals = _prop_number_equals,
+ .pot_lock = _prop_number_lock,
+ .pot_unlock = _prop_number_unlock,
+};
+
+#define prop_object_is_number(x) \
+ ((x) != NULL && (x)->pn_obj.po_type == &_prop_object_type_number)
+
+/*
+ * Number objects are immutable, and we are likely to have many number
+ * objects that have the same value. So, to save memory, we unique'ify
+ * numbers so we only have one copy of each.
+ */
+
+static int
+_prop_number_compare_values(const struct _prop_number_value *pnv1,
+ const struct _prop_number_value *pnv2)
+{
+
+ /* Signed numbers are sorted before unsigned numbers. */
+
+ if (pnv1->pnv_is_unsigned) {
+ if (! pnv2->pnv_is_unsigned)
+ return (1);
+ if (pnv1->pnv_unsigned < pnv2->pnv_unsigned)
+ return (-1);
+ if (pnv1->pnv_unsigned > pnv2->pnv_unsigned)
+ return (1);
+ return (0);
+ }
+
+ if (pnv2->pnv_is_unsigned)
+ return (-1);
+ if (pnv1->pnv_signed < pnv2->pnv_signed)
+ return (-1);
+ if (pnv1->pnv_signed > pnv2->pnv_signed)
+ return (1);
+ return (0);
+}
+
+static int
+/*ARGSUSED*/
+_prop_number_rb_compare_nodes(void *ctx __unused,
+ const void *n1, const void *n2)
+{
+ const struct _prop_number *pn1 = n1;
+ const struct _prop_number *pn2 = n2;
+
+ return _prop_number_compare_values(&pn1->pn_value, &pn2->pn_value);
+}
+
+static int
+/*ARGSUSED*/
+_prop_number_rb_compare_key(void *ctx __unused, const void *n, const void *v)
+{
+ const struct _prop_number *pn = n;
+ const struct _prop_number_value *pnv = v;
+
+ return _prop_number_compare_values(&pn->pn_value, pnv);
+}
+
+static const rb_tree_ops_t _prop_number_rb_tree_ops = {
+ .rbto_compare_nodes = _prop_number_rb_compare_nodes,
+ .rbto_compare_key = _prop_number_rb_compare_key,
+ .rbto_node_offset = offsetof(struct _prop_number, pn_link),
+ .rbto_context = NULL
+};
+
+static struct rb_tree _prop_number_tree;
+_PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex)
+
+/* ARGSUSED */
+static _prop_object_free_rv_t
+_prop_number_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_number_t pn = *obj;
+
+ _prop_rb_tree_remove_node(&_prop_number_tree, pn);
+
+ _PROP_POOL_PUT(_prop_number_pool, pn);
+
+ return (_PROP_OBJECT_FREE_DONE);
+}
+
+_PROP_ONCE_DECL(_prop_number_init_once)
+
+static int
+_prop_number_init(void)
+{
+
+ _PROP_MUTEX_INIT(_prop_number_tree_mutex);
+ _prop_rb_tree_init(&_prop_number_tree, &_prop_number_rb_tree_ops);
+ return 0;
+}
+
+static void
+_prop_number_lock(void)
+{
+ /* XXX: init necessary? */
+ _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init);
+ _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
+}
+
+static void
+_prop_number_unlock(void)
+{
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+}
+
+static bool
+_prop_number_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_number_t pn = v;
+ char tmpstr[32];
+
+ /*
+ * For unsigned numbers, we output in hex. For signed numbers,
+ * we output in decimal.
+ */
+ if (pn->pn_value.pnv_is_unsigned)
+ sprintf(tmpstr, "0x%" PRIx64, pn->pn_value.pnv_unsigned);
+ else
+ sprintf(tmpstr, "%" PRIi64, pn->pn_value.pnv_signed);
+
+ if (_prop_object_externalize_start_tag(ctx, "integer") == false ||
+ _prop_object_externalize_append_cstring(ctx, tmpstr) == false ||
+ _prop_object_externalize_end_tag(ctx, "integer") == false)
+ return (false);
+
+ return (true);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_number_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_number_t num1 = v1;
+ prop_number_t num2 = v2;
+
+ /*
+ * There is only ever one copy of a number object at any given
+ * time, so we can reduce this to a simple pointer equality check
+ * in the common case.
+ */
+ if (num1 == num2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+
+ /*
+ * If the numbers are the same signed-ness, then we know they
+ * cannot be equal because they would have had pointer equality.
+ */
+ if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+
+ /*
+ * We now have one signed value and one unsigned value. We can
+ * compare them iff:
+ * - The unsigned value is not larger than the signed value
+ * can represent.
+ * - The signed value is not smaller than the unsigned value
+ * can represent.
+ */
+ if (num1->pn_value.pnv_is_unsigned) {
+ /*
+ * num1 is unsigned and num2 is signed.
+ */
+ if (num1->pn_value.pnv_unsigned > INT64_MAX)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ if (num2->pn_value.pnv_signed < 0)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ } else {
+ /*
+ * num1 is signed and num2 is unsigned.
+ */
+ if (num1->pn_value.pnv_signed < 0)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ if (num2->pn_value.pnv_unsigned > INT64_MAX)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ }
+
+ if (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed)
+ return _PROP_OBJECT_EQUALS_TRUE;
+ else
+ return _PROP_OBJECT_EQUALS_FALSE;
+}
+
+static prop_number_t
+_prop_number_alloc(const struct _prop_number_value *pnv)
+{
+ prop_number_t opn, pn, rpn;
+
+ _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init);
+
+ /*
+ * Check to see if this already exists in the tree. If it does,
+ * we just retain it and return it.
+ */
+ _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
+ opn = _prop_rb_tree_find(&_prop_number_tree, pnv);
+ if (opn != NULL) {
+ prop_object_retain(opn);
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+ return (opn);
+ }
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+
+ /*
+ * Not in the tree. Create it now.
+ */
+
+ pn = _PROP_POOL_GET(_prop_number_pool);
+ if (pn == NULL)
+ return (NULL);
+
+ _prop_object_init(&pn->pn_obj, &_prop_object_type_number);
+
+ pn->pn_value = *pnv;
+
+ /*
+ * We dropped the mutex when we allocated the new object, so
+ * we have to check again if it is in the tree.
+ */
+ _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
+ opn = _prop_rb_tree_find(&_prop_number_tree, pnv);
+ if (opn != NULL) {
+ prop_object_retain(opn);
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+ _PROP_POOL_PUT(_prop_number_pool, pn);
+ return (opn);
+ }
+ rpn = _prop_rb_tree_insert_node(&_prop_number_tree, pn);
+ _PROP_ASSERT(rpn == pn);
+ _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
+ return (pn);
+}
+
+/*
+ * prop_number_create_integer --
+ * Create a prop_number_t and initialize it with the
+ * provided integer value.
+ */
+prop_number_t
+prop_number_create_integer(int64_t val)
+{
+ struct _prop_number_value pnv;
+
+ memset(&pnv, 0, sizeof(pnv));
+ pnv.pnv_signed = val;
+ pnv.pnv_is_unsigned = false;
+
+ return (_prop_number_alloc(&pnv));
+}
+
+/*
+ * prop_number_create_unsigned_integer --
+ * Create a prop_number_t and initialize it with the
+ * provided unsigned integer value.
+ */
+prop_number_t
+prop_number_create_unsigned_integer(uint64_t val)
+{
+ struct _prop_number_value pnv;
+
+ memset(&pnv, 0, sizeof(pnv));
+ pnv.pnv_unsigned = val;
+ pnv.pnv_is_unsigned = true;
+
+ return (_prop_number_alloc(&pnv));
+}
+
+/*
+ * prop_number_copy --
+ * Copy a prop_number_t.
+ */
+prop_number_t
+prop_number_copy(prop_number_t opn)
+{
+
+ if (! prop_object_is_number(opn))
+ return (NULL);
+
+ /*
+ * Because we only ever allocate one object for any given
+ * value, this can be reduced to a simple retain operation.
+ */
+ prop_object_retain(opn);
+ return (opn);
+}
+
+/*
+ * prop_number_unsigned --
+ * Returns true if the prop_number_t has an unsigned value.
+ */
+bool
+prop_number_unsigned(prop_number_t pn)
+{
+
+ return (pn->pn_value.pnv_is_unsigned);
+}
+
+/*
+ * prop_number_size --
+ * Return the size, in bits, required to hold the value of
+ * the specified number.
+ */
+int
+prop_number_size(prop_number_t pn)
+{
+ struct _prop_number_value *pnv;
+
+ if (! prop_object_is_number(pn))
+ return (0);
+
+ pnv = &pn->pn_value;
+
+ if (pnv->pnv_is_unsigned) {
+ if (pnv->pnv_unsigned > UINT32_MAX)
+ return (64);
+ if (pnv->pnv_unsigned > UINT16_MAX)
+ return (32);
+ if (pnv->pnv_unsigned > UINT8_MAX)
+ return (16);
+ return (8);
+ }
+
+ if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN)
+ return (64);
+ if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN)
+ return (32);
+ if (pnv->pnv_signed > INT8_MAX || pnv->pnv_signed < INT8_MIN)
+ return (16);
+ return (8);
+}
+
+/*
+ * prop_number_integer_value --
+ * Get the integer value of a prop_number_t.
+ */
+int64_t
+prop_number_integer_value(prop_number_t pn)
+{
+
+ /*
+ * XXX Impossible to distinguish between "not a prop_number_t"
+ * XXX and "prop_number_t has a value of 0".
+ */
+ if (! prop_object_is_number(pn))
+ return (0);
+
+ return (pn->pn_value.pnv_signed);
+}
+
+/*
+ * prop_number_unsigned_integer_value --
+ * Get the unsigned integer value of a prop_number_t.
+ */
+uint64_t
+prop_number_unsigned_integer_value(prop_number_t pn)
+{
+
+ /*
+ * XXX Impossible to distinguish between "not a prop_number_t"
+ * XXX and "prop_number_t has a value of 0".
+ */
+ if (! prop_object_is_number(pn))
+ return (0);
+
+ return (pn->pn_value.pnv_unsigned);
+}
+
+/*
+ * prop_number_equals --
+ * Return true if two numbers are equivalent.
+ */
+bool
+prop_number_equals(prop_number_t num1, prop_number_t num2)
+{
+ if (!prop_object_is_number(num1) || !prop_object_is_number(num2))
+ return (false);
+
+ return (prop_object_equals(num1, num2));
+}
+
+/*
+ * prop_number_equals_integer --
+ * Return true if the number is equivalent to the specified integer.
+ */
+bool
+prop_number_equals_integer(prop_number_t pn, int64_t val)
+{
+
+ if (! prop_object_is_number(pn))
+ return (false);
+
+ if (pn->pn_value.pnv_is_unsigned &&
+ (pn->pn_value.pnv_unsigned > INT64_MAX || val < 0))
+ return (false);
+
+ return (pn->pn_value.pnv_signed == val);
+}
+
+/*
+ * prop_number_equals_unsigned_integer --
+ * Return true if the number is equivalent to the specified
+ * unsigned integer.
+ */
+bool
+prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val)
+{
+
+ if (! prop_object_is_number(pn))
+ return (false);
+
+ if (! pn->pn_value.pnv_is_unsigned &&
+ (pn->pn_value.pnv_signed < 0 || val > INT64_MAX))
+ return (false);
+
+ return (pn->pn_value.pnv_unsigned == val);
+}
+
+static bool
+_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
+ struct _prop_number_value *pnv)
+{
+ char *cp;
+
+ _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) ==
+ sizeof(uint64_t));
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
+ return (false);
+#endif
+ pnv->pnv_is_unsigned = true;
+ ctx->poic_cp = cp;
+
+ return (true);
+}
+
+static bool
+_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
+ struct _prop_number_value *pnv)
+{
+ char *cp;
+
+ _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t));
+
+#ifndef _KERNEL
+ errno = 0;
+#endif
+ pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
+#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
+ if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
+ errno == ERANGE)
+ return (false);
+#endif
+ pnv->pnv_is_unsigned = false;
+ ctx->poic_cp = cp;
+
+ return (true);
+}
+
+/*
+ * _prop_number_internalize --
+ * Parse a <number>...</number> and return the object created from
+ * the external representation.
+ */
+/* ARGSUSED */
+bool
+_prop_number_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ struct _prop_number_value pnv;
+
+ memset(&pnv, 0, sizeof(pnv));
+
+ /* No attributes, no empty elements. */
+ if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
+ return (true);
+
+ /*
+ * If the first character is '-', then we treat as signed.
+ * If the first two characters are "0x" (i.e. the number is
+ * in hex), then we treat as unsigned. Otherwise, we try
+ * signed first, and if that fails (presumably due to ERANGE),
+ * then we switch to unsigned.
+ */
+ if (ctx->poic_cp[0] == '-') {
+ if (_prop_number_internalize_signed(ctx, &pnv) == false)
+ return (true);
+ } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
+ if (_prop_number_internalize_unsigned(ctx, &pnv) == false)
+ return (true);
+ } else {
+ if (_prop_number_internalize_signed(ctx, &pnv) == false &&
+ _prop_number_internalize_unsigned(ctx, &pnv) == false)
+ return (true);
+ }
+
+ if (_prop_object_internalize_find_tag(ctx, "integer",
+ _PROP_TAG_TYPE_END) == false)
+ return (true);
+
+ *obj = _prop_number_alloc(&pnv);
+ return (true);
+}
--- /dev/null
+.\" $NetBSD: prop_object.3,v 1.8 2011/01/20 10:44:42 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd August 21, 2006
+.Dt PROP_OBJECT 3
+.Os
+.Sh NAME
+.Nm prop_object ,
+.Nm prop_object_retain ,
+.Nm prop_object_release ,
+.Nm prop_object_type ,
+.Nm prop_object_equals ,
+.Nm prop_object_iterator_next ,
+.Nm prop_object_iterator_reset ,
+.Nm prop_object_iterator_release
+.Nd general property container object functions
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft void
+.Fn prop_object_retain "prop_object_t obj"
+.Ft void
+.Fn prop_object_release "prop_object_t obj"
+.\"
+.Ft prop_type_t
+.Fn prop_object_type "prop_object_t obj"
+.Ft bool
+.Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2"
+.\"
+.Ft prop_object_t
+.Fn prop_object_iterator_next "prop_object_iterator_t iter"
+.Ft void
+.Fn prop_object_iterator_reset "prop_object_iterator_t iter"
+.Ft void
+.Fn prop_object_iterator_release "prop_object_iterator_t iter"
+.Sh DESCRIPTION
+The
+.Nm prop_object
+family of functions operate on all property container object types.
+.Bl -tag -width ""
+.It Fn prop_object_retain "prop_object_t obj"
+Increment the reference count on an object.
+.It Fn prop_object_release "prop_object_t obj"
+Decrement the reference count on an object.
+If the last reference is dropped, the object is freed.
+.It Fn prop_object_type "prop_object_t obj"
+Determine the type of the object.
+Objects are one of the following types:
+.Pp
+.Bl -tag -width "PROP_TYPE_DICT_KEYSYM" -compact
+.It Dv PROP_TYPE_BOOL
+Boolean value
+.Pq prop_bool_t
+.It Dv PROP_TYPE_NUMBER
+Number
+.Pq prop_number_t
+.It Dv PROP_TYPE_STRING
+String
+.Pq prop_string_t
+.It Dv PROP_TYPE_DATA
+Opaque data
+.Pq prop_data_t
+.It Dv PROP_TYPE_ARRAY
+Array
+.Pq prop_array_t
+.It Dv PROP_TYPE_DICTIONARY
+Dictionary
+.Pq prop_dictionary_t
+.It Dv PROP_TYPE_DICT_KEYSYM
+Dictionary key symbol
+.Pq prop_dictionary_keysym_t
+.El
+.Pp
+If
+.Fa obj
+is
+.Dv NULL ,
+then
+.Dv PROP_TYPE_UNKNOWN
+is returned.
+.It Fn prop_object_equals "prop_object_t obj1" "prop_object_t obj2"
+Returns
+.Dv true
+if the two objects are of the same type and are equivalent.
+.It Fn prop_object_iterator_next "prop_object_iterator_t iter"
+Return the next object in the collection
+.Pq array or dictionary
+being iterated by the iterator
+.Fa iter .
+If there are no more objects in the collection,
+.Dv NULL
+is returned.
+.It Fn prop_object_iterator_reset "prop_object_iterator_t iter"
+Reset the iterator to the first object in the collection being iterated
+by the iterator
+.Fa iter .
+.It Fn prop_object_iterator_release "prop_object_iterator_t iter"
+Release the iterator
+.Fa iter .
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr prop_string 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_object.c,v 1.27 2011/04/20 20:00:07 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_object.h>
+#include "prop_object_impl.h"
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <assert.h>
+#endif
+#include <sys/atomic.h>
+
+#ifdef _STANDALONE
+void *
+_prop_standalone_calloc(size_t size)
+{
+ void *rv;
+
+ rv = alloc(size);
+ if (rv != NULL)
+ memset(rv, 0, size);
+
+ return (rv);
+}
+
+void *
+_prop_standalone_realloc(void *v, size_t size)
+{
+ void *rv;
+
+ rv = alloc(size);
+ if (rv != NULL) {
+ memcpy(rv, v, size); /* XXX */
+ dealloc(v, 0); /* XXX */
+ }
+
+ return (rv);
+}
+#endif /* _STANDALONE */
+
+/*
+ * _prop_object_init --
+ * Initialize an object. Called when sub-classes create
+ * an instance.
+ */
+void
+_prop_object_init(struct _prop_object *po, const struct _prop_object_type *pot)
+{
+
+ po->po_type = pot;
+ po->po_refcnt = 1;
+}
+
+/*
+ * _prop_object_fini --
+ * Finalize an object. Called when sub-classes destroy
+ * an instance.
+ */
+/*ARGSUSED*/
+void
+_prop_object_fini(struct _prop_object *po _PROP_ARG_UNUSED)
+{
+ /* Nothing to do, currently. */
+}
+
+/*
+ * _prop_object_externalize_start_tag --
+ * Append an XML-style start tag to the externalize buffer.
+ */
+bool
+_prop_object_externalize_start_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == false)
+ return (false);
+ }
+ if (_prop_object_externalize_append_char(ctx, '<') == false ||
+ _prop_object_externalize_append_cstring(ctx, tag) == false ||
+ _prop_object_externalize_append_char(ctx, '>') == false)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_end_tag --
+ * Append an XML-style end tag to the externalize buffer.
+ */
+bool
+_prop_object_externalize_end_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+
+ if (_prop_object_externalize_append_char(ctx, '<') == false ||
+ _prop_object_externalize_append_char(ctx, '/') == false ||
+ _prop_object_externalize_append_cstring(ctx, tag) == false ||
+ _prop_object_externalize_append_char(ctx, '>') == false ||
+ _prop_object_externalize_append_char(ctx, '\n') == false)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_empty_tag --
+ * Append an XML-style empty tag to the externalize buffer.
+ */
+bool
+_prop_object_externalize_empty_tag(
+ struct _prop_object_externalize_context *ctx, const char *tag)
+{
+ unsigned int i;
+
+ for (i = 0; i < ctx->poec_depth; i++) {
+ if (_prop_object_externalize_append_char(ctx, '\t') == false)
+ return (false);
+ }
+
+ if (_prop_object_externalize_append_char(ctx, '<') == false ||
+ _prop_object_externalize_append_cstring(ctx, tag) == false ||
+ _prop_object_externalize_append_char(ctx, '/') == false ||
+ _prop_object_externalize_append_char(ctx, '>') == false ||
+ _prop_object_externalize_append_char(ctx, '\n') == false)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_append_cstring --
+ * Append a C string to the externalize buffer.
+ */
+bool
+_prop_object_externalize_append_cstring(
+ struct _prop_object_externalize_context *ctx, const char *cp)
+{
+
+ while (*cp != '\0') {
+ if (_prop_object_externalize_append_char(ctx,
+ (unsigned char) *cp) == false)
+ return (false);
+ cp++;
+ }
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_append_encoded_cstring --
+ * Append an encoded C string to the externalize buffer.
+ */
+bool
+_prop_object_externalize_append_encoded_cstring(
+ struct _prop_object_externalize_context *ctx, const char *cp)
+{
+
+ while (*cp != '\0') {
+ switch (*cp) {
+ case '<':
+ if (_prop_object_externalize_append_cstring(ctx,
+ "<") == false)
+ return (false);
+ break;
+ case '>':
+ if (_prop_object_externalize_append_cstring(ctx,
+ ">") == false)
+ return (false);
+ break;
+ case '&':
+ if (_prop_object_externalize_append_cstring(ctx,
+ "&") == false)
+ return (false);
+ break;
+ default:
+ if (_prop_object_externalize_append_char(ctx,
+ (unsigned char) *cp) == false)
+ return (false);
+ break;
+ }
+ cp++;
+ }
+
+ return (true);
+}
+
+#define BUF_EXPAND 256
+
+/*
+ * _prop_object_externalize_append_char --
+ * Append a single character to the externalize buffer.
+ */
+bool
+_prop_object_externalize_append_char(
+ struct _prop_object_externalize_context *ctx, unsigned char c)
+{
+
+ _PROP_ASSERT(ctx->poec_capacity != 0);
+ _PROP_ASSERT(ctx->poec_buf != NULL);
+ _PROP_ASSERT(ctx->poec_len <= ctx->poec_capacity);
+
+ if (ctx->poec_len == ctx->poec_capacity) {
+ char *cp = _PROP_REALLOC(ctx->poec_buf,
+ ctx->poec_capacity + BUF_EXPAND,
+ M_TEMP);
+ if (cp == NULL)
+ return (false);
+ ctx->poec_capacity = ctx->poec_capacity + BUF_EXPAND;
+ ctx->poec_buf = cp;
+ }
+
+ ctx->poec_buf[ctx->poec_len++] = c;
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_header --
+ * Append the standard XML header to the externalize buffer.
+ */
+bool
+_prop_object_externalize_header(struct _prop_object_externalize_context *ctx)
+{
+ static const char _plist_xml_header[] =
+"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n";
+
+ if (_prop_object_externalize_append_cstring(ctx,
+ _plist_xml_header) == false ||
+ _prop_object_externalize_start_tag(ctx,
+ "plist version=\"1.0\"") == false ||
+ _prop_object_externalize_append_char(ctx, '\n') == false)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_footer --
+ * Append the standard XML footer to the externalize buffer. This
+ * also NUL-terminates the buffer.
+ */
+bool
+_prop_object_externalize_footer(struct _prop_object_externalize_context *ctx)
+{
+
+ if (_prop_object_externalize_end_tag(ctx, "plist") == false ||
+ _prop_object_externalize_append_char(ctx, '\0') == false)
+ return (false);
+
+ return (true);
+}
+
+/*
+ * _prop_object_externalize_context_alloc --
+ * Allocate an externalize context.
+ */
+struct _prop_object_externalize_context *
+_prop_object_externalize_context_alloc(void)
+{
+ struct _prop_object_externalize_context *ctx;
+
+ ctx = _PROP_MALLOC(sizeof(*ctx), M_TEMP);
+ if (ctx != NULL) {
+ ctx->poec_buf = _PROP_MALLOC(BUF_EXPAND, M_TEMP);
+ if (ctx->poec_buf == NULL) {
+ _PROP_FREE(ctx, M_TEMP);
+ return (NULL);
+ }
+ ctx->poec_len = 0;
+ ctx->poec_capacity = BUF_EXPAND;
+ ctx->poec_depth = 0;
+ }
+ return (ctx);
+}
+
+/*
+ * _prop_object_externalize_context_free --
+ * Free an externalize context.
+ */
+void
+_prop_object_externalize_context_free(
+ struct _prop_object_externalize_context *ctx)
+{
+
+ /* Buffer is always freed by the caller. */
+ _PROP_FREE(ctx, M_TEMP);
+}
+
+/*
+ * _prop_object_internalize_skip_comment --
+ * Skip the body and end tag of a comment.
+ */
+static bool
+_prop_object_internalize_skip_comment(
+ struct _prop_object_internalize_context *ctx)
+{
+ const char *cp = ctx->poic_cp;
+
+ while (!_PROP_EOF(*cp)) {
+ if (cp[0] == '-' &&
+ cp[1] == '-' &&
+ cp[2] == '>') {
+ ctx->poic_cp = cp + 3;
+ return (true);
+ }
+ cp++;
+ }
+
+ return (false); /* ran out of buffer */
+}
+
+/*
+ * _prop_object_internalize_find_tag --
+ * Find the next tag in an XML stream. Optionally compare the found
+ * tag to an expected tag name. State of the context is undefined
+ * if this routine returns false. Upon success, the context points
+ * to the first octet after the tag.
+ */
+bool
+_prop_object_internalize_find_tag(struct _prop_object_internalize_context *ctx,
+ const char *tag, _prop_tag_type_t type)
+{
+ const char *cp;
+ size_t taglen;
+
+ if (tag != NULL)
+ taglen = strlen(tag);
+ else
+ taglen = 0;
+
+ start_over:
+ cp = ctx->poic_cp;
+
+ /*
+ * Find the start of the tag.
+ */
+ while (_PROP_ISSPACE(*cp))
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ if (*cp != '<')
+ return (false);
+
+ ctx->poic_tag_start = cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ if (*cp == '!') {
+ if (cp[1] != '-' || cp[2] != '-')
+ return (false);
+ /*
+ * Comment block -- only allowed if we are allowed to
+ * return a start tag.
+ */
+ if (type == _PROP_TAG_TYPE_END)
+ return (false);
+ ctx->poic_cp = cp + 3;
+ if (_prop_object_internalize_skip_comment(ctx) == false)
+ return (false);
+ goto start_over;
+ }
+
+ if (*cp == '/') {
+ if (type != _PROP_TAG_TYPE_END &&
+ type != _PROP_TAG_TYPE_EITHER)
+ return (false);
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+ ctx->poic_tag_type = _PROP_TAG_TYPE_END;
+ } else {
+ if (type != _PROP_TAG_TYPE_START &&
+ type != _PROP_TAG_TYPE_EITHER)
+ return (false);
+ ctx->poic_tag_type = _PROP_TAG_TYPE_START;
+ }
+
+ ctx->poic_tagname = cp;
+
+ while (!_PROP_ISSPACE(*cp) && *cp != '/' && *cp != '>')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ ctx->poic_tagname_len = cp - ctx->poic_tagname;
+
+ /* Make sure this is the tag we're looking for. */
+ if (tag != NULL &&
+ (taglen != ctx->poic_tagname_len ||
+ memcmp(tag, ctx->poic_tagname, taglen) != 0))
+ return (false);
+
+ /* Check for empty tag. */
+ if (*cp == '/') {
+ if (ctx->poic_tag_type != _PROP_TAG_TYPE_START)
+ return(false); /* only valid on start tags */
+ ctx->poic_is_empty_element = true;
+ cp++;
+ if (_PROP_EOF(*cp) || *cp != '>')
+ return (false);
+ } else
+ ctx->poic_is_empty_element = false;
+
+ /* Easy case of no arguments. */
+ if (*cp == '>') {
+ ctx->poic_tagattr = NULL;
+ ctx->poic_tagattr_len = 0;
+ ctx->poic_tagattrval = NULL;
+ ctx->poic_tagattrval_len = 0;
+ ctx->poic_cp = cp + 1;
+ return (true);
+ }
+
+ _PROP_ASSERT(!_PROP_EOF(*cp));
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ while (_PROP_ISSPACE(*cp))
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ ctx->poic_tagattr = cp;
+
+ while (!_PROP_ISSPACE(*cp) && *cp != '=')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ ctx->poic_tagattr_len = cp - ctx->poic_tagattr;
+
+ cp++;
+ if (*cp != '\"')
+ return (false);
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+
+ ctx->poic_tagattrval = cp;
+ while (*cp != '\"')
+ cp++;
+ if (_PROP_EOF(*cp))
+ return (false);
+ ctx->poic_tagattrval_len = cp - ctx->poic_tagattrval;
+
+ cp++;
+ if (*cp != '>')
+ return (false);
+
+ ctx->poic_cp = cp + 1;
+ return (true);
+}
+
+/*
+ * _prop_object_internalize_decode_string --
+ * Decode an encoded string.
+ */
+bool
+_prop_object_internalize_decode_string(
+ struct _prop_object_internalize_context *ctx,
+ char *target, size_t targsize, size_t *sizep,
+ const char **cpp)
+{
+ const char *src;
+ size_t tarindex;
+ char c;
+
+ tarindex = 0;
+ src = ctx->poic_cp;
+
+ for (;;) {
+ if (_PROP_EOF(*src))
+ return (false);
+ if (*src == '<') {
+ break;
+ }
+
+ if ((c = *src) == '&') {
+ if (src[1] == 'a' &&
+ src[2] == 'm' &&
+ src[3] == 'p' &&
+ src[4] == ';') {
+ c = '&';
+ src += 5;
+ } else if (src[1] == 'l' &&
+ src[2] == 't' &&
+ src[3] == ';') {
+ c = '<';
+ src += 4;
+ } else if (src[1] == 'g' &&
+ src[2] == 't' &&
+ src[3] == ';') {
+ c = '>';
+ src += 4;
+ } else if (src[1] == 'a' &&
+ src[2] == 'p' &&
+ src[3] == 'o' &&
+ src[4] == 's' &&
+ src[5] == ';') {
+ c = '\'';
+ src += 6;
+ } else if (src[1] == 'q' &&
+ src[2] == 'u' &&
+ src[3] == 'o' &&
+ src[4] == 't' &&
+ src[5] == ';') {
+ c = '\"';
+ src += 6;
+ } else
+ return (false);
+ } else
+ src++;
+ if (target) {
+ if (tarindex >= targsize)
+ return (false);
+ target[tarindex] = c;
+ }
+ tarindex++;
+ }
+
+ _PROP_ASSERT(*src == '<');
+ if (sizep != NULL)
+ *sizep = tarindex;
+ if (cpp != NULL)
+ *cpp = src;
+
+ return (true);
+}
+
+/*
+ * _prop_object_internalize_match --
+ * Returns true if the two character streams match.
+ */
+bool
+_prop_object_internalize_match(const char *str1, size_t len1,
+ const char *str2, size_t len2)
+{
+
+ return (len1 == len2 && memcmp(str1, str2, len1) == 0);
+}
+
+#define INTERNALIZER(t, f) \
+{ t, sizeof(t) - 1, f }
+
+static const struct _prop_object_internalizer {
+ const char *poi_tag;
+ size_t poi_taglen;
+ prop_object_internalizer_t poi_intern;
+} _prop_object_internalizer_table[] = {
+ INTERNALIZER("array", _prop_array_internalize),
+
+ INTERNALIZER("true", _prop_bool_internalize),
+ INTERNALIZER("false", _prop_bool_internalize),
+
+ INTERNALIZER("data", _prop_data_internalize),
+
+ INTERNALIZER("dict", _prop_dictionary_internalize),
+
+ INTERNALIZER("integer", _prop_number_internalize),
+
+ INTERNALIZER("string", _prop_string_internalize),
+
+ { 0, 0, NULL }
+};
+
+#undef INTERNALIZER
+
+/*
+ * _prop_object_internalize_by_tag --
+ * Determine the object type from the tag in the context and
+ * internalize it.
+ */
+prop_object_t
+_prop_object_internalize_by_tag(struct _prop_object_internalize_context *ctx)
+{
+ const struct _prop_object_internalizer *poi;
+ prop_object_t obj, parent_obj;
+ void *data, *iter;
+ prop_object_internalizer_continue_t iter_func;
+ struct _prop_stack stack;
+
+ _prop_stack_init(&stack);
+
+match_start:
+ for (poi = _prop_object_internalizer_table;
+ poi->poi_tag != NULL; poi++) {
+ if (_prop_object_internalize_match(ctx->poic_tagname,
+ ctx->poic_tagname_len,
+ poi->poi_tag,
+ poi->poi_taglen))
+ break;
+ }
+ if ((poi == NULL) || (poi->poi_tag == NULL)) {
+ while (_prop_stack_pop(&stack, &obj, &iter, &data, NULL)) {
+ iter_func = (prop_object_internalizer_continue_t)iter;
+ (*iter_func)(&stack, &obj, ctx, data, NULL);
+ }
+
+ return (NULL);
+ }
+
+ obj = NULL;
+ if (!(*poi->poi_intern)(&stack, &obj, ctx))
+ goto match_start;
+
+ parent_obj = obj;
+ while (_prop_stack_pop(&stack, &parent_obj, &iter, &data, NULL)) {
+ iter_func = (prop_object_internalizer_continue_t)iter;
+ if (!(*iter_func)(&stack, &parent_obj, ctx, data, obj))
+ goto match_start;
+ obj = parent_obj;
+ }
+
+ return (parent_obj);
+}
+
+prop_object_t
+_prop_generic_internalize(const char *xml, const char *master_tag)
+{
+ prop_object_t obj = NULL;
+ struct _prop_object_internalize_context *ctx;
+
+ ctx = _prop_object_internalize_context_alloc(xml);
+ if (ctx == NULL)
+ return (NULL);
+
+ /* We start with a <plist> tag. */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_START) == false)
+ goto out;
+
+ /* Plist elements cannot be empty. */
+ if (ctx->poic_is_empty_element)
+ goto out;
+
+ /*
+ * We don't understand any plist attributes, but Apple XML
+ * property lists often have a "version" attribute. If we
+ * see that one, we simply ignore it.
+ */
+ if (ctx->poic_tagattr != NULL &&
+ !_PROP_TAGATTR_MATCH(ctx, "version"))
+ goto out;
+
+ /* Next we expect to see opening master_tag. */
+ if (_prop_object_internalize_find_tag(ctx, master_tag,
+ _PROP_TAG_TYPE_START) == false)
+ goto out;
+
+ obj = _prop_object_internalize_by_tag(ctx);
+ if (obj == NULL)
+ goto out;
+
+ /*
+ * We've advanced past the closing master_tag.
+ * Now we want </plist>.
+ */
+ if (_prop_object_internalize_find_tag(ctx, "plist",
+ _PROP_TAG_TYPE_END) == false) {
+ prop_object_release(obj);
+ obj = NULL;
+ }
+
+ out:
+ _prop_object_internalize_context_free(ctx);
+ return (obj);
+}
+
+/*
+ * _prop_object_internalize_context_alloc --
+ * Allocate an internalize context.
+ */
+struct _prop_object_internalize_context *
+_prop_object_internalize_context_alloc(const char *xml)
+{
+ struct _prop_object_internalize_context *ctx;
+
+ ctx = _PROP_MALLOC(sizeof(struct _prop_object_internalize_context),
+ M_TEMP);
+ if (ctx == NULL)
+ return (NULL);
+
+ ctx->poic_xml = ctx->poic_cp = xml;
+
+ /*
+ * Skip any whitespace and XML preamble stuff that we don't
+ * know about / care about.
+ */
+ for (;;) {
+ while (_PROP_ISSPACE(*xml))
+ xml++;
+ if (_PROP_EOF(*xml) || *xml != '<')
+ goto bad;
+
+#define MATCH(str) (memcmp(&xml[1], str, sizeof(str) - 1) == 0)
+
+ /*
+ * Skip over the XML preamble that Apple XML property
+ * lists usually include at the top of the file.
+ */
+ if (MATCH("?xml ") ||
+ MATCH("!DOCTYPE plist")) {
+ while (*xml != '>' && !_PROP_EOF(*xml))
+ xml++;
+ if (_PROP_EOF(*xml))
+ goto bad;
+ xml++; /* advance past the '>' */
+ continue;
+ }
+
+ if (MATCH("<!--")) {
+ ctx->poic_cp = xml + 4;
+ if (_prop_object_internalize_skip_comment(ctx) == false)
+ goto bad;
+ xml = ctx->poic_cp;
+ continue;
+ }
+
+#undef MATCH
+
+ /*
+ * We don't think we should skip it, so let's hope we can
+ * parse it.
+ */
+ break;
+ }
+
+ ctx->poic_cp = xml;
+ return (ctx);
+ bad:
+ _PROP_FREE(ctx, M_TEMP);
+ return (NULL);
+}
+
+/*
+ * _prop_object_internalize_context_free --
+ * Free an internalize context.
+ */
+void
+_prop_object_internalize_context_free(
+ struct _prop_object_internalize_context *ctx)
+{
+
+ _PROP_FREE(ctx, M_TEMP);
+}
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+/*
+ * _prop_object_externalize_file_dirname --
+ * dirname(3), basically. We have to roll our own because the
+ * system dirname(3) isn't reentrant.
+ */
+static void
+_prop_object_externalize_file_dirname(const char *path, char *result)
+{
+ const char *lastp;
+ size_t len;
+
+ /*
+ * If `path' is a NULL pointer or points to an empty string,
+ * return ".".
+ */
+ if (path == NULL || *path == '\0')
+ goto singledot;
+
+ /* String trailing slashes, if any. */
+ lastp = path + strlen(path) - 1;
+ while (lastp != path && *lastp == '/')
+ lastp--;
+
+ /* Terminate path at the last occurrence of '/'. */
+ do {
+ if (*lastp == '/') {
+ /* Strip trailing slashes, if any. */
+ while (lastp != path && *lastp == '/')
+ lastp--;
+
+ /* ...and copy the result into the result buffer. */
+ len = (lastp - path) + 1 /* last char */;
+ if (len > (PATH_MAX - 1))
+ len = PATH_MAX - 1;
+
+ memcpy(result, path, len);
+ result[len] = '\0';
+ return;
+ }
+ } while (--lastp >= path);
+
+ /* No /'s found, return ".". */
+ singledot:
+ strcpy(result, ".");
+}
+
+/*
+ * _prop_object_externalize_write_file --
+ * Write an externalized dictionary to the specified file.
+ * The file is written atomically from the caller's perspective,
+ * and the mode set to 0666 modified by the caller's umask.
+ */
+bool
+_prop_object_externalize_write_file(const char *fname, const char *xml,
+ size_t len)
+{
+ char tname[PATH_MAX];
+ int fd;
+ int save_errno;
+ mode_t myumask;
+
+ if (len > SSIZE_MAX) {
+ errno = EFBIG;
+ return (false);
+ }
+
+ /*
+ * Get the directory name where the file is to be written
+ * and create the temporary file.
+ */
+ _prop_object_externalize_file_dirname(fname, tname);
+ if (strlcat(tname, "/.plistXXXXXX", sizeof(tname)) >= sizeof(tname)) {
+ errno = ENAMETOOLONG;
+ return (false);
+ }
+ if ((fd = mkstemp(tname)) == -1)
+ return (false);
+
+ if (write(fd, xml, len) != (ssize_t)len)
+ goto bad;
+
+ if (fsync(fd) == -1)
+ goto bad;
+
+ myumask = umask(0);
+ (void)umask(myumask);
+ if (fchmod(fd, 0666 & ~myumask) == -1)
+ goto bad;
+
+ (void) close(fd);
+ fd = -1;
+
+ if (rename(tname, fname) == -1)
+ goto bad;
+
+ return (true);
+
+ bad:
+ save_errno = errno;
+ if (fd != -1)
+ (void) close(fd);
+ (void) unlink(tname);
+ errno = save_errno;
+ return (false);
+}
+
+/*
+ * _prop_object_internalize_map_file --
+ * Map a file for the purpose of internalizing it.
+ */
+struct _prop_object_internalize_mapped_file *
+_prop_object_internalize_map_file(const char *fname)
+{
+ struct stat sb;
+ struct _prop_object_internalize_mapped_file *mf;
+ size_t pgsize = (size_t)sysconf(_SC_PAGESIZE);
+ size_t pgmask = pgsize - 1;
+ bool need_guard = false;
+ int fd;
+
+ mf = _PROP_MALLOC(sizeof(*mf), M_TEMP);
+ if (mf == NULL)
+ return (NULL);
+
+ fd = open(fname, O_RDONLY, 0400);
+ if (fd == -1) {
+ _PROP_FREE(mf, M_TEMP);
+ return (NULL);
+ }
+
+ if (fstat(fd, &sb) == -1) {
+ (void) close(fd);
+ _PROP_FREE(mf, M_TEMP);
+ return (NULL);
+ }
+ mf->poimf_mapsize = ((size_t)sb.st_size + pgmask) & ~pgmask;
+ if (mf->poimf_mapsize < (size_t)sb.st_size) {
+ (void) close(fd);
+ _PROP_FREE(mf, M_TEMP);
+ return (NULL);
+ }
+
+ /*
+ * If the file length is an integral number of pages, then we
+ * need to map a guard page at the end in order to provide the
+ * necessary NUL-termination of the buffer.
+ */
+ if ((sb.st_size & pgmask) == 0)
+ need_guard = true;
+
+#ifndef __minix
+ mf->poimf_xml = mmap(NULL, need_guard ? mf->poimf_mapsize + pgsize
+ : mf->poimf_mapsize,
+ PROT_READ, MAP_FILE|MAP_SHARED, fd, (off_t)0);
+#else
+ mf->poimf_xml = MAP_FAILED;
+#endif
+ (void) close(fd);
+ if (mf->poimf_xml == MAP_FAILED) {
+ _PROP_FREE(mf, M_TEMP);
+ return (NULL);
+ }
+
+#ifndef __minix
+ (void) madvise(mf->poimf_xml, mf->poimf_mapsize, MADV_SEQUENTIAL);
+
+ if (need_guard) {
+ if (mmap(mf->poimf_xml + mf->poimf_mapsize,
+ pgsize, PROT_READ,
+ MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1,
+ (off_t)0) == MAP_FAILED) {
+ (void) munmap(mf->poimf_xml, mf->poimf_mapsize);
+ _PROP_FREE(mf, M_TEMP);
+ return (NULL);
+ }
+ mf->poimf_mapsize += pgsize;
+ }
+#endif
+
+ return (mf);
+}
+
+/*
+ * _prop_object_internalize_unmap_file --
+ * Unmap a file previously mapped for internalizing.
+ */
+void
+_prop_object_internalize_unmap_file(
+ struct _prop_object_internalize_mapped_file *mf)
+{
+
+#ifndef __minix
+ (void) madvise(mf->poimf_xml, mf->poimf_mapsize, MADV_DONTNEED);
+ (void) munmap(mf->poimf_xml, mf->poimf_mapsize);
+ _PROP_FREE(mf, M_TEMP);
+#else
+ assert(0);
+#endif
+}
+#endif /* !_KERNEL && !_STANDALONE */
+
+/*
+ * prop_object_retain --
+ * Increment the reference count on an object.
+ */
+void
+prop_object_retain(prop_object_t obj)
+{
+ struct _prop_object *po = obj;
+ uint32_t ncnt;
+
+ ncnt = atomic_inc_32_nv(&po->po_refcnt);
+ _PROP_ASSERT(ncnt != 0);
+}
+
+/*
+ * prop_object_release_emergency
+ * A direct free with prop_object_release failed.
+ * Walk down the tree until a leaf is found and
+ * free that. Do not recurse to avoid stack overflows.
+ *
+ * This is a slow edge condition, but necessary to
+ * guarantee that an object can always be freed.
+ */
+static void
+prop_object_release_emergency(prop_object_t obj)
+{
+ struct _prop_object *po;
+ void (*unlock)(void);
+ prop_object_t parent = NULL;
+ uint32_t ocnt;
+
+ for (;;) {
+ po = obj;
+ _PROP_ASSERT(obj);
+
+ if (po->po_type->pot_lock != NULL)
+ po->po_type->pot_lock();
+
+ /* Save pointerto unlock function */
+ unlock = po->po_type->pot_unlock;
+
+ /* Dance a bit to make sure we always get the non-racy ocnt */
+ ocnt = atomic_dec_32_nv(&po->po_refcnt);
+ ocnt++;
+ _PROP_ASSERT(ocnt != 0);
+
+ if (ocnt != 1) {
+ if (unlock != NULL)
+ unlock();
+ break;
+ }
+
+ _PROP_ASSERT(po->po_type);
+ if ((po->po_type->pot_free)(NULL, &obj) ==
+ _PROP_OBJECT_FREE_DONE) {
+ if (unlock != NULL)
+ unlock();
+ break;
+ }
+
+ if (unlock != NULL)
+ unlock();
+
+ parent = po;
+ atomic_inc_32(&po->po_refcnt);
+ }
+ _PROP_ASSERT(parent);
+ /* One object was just freed. */
+ po = parent;
+ (*po->po_type->pot_emergency_free)(parent);
+}
+
+/*
+ * prop_object_release --
+ * Decrement the reference count on an object.
+ *
+ * Free the object if we are releasing the final
+ * reference.
+ */
+void
+prop_object_release(prop_object_t obj)
+{
+ struct _prop_object *po;
+ struct _prop_stack stack;
+ void (*unlock)(void);
+ int ret;
+ uint32_t ocnt;
+
+ _prop_stack_init(&stack);
+
+ do {
+ do {
+ po = obj;
+ _PROP_ASSERT(obj);
+
+ if (po->po_type->pot_lock != NULL)
+ po->po_type->pot_lock();
+
+ /* Save pointer to object unlock function */
+ unlock = po->po_type->pot_unlock;
+
+ ocnt = atomic_dec_32_nv(&po->po_refcnt);
+ ocnt++;
+ _PROP_ASSERT(ocnt != 0);
+
+ if (ocnt != 1) {
+ ret = 0;
+ if (unlock != NULL)
+ unlock();
+ break;
+ }
+
+ ret = (po->po_type->pot_free)(&stack, &obj);
+
+ if (unlock != NULL)
+ unlock();
+
+ if (ret == _PROP_OBJECT_FREE_DONE)
+ break;
+
+ atomic_inc_32(&po->po_refcnt);
+ } while (ret == _PROP_OBJECT_FREE_RECURSE);
+ if (ret == _PROP_OBJECT_FREE_FAILED)
+ prop_object_release_emergency(obj);
+ } while (_prop_stack_pop(&stack, &obj, NULL, NULL, NULL));
+}
+
+/*
+ * prop_object_type --
+ * Return the type of an object.
+ */
+prop_type_t
+prop_object_type(prop_object_t obj)
+{
+ struct _prop_object *po = obj;
+
+ if (obj == NULL)
+ return (PROP_TYPE_UNKNOWN);
+
+ return (po->po_type->pot_type);
+}
+
+/*
+ * prop_object_equals --
+ * Returns true if thw two objects are equivalent.
+ */
+bool
+prop_object_equals(prop_object_t obj1, prop_object_t obj2)
+{
+ return (prop_object_equals_with_error(obj1, obj2, NULL));
+}
+
+bool
+prop_object_equals_with_error(prop_object_t obj1, prop_object_t obj2,
+ bool *error_flag)
+{
+ struct _prop_object *po1;
+ struct _prop_object *po2;
+ void *stored_pointer1, *stored_pointer2;
+ prop_object_t next_obj1, next_obj2;
+ struct _prop_stack stack;
+ _prop_object_equals_rv_t ret;
+
+ _prop_stack_init(&stack);
+ if (error_flag)
+ *error_flag = false;
+
+ start_subtree:
+ stored_pointer1 = NULL;
+ stored_pointer2 = NULL;
+ po1 = obj1;
+ po2 = obj2;
+
+ if (po1->po_type != po2->po_type)
+ return (false);
+
+ continue_subtree:
+ ret = (*po1->po_type->pot_equals)(obj1, obj2,
+ &stored_pointer1, &stored_pointer2,
+ &next_obj1, &next_obj2);
+ if (ret == _PROP_OBJECT_EQUALS_FALSE)
+ goto finish;
+ if (ret == _PROP_OBJECT_EQUALS_TRUE) {
+ if (!_prop_stack_pop(&stack, &obj1, &obj2,
+ &stored_pointer1, &stored_pointer2))
+ return true;
+ po1 = obj1;
+ po2 = obj2;
+ goto continue_subtree;
+ }
+ _PROP_ASSERT(ret == _PROP_OBJECT_EQUALS_RECURSE);
+
+ if (!_prop_stack_push(&stack, obj1, obj2,
+ stored_pointer1, stored_pointer2)) {
+ if (error_flag)
+ *error_flag = true;
+ goto finish;
+ }
+ obj1 = next_obj1;
+ obj2 = next_obj2;
+ goto start_subtree;
+
+finish:
+ while (_prop_stack_pop(&stack, &obj1, &obj2, NULL, NULL)) {
+ po1 = obj1;
+ (*po1->po_type->pot_equals_finish)(obj1, obj2);
+ }
+ return (false);
+}
+
+/*
+ * prop_object_iterator_next --
+ * Return the next item during an iteration.
+ */
+prop_object_t
+prop_object_iterator_next(prop_object_iterator_t pi)
+{
+
+ return ((*pi->pi_next_object)(pi));
+}
+
+/*
+ * prop_object_iterator_reset --
+ * Reset the iterator to the first object so as to restart
+ * iteration.
+ */
+void
+prop_object_iterator_reset(prop_object_iterator_t pi)
+{
+
+ (*pi->pi_reset)(pi);
+}
+
+/*
+ * prop_object_iterator_release --
+ * Release the object iterator.
+ */
+void
+prop_object_iterator_release(prop_object_iterator_t pi)
+{
+
+ prop_object_release(pi->pi_obj);
+ _PROP_FREE(pi, M_TEMP);
+}
--- /dev/null
+/* $NetBSD: prop_object_impl.h,v 1.30 2009/09/13 18:45:10 pooka Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_OBJECT_IMPL_H_
+#define _PROPLIB_PROP_OBJECT_IMPL_H_
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+#include <lib/libkern/libkern.h>
+#else
+#include <inttypes.h>
+#endif
+
+#include "prop_stack.h"
+
+struct _prop_object_externalize_context {
+ char * poec_buf; /* string buffer */
+ size_t poec_capacity; /* capacity of buffer */
+ size_t poec_len; /* current length of string */
+ unsigned int poec_depth; /* nesting depth */
+};
+
+bool _prop_object_externalize_start_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+bool _prop_object_externalize_end_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+bool _prop_object_externalize_empty_tag(
+ struct _prop_object_externalize_context *,
+ const char *);
+bool _prop_object_externalize_append_cstring(
+ struct _prop_object_externalize_context *,
+ const char *);
+bool _prop_object_externalize_append_encoded_cstring(
+ struct _prop_object_externalize_context *,
+ const char *);
+bool _prop_object_externalize_append_char(
+ struct _prop_object_externalize_context *,
+ unsigned char);
+bool _prop_object_externalize_header(
+ struct _prop_object_externalize_context *);
+bool _prop_object_externalize_footer(
+ struct _prop_object_externalize_context *);
+
+struct _prop_object_externalize_context *
+ _prop_object_externalize_context_alloc(void);
+void _prop_object_externalize_context_free(
+ struct _prop_object_externalize_context *);
+
+typedef enum {
+ _PROP_TAG_TYPE_START, /* e.g. <dict> */
+ _PROP_TAG_TYPE_END, /* e.g. </dict> */
+ _PROP_TAG_TYPE_EITHER
+} _prop_tag_type_t;
+
+struct _prop_object_internalize_context {
+ const char *poic_xml;
+ const char *poic_cp;
+
+ const char *poic_tag_start;
+
+ const char *poic_tagname;
+ size_t poic_tagname_len;
+ const char *poic_tagattr;
+ size_t poic_tagattr_len;
+ const char *poic_tagattrval;
+ size_t poic_tagattrval_len;
+
+ bool poic_is_empty_element;
+ _prop_tag_type_t poic_tag_type;
+};
+
+typedef enum {
+ _PROP_OBJECT_FREE_DONE,
+ _PROP_OBJECT_FREE_RECURSE,
+ _PROP_OBJECT_FREE_FAILED
+} _prop_object_free_rv_t;
+
+typedef enum {
+ _PROP_OBJECT_EQUALS_FALSE,
+ _PROP_OBJECT_EQUALS_TRUE,
+ _PROP_OBJECT_EQUALS_RECURSE
+} _prop_object_equals_rv_t;
+
+#define _PROP_EOF(c) ((c) == '\0')
+#define _PROP_ISSPACE(c) \
+ ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' || \
+ _PROP_EOF(c))
+
+#define _PROP_TAG_MATCH(ctx, t) \
+ _prop_object_internalize_match((ctx)->poic_tagname, \
+ (ctx)->poic_tagname_len, \
+ (t), strlen(t))
+
+#define _PROP_TAGATTR_MATCH(ctx, a) \
+ _prop_object_internalize_match((ctx)->poic_tagattr, \
+ (ctx)->poic_tagattr_len, \
+ (a), strlen(a))
+
+#define _PROP_TAGATTRVAL_MATCH(ctx, a) \
+ _prop_object_internalize_match((ctx)->poic_tagattrval, \
+ (ctx)->poic_tagattrval_len,\
+ (a), strlen(a))
+
+bool _prop_object_internalize_find_tag(
+ struct _prop_object_internalize_context *,
+ const char *, _prop_tag_type_t);
+bool _prop_object_internalize_match(const char *, size_t,
+ const char *, size_t);
+prop_object_t _prop_object_internalize_by_tag(
+ struct _prop_object_internalize_context *);
+bool _prop_object_internalize_decode_string(
+ struct _prop_object_internalize_context *,
+ char *, size_t, size_t *, const char **);
+prop_object_t _prop_generic_internalize(const char *, const char *);
+
+struct _prop_object_internalize_context *
+ _prop_object_internalize_context_alloc(const char *);
+void _prop_object_internalize_context_free(
+ struct _prop_object_internalize_context *);
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+bool _prop_object_externalize_write_file(const char *,
+ const char *, size_t);
+
+struct _prop_object_internalize_mapped_file {
+ char * poimf_xml;
+ size_t poimf_mapsize;
+};
+
+struct _prop_object_internalize_mapped_file *
+ _prop_object_internalize_map_file(const char *);
+void _prop_object_internalize_unmap_file(
+ struct _prop_object_internalize_mapped_file *);
+#endif /* !_KERNEL && !_STANDALONE */
+
+typedef bool (*prop_object_internalizer_t)(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+typedef bool (*prop_object_internalizer_continue_t)(prop_stack_t,
+ prop_object_t *,
+ struct _prop_object_internalize_context *,
+ void *, prop_object_t);
+
+ /* These are here because they're required by shared code. */
+bool _prop_array_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+bool _prop_bool_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+bool _prop_data_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+bool _prop_dictionary_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+bool _prop_number_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+bool _prop_string_internalize(prop_stack_t, prop_object_t *,
+ struct _prop_object_internalize_context *);
+
+struct _prop_object_type {
+ /* type indicator */
+ uint32_t pot_type;
+ /* func to free object */
+ _prop_object_free_rv_t
+ (*pot_free)(prop_stack_t, prop_object_t *);
+ /*
+ * func to free the child returned by pot_free with stack == NULL.
+ *
+ * Must be implemented if pot_free can return anything other than
+ * _PROP_OBJECT_FREE_DONE.
+ */
+ void (*pot_emergency_free)(prop_object_t);
+ /* func to externalize object */
+ bool (*pot_extern)(struct _prop_object_externalize_context *,
+ void *);
+ /* func to test quality */
+ _prop_object_equals_rv_t
+ (*pot_equals)(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+ /*
+ * func to finish equality iteration.
+ *
+ * Must be implemented if pot_equals can return
+ * _PROP_OBJECT_EQUALS_RECURSE
+ */
+ void (*pot_equals_finish)(prop_object_t, prop_object_t);
+ void (*pot_lock)(void);
+ void (*pot_unlock)(void);
+};
+
+struct _prop_object {
+ const struct _prop_object_type *po_type;/* type descriptor */
+ uint32_t po_refcnt; /* reference count */
+};
+
+void _prop_object_init(struct _prop_object *,
+ const struct _prop_object_type *);
+void _prop_object_fini(struct _prop_object *);
+
+struct _prop_object_iterator {
+ prop_object_t (*pi_next_object)(void *);
+ void (*pi_reset)(void *);
+ prop_object_t pi_obj;
+ uint32_t pi_version;
+};
+
+#define _PROP_NOTHREAD_ONCE_DECL(x) static bool x = false;
+#define _PROP_NOTHREAD_ONCE_RUN(x,f) \
+ do { \
+ if ((x) == false) { \
+ f(); \
+ x = true; \
+ } \
+ } while (/*CONSTCOND*/0)
+
+#if defined(_KERNEL)
+
+/*
+ * proplib in the kernel...
+ */
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/pool.h>
+#include <sys/systm.h>
+#include <sys/rwlock.h>
+#include <sys/once.h>
+
+#define _PROP_ASSERT(x) KASSERT(x)
+
+#define _PROP_MALLOC(s, t) malloc((s), (t), M_WAITOK)
+#define _PROP_CALLOC(s, t) malloc((s), (t), M_WAITOK | M_ZERO)
+#define _PROP_REALLOC(v, s, t) realloc((v), (s), (t), M_WAITOK)
+#define _PROP_FREE(v, t) free((v), (t))
+
+#define _PROP_POOL_GET(p) pool_get(&(p), PR_WAITOK)
+#define _PROP_POOL_PUT(p, v) pool_put(&(p), (v))
+
+struct prop_pool_init {
+ struct pool *pp;
+ size_t size;
+ const char *wchan;
+};
+#define _PROP_POOL_INIT(pp, size, wchan) \
+struct pool pp; \
+static const struct prop_pool_init _link_ ## pp[1] = { \
+ { &pp, size, wchan } \
+}; \
+__link_set_add_rodata(prop_linkpools, _link_ ## pp);
+
+#define _PROP_MALLOC_DEFINE(t, s, l) \
+ MALLOC_DEFINE(t, s, l);
+
+#define _PROP_MUTEX_DECL_STATIC(x) static kmutex_t x;
+#define _PROP_MUTEX_INIT(x) mutex_init(&(x),MUTEX_DEFAULT,IPL_NONE)
+#define _PROP_MUTEX_LOCK(x) mutex_enter(&(x))
+#define _PROP_MUTEX_UNLOCK(x) mutex_exit(&(x))
+
+#define _PROP_RWLOCK_DECL(x) krwlock_t x ;
+#define _PROP_RWLOCK_INIT(x) rw_init(&(x))
+#define _PROP_RWLOCK_RDLOCK(x) rw_enter(&(x), RW_READER)
+#define _PROP_RWLOCK_WRLOCK(x) rw_enter(&(x), RW_WRITER)
+#define _PROP_RWLOCK_UNLOCK(x) rw_exit(&(x))
+#define _PROP_RWLOCK_DESTROY(x) rw_destroy(&(x))
+
+#define _PROP_ONCE_DECL(x) static ONCE_DECL(x);
+#define _PROP_ONCE_RUN(x,f) RUN_ONCE(&(x), f)
+
+#elif defined(_STANDALONE)
+
+/*
+ * proplib in a standalone environment...
+ */
+
+#include <lib/libsa/stand.h>
+
+void * _prop_standalone_calloc(size_t);
+void * _prop_standalone_realloc(void *, size_t);
+
+#define _PROP_ASSERT(x) /* nothing */
+
+#define _PROP_MALLOC(s, t) alloc((s))
+#define _PROP_CALLOC(s, t) _prop_standalone_calloc((s))
+#define _PROP_REALLOC(v, s, t) _prop_standalone_realloc((v), (s))
+#define _PROP_FREE(v, t) dealloc((v), 0) /* XXX */
+
+#define _PROP_POOL_GET(p) alloc((p))
+#define _PROP_POOL_PUT(p, v) dealloc((v), (p))
+
+#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
+
+#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
+
+#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
+#define _PROP_MUTEX_INIT(x) /* nothing */
+#define _PROP_MUTEX_LOCK(x) /* nothing */
+#define _PROP_MUTEX_UNLOCK(x) /* nothing */
+
+#define _PROP_RWLOCK_DECL(x) /* nothing */
+#define _PROP_RWLOCK_INIT(x) /* nothing */
+#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
+#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
+#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
+#define _PROP_RWLOCK_DESTROY(x) /* nothing */
+
+#define _PROP_ONCE_DECL(x) _PROP_NOTHREAD_ONCE_DECL(x)
+#define _PROP_ONCE_RUN(x,f) _PROP_NOTHREAD_ONCE_RUN(x,f)
+
+#else
+
+/*
+ * proplib in user space...
+ */
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+#define _PROP_ASSERT(x) /*LINTED*/assert(x)
+
+#define _PROP_MALLOC(s, t) malloc((s))
+#define _PROP_CALLOC(s, t) calloc(1, (s))
+#define _PROP_REALLOC(v, s, t) realloc((v), (s))
+#define _PROP_FREE(v, t) free((v))
+
+#define _PROP_POOL_GET(p) malloc((p))
+#define _PROP_POOL_PUT(p, v) free((v))
+
+#define _PROP_POOL_INIT(p, s, d) static const size_t p = s;
+
+#define _PROP_MALLOC_DEFINE(t, s, l) /* nothing */
+
+#if (defined(__NetBSD__) && defined(_LIBPROP))
+/*
+ * Use the same mechanism as libc; we get pthread mutexes for threaded
+ * programs and do-nothing stubs for non-threaded programs.
+ */
+#include "reentrant.h"
+#define _PROP_MUTEX_DECL_STATIC(x) static mutex_t x;
+#define _PROP_MUTEX_INIT(x) mutex_init(&(x), NULL)
+#define _PROP_MUTEX_LOCK(x) mutex_lock(&(x))
+#define _PROP_MUTEX_UNLOCK(x) mutex_unlock(&(x))
+
+#define _PROP_RWLOCK_DECL(x) rwlock_t x ;
+#define _PROP_RWLOCK_INIT(x) rwlock_init(&(x), NULL)
+#define _PROP_RWLOCK_RDLOCK(x) rwlock_rdlock(&(x))
+#define _PROP_RWLOCK_WRLOCK(x) rwlock_wrlock(&(x))
+#define _PROP_RWLOCK_UNLOCK(x) rwlock_unlock(&(x))
+#define _PROP_RWLOCK_DESTROY(x) rwlock_destroy(&(x))
+
+#define _PROP_ONCE_DECL(x) \
+ static pthread_once_t x = PTHREAD_ONCE_INIT;
+#define _PROP_ONCE_RUN(x,f) thr_once(&(x), (void(*)(void))f);
+
+#elif defined(HAVE_NBTOOL_CONFIG_H) || defined(__minix)
+/*
+ * None of NetBSD's build tools are multi-threaded.
+ */
+#define _PROP_MUTEX_DECL_STATIC(x) /* nothing */
+#define _PROP_MUTEX_INIT(x) /* nothing */
+#define _PROP_MUTEX_LOCK(x) /* nothing */
+#define _PROP_MUTEX_UNLOCK(x) /* nothing */
+
+#define _PROP_RWLOCK_DECL(x) /* nothing */
+#define _PROP_RWLOCK_INIT(x) /* nothing */
+#define _PROP_RWLOCK_RDLOCK(x) /* nothing */
+#define _PROP_RWLOCK_WRLOCK(x) /* nothing */
+#define _PROP_RWLOCK_UNLOCK(x) /* nothing */
+#define _PROP_RWLOCK_DESTROY(x) /* nothing */
+
+#define _PROP_ONCE_DECL(x) _PROP_NOTHREAD_ONCE_DECL(x)
+#define _PROP_ONCE_RUN(x,f) _PROP_NOTHREAD_ONCE_RUN(x,f)
+#else
+/*
+ * Use pthread mutexes everywhere else.
+ */
+#include <pthread.h>
+#define _PROP_MUTEX_DECL_STATIC(x) static pthread_mutex_t x;
+#define _PROP_MUTEX_INIT(x) pthread_mutex_init(&(x), NULL)
+#define _PROP_MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+#define _PROP_MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+
+#define _PROP_RWLOCK_DECL(x) pthread_rwlock_t x ;
+#define _PROP_RWLOCK_INIT(x) pthread_rwlock_init(&(x), NULL)
+#define _PROP_RWLOCK_RDLOCK(x) pthread_rwlock_rdlock(&(x))
+#define _PROP_RWLOCK_WRLOCK(x) pthread_rwlock_wrlock(&(x))
+#define _PROP_RWLOCK_UNLOCK(x) pthread_rwlock_unlock(&(x))
+#define _PROP_RWLOCK_DESTROY(x) pthread_rwlock_destroy(&(x))
+
+#define _PROP_ONCE_DECL(x) \
+ static pthread_once_t x = PTHREAD_ONCE_INIT;
+#define _PROP_ONCE_RUN(x,f) pthread_once(&(x),(void(*)(void))f)
+#endif
+
+#endif /* _KERNEL */
+
+/*
+ * Language features.
+ */
+#if defined(__NetBSD__)
+#include <sys/cdefs.h>
+#define _PROP_ARG_UNUSED __unused
+#else
+#define _PROP_ARG_UNUSED /* delete */
+#endif /* __NetBSD__ */
+
+#endif /* _PROPLIB_PROP_OBJECT_IMPL_H_ */
--- /dev/null
+/* $NetBSD: prop_rb.c,v 1.9 2008/06/17 21:29:47 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt@3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/proplib.h>
+
+#include "prop_object_impl.h"
+#include "prop_rb_impl.h"
+
+#undef KASSERT
+#ifdef RBDEBUG
+#define KASSERT(x) _PROP_ASSERT(x)
+#else
+#define KASSERT(x) /* nothing */
+#endif
+
+#ifndef __predict_false
+#define __predict_false(x) (x)
+#endif
+
+static void rb_tree_reparent_nodes(struct rb_tree *, struct rb_node *,
+ unsigned int);
+static void rb_tree_insert_rebalance(struct rb_tree *, struct rb_node *);
+static void rb_tree_removal_rebalance(struct rb_tree *, struct rb_node *,
+ unsigned int);
+#ifdef RBDEBUG
+static const struct rb_node *rb_tree_iterate_const(const struct rb_tree *,
+ const struct rb_node *, unsigned int);
+static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *,
+ const struct rb_node *, bool);
+#endif
+
+#ifdef RBDEBUG
+#define RBT_COUNT_INCR(rbt) (rbt)->rbt_count++
+#define RBT_COUNT_DECR(rbt) (rbt)->rbt_count--
+#else
+#define RBT_COUNT_INCR(rbt) /* nothing */
+#define RBT_COUNT_DECR(rbt) /* nothing */
+#endif
+
+#define RBUNCONST(a) ((void *)(unsigned long)(const void *)(a))
+
+/*
+ * Rather than testing for the NULL everywhere, all terminal leaves are
+ * pointed to this node (and that includes itself). Note that by setting
+ * it to be const, that on some architectures trying to write to it will
+ * cause a fault.
+ */
+static const struct rb_node sentinel_node = {
+ .rb_nodes = { RBUNCONST(&sentinel_node),
+ RBUNCONST(&sentinel_node),
+ NULL },
+ .rb_u = { .u_s = { .s_sentinel = 1 } },
+};
+
+void
+_prop_rb_tree_init(struct rb_tree *rbt, const struct rb_tree_ops *ops)
+{
+ RB_TAILQ_INIT(&rbt->rbt_nodes);
+#ifdef RBDEBUG
+ rbt->rbt_count = 0;
+#endif
+ rbt->rbt_ops = ops;
+ *((const struct rb_node **)&rbt->rbt_root) = &sentinel_node;
+}
+
+/*
+ * Swap the location and colors of 'self' and its child @ which. The child
+ * can not be a sentinel node.
+ */
+/*ARGSUSED*/
+static void
+rb_tree_reparent_nodes(struct rb_tree *rbt _PROP_ARG_UNUSED,
+ struct rb_node *old_father, unsigned int which)
+{
+ const unsigned int other = which ^ RB_NODE_OTHER;
+ struct rb_node * const grandpa = old_father->rb_parent;
+ struct rb_node * const old_child = old_father->rb_nodes[which];
+ struct rb_node * const new_father = old_child;
+ struct rb_node * const new_child = old_father;
+ unsigned int properties;
+
+ KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT);
+
+ KASSERT(!RB_SENTINEL_P(old_child));
+ KASSERT(old_child->rb_parent == old_father);
+
+ KASSERT(rb_tree_check_node(rbt, old_father, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, old_child, NULL, false));
+ KASSERT(RB_ROOT_P(old_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
+
+ /*
+ * Exchange descendant linkages.
+ */
+ grandpa->rb_nodes[old_father->rb_position] = new_father;
+ new_child->rb_nodes[which] = old_child->rb_nodes[other];
+ new_father->rb_nodes[other] = new_child;
+
+ /*
+ * Update ancestor linkages
+ */
+ new_father->rb_parent = grandpa;
+ new_child->rb_parent = new_father;
+
+ /*
+ * Exchange properties between new_father and new_child. The only
+ * change is that new_child's position is now on the other side.
+ */
+ properties = old_child->rb_properties;
+ new_father->rb_properties = old_father->rb_properties;
+ new_child->rb_properties = properties;
+ new_child->rb_position = other;
+
+ /*
+ * Make sure to reparent the new child to ourself.
+ */
+ if (!RB_SENTINEL_P(new_child->rb_nodes[which])) {
+ new_child->rb_nodes[which]->rb_parent = new_child;
+ new_child->rb_nodes[which]->rb_position = which;
+ }
+
+ KASSERT(rb_tree_check_node(rbt, new_father, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, new_child, NULL, false));
+ KASSERT(RB_ROOT_P(new_father) || rb_tree_check_node(rbt, grandpa, NULL, false));
+}
+
+bool
+_prop_rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self)
+{
+ struct rb_node *parent, *tmp;
+ rb_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes;
+ unsigned int position;
+
+ self->rb_properties = 0;
+ tmp = rbt->rbt_root;
+ /*
+ * This is a hack. Because rbt->rbt_root is just a struct rb_node *,
+ * just like rb_node->rb_nodes[RB_NODE_LEFT], we can use this fact to
+ * avoid a lot of tests for root and know that even at root,
+ * updating rb_node->rb_parent->rb_nodes[rb_node->rb_position] will
+ * rbt->rbt_root.
+ */
+ /* LINTED: see above */
+ parent = (struct rb_node *)&rbt->rbt_root;
+ position = RB_NODE_LEFT;
+
+ /*
+ * Find out where to place this new leaf.
+ */
+ while (!RB_SENTINEL_P(tmp)) {
+ const int diff = (*compare_nodes)(tmp, self);
+ if (__predict_false(diff == 0)) {
+ /*
+ * Node already exists; don't insert.
+ */
+ return false;
+ }
+ parent = tmp;
+ KASSERT(diff != 0);
+ if (diff < 0) {
+ position = RB_NODE_LEFT;
+ } else {
+ position = RB_NODE_RIGHT;
+ }
+ tmp = parent->rb_nodes[position];
+ }
+
+#ifdef RBDEBUG
+ {
+ struct rb_node *prev = NULL, *next = NULL;
+
+ if (position == RB_NODE_RIGHT)
+ prev = parent;
+ else if (tmp != rbt->rbt_root)
+ next = parent;
+
+ /*
+ * Verify our sequential position
+ */
+ KASSERT(prev == NULL || !RB_SENTINEL_P(prev));
+ KASSERT(next == NULL || !RB_SENTINEL_P(next));
+ if (prev != NULL && next == NULL)
+ next = TAILQ_NEXT(prev, rb_link);
+ if (prev == NULL && next != NULL)
+ prev = TAILQ_PREV(next, rb_node_qh, rb_link);
+ KASSERT(prev == NULL || !RB_SENTINEL_P(prev));
+ KASSERT(next == NULL || !RB_SENTINEL_P(next));
+ KASSERT(prev == NULL
+ || (*compare_nodes)(prev, self) > 0);
+ KASSERT(next == NULL
+ || (*compare_nodes)(self, next) > 0);
+ }
+#endif
+
+ /*
+ * Initialize the node and insert as a leaf into the tree.
+ */
+ self->rb_parent = parent;
+ self->rb_position = position;
+ /* LINTED: rbt_root hack */
+ if (__predict_false(parent == (struct rb_node *) &rbt->rbt_root)) {
+ RB_MARK_ROOT(self);
+ } else {
+ KASSERT(position == RB_NODE_LEFT || position == RB_NODE_RIGHT);
+ KASSERT(!RB_ROOT_P(self)); /* Already done */
+ }
+ KASSERT(RB_SENTINEL_P(parent->rb_nodes[position]));
+ self->rb_left = parent->rb_nodes[position];
+ self->rb_right = parent->rb_nodes[position];
+ parent->rb_nodes[position] = self;
+ KASSERT(self->rb_left == &sentinel_node &&
+ self->rb_right == &sentinel_node);
+
+ /*
+ * Insert the new node into a sorted list for easy sequential access
+ */
+ RBT_COUNT_INCR(rbt);
+#ifdef RBDEBUG
+ if (RB_ROOT_P(self)) {
+ RB_TAILQ_INSERT_HEAD(&rbt->rbt_nodes, self, rb_link);
+ } else if (position == RB_NODE_LEFT) {
+ KASSERT((*compare_nodes)(self, self->rb_parent) > 0);
+ RB_TAILQ_INSERT_BEFORE(self->rb_parent, self, rb_link);
+ } else {
+ KASSERT((*compare_nodes)(self->rb_parent, self) > 0);
+ RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, self->rb_parent,
+ self, rb_link);
+ }
+#endif
+
+#if 0
+ /*
+ * Validate the tree before we rebalance
+ */
+ _prop_rb_tree_check(rbt, false);
+#endif
+
+ /*
+ * Rebalance tree after insertion
+ */
+ rb_tree_insert_rebalance(rbt, self);
+
+#if 0
+ /*
+ * Validate the tree after we rebalanced
+ */
+ _prop_rb_tree_check(rbt, true);
+#endif
+
+ return true;
+}
+\f
+static void
+rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self)
+{
+ RB_MARK_RED(self);
+
+ while (!RB_ROOT_P(self) && RB_RED_P(self->rb_parent)) {
+ const unsigned int which =
+ (self->rb_parent == self->rb_parent->rb_parent->rb_left
+ ? RB_NODE_LEFT
+ : RB_NODE_RIGHT);
+ const unsigned int other = which ^ RB_NODE_OTHER;
+ struct rb_node * father = self->rb_parent;
+ struct rb_node * grandpa = father->rb_parent;
+ struct rb_node * const uncle = grandpa->rb_nodes[other];
+
+ KASSERT(!RB_SENTINEL_P(self));
+ /*
+ * We are red and our parent is red, therefore we must have a
+ * grandfather and he must be black.
+ */
+ KASSERT(RB_RED_P(self)
+ && RB_RED_P(father)
+ && RB_BLACK_P(grandpa));
+
+ if (RB_RED_P(uncle)) {
+ /*
+ * Case 1: our uncle is red
+ * Simply invert the colors of our parent and
+ * uncle and make our grandparent red. And
+ * then solve the problem up at his level.
+ */
+ RB_MARK_BLACK(uncle);
+ RB_MARK_BLACK(father);
+ RB_MARK_RED(grandpa);
+ self = grandpa;
+ continue;
+ }
+ /*
+ * Case 2&3: our uncle is black.
+ */
+ if (self == father->rb_nodes[other]) {
+ /*
+ * Case 2: we are on the same side as our uncle
+ * Swap ourselves with our parent so this case
+ * becomes case 3. Basically our parent becomes our
+ * child.
+ */
+ rb_tree_reparent_nodes(rbt, father, other);
+ KASSERT(father->rb_parent == self);
+ KASSERT(self->rb_nodes[which] == father);
+ KASSERT(self->rb_parent == grandpa);
+ self = father;
+ father = self->rb_parent;
+ }
+ KASSERT(RB_RED_P(self) && RB_RED_P(father));
+ KASSERT(grandpa->rb_nodes[which] == father);
+ /*
+ * Case 3: we are opposite a child of a black uncle.
+ * Swap our parent and grandparent. Since our grandfather
+ * is black, our father will become black and our new sibling
+ * (former grandparent) will become red.
+ */
+ rb_tree_reparent_nodes(rbt, grandpa, which);
+ KASSERT(self->rb_parent == father);
+ KASSERT(self->rb_parent->rb_nodes[self->rb_position ^ RB_NODE_OTHER] == grandpa);
+ KASSERT(RB_RED_P(self));
+ KASSERT(RB_BLACK_P(father));
+ KASSERT(RB_RED_P(grandpa));
+ break;
+ }
+
+ /*
+ * Final step: Set the root to black.
+ */
+ RB_MARK_BLACK(rbt->rbt_root);
+}
+\f
+struct rb_node *
+_prop_rb_tree_find(struct rb_tree *rbt, const void *key)
+{
+ struct rb_node *parent = rbt->rbt_root;
+ rb_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key;
+
+ while (!RB_SENTINEL_P(parent)) {
+ const int diff = (*compare_key)(parent, key);
+ if (diff == 0)
+ return parent;
+ parent = parent->rb_nodes[diff > 0];
+ }
+
+ return NULL;
+}
+\f
+static void
+rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, int rebalance)
+{
+ const unsigned int which = self->rb_position;
+ struct rb_node *father = self->rb_parent;
+
+ KASSERT(rebalance || (RB_ROOT_P(self) || RB_RED_P(self)));
+ KASSERT(!rebalance || RB_BLACK_P(self));
+ KASSERT(RB_CHILDLESS_P(self));
+ KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+
+ father->rb_nodes[which] = self->rb_left;
+
+ /*
+ * Remove ourselves from the node list and decrement the count.
+ */
+ RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+ RBT_COUNT_DECR(rbt);
+
+ if (rebalance)
+ rb_tree_removal_rebalance(rbt, father, which);
+ KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, father, NULL, true));
+}
+
+static void
+rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self,
+ struct rb_node *standin)
+{
+ unsigned int standin_which = standin->rb_position;
+ unsigned int standin_other = standin_which ^ RB_NODE_OTHER;
+ struct rb_node *standin_child;
+ struct rb_node *standin_father;
+ bool rebalance = RB_BLACK_P(standin);
+
+ if (standin->rb_parent == self) {
+ /*
+ * As a child of self, any childen would be opposite of
+ * our parent (self).
+ */
+ KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other]));
+ standin_child = standin->rb_nodes[standin_which];
+ } else {
+ /*
+ * Since we aren't a child of self, any childen would be
+ * on the same side as our parent (self).
+ */
+ KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_which]));
+ standin_child = standin->rb_nodes[standin_other];
+ }
+
+ /*
+ * the node we are removing must have two children.
+ */
+ KASSERT(RB_TWOCHILDREN_P(self));
+ /*
+ * If standin has a child, it must be red.
+ */
+ KASSERT(RB_SENTINEL_P(standin_child) || RB_RED_P(standin_child));
+
+ /*
+ * Verify things are sane.
+ */
+ KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
+
+ if (!RB_SENTINEL_P(standin_child)) {
+ /*
+ * We know we have a red child so if we swap them we can
+ * void flipping standin's child to black afterwards.
+ */
+ KASSERT(rb_tree_check_node(rbt, standin_child, NULL, true));
+ rb_tree_reparent_nodes(rbt, standin,
+ standin_child->rb_position);
+ KASSERT(rb_tree_check_node(rbt, standin, NULL, true));
+ KASSERT(rb_tree_check_node(rbt, standin_child, NULL, true));
+ /*
+ * Since we are removing a red leaf, no need to rebalance.
+ */
+ rebalance = false;
+ /*
+ * We know that standin can not be a child of self, so
+ * update before of that.
+ */
+ KASSERT(standin->rb_parent != self);
+ standin_which = standin->rb_position;
+ standin_other = standin_which ^ RB_NODE_OTHER;
+ }
+ KASSERT(RB_CHILDLESS_P(standin));
+
+ /*
+ * If we are about to delete the standin's father, then when we call
+ * rebalance, we need to use ourselves as our father. Otherwise
+ * remember our original father. Also, if we are our standin's father
+ * we only need to reparent the standin's brother.
+ */
+ if (standin->rb_parent == self) {
+ /*
+ * | R --> S |
+ * | Q S --> Q * |
+ * | --> |
+ */
+ standin_father = standin;
+ KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other]));
+ KASSERT(!RB_SENTINEL_P(self->rb_nodes[standin_other]));
+ KASSERT(self->rb_nodes[standin_which] == standin);
+ /*
+ * Make our brother our son.
+ */
+ standin->rb_nodes[standin_other] = self->rb_nodes[standin_other];
+ standin->rb_nodes[standin_other]->rb_parent = standin;
+ KASSERT(standin->rb_nodes[standin_other]->rb_position == standin_other);
+ } else {
+ /*
+ * | P --> P |
+ * | S --> Q |
+ * | Q --> |
+ */
+ standin_father = standin->rb_parent;
+ standin_father->rb_nodes[standin_which] =
+ standin->rb_nodes[standin_which];
+ standin->rb_left = self->rb_left;
+ standin->rb_right = self->rb_right;
+ standin->rb_left->rb_parent = standin;
+ standin->rb_right->rb_parent = standin;
+ }
+
+ /*
+ * Now copy the result of self to standin and then replace
+ * self with standin in the tree.
+ */
+ standin->rb_parent = self->rb_parent;
+ standin->rb_properties = self->rb_properties;
+ standin->rb_parent->rb_nodes[standin->rb_position] = standin;
+
+ /*
+ * Remove ourselves from the node list and decrement the count.
+ */
+ RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+ RBT_COUNT_DECR(rbt);
+
+ KASSERT(rb_tree_check_node(rbt, standin, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, standin_father, NULL, false));
+
+ if (!rebalance)
+ return;
+
+ rb_tree_removal_rebalance(rbt, standin_father, standin_which);
+ KASSERT(rb_tree_check_node(rbt, standin, NULL, true));
+}
+
+/*
+ * We could do this by doing
+ * rb_tree_node_swap(rbt, self, which);
+ * rb_tree_prune_node(rbt, self, false);
+ *
+ * But it's more efficient to just evalate and recolor the child.
+ */
+/*ARGSUSED*/
+static void
+rb_tree_prune_blackred_branch(struct rb_tree *rbt _PROP_ARG_UNUSED,
+ struct rb_node *self, unsigned int which)
+{
+ struct rb_node *parent = self->rb_parent;
+ struct rb_node *child = self->rb_nodes[which];
+
+ KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT);
+ KASSERT(RB_BLACK_P(self) && RB_RED_P(child));
+ KASSERT(!RB_TWOCHILDREN_P(child));
+ KASSERT(RB_CHILDLESS_P(child));
+ KASSERT(rb_tree_check_node(rbt, self, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, child, NULL, false));
+
+ /*
+ * Remove ourselves from the tree and give our former child our
+ * properties (position, color, root).
+ */
+ parent->rb_nodes[self->rb_position] = child;
+ child->rb_parent = parent;
+ child->rb_properties = self->rb_properties;
+
+ /*
+ * Remove ourselves from the node list and decrement the count.
+ */
+ RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link);
+ RBT_COUNT_DECR(rbt);
+
+ KASSERT(RB_ROOT_P(self) || rb_tree_check_node(rbt, parent, NULL, true));
+ KASSERT(rb_tree_check_node(rbt, child, NULL, true));
+}
+/*
+ *
+ */
+void
+_prop_rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self)
+{
+ struct rb_node *standin;
+ unsigned int which;
+ /*
+ * In the following diagrams, we (the node to be removed) are S. Red
+ * nodes are lowercase. T could be either red or black.
+ *
+ * Remember the major axiom of the red-black tree: the number of
+ * black nodes from the root to each leaf is constant across all
+ * leaves, only the number of red nodes varies.
+ *
+ * Thus removing a red leaf doesn't require any other changes to a
+ * red-black tree. So if we must remove a node, attempt to rearrange
+ * the tree so we can remove a red node.
+ *
+ * The simpliest case is a childless red node or a childless root node:
+ *
+ * | T --> T | or | R --> * |
+ * | s --> * |
+ */
+ if (RB_CHILDLESS_P(self)) {
+ if (RB_RED_P(self) || RB_ROOT_P(self)) {
+ rb_tree_prune_node(rbt, self, false);
+ return;
+ }
+ rb_tree_prune_node(rbt, self, true);
+ return;
+ }
+ KASSERT(!RB_CHILDLESS_P(self));
+ if (!RB_TWOCHILDREN_P(self)) {
+ /*
+ * The next simpliest case is the node we are deleting is
+ * black and has one red child.
+ *
+ * | T --> T --> T |
+ * | S --> R --> R |
+ * | r --> s --> * |
+ */
+ which = RB_LEFT_SENTINEL_P(self) ? RB_NODE_RIGHT : RB_NODE_LEFT;
+ KASSERT(RB_BLACK_P(self));
+ KASSERT(RB_RED_P(self->rb_nodes[which]));
+ KASSERT(RB_CHILDLESS_P(self->rb_nodes[which]));
+ rb_tree_prune_blackred_branch(rbt, self, which);
+ return;
+ }
+ KASSERT(RB_TWOCHILDREN_P(self));
+
+ /*
+ * We invert these because we prefer to remove from the inside of
+ * the tree.
+ */
+ which = self->rb_position ^ RB_NODE_OTHER;
+
+ /*
+ * Let's find the node closes to us opposite of our parent
+ * Now swap it with ourself, "prune" it, and rebalance, if needed.
+ */
+ standin = _prop_rb_tree_iterate(rbt, self, which);
+ rb_tree_swap_prune_and_rebalance(rbt, self, standin);
+}
+
+static void
+rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent,
+ unsigned int which)
+{
+ KASSERT(!RB_SENTINEL_P(parent));
+ KASSERT(RB_SENTINEL_P(parent->rb_nodes[which]));
+ KASSERT(which == RB_NODE_LEFT || which == RB_NODE_RIGHT);
+
+ while (RB_BLACK_P(parent->rb_nodes[which])) {
+ unsigned int other = which ^ RB_NODE_OTHER;
+ struct rb_node *brother = parent->rb_nodes[other];
+
+ KASSERT(!RB_SENTINEL_P(brother));
+ /*
+ * For cases 1, 2a, and 2b, our brother's children must
+ * be black and our father must be black
+ */
+ if (RB_BLACK_P(parent)
+ && RB_BLACK_P(brother->rb_left)
+ && RB_BLACK_P(brother->rb_right)) {
+ /*
+ * Case 1: Our brother is red, swap its position
+ * (and colors) with our parent. This is now case 2b.
+ *
+ * B -> D
+ * x d -> b E
+ * C E -> x C
+ */
+ if (RB_RED_P(brother)) {
+ KASSERT(RB_BLACK_P(parent));
+ rb_tree_reparent_nodes(rbt, parent, other);
+ brother = parent->rb_nodes[other];
+ KASSERT(!RB_SENTINEL_P(brother));
+ KASSERT(RB_BLACK_P(brother));
+ KASSERT(RB_RED_P(parent));
+ KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
+ } else {
+ /*
+ * Both our parent and brother are black.
+ * Change our brother to red, advance up rank
+ * and go through the loop again.
+ *
+ * B -> B
+ * A D -> A d
+ * C E -> C E
+ */
+ RB_MARK_RED(brother);
+ KASSERT(RB_BLACK_P(brother->rb_left));
+ KASSERT(RB_BLACK_P(brother->rb_right));
+ if (RB_ROOT_P(parent))
+ return;
+ KASSERT(rb_tree_check_node(rbt, brother, NULL, false));
+ KASSERT(rb_tree_check_node(rbt, parent, NULL, false));
+ which = parent->rb_position;
+ parent = parent->rb_parent;
+ }
+ } else if (RB_RED_P(parent)
+ && RB_BLACK_P(brother)
+ && RB_BLACK_P(brother->rb_left)
+ && RB_BLACK_P(brother->rb_right)) {
+ KASSERT(RB_BLACK_P(brother));
+ KASSERT(RB_BLACK_P(brother->rb_left));
+ KASSERT(RB_BLACK_P(brother->rb_right));
+ RB_MARK_BLACK(parent);
+ RB_MARK_RED(brother);
+ KASSERT(rb_tree_check_node(rbt, brother, NULL, true));
+ break; /* We're done! */
+ } else {
+ KASSERT(RB_BLACK_P(brother));
+ KASSERT(!RB_CHILDLESS_P(brother));
+ /*
+ * Case 3: our brother is black, our left nephew is
+ * red, and our right nephew is black. Swap our
+ * brother with our left nephew. This result in a
+ * tree that matches case 4.
+ *
+ * B -> D
+ * A D -> B E
+ * c e -> A C
+ */
+ if (RB_BLACK_P(brother->rb_nodes[other])) {
+ KASSERT(RB_RED_P(brother->rb_nodes[which]));
+ rb_tree_reparent_nodes(rbt, brother, which);
+ KASSERT(brother->rb_parent == parent->rb_nodes[other]);
+ brother = parent->rb_nodes[other];
+ KASSERT(RB_RED_P(brother->rb_nodes[other]));
+ }
+ /*
+ * Case 4: our brother is black and our right nephew
+ * is red. Swap our parent and brother locations and
+ * change our right nephew to black. (these can be
+ * done in either order so we change the color first).
+ * The result is a valid red-black tree and is a
+ * terminal case.
+ *
+ * B -> D
+ * A D -> B E
+ * c e -> A C
+ */
+ RB_MARK_BLACK(brother->rb_nodes[other]);
+ rb_tree_reparent_nodes(rbt, parent, other);
+ break; /* We're done! */
+ }
+ }
+ KASSERT(rb_tree_check_node(rbt, parent, NULL, true));
+}
+
+struct rb_node *
+_prop_rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self,
+ unsigned int direction)
+{
+ const unsigned int other = direction ^ RB_NODE_OTHER;
+ KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT);
+
+ if (self == NULL) {
+ self = rbt->rbt_root;
+ if (RB_SENTINEL_P(self))
+ return NULL;
+ while (!RB_SENTINEL_P(self->rb_nodes[other]))
+ self = self->rb_nodes[other];
+ return self;
+ }
+ KASSERT(!RB_SENTINEL_P(self));
+ /*
+ * We can't go any further in this direction. We proceed up in the
+ * opposite direction until our parent is in direction we want to go.
+ */
+ if (RB_SENTINEL_P(self->rb_nodes[direction])) {
+ while (!RB_ROOT_P(self)) {
+ if (other == self->rb_position)
+ return self->rb_parent;
+ self = self->rb_parent;
+ }
+ return NULL;
+ }
+
+ /*
+ * Advance down one in current direction and go down as far as possible
+ * in the opposite direction.
+ */
+ self = self->rb_nodes[direction];
+ KASSERT(!RB_SENTINEL_P(self));
+ while (!RB_SENTINEL_P(self->rb_nodes[other]))
+ self = self->rb_nodes[other];
+ return self;
+}
+
+#ifdef RBDEBUG
+static const struct rb_node *
+rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self,
+ unsigned int direction)
+{
+ const unsigned int other = direction ^ RB_NODE_OTHER;
+ KASSERT(direction == RB_NODE_LEFT || direction == RB_NODE_RIGHT);
+
+ if (self == NULL) {
+ self = rbt->rbt_root;
+ if (RB_SENTINEL_P(self))
+ return NULL;
+ while (!RB_SENTINEL_P(self->rb_nodes[other]))
+ self = self->rb_nodes[other];
+ return self;
+ }
+ KASSERT(!RB_SENTINEL_P(self));
+ /*
+ * We can't go any further in this direction. We proceed up in the
+ * opposite direction until our parent is in direction we want to go.
+ */
+ if (RB_SENTINEL_P(self->rb_nodes[direction])) {
+ while (!RB_ROOT_P(self)) {
+ if (other == self->rb_position)
+ return self->rb_parent;
+ self = self->rb_parent;
+ }
+ return NULL;
+ }
+
+ /*
+ * Advance down one in current direction and go down as far as possible
+ * in the opposite direction.
+ */
+ self = self->rb_nodes[direction];
+ KASSERT(!RB_SENTINEL_P(self));
+ while (!RB_SENTINEL_P(self->rb_nodes[other]))
+ self = self->rb_nodes[other];
+ return self;
+}
+
+static bool
+rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self,
+ const struct rb_node *prev, bool red_check)
+{
+ KASSERT(!self->rb_sentinel);
+ KASSERT(self->rb_left);
+ KASSERT(self->rb_right);
+ KASSERT(prev == NULL ||
+ (*rbt->rbt_ops->rbto_compare_nodes)(prev, self) > 0);
+
+ /*
+ * Verify our relationship to our parent.
+ */
+ if (RB_ROOT_P(self)) {
+ KASSERT(self == rbt->rbt_root);
+ KASSERT(self->rb_position == RB_NODE_LEFT);
+ KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self);
+ KASSERT(self->rb_parent == (const struct rb_node *) &rbt->rbt_root);
+ } else {
+ KASSERT(self != rbt->rbt_root);
+ KASSERT(!RB_PARENT_SENTINEL_P(self));
+ if (self->rb_position == RB_NODE_LEFT) {
+ KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) > 0);
+ KASSERT(self->rb_parent->rb_nodes[RB_NODE_LEFT] == self);
+ } else {
+ KASSERT((*rbt->rbt_ops->rbto_compare_nodes)(self, self->rb_parent) < 0);
+ KASSERT(self->rb_parent->rb_nodes[RB_NODE_RIGHT] == self);
+ }
+ }
+
+ /*
+ * Verify our position in the linked list against the tree itself.
+ */
+ {
+ const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT);
+ const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT);
+ KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link));
+ if (next0 != TAILQ_NEXT(self, rb_link))
+ next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT);
+ KASSERT(next0 == TAILQ_NEXT(self, rb_link));
+ }
+
+ /*
+ * The root must be black.
+ * There can never be two adjacent red nodes.
+ */
+ if (red_check) {
+ KASSERT(!RB_ROOT_P(self) || RB_BLACK_P(self));
+ if (RB_RED_P(self)) {
+ const struct rb_node *brother;
+ KASSERT(!RB_ROOT_P(self));
+ brother = self->rb_parent->rb_nodes[self->rb_position ^ RB_NODE_OTHER];
+ KASSERT(RB_BLACK_P(self->rb_parent));
+ /*
+ * I'm red and have no children, then I must either
+ * have no brother or my brother also be red and
+ * also have no children. (black count == 0)
+ */
+ KASSERT(!RB_CHILDLESS_P(self)
+ || RB_SENTINEL_P(brother)
+ || RB_RED_P(brother)
+ || RB_CHILDLESS_P(brother));
+ /*
+ * If I'm not childless, I must have two children
+ * and they must be both be black.
+ */
+ KASSERT(RB_CHILDLESS_P(self)
+ || (RB_TWOCHILDREN_P(self)
+ && RB_BLACK_P(self->rb_left)
+ && RB_BLACK_P(self->rb_right)));
+ /*
+ * If I'm not childless, thus I have black children,
+ * then my brother must either be black or have two
+ * black children.
+ */
+ KASSERT(RB_CHILDLESS_P(self)
+ || RB_BLACK_P(brother)
+ || (RB_TWOCHILDREN_P(brother)
+ && RB_BLACK_P(brother->rb_left)
+ && RB_BLACK_P(brother->rb_right)));
+ } else {
+ /*
+ * If I'm black and have one child, that child must
+ * be red and childless.
+ */
+ KASSERT(RB_CHILDLESS_P(self)
+ || RB_TWOCHILDREN_P(self)
+ || (!RB_LEFT_SENTINEL_P(self)
+ && RB_RIGHT_SENTINEL_P(self)
+ && RB_RED_P(self->rb_left)
+ && RB_CHILDLESS_P(self->rb_left))
+ || (!RB_RIGHT_SENTINEL_P(self)
+ && RB_LEFT_SENTINEL_P(self)
+ && RB_RED_P(self->rb_right)
+ && RB_CHILDLESS_P(self->rb_right)));
+
+ /*
+ * If I'm a childless black node and my parent is
+ * black, my 2nd closet relative away from my parent
+ * is either red or has a red parent or red children.
+ */
+ if (!RB_ROOT_P(self)
+ && RB_CHILDLESS_P(self)
+ && RB_BLACK_P(self->rb_parent)) {
+ const unsigned int which = self->rb_position;
+ const unsigned int other = which ^ RB_NODE_OTHER;
+ const struct rb_node *relative0, *relative;
+
+ relative0 = rb_tree_iterate_const(rbt,
+ self, other);
+ KASSERT(relative0 != NULL);
+ relative = rb_tree_iterate_const(rbt,
+ relative0, other);
+ KASSERT(relative != NULL);
+ KASSERT(RB_SENTINEL_P(relative->rb_nodes[which]));
+#if 0
+ KASSERT(RB_RED_P(relative)
+ || RB_RED_P(relative->rb_left)
+ || RB_RED_P(relative->rb_right)
+ || RB_RED_P(relative->rb_parent));
+#endif
+ }
+ }
+ /*
+ * A grandparent's children must be real nodes and not
+ * sentinels. First check out grandparent.
+ */
+ KASSERT(RB_ROOT_P(self)
+ || RB_ROOT_P(self->rb_parent)
+ || RB_TWOCHILDREN_P(self->rb_parent->rb_parent));
+ /*
+ * If we are have grandchildren on our left, then
+ * we must have a child on our right.
+ */
+ KASSERT(RB_LEFT_SENTINEL_P(self)
+ || RB_CHILDLESS_P(self->rb_left)
+ || !RB_RIGHT_SENTINEL_P(self));
+ /*
+ * If we are have grandchildren on our right, then
+ * we must have a child on our left.
+ */
+ KASSERT(RB_RIGHT_SENTINEL_P(self)
+ || RB_CHILDLESS_P(self->rb_right)
+ || !RB_LEFT_SENTINEL_P(self));
+
+ /*
+ * If we have a child on the left and it doesn't have two
+ * children make sure we don't have great-great-grandchildren on
+ * the right.
+ */
+ KASSERT(RB_TWOCHILDREN_P(self->rb_left)
+ || RB_CHILDLESS_P(self->rb_right)
+ || RB_CHILDLESS_P(self->rb_right->rb_left)
+ || RB_CHILDLESS_P(self->rb_right->rb_left->rb_left)
+ || RB_CHILDLESS_P(self->rb_right->rb_left->rb_right)
+ || RB_CHILDLESS_P(self->rb_right->rb_right)
+ || RB_CHILDLESS_P(self->rb_right->rb_right->rb_left)
+ || RB_CHILDLESS_P(self->rb_right->rb_right->rb_right));
+
+ /*
+ * If we have a child on the right and it doesn't have two
+ * children make sure we don't have great-great-grandchildren on
+ * the left.
+ */
+ KASSERT(RB_TWOCHILDREN_P(self->rb_right)
+ || RB_CHILDLESS_P(self->rb_left)
+ || RB_CHILDLESS_P(self->rb_left->rb_left)
+ || RB_CHILDLESS_P(self->rb_left->rb_left->rb_left)
+ || RB_CHILDLESS_P(self->rb_left->rb_left->rb_right)
+ || RB_CHILDLESS_P(self->rb_left->rb_right)
+ || RB_CHILDLESS_P(self->rb_left->rb_right->rb_left)
+ || RB_CHILDLESS_P(self->rb_left->rb_right->rb_right));
+
+ /*
+ * If we are fully interior node, then our predecessors and
+ * successors must have no children in our direction.
+ */
+ if (RB_TWOCHILDREN_P(self)) {
+ const struct rb_node *prev0;
+ const struct rb_node *next0;
+
+ prev0 = rb_tree_iterate_const(rbt, self, RB_NODE_LEFT);
+ KASSERT(prev0 != NULL);
+ KASSERT(RB_RIGHT_SENTINEL_P(prev0));
+
+ next0 = rb_tree_iterate_const(rbt, self, RB_NODE_RIGHT);
+ KASSERT(next0 != NULL);
+ KASSERT(RB_LEFT_SENTINEL_P(next0));
+ }
+ }
+
+ return true;
+}
+
+static unsigned int
+rb_tree_count_black(const struct rb_node *self)
+{
+ unsigned int left, right;
+
+ if (RB_SENTINEL_P(self))
+ return 0;
+
+ left = rb_tree_count_black(self->rb_left);
+ right = rb_tree_count_black(self->rb_right);
+
+ KASSERT(left == right);
+
+ return left + RB_BLACK_P(self);
+}
+
+void
+_prop_rb_tree_check(const struct rb_tree *rbt, bool red_check)
+{
+ const struct rb_node *self;
+ const struct rb_node *prev;
+ unsigned int count;
+
+ KASSERT(rbt->rbt_root == NULL || rbt->rbt_root->rb_position == RB_NODE_LEFT);
+
+ prev = NULL;
+ count = 0;
+ TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
+ rb_tree_check_node(rbt, self, prev, false);
+ count++;
+ }
+ KASSERT(rbt->rbt_count == count);
+ KASSERT(RB_SENTINEL_P(rbt->rbt_root)
+ || rb_tree_count_black(rbt->rbt_root));
+
+ /*
+ * The root must be black.
+ * There can never be two adjacent red nodes.
+ */
+ if (red_check) {
+ KASSERT(rbt->rbt_root == NULL || RB_BLACK_P(rbt->rbt_root));
+ TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) {
+ rb_tree_check_node(rbt, self, NULL, true);
+ }
+ }
+}
+#endif /* RBDEBUG */
--- /dev/null
+/* $NetBSD: prop_rb_impl.h,v 1.8 2010/09/25 01:42:38 matt Exp $ */
+
+/*-
+ * Copyright (c) 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Matt Thomas <matt@3am-software.com>.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROP_RB_IMPL_H_
+#define _PROP_RB_IMPL_H_
+
+#if defined(__NetBSD__) || defined(__minix)
+#include <sys/rbtree.h>
+
+/*
+ * Define local names for common rb_tree functions.
+ */
+#define _prop_rb_tree_init rb_tree_init
+#define _prop_rb_tree_insert_node rb_tree_insert_node
+#define _prop_rb_tree_find rb_tree_find_node
+#define _prop_rb_tree_remove_node rb_tree_remove_node
+#define _prop_rb_tree_iterate rb_tree_iterate
+
+#else /* __NetBSD__ */
+
+#include <sys/types.h>
+#include <sys/queue.h>
+#include <machine/endian.h>
+
+struct rb_node {
+ struct rb_node *rb_nodes[3];
+#define RB_NODE_LEFT 0
+#define RB_NODE_RIGHT 1
+#define RB_NODE_OTHER 1
+#define RB_NODE_PARENT 2
+#define rb_left rb_nodes[RB_NODE_LEFT]
+#define rb_right rb_nodes[RB_NODE_RIGHT]
+#define rb_parent rb_nodes[RB_NODE_PARENT]
+ union {
+ struct {
+#if BYTE_ORDER == LITTLE_ENDIAN
+ unsigned int : 28;
+ unsigned int s_root : 1;
+ unsigned int s_position : 1;
+ unsigned int s_color : 1;
+ unsigned int s_sentinel : 1;
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ unsigned int s_sentinel : 1;
+ unsigned int s_color : 1;
+ unsigned int s_position : 1;
+ unsigned int s_root : 1;
+ unsigned int : 28;
+#endif
+ } u_s;
+ unsigned int u_i;
+ } rb_u;
+#define rb_root rb_u.u_s.s_root
+#define rb_position rb_u.u_s.s_position
+#define rb_color rb_u.u_s.s_color
+#define rb_sentinel rb_u.u_s.s_sentinel
+#define rb_properties rb_u.u_i
+#define RB_SENTINEL_P(rb) ((rb)->rb_sentinel + 0)
+#define RB_LEFT_SENTINEL_P(rb) ((rb)->rb_left->rb_sentinel + 0)
+#define RB_RIGHT_SENTINEL_P(rb) ((rb)->rb_right->rb_sentinel + 0)
+#define RB_PARENT_SENTINEL_P(rb) ((rb)->rb_parent->rb_sentinel + 0)
+#define RB_CHILDLESS_P(rb) (RB_LEFT_SENTINEL_P(rb) \
+ && RB_RIGHT_SENTINEL_P(rb))
+#define RB_TWOCHILDREN_P(rb) (!RB_LEFT_SENTINEL_P(rb) \
+ && !RB_RIGHT_SENTINEL_P(rb))
+#define RB_ROOT_P(rb) ((rb)->rb_root != false)
+#define RB_RED_P(rb) ((rb)->rb_color + 0)
+#define RB_BLACK_P(rb) (!(rb)->rb_color)
+#define RB_MARK_RED(rb) ((void)((rb)->rb_color = 1))
+#define RB_MARK_BLACK(rb) ((void)((rb)->rb_color = 0))
+#define RB_MARK_ROOT(rb) ((void)((rb)->rb_root = 1))
+#ifdef RBDEBUG
+ TAILQ_ENTRY(rb_node) rb_link;
+#endif
+};
+
+#ifdef RBDEBUG
+TAILQ_HEAD(rb_node_qh, rb_node);
+
+#define RB_TAILQ_REMOVE TAILQ_REMOVE
+#define RB_TAILQ_INIT TAILQ_INIT
+#define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD
+#define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE
+#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER
+#else
+#define RB_TAILQ_REMOVE(a, b, c) do { } while (/*CONSTCOND*/0)
+#define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0)
+#define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0)
+#define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0)
+#define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0)
+#endif
+
+typedef int (*rb_compare_nodes_fn)(const struct rb_node *,
+ const struct rb_node *);
+typedef int (*rb_compare_key_fn)(const struct rb_node *, const void *);
+
+struct rb_tree_ops {
+ rb_compare_nodes_fn rbto_compare_nodes;
+ rb_compare_key_fn rbto_compare_key;
+};
+
+struct rb_tree {
+ struct rb_node *rbt_root;
+#ifdef RBDEBUG
+ struct rb_node_qh rbt_nodes;
+#endif
+ const struct rb_tree_ops *rbt_ops;
+#ifdef RBDEBUG
+ unsigned int rbt_count;
+#endif
+};
+
+void _prop_rb_tree_init(struct rb_tree *, const struct rb_tree_ops *);
+bool _prop_rb_tree_insert_node(struct rb_tree *, struct rb_node *);
+struct rb_node *
+ _prop_rb_tree_find(struct rb_tree *, const void *);
+void _prop_rb_tree_remove_node(struct rb_tree *, struct rb_node *);
+#ifdef RBDEBUG
+void _prop_rb_tree_check(const struct rb_tree *, bool);
+#endif
+struct rb_node *
+ _prop_rb_tree_iterate(struct rb_tree *, struct rb_node *, unsigned int);
+
+#endif /* __NetBSD__ */
+
+#endif /* _PROP_RB_IMPL_H_*/
--- /dev/null
+.\" $NetBSD: prop_send_ioctl.3,v 1.8 2011/09/27 11:12:49 jym Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 21, 2008
+.Dt PROP_SEND_IOCTL 3
+.Os
+.Sh NAME
+.Nm prop_array_send_ioctl ,
+.Nm prop_array_recv_ioctl ,
+.Nm prop_dictionary_send_ioctl ,
+.Nm prop_dictionary_recv_ioctl ,
+.Nm prop_dictionary_sendrecv_ioctl
+.Nd Send and receive propertly lists to and from the kernel using ioctl
+.Sh SYNOPSIS
+.In prop/proplib.h
+.Ft int
+.Fn prop_array_send_ioctl "prop_array_t array" "int fd" "unsigned long cmd"
+.Ft int
+.Fn prop_array_recv_ioctl "int fd" "unsigned long cmd" "prop_array_t *arrayp"
+.Ft int
+.Fn prop_dictionary_send_ioctl "prop_dictionary_t dict" "int fd" \
+ "unsigned long cmd"
+.Ft int
+.Fn prop_dictionary_recv_ioctl "int fd" "unsigned long cmd" \
+ "prop_dictionary_t *dictp"
+.Ft int
+.Fn prop_dictionary_sendrecv_ioctl "prop_dictionary_t dict" "int fd" \
+ "unsigned long cmd" "prop_dictionary_t *dictp"
+.Sh DESCRIPTION
+The
+.Nm prop_array_send_ioctl ,
+.Nm prop_array_recv_ioctl ,
+.Nm prop_dictionary_send_ioctl ,
+.Nm prop_dictionary_recv_ioctl ,
+and
+.Nm prop_dictionary_sendrecv_ioctl
+functions implement the user space side of a protocol for sending property
+lists to and from the kernel using
+.Xr ioctl 2 .
+.Sh RETURN VALUES
+If successful, functions return zero.
+Otherwise, an error number is returned to indicate the error.
+.Sh EXAMPLES
+The following
+.Pq simplified
+example demonstrates using
+.Fn prop_dictionary_send_ioctl
+and
+.Fn prop_dictionary_recv_ioctl
+in an application:
+.Bd -literal
+void
+foo_setprops(prop_dictionary_t dict)
+{
+ int fd;
+
+ fd = open("/dev/foo", O_RDWR, 0640);
+ if (fd == -1)
+ return;
+
+ (void) prop_dictionary_send_ioctl(dict, fd, FOOSETPROPS);
+
+ (void) close(fd);
+}
+
+prop_dictionary_t
+foo_getprops(void)
+{
+ prop_dictionary_t dict;
+ int fd;
+
+ fd = open("/dev/foo", O_RDONLY, 0640);
+ if (fd == -1)
+ return (NULL);
+
+ if (prop_dictionary_recv_ioctl(fd, FOOGETPROPS, \*[Am]dict) != 0)
+ return (NULL);
+
+ (void) close(fd);
+
+ return (dict);
+}
+.Ed
+.Pp
+The
+.Nm prop_dictionary_sendrecv_ioctl
+function combines the send and receive functionality, allowing for
+ioctls that require two-way communication
+.Pq for example to specify arguments for the ioctl operation .
+.Sh ERRORS
+.Fn prop_array_send_ioctl
+and
+.Fn prop_dictionary_send_ioctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Cannot allocate memory
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Pp
+.Fn prop_array_recv_ioctl
+and
+.Fn prop_dictionary_recv_ioctl
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EIO
+Input/output error
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Pp
+In addition to these,
+.Xr ioctl 2
+errors may be returned.
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_dictionary 3 ,
+.Xr proplib 3 ,
+.Xr prop_copyin_ioctl 9
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+.\" $NetBSD: prop_send_syscall.3,v 1.5 2011/09/30 22:08:18 jym Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 17, 2011
+.Dt PROP_SEND_SYCALL 3
+.Os
+.Sh NAME
+.Nm prop_array_send_syscall ,
+.Nm prop_array_recv_syscall ,
+.Nm prop_dictionary_send_syscall ,
+.Nm prop_dictionary_recv_syscall
+.Nd send and receive property lists to and from the kernel using syscalls
+.Sh SYNOPSIS
+.In prop/proplib.h
+.Ft int
+.Fn prop_array_send_syscall "prop_array_t array" "struct plistref *prefp"
+.Ft int
+.Fn prop_array_recv_syscall "const struct plistref *prefp" \
+ "prop_array_t *arrayp"
+.Ft int
+.Fn prop_dictionary_send_syscall "prop_dictionary_t dict" \
+ "struct plistref *prefp"
+.Ft int
+.Fn prop_dictionary_recv_syscall "const struct plistref *prefp" \
+ "prop_dictionary_t *dictp"
+.Sh DESCRIPTION
+The
+.Nm prop_array_send_syscall ,
+.Nm prop_array_recv_syscall ,
+.Nm prop_dictionary_send_syscall ,
+and
+.Nm prop_dictionary_recv_syscall
+functions implement the user space side of a protocol for sending property
+lists to and from the kernel using
+.Xr syscall 2 .
+.Sh RETURN VALUES
+If successful, functions return zero.
+Otherwise, an error number is returned to indicate the error.
+.Sh EXAMPLES
+The following
+.Pq simplified
+example demonstrates using
+.Fn prop_dictionary_send_syscall
+and
+.Fn prop_dictionary_recv_syscall
+in an application:
+.Bd -literal
+void
+foo_setprops(prop_dictionary_t dict)
+{
+ struct pref pref;
+
+ (void) prop_dictionary_send_syscall(dict, \*[Am]pref);
+ (void) my_syscall_set(\*[Am]pref);
+
+}
+
+prop_dictionary_t
+foo_getprops(void)
+{
+ prop_dictionary_t dict;
+ struct pref pref;
+
+ (void) my_syscall_get(\*[Am]pref);
+ if (prop_dictionary_recv_syscall(\*[Am]pref, \*[Am]dict) != 0)
+ return (NULL);
+
+ return (dict);
+}
+.Ed
+.Sh ERRORS
+.Fn prop_array_send_syscall
+and
+.Fn prop_dictionary_send_syscall
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Cannot allocate memory
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Pp
+.Fn prop_array_recv_syscall
+and
+.Fn prop_dictionary_recv_syscall
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EIO
+Input/output error
+.It Bq Er ENOTSUP
+Not supported
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_dictionary 3 ,
+.Xr proplib 3 ,
+.Xr prop_copyin_ioctl 9
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_stack.c,v 1.2 2007/08/30 12:23:54 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "prop_stack.h"
+#include "prop_object_impl.h"
+
+void
+_prop_stack_init(prop_stack_t stack)
+{
+ stack->used_intern_elems = 0;
+ SLIST_INIT(&stack->extern_elems);
+}
+
+bool
+_prop_stack_push(prop_stack_t stack, prop_object_t obj, void *data1,
+ void *data2, void *data3)
+{
+ struct _prop_stack_extern_elem *eelem;
+ struct _prop_stack_intern_elem *ielem;
+
+ if (stack->used_intern_elems == PROP_STACK_INTERN_ELEMS) {
+ eelem = _PROP_MALLOC(sizeof(*eelem), M_TEMP);
+
+ if (eelem == NULL)
+ return false;
+
+ eelem->object = obj;
+ eelem->object_data[0] = data1;
+ eelem->object_data[1] = data2;
+ eelem->object_data[2] = data3;
+
+ SLIST_INSERT_HEAD(&stack->extern_elems, eelem, stack_link);
+
+ return true;
+ }
+
+ _PROP_ASSERT(stack->used_intern_elems < PROP_STACK_INTERN_ELEMS);
+ _PROP_ASSERT(SLIST_EMPTY(&stack->extern_elems));
+
+ ielem = &stack->intern_elems[stack->used_intern_elems];
+ ielem->object = obj;
+ ielem->object_data[0] = data1;
+ ielem->object_data[1] = data2;
+ ielem->object_data[2] = data3;
+
+ ++stack->used_intern_elems;
+
+ return true;
+}
+
+bool
+_prop_stack_pop(prop_stack_t stack, prop_object_t *obj, void **data1,
+ void **data2, void **data3)
+{
+ struct _prop_stack_extern_elem *eelem;
+ struct _prop_stack_intern_elem *ielem;
+
+ if (stack->used_intern_elems == 0)
+ return false;
+
+ if ((eelem = SLIST_FIRST(&stack->extern_elems)) != NULL) {
+ _PROP_ASSERT(stack->used_intern_elems == PROP_STACK_INTERN_ELEMS);
+
+ SLIST_REMOVE_HEAD(&stack->extern_elems, stack_link);
+ if (obj)
+ *obj = eelem->object;
+ if (data1)
+ *data1 = eelem->object_data[0];
+ if (data2)
+ *data2 = eelem->object_data[1];
+ if (data3)
+ *data3 = eelem->object_data[2];
+ _PROP_FREE(eelem, M_TEMP);
+ return true;
+ }
+
+ --stack->used_intern_elems;
+ ielem = &stack->intern_elems[stack->used_intern_elems];
+
+ if (obj)
+ *obj = ielem->object;
+ if (data1)
+ *data1 = ielem->object_data[0];
+ if (data2)
+ *data2 = ielem->object_data[1];
+ if (data3)
+ *data3 = ielem->object_data[2];
+
+ return true;
+}
--- /dev/null
+/* $NetBSD: prop_stack.h,v 1.2 2007/08/30 12:23:54 joerg Exp $ */
+
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger <joerg@NetBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _PROP_STACK_H
+#define _PROP_STACK_H
+
+#include <sys/queue.h>
+
+#include <prop/prop_object.h>
+
+struct _prop_stack_intern_elem {
+ prop_object_t object;
+ void *object_data[3];
+};
+
+struct _prop_stack_extern_elem {
+ SLIST_ENTRY(_prop_stack_extern_elem) stack_link;
+ prop_object_t object;
+ void *object_data[3];
+};
+
+#define PROP_STACK_INTERN_ELEMS 16
+
+struct _prop_stack {
+ struct _prop_stack_intern_elem intern_elems[PROP_STACK_INTERN_ELEMS];
+ size_t used_intern_elems;
+ SLIST_HEAD(, _prop_stack_extern_elem) extern_elems;
+};
+
+typedef struct _prop_stack *prop_stack_t;
+
+void _prop_stack_init(prop_stack_t);
+bool _prop_stack_push(prop_stack_t, prop_object_t, void *, void *, void *);
+bool _prop_stack_pop(prop_stack_t, prop_object_t *, void **, void **, void **);
+
+#endif
--- /dev/null
+.\" $NetBSD: prop_string.3,v 1.8 2011/02/26 12:56:36 wiz Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 21, 2008
+.Dt PROP_STRING 3
+.Os
+.Sh NAME
+.Nm prop_string ,
+.Nm prop_string_create ,
+.Nm prop_string_create_cstring ,
+.Nm prop_string_create_cstring_nocopy ,
+.Nm prop_string_copy ,
+.Nm prop_string_copy_mutable ,
+.Nm prop_string_size ,
+.Nm prop_string_mutable ,
+.Nm prop_string_cstring ,
+.Nm prop_string_cstring_nocopy ,
+.Nm prop_string_append ,
+.Nm prop_string_append_cstring ,
+.Nm prop_string_equals ,
+.Nm prop_string_equals_cstring
+.Nd string value property object
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.\"
+.Ft prop_string_t
+.Fn prop_string_create "void"
+.Ft prop_string_t
+.Fn prop_string_create_cstring "const char *cstring"
+.Ft prop_string_t
+.Fn prop_string_create_cstring_nocopy "const char *cstring"
+.\"
+.Ft prop_string_t
+.Fn prop_string_copy "prop_string_t string"
+.Ft prop_string_t
+.Fn prop_string_copy_mutable "prop_string_t string"
+.\"
+.Ft size_t
+.Fn prop_string_size "prop_string_t string"
+.Ft bool
+.Fn prop_string_mutable "prop_string_t string"
+.\"
+.Ft char *
+.Fn prop_string_cstring "prop_string_t string"
+.Ft const char *
+.Fn prop_string_cstring_nocopy "prop_string_t string"
+.\"
+.Ft bool
+.Fn prop_string_append "prop_string_t str1" "prop_string_t str2"
+.Ft bool
+.Fn prop_string_append_cstring "prop_string_t string" "const char *cstring"
+.\"
+.Ft bool
+.Fn prop_string_equals "prop_string_t str1" "prop_string_t str2"
+.Ft bool
+.Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring"
+.Sh DESCRIPTION
+The
+.Nm prop_string
+family of functions operate on a string value property object type.
+.Bl -tag -width "xxxxx"
+.It Fn prop_string_create "void"
+Create an empty mutable string.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_create_cstring "const char *cstring"
+Create a mutable string that contains a copy of
+.Fa cstring .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_create_cstring_nocopy "const char *cstring"
+Create an immutable string that contains a reference to
+.Fa cstring .
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_copy "prop_string_t string"
+Copy a string.
+If the string being copied is an immutable external C string reference,
+then the copy is also immutable and references the same external C string.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_copy_mutable "prop_string_t string"
+Copy a string, always creating a mutable copy.
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_size "prop_string_t string"
+Returns the size of the string, not including the terminating NUL.
+If the supplied object isn't a string, zero is returned.
+.It Fn prop_string_mutable "prop_string_t string"
+Returns
+.Dv true
+if the string is mutable.
+If the supplied object isn't a string,
+.Dv false
+is returned.
+.It Fn prop_string_cstring "prop_string_t string"
+Returns a copy of the string's contents as a C string.
+The caller is responsible for freeing the returned buffer.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.Pp
+Returns
+.Dv NULL
+on failure.
+.It Fn prop_string_cstring_nocopy "prop_string_t string"
+Returns an immutable reference to the contents of the string as a
+C string.
+If the supplied object isn't a string,
+.Dv NULL
+is returned.
+.It Fn prop_string_append "prop_string_t str1" "prop_string_t str2"
+Append the contents of
+.Fa str2
+to
+.Fa str1 ,
+which must be mutable.
+Returns
+.Dv true
+upon success and
+.Dv false
+otherwise.
+.It Fn prop_string_append_cstring "prop_string_t string" "const char *cstring"
+Append the C string
+.Fa cstring
+to
+.Fa string ,
+which must be mutable.
+Returns
+.Dv true
+upon success and
+.Dv false
+otherwise.
+.It Fn prop_string_equals "prop_string_t str1" "prop_string_t str2"
+Returns
+.Dv true
+if the two string objects are equivalent.
+.It Fn prop_string_equals_cstring "prop_string_t string" "const char *cstring"
+Returns
+.Dv true
+if the string's value is equivalent to
+.Fa cstring .
+.El
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr proplib 3
+.Sh HISTORY
+The
+.Nm proplib
+property container object library first appeared in
+.Nx 4.0 .
--- /dev/null
+/* $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <prop/prop_string.h>
+#include "prop_object_impl.h"
+
+struct _prop_string {
+ struct _prop_object ps_obj;
+ union {
+ char * psu_mutable;
+ const char * psu_immutable;
+ } ps_un;
+#define ps_mutable ps_un.psu_mutable
+#define ps_immutable ps_un.psu_immutable
+ size_t ps_size; /* not including \0 */
+ int ps_flags;
+};
+
+#define PS_F_NOCOPY 0x01
+
+_PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
+
+_PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
+ "property string container object")
+
+static _prop_object_free_rv_t
+ _prop_string_free(prop_stack_t, prop_object_t *);
+static bool _prop_string_externalize(
+ struct _prop_object_externalize_context *,
+ void *);
+static _prop_object_equals_rv_t
+ _prop_string_equals(prop_object_t, prop_object_t,
+ void **, void **,
+ prop_object_t *, prop_object_t *);
+
+static const struct _prop_object_type _prop_object_type_string = {
+ .pot_type = PROP_TYPE_STRING,
+ .pot_free = _prop_string_free,
+ .pot_extern = _prop_string_externalize,
+ .pot_equals = _prop_string_equals,
+};
+
+#define prop_object_is_string(x) \
+ ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
+#define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "")
+
+/* ARGSUSED */
+static _prop_object_free_rv_t
+_prop_string_free(prop_stack_t stack, prop_object_t *obj)
+{
+ prop_string_t ps = *obj;
+
+ if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
+ _PROP_FREE(ps->ps_mutable, M_PROP_STRING);
+ _PROP_POOL_PUT(_prop_string_pool, ps);
+
+ return (_PROP_OBJECT_FREE_DONE);
+}
+
+static bool
+_prop_string_externalize(struct _prop_object_externalize_context *ctx,
+ void *v)
+{
+ prop_string_t ps = v;
+
+ if (ps->ps_size == 0)
+ return (_prop_object_externalize_empty_tag(ctx, "string"));
+
+ if (_prop_object_externalize_start_tag(ctx, "string") == false ||
+ _prop_object_externalize_append_encoded_cstring(ctx,
+ ps->ps_immutable) == false ||
+ _prop_object_externalize_end_tag(ctx, "string") == false)
+ return (false);
+
+ return (true);
+}
+
+/* ARGSUSED */
+static _prop_object_equals_rv_t
+_prop_string_equals(prop_object_t v1, prop_object_t v2,
+ void **stored_pointer1, void **stored_pointer2,
+ prop_object_t *next_obj1, prop_object_t *next_obj2)
+{
+ prop_string_t str1 = v1;
+ prop_string_t str2 = v2;
+
+ if (str1 == str2)
+ return (_PROP_OBJECT_EQUALS_TRUE);
+ if (str1->ps_size != str2->ps_size)
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
+ return (_PROP_OBJECT_EQUALS_FALSE);
+ else
+ return (_PROP_OBJECT_EQUALS_TRUE);
+}
+
+static prop_string_t
+_prop_string_alloc(void)
+{
+ prop_string_t ps;
+
+ ps = _PROP_POOL_GET(_prop_string_pool);
+ if (ps != NULL) {
+ _prop_object_init(&ps->ps_obj, &_prop_object_type_string);
+
+ ps->ps_mutable = NULL;
+ ps->ps_size = 0;
+ ps->ps_flags = 0;
+ }
+
+ return (ps);
+}
+
+/*
+ * prop_string_create --
+ * Create an empty mutable string.
+ */
+prop_string_t
+prop_string_create(void)
+{
+
+ return (_prop_string_alloc());
+}
+
+/*
+ * prop_string_create_cstring --
+ * Create a string that contains a copy of the provided C string.
+ */
+prop_string_t
+prop_string_create_cstring(const char *str)
+{
+ prop_string_t ps;
+ char *cp;
+ size_t len;
+
+ ps = _prop_string_alloc();
+ if (ps != NULL) {
+ len = strlen(str);
+ cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
+ if (cp == NULL) {
+ prop_object_release(ps);
+ return (NULL);
+ }
+ strcpy(cp, str);
+ ps->ps_mutable = cp;
+ ps->ps_size = len;
+ }
+ return (ps);
+}
+
+/*
+ * prop_string_create_cstring_nocopy --
+ * Create an immutable string that contains a refrence to the
+ * provided C string.
+ */
+prop_string_t
+prop_string_create_cstring_nocopy(const char *str)
+{
+ prop_string_t ps;
+
+ ps = _prop_string_alloc();
+ if (ps != NULL) {
+ ps->ps_immutable = str;
+ ps->ps_size = strlen(str);
+ ps->ps_flags |= PS_F_NOCOPY;
+ }
+ return (ps);
+}
+
+/*
+ * prop_string_copy --
+ * Copy a string. If the original string is immutable, then the
+ * copy is also immutable and references the same external data.
+ */
+prop_string_t
+prop_string_copy(prop_string_t ops)
+{
+ prop_string_t ps;
+
+ if (! prop_object_is_string(ops))
+ return (NULL);
+
+ ps = _prop_string_alloc();
+ if (ps != NULL) {
+ ps->ps_size = ops->ps_size;
+ ps->ps_flags = ops->ps_flags;
+ if (ops->ps_flags & PS_F_NOCOPY)
+ ps->ps_immutable = ops->ps_immutable;
+ else {
+ char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
+ if (cp == NULL) {
+ prop_object_release(ps);
+ return (NULL);
+ }
+ strcpy(cp, prop_string_contents(ops));
+ ps->ps_mutable = cp;
+ }
+ }
+ return (ps);
+}
+
+/*
+ * prop_string_copy_mutable --
+ * Copy a string, always returning a mutable copy.
+ */
+prop_string_t
+prop_string_copy_mutable(prop_string_t ops)
+{
+ prop_string_t ps;
+ char *cp;
+
+ if (! prop_object_is_string(ops))
+ return (NULL);
+
+ ps = _prop_string_alloc();
+ if (ps != NULL) {
+ ps->ps_size = ops->ps_size;
+ cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
+ if (cp == NULL) {
+ prop_object_release(ps);
+ return (NULL);
+ }
+ strcpy(cp, prop_string_contents(ops));
+ ps->ps_mutable = cp;
+ }
+ return (ps);
+}
+
+/*
+ * prop_string_size --
+ * Return the size of the string, not including the terminating NUL.
+ */
+size_t
+prop_string_size(prop_string_t ps)
+{
+
+ if (! prop_object_is_string(ps))
+ return (0);
+
+ return (ps->ps_size);
+}
+
+/*
+ * prop_string_mutable --
+ * Return true if the string is a mutable string.
+ */
+bool
+prop_string_mutable(prop_string_t ps)
+{
+
+ if (! prop_object_is_string(ps))
+ return (false);
+
+ return ((ps->ps_flags & PS_F_NOCOPY) == 0);
+}
+
+/*
+ * prop_string_cstring --
+ * Return a copy of the contents of the string as a C string.
+ * The string is allocated with the M_TEMP malloc type.
+ */
+char *
+prop_string_cstring(prop_string_t ps)
+{
+ char *cp;
+
+ if (! prop_object_is_string(ps))
+ return (NULL);
+
+ cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
+ if (cp != NULL)
+ strcpy(cp, prop_string_contents(ps));
+
+ return (cp);
+}
+
+/*
+ * prop_string_cstring_nocopy --
+ * Return an immutable reference to the contents of the string
+ * as a C string.
+ */
+const char *
+prop_string_cstring_nocopy(prop_string_t ps)
+{
+
+ if (! prop_object_is_string(ps))
+ return (NULL);
+
+ return (prop_string_contents(ps));
+}
+
+/*
+ * prop_string_append --
+ * Append the contents of one string to another. Returns true
+ * upon success. The destination string must be mutable.
+ */
+bool
+prop_string_append(prop_string_t dst, prop_string_t src)
+{
+ char *ocp, *cp;
+ size_t len;
+
+ if (! (prop_object_is_string(dst) &&
+ prop_object_is_string(src)))
+ return (false);
+
+ if (dst->ps_flags & PS_F_NOCOPY)
+ return (false);
+
+ len = dst->ps_size + src->ps_size;
+ cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
+ if (cp == NULL)
+ return (false);
+ sprintf(cp, "%s%s", prop_string_contents(dst),
+ prop_string_contents(src));
+ ocp = dst->ps_mutable;
+ dst->ps_mutable = cp;
+ dst->ps_size = len;
+ if (ocp != NULL)
+ _PROP_FREE(ocp, M_PROP_STRING);
+
+ return (true);
+}
+
+/*
+ * prop_string_append_cstring --
+ * Append a C string to a string. Returns true upon success.
+ * The destination string must be mutable.
+ */
+bool
+prop_string_append_cstring(prop_string_t dst, const char *src)
+{
+ char *ocp, *cp;
+ size_t len;
+
+ if (! prop_object_is_string(dst))
+ return (false);
+
+ _PROP_ASSERT(src != NULL);
+
+ if (dst->ps_flags & PS_F_NOCOPY)
+ return (false);
+
+ len = dst->ps_size + strlen(src);
+ cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
+ if (cp == NULL)
+ return (false);
+ sprintf(cp, "%s%s", prop_string_contents(dst), src);
+ ocp = dst->ps_mutable;
+ dst->ps_mutable = cp;
+ dst->ps_size = len;
+ if (ocp != NULL)
+ _PROP_FREE(ocp, M_PROP_STRING);
+
+ return (true);
+}
+
+/*
+ * prop_string_equals --
+ * Return true if two strings are equivalent.
+ */
+bool
+prop_string_equals(prop_string_t str1, prop_string_t str2)
+{
+ if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
+ return (false);
+
+ return prop_object_equals(str1, str2);
+}
+
+/*
+ * prop_string_equals_cstring --
+ * Return true if the string is equivalent to the specified
+ * C string.
+ */
+bool
+prop_string_equals_cstring(prop_string_t ps, const char *cp)
+{
+
+ if (! prop_object_is_string(ps))
+ return (false);
+
+ return (strcmp(prop_string_contents(ps), cp) == 0);
+}
+
+/*
+ * _prop_string_internalize --
+ * Parse a <string>...</string> and return the object created from the
+ * external representation.
+ */
+/* ARGSUSED */
+bool
+_prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
+ struct _prop_object_internalize_context *ctx)
+{
+ prop_string_t string;
+ char *str;
+ size_t len, alen;
+
+ if (ctx->poic_is_empty_element) {
+ *obj = prop_string_create();
+ return (true);
+ }
+
+ /* No attributes recognized here. */
+ if (ctx->poic_tagattr != NULL)
+ return (true);
+
+ /* Compute the length of the result. */
+ if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
+ NULL) == false)
+ return (true);
+
+ str = _PROP_MALLOC(len + 1, M_PROP_STRING);
+ if (str == NULL)
+ return (true);
+
+ if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
+ &ctx->poic_cp) == false ||
+ alen != len) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (true);
+ }
+ str[len] = '\0';
+
+ if (_prop_object_internalize_find_tag(ctx, "string",
+ _PROP_TAG_TYPE_END) == false) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (true);
+ }
+
+ string = _prop_string_alloc();
+ if (string == NULL) {
+ _PROP_FREE(str, M_PROP_STRING);
+ return (true);
+ }
+
+ string->ps_mutable = str;
+ string->ps_size = len;
+ *obj = string;
+
+ return (true);
+}
--- /dev/null
+.\" $NetBSD: proplib.3,v 1.7 2011/01/19 20:34:23 bouyer Exp $
+.\"
+.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Jason R. Thorpe.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd January 17, 2011
+.Dt PROPLIB 3
+.Os
+.Sh NAME
+.Nm proplib
+.Nd property container object library
+.Sh LIBRARY
+.Lb libprop
+.Sh SYNOPSIS
+.In prop/proplib.h
+.Sh DESCRIPTION
+The
+.Nm
+library provides an abstract interface for creating and manipulating
+property lists.
+Property lists have object types for boolean values, opaque data, numbers,
+and strings.
+Structure is provided by the array and dictionary collection types.
+.Pp
+Property lists can be passed across protection boundaries by translating
+them to an external representation.
+This external representation is an XML document whose format is described
+by the following DTD:
+.Bd -literal -offset indent
+http://www.apple.com/DTDs/PropertyList-1.0.dtd
+.Ed
+.Pp
+Property container objects are reference counted.
+When an object is created, its reference count is set to 1.
+Any code that keeps a reference to an object, including the collection
+types
+.Pq arrays and dictionaries ,
+must
+.Dq retain
+the object
+.Pq increment its reference count .
+When that reference is dropped, the object must be
+.Dq released
+.Pq reference count decremented .
+When an object's reference count drops to 0, it is automatically freed.
+.Pp
+The rules for managing reference counts are very simple:
+.Bl -bullet
+.It
+If you create an object and do not explicitly maintain a reference to it,
+you must release it.
+.It
+If you get a reference to an object from other code and wish to maintain
+a reference to it, you must retain the object.
+You are responsible for
+releasing the object once you drop that reference.
+.It
+You must never release an object unless you create it or retain it.
+.El
+.Pp
+Object collections may be iterated by creating a special iterator object.
+Iterator objects are special; they may not be retained, and they are
+released using an iterator-specific release function.
+.Sh SEE ALSO
+.Xr prop_array 3 ,
+.Xr prop_bool 3 ,
+.Xr prop_data 3 ,
+.Xr prop_dictionary 3 ,
+.Xr prop_dictionary_util 3 ,
+.Xr prop_number 3 ,
+.Xr prop_object 3 ,
+.Xr prop_send_ioctl 3 ,
+.Xr prop_send_syscall 3 ,
+.Xr prop_string 3
+.Sh HISTORY
+The
+.Nm
+property container object library first appeared in
+.Nx 4.0 .
+.Sh CAVEATS
+.Nm
+does not have a
+.Sq date
+object type, and thus will not parse
+.Sq date
+elements from an Apple XML property list.
+.Pp
+The
+.Nm
+.Sq number
+object type differs from the Apple XML property list format in the following
+ways:
+.Bl -bullet
+.It
+The external representation is in base 16, not base 10.
+.Nm
+is able to parse base 8, base 10, and base 16
+.Sq integer
+elements.
+.It
+Internally, integers are always stored as unsigned numbers
+.Pq uint64_t .
+Therefore, the external representation will never be negative.
+.It
+Because floating point numbers are not supported,
+.Sq real
+elements from an Apple XML property list will not be parsed.
+.El
+.Pp
+In order to facilitate use of
+.Nm
+in kernel, standalone, and user space environments, the
+.Nm
+parser is not a real XML parser.
+It is hard-coded to parse only the property list external representation.
755 root operator /usr/include/arpa
755 root operator /usr/include/compat
755 root operator /usr/include/compat/machine
+755 root operator /usr/include/prop
755 root operator /usr/include/ddekit
755 root operator /usr/include/ddekit/minix
755 root operator /usr/include/minix
.if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no")
SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert libutil \
- libpuffs librefuse libbz2 libarchive
+ libpuffs librefuse libbz2 libarchive libprop
.endif
.if ${COMPILER_TYPE} == "ack"
--- /dev/null
+# $NetBSD: Makefile,v 1.19 2011/09/30 22:08:19 jym Exp $
+
+.include <bsd.own.mk>
+
+WARNS=4
+USE_SHLIBDIR= yes
+
+PROPLIBDIR=${NETBSDSRCDIR}/common/lib/libprop
+
+.include "${PROPLIBDIR}/Makefile.inc"
+
+CPPFLAGS+=-D_LIBPROP
+CPPFLAGS+= -I${NETBSDSRCDIR}/lib/nbsd_libc/include # -D_REENTRANT
+
+LINTFLAGS+=-w
+LIB= prop
+
+MAN= prop_array.3 prop_bool.3 prop_data.3 prop_dictionary.3 \
+ prop_ingest.3 prop_number.3 prop_object.3 prop_string.3 proplib.3
+
+MAN+= prop_copyin_ioctl.9
+MLINKS+= prop_copyin_ioctl.9 prop_array_copyin_ioctl.9
+MLINKS+= prop_copyin_ioctl.9 prop_array_copyout_ioctl.9
+MLINKS+= prop_copyin_ioctl.9 prop_dictionary_copyin_ioctl.9
+MLINKS+= prop_copyin_ioctl.9 prop_dictionary_copyout_ioctl.9
+
+MAN+= prop_send_ioctl.3
+MLINKS+= prop_send_ioctl.3 prop_array_send_ioctl.3
+MLINKS+= prop_send_ioctl.3 prop_array_recv_ioctl.3
+MLINKS+= prop_send_ioctl.3 prop_dictionary_send_ioctl.3
+MLINKS+= prop_send_ioctl.3 prop_dictionary_recv_ioctl.3
+MLINKS+= prop_send_ioctl.3 prop_dictionary_sendrecv_ioctl.3
+
+MAN+= prop_send_syscall.3
+MLINKS+= prop_send_syscall.3 prop_array_send_syscall.3
+MLINKS+= prop_send_syscall.3 prop_array_recv_syscall.3
+MLINKS+= prop_send_syscall.3 prop_dictionary_send_syscall.3
+MLINKS+= prop_send_syscall.3 prop_dictionary_recv_syscall.3
+
+MAN+= prop_dictionary_util.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_bool.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_bool.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_int8.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_uint8.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_int8.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_uint8.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_int16.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_uint16.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_int16.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_uint16.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_int32.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_uint32.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_int32.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_uint32.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_int64.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_uint64.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_int64.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_uint64.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_cstring.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_cstring.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_get_cstring_nocopy.3
+MLINKS+= prop_dictionary_util.3 prop_dictionary_set_cstring_nocopy.3
+
+MLINKS+= prop_array.3 prop_array_add.3
+MLINKS+= prop_array.3 prop_array_capacity.3
+MLINKS+= prop_array.3 prop_array_copy.3
+MLINKS+= prop_array.3 prop_array_copy_mutable.3
+MLINKS+= prop_array.3 prop_array_count.3
+MLINKS+= prop_array.3 prop_array_create.3
+MLINKS+= prop_array.3 prop_array_create_with_capacity.3
+MLINKS+= prop_array.3 prop_array_ensure_capacity.3
+MLINKS+= prop_array.3 prop_array_equals.3
+MLINKS+= prop_array.3 prop_array_externalize.3
+MLINKS+= prop_array.3 prop_array_externalize_to_file.3
+MLINKS+= prop_array.3 prop_array_externalize_to_pref.3
+MLINKS+= prop_array.3 prop_array_get.3
+MLINKS+= prop_array.3 prop_array_internalize.3
+MLINKS+= prop_array.3 prop_array_internalize_from_file.3
+MLINKS+= prop_array.3 prop_array_internalize_from_pref.3
+MLINKS+= prop_array.3 prop_array_iterator.3
+MLINKS+= prop_array.3 prop_array_make_immutable.3
+MLINKS+= prop_array.3 prop_array_mutable.3
+MLINKS+= prop_array.3 prop_array_remove.3
+MLINKS+= prop_array.3 prop_array_set.3
+
+MAN+= prop_array_util.3
+MLINKS+= prop_array_util.3 prop_array_get_bool.3
+MLINKS+= prop_array_util.3 prop_array_set_bool.3
+MLINKS+= prop_array_util.3 prop_array_get_int8.3
+MLINKS+= prop_array_util.3 prop_array_get_uint8.3
+MLINKS+= prop_array_util.3 prop_array_set_int8.3
+MLINKS+= prop_array_util.3 prop_array_set_uint8.3
+MLINKS+= prop_array_util.3 prop_array_get_int16.3
+MLINKS+= prop_array_util.3 prop_array_get_uint16.3
+MLINKS+= prop_array_util.3 prop_array_set_int16.3
+MLINKS+= prop_array_util.3 prop_array_set_uint16.3
+MLINKS+= prop_array_util.3 prop_array_get_int32.3
+MLINKS+= prop_array_util.3 prop_array_get_uint32.3
+MLINKS+= prop_array_util.3 prop_array_set_int32.3
+MLINKS+= prop_array_util.3 prop_array_set_uint32.3
+MLINKS+= prop_array_util.3 prop_array_get_int64.3
+MLINKS+= prop_array_util.3 prop_array_get_uint64.3
+MLINKS+= prop_array_util.3 prop_array_set_int64.3
+MLINKS+= prop_array_util.3 prop_array_set_uint64.3
+MLINKS+= prop_array_util.3 prop_array_get_cstring.3
+MLINKS+= prop_array_util.3 prop_array_set_cstring.3
+MLINKS+= prop_array_util.3 prop_array_get_cstring_nocopy.3
+MLINKS+= prop_array_util.3 prop_array_set_cstring_nocopy.3
+
+MLINKS+= prop_bool.3 prop_bool_copy.3
+MLINKS+= prop_bool.3 prop_bool_create.3
+MLINKS+= prop_bool.3 prop_bool_true.3
+
+MLINKS+= prop_data.3 prop_data_copy.3
+MLINKS+= prop_data.3 prop_data_create_data.3
+MLINKS+= prop_data.3 prop_data_create_data_nocopy.3
+MLINKS+= prop_data.3 prop_data_data.3
+MLINKS+= prop_data.3 prop_data_data_nocopy.3
+MLINKS+= prop_data.3 prop_data_equals.3
+MLINKS+= prop_data.3 prop_data_equals_data.3
+MLINKS+= prop_data.3 prop_data_size.3
+
+MLINKS+= prop_dictionary.3 prop_dictionary_all_keys.3
+MLINKS+= prop_dictionary.3 prop_dictionary_capacity.3
+MLINKS+= prop_dictionary.3 prop_dictionary_copy.3
+MLINKS+= prop_dictionary.3 prop_dictionary_copy_mutable.3
+MLINKS+= prop_dictionary.3 prop_dictionary_count.3
+MLINKS+= prop_dictionary.3 prop_dictionary_create.3
+MLINKS+= prop_dictionary.3 prop_dictionary_create_with_capacity.3
+MLINKS+= prop_dictionary.3 prop_dictionary_ensure_capacity.3
+MLINKS+= prop_dictionary.3 prop_dictionary_equals.3
+MLINKS+= prop_dictionary.3 prop_dictionary_externalize.3
+MLINKS+= prop_dictionary.3 prop_dictionary_externalize_to_file.3
+MLINKS+= prop_dictionary.3 prop_dictionary_externalize_to_pref.3
+MLINKS+= prop_dictionary.3 prop_dictionary_get.3
+MLINKS+= prop_dictionary.3 prop_dictionary_get_keysym.3
+MLINKS+= prop_dictionary.3 prop_dictionary_internalize.3
+MLINKS+= prop_dictionary.3 prop_dictionary_internalize_from_file.3
+MLINKS+= prop_dictionary.3 prop_dictionary_internalize_from_pref.3
+MLINKS+= prop_dictionary.3 prop_dictionary_iterator.3
+MLINKS+= prop_dictionary.3 prop_dictionary_keysym_cstring_nocopy.3
+MLINKS+= prop_dictionary.3 prop_dictionary_keysym_equals.3
+MLINKS+= prop_dictionary.3 prop_dictionary_make_immutable.3
+MLINKS+= prop_dictionary.3 prop_dictionary_mutable.3
+MLINKS+= prop_dictionary.3 prop_dictionary_remove.3
+MLINKS+= prop_dictionary.3 prop_dictionary_remove_keysym.3
+MLINKS+= prop_dictionary.3 prop_dictionary_set.3
+MLINKS+= prop_dictionary.3 prop_dictionary_set_keysym.3
+
+MLINKS+= prop_ingest.3 prop_ingest_context_alloc.3
+MLINKS+= prop_ingest.3 prop_ingest_context_error.3
+MLINKS+= prop_ingest.3 prop_ingest_context_free.3
+MLINKS+= prop_ingest.3 prop_ingest_context_key.3
+MLINKS+= prop_ingest.3 prop_ingest_context_private.3
+MLINKS+= prop_ingest.3 prop_ingest_context_type.3
+MLINKS+= prop_ingest.3 prop_dictionary_ingest.3
+
+MLINKS+= prop_number.3 prop_number_copy.3
+MLINKS+= prop_number.3 prop_number_create_integer.3
+MLINKS+= prop_number.3 prop_number_create_unsigned_integer.3
+MLINKS+= prop_number.3 prop_number_equals.3
+MLINKS+= prop_number.3 prop_number_equals_integer.3
+MLINKS+= prop_number.3 prop_number_equals_unsigned_integer.3
+MLINKS+= prop_number.3 prop_number_size.3
+MLINKS+= prop_number.3 prop_number_unsigned.3
+MLINKS+= prop_number.3 prop_number_integer_value.3
+MLINKS+= prop_number.3 prop_number_unsigned_integer_value.3
+
+MLINKS+= prop_object.3 prop_object_equals.3
+MLINKS+= prop_object.3 prop_object_iterator_next.3
+MLINKS+= prop_object.3 prop_object_iterator_release.3
+MLINKS+= prop_object.3 prop_object_iterator_reset.3
+MLINKS+= prop_object.3 prop_object_release.3
+MLINKS+= prop_object.3 prop_object_retain.3
+MLINKS+= prop_object.3 prop_object_type.3
+
+MLINKS+= prop_string.3 prop_string_append.3
+MLINKS+= prop_string.3 prop_string_append_cstring.3
+MLINKS+= prop_string.3 prop_string_copy.3
+MLINKS+= prop_string.3 prop_string_copy_mutable.3
+MLINKS+= prop_string.3 prop_string_create.3
+MLINKS+= prop_string.3 prop_string_create_cstring.3
+MLINKS+= prop_string.3 prop_string_create_cstring_nocopy.3
+MLINKS+= prop_string.3 prop_string_cstring.3
+MLINKS+= prop_string.3 prop_string_cstring_nocopy.3
+MLINKS+= prop_string.3 prop_string_equals.3
+MLINKS+= prop_string.3 prop_string_equals_cstring.3
+MLINKS+= prop_string.3 prop_string_mutable.3
+MLINKS+= prop_string.3 prop_string_size.3
+
+.include <bsd.lib.mk>
--- /dev/null
+# $NetBSD: shlib_version,v 1.10 2009/10/10 18:06:54 bad Exp $
+# Remember to update distrib/sets/lists/base/shl.* when changing
+major=1
+minor=1
.else
SUBDIR= rpc
.endif
-.if !defined(__MINIX)
+.if defined(__MINIX)
+SUBDIR+= prop
+.else
SUBDIR+= ../common/include/prop
.endif
--- /dev/null
+# $NetBSD: Makefile,v 1.3 2007/08/17 11:05:04 pavel Exp $
+
+INCS= prop_array.h prop_bool.h prop_data.h prop_dictionary.h \
+ prop_ingest.h prop_number.h prop_object.h prop_string.h \
+ proplib.h plistref.h
+
+INCSDIR= /usr/include/prop
+
+.include <bsd.prog.mk>
--- /dev/null
+/* $NetBSD: plistref.h,v 1.2 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PLISTREF_H_
+#define _PROPLIB_PLISTREF_H_
+
+/* for size_t */
+#include <sys/types.h>
+
+/*
+ * Property List Reference --
+ * Used to pass externalized property lists across protection
+ * boundaries (ioctls, syscalls, etc.).
+ */
+struct plistref {
+ void *pref_plist; /* plist data */
+ size_t pref_len; /* total length of plist data */
+};
+
+#endif /* _PROPLIB_PLISTREF_H_ */
--- /dev/null
+/* $NetBSD: prop_array.h,v 1.13 2011/09/30 22:08:18 jym Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_ARRAY_H_
+#define _PROPLIB_PROP_ARRAY_H_
+
+#include <prop/prop_object.h>
+
+typedef struct _prop_array *prop_array_t;
+
+__BEGIN_DECLS
+prop_array_t prop_array_create(void);
+prop_array_t prop_array_create_with_capacity(unsigned int);
+
+prop_array_t prop_array_copy(prop_array_t);
+prop_array_t prop_array_copy_mutable(prop_array_t);
+
+unsigned int prop_array_capacity(prop_array_t);
+unsigned int prop_array_count(prop_array_t);
+bool prop_array_ensure_capacity(prop_array_t, unsigned int);
+
+void prop_array_make_immutable(prop_array_t);
+bool prop_array_mutable(prop_array_t);
+
+prop_object_iterator_t prop_array_iterator(prop_array_t);
+
+prop_object_t prop_array_get(prop_array_t, unsigned int);
+bool prop_array_set(prop_array_t, unsigned int, prop_object_t);
+bool prop_array_add(prop_array_t, prop_object_t);
+void prop_array_remove(prop_array_t, unsigned int);
+
+bool prop_array_equals(prop_array_t, prop_array_t);
+
+char * prop_array_externalize(prop_array_t);
+prop_array_t prop_array_internalize(const char *);
+
+bool prop_array_externalize_to_file(prop_array_t, const char *);
+prop_array_t prop_array_internalize_from_file(const char *);
+
+#if defined(__NetBSD__)
+struct plistref;
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+bool prop_array_externalize_to_pref(prop_array_t, struct plistref *);
+bool prop_array_internalize_from_pref(const struct plistref *,
+ prop_array_t *);
+int prop_array_send_ioctl(prop_array_t, int, unsigned long);
+int prop_array_recv_ioctl(int, unsigned long, prop_array_t *);
+int prop_array_send_syscall(prop_array_t, struct plistref *);
+int prop_array_recv_syscall(const struct plistref *,
+ prop_array_t *);
+#elif defined(_KERNEL)
+int prop_array_copyin(const struct plistref *, prop_array_t *);
+int prop_array_copyout(struct plistref *, prop_array_t);
+int prop_array_copyin_ioctl(const struct plistref *, const u_long,
+ prop_array_t *);
+int prop_array_copyout_ioctl(struct plistref *, const u_long,
+ prop_array_t);
+#endif
+#endif /* __NetBSD__ */
+
+/*
+ * Utility routines to make it more convenient to work with values
+ * stored in dictionaries.
+ */
+bool prop_array_get_bool(prop_array_t, unsigned int,
+ bool *);
+bool prop_array_set_bool(prop_array_t, unsigned int,
+ bool);
+
+bool prop_array_get_int8(prop_array_t, unsigned int,
+ int8_t *);
+bool prop_array_get_uint8(prop_array_t, unsigned int,
+ uint8_t *);
+bool prop_array_set_int8(prop_array_t, unsigned int,
+ int8_t);
+bool prop_array_set_uint8(prop_array_t, unsigned int,
+ uint8_t);
+
+bool prop_array_get_int16(prop_array_t, unsigned int,
+ int16_t *);
+bool prop_array_get_uint16(prop_array_t, unsigned int,
+ uint16_t *);
+bool prop_array_set_int16(prop_array_t, unsigned int,
+ int16_t);
+bool prop_array_set_uint16(prop_array_t, unsigned int,
+ uint16_t);
+
+bool prop_array_get_int32(prop_array_t, unsigned int,
+ int32_t *);
+bool prop_array_get_uint32(prop_array_t, unsigned int,
+ uint32_t *);
+bool prop_array_set_int32(prop_array_t, unsigned int,
+ int32_t);
+bool prop_array_set_uint32(prop_array_t, unsigned int,
+ uint32_t);
+
+bool prop_array_get_int64(prop_array_t, unsigned int,
+ int64_t *);
+bool prop_array_get_uint64(prop_array_t, unsigned int,
+ uint64_t *);
+bool prop_array_set_int64(prop_array_t, unsigned int,
+ int64_t);
+bool prop_array_set_uint64(prop_array_t, unsigned int,
+ uint64_t);
+
+bool prop_array_add_int8(prop_array_t, int8_t);
+bool prop_array_add_uint8(prop_array_t, uint8_t);
+
+bool prop_array_add_int16(prop_array_t, int16_t);
+bool prop_array_add_uint16(prop_array_t, uint16_t);
+
+bool prop_array_add_int32(prop_array_t, int32_t);
+bool prop_array_add_uint32(prop_array_t, uint32_t);
+
+bool prop_array_add_int64(prop_array_t, int64_t);
+bool prop_array_add_uint64(prop_array_t, uint64_t);
+
+bool prop_array_get_cstring(prop_array_t, unsigned int,
+ char **);
+bool prop_array_set_cstring(prop_array_t, unsigned int,
+ const char *);
+
+bool prop_array_get_cstring_nocopy(prop_array_t,
+ unsigned int,
+ const char **);
+bool prop_array_set_cstring_nocopy(prop_array_t,
+ unsigned int,
+ const char *);
+
+bool prop_array_add_and_rel(prop_array_t, prop_object_t);
+
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_ARRAY_H_ */
--- /dev/null
+/* $NetBSD: prop_bool.h,v 1.4 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_BOOL_H_
+#define _PROPLIB_PROP_BOOL_H_
+
+#include <prop/prop_object.h>
+
+typedef struct _prop_bool *prop_bool_t;
+
+__BEGIN_DECLS
+prop_bool_t prop_bool_create(bool);
+prop_bool_t prop_bool_copy(prop_bool_t);
+
+bool prop_bool_true(prop_bool_t);
+
+bool prop_bool_equals(prop_bool_t, prop_bool_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_BOOL_H_ */
--- /dev/null
+/* $NetBSD: prop_data.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_DATA_H_
+#define _PROPLIB_PROP_DATA_H_
+
+#include <prop/prop_object.h>
+
+typedef struct _prop_data *prop_data_t;
+
+__BEGIN_DECLS
+prop_data_t prop_data_create_data(const void *, size_t);
+prop_data_t prop_data_create_data_nocopy(const void *, size_t);
+
+prop_data_t prop_data_copy(prop_data_t);
+
+size_t prop_data_size(prop_data_t);
+
+void * prop_data_data(prop_data_t);
+const void * prop_data_data_nocopy(prop_data_t);
+
+bool prop_data_equals(prop_data_t, prop_data_t);
+bool prop_data_equals_data(prop_data_t, const void *, size_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_DATA_H_ */
--- /dev/null
+/* $NetBSD: prop_dictionary.h,v 1.14 2011/09/30 22:08:18 jym Exp $ */
+
+/*-
+ * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_DICTIONARY_H_
+#define _PROPLIB_PROP_DICTIONARY_H_
+
+#include <prop/prop_object.h>
+
+typedef struct _prop_dictionary *prop_dictionary_t;
+typedef struct _prop_dictionary_keysym *prop_dictionary_keysym_t;
+
+__BEGIN_DECLS
+prop_dictionary_t prop_dictionary_create(void);
+prop_dictionary_t prop_dictionary_create_with_capacity(unsigned int);
+
+prop_dictionary_t prop_dictionary_copy(prop_dictionary_t);
+prop_dictionary_t prop_dictionary_copy_mutable(prop_dictionary_t);
+
+unsigned int prop_dictionary_count(prop_dictionary_t);
+bool prop_dictionary_ensure_capacity(prop_dictionary_t,
+ unsigned int);
+
+void prop_dictionary_make_immutable(prop_dictionary_t);
+bool prop_dictionary_mutable(prop_dictionary_t);
+
+prop_object_iterator_t prop_dictionary_iterator(prop_dictionary_t);
+prop_array_t prop_dictionary_all_keys(prop_dictionary_t);
+
+prop_object_t prop_dictionary_get(prop_dictionary_t, const char *);
+bool prop_dictionary_set(prop_dictionary_t, const char *,
+ prop_object_t);
+void prop_dictionary_remove(prop_dictionary_t, const char *);
+
+prop_object_t prop_dictionary_get_keysym(prop_dictionary_t,
+ prop_dictionary_keysym_t);
+bool prop_dictionary_set_keysym(prop_dictionary_t,
+ prop_dictionary_keysym_t,
+ prop_object_t);
+void prop_dictionary_remove_keysym(prop_dictionary_t,
+ prop_dictionary_keysym_t);
+
+bool prop_dictionary_equals(prop_dictionary_t, prop_dictionary_t);
+
+char * prop_dictionary_externalize(prop_dictionary_t);
+prop_dictionary_t prop_dictionary_internalize(const char *);
+
+bool prop_dictionary_externalize_to_file(prop_dictionary_t,
+ const char *);
+prop_dictionary_t prop_dictionary_internalize_from_file(const char *);
+
+const char * prop_dictionary_keysym_cstring_nocopy(prop_dictionary_keysym_t);
+
+bool prop_dictionary_keysym_equals(prop_dictionary_keysym_t,
+ prop_dictionary_keysym_t);
+
+#if defined(__NetBSD__)
+struct plistref;
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+bool prop_dictionary_externalize_to_pref(prop_dictionary_t, struct plistref *);
+bool prop_dictionary_internalize_from_pref(const struct plistref *,
+ prop_dictionary_t *);
+int prop_dictionary_send_ioctl(prop_dictionary_t, int,
+ unsigned long);
+int prop_dictionary_recv_ioctl(int, unsigned long,
+ prop_dictionary_t *);
+int prop_dictionary_sendrecv_ioctl(prop_dictionary_t,
+ int, unsigned long,
+ prop_dictionary_t *);
+int prop_dictionary_send_syscall(prop_dictionary_t,
+ struct plistref *);
+int prop_dictionary_recv_syscall(const struct plistref *,
+ prop_dictionary_t *);
+#elif defined(_KERNEL)
+int prop_dictionary_copyin(const struct plistref *,
+ prop_dictionary_t *);
+int prop_dictionary_copyout(struct plistref *,
+ prop_dictionary_t);
+int prop_dictionary_copyin_ioctl(const struct plistref *,
+ const u_long,
+ prop_dictionary_t *);
+int prop_dictionary_copyout_ioctl(struct plistref *,
+ const u_long,
+ prop_dictionary_t);
+#endif
+#endif /* __NetBSD__ */
+
+/*
+ * Utility routines to make it more convenient to work with values
+ * stored in dictionaries.
+ */
+bool prop_dictionary_get_dict(prop_dictionary_t, const char *,
+ prop_dictionary_t *);
+bool prop_dictionary_get_bool(prop_dictionary_t, const char *,
+ bool *);
+bool prop_dictionary_set_bool(prop_dictionary_t, const char *,
+ bool);
+
+bool prop_dictionary_get_int8(prop_dictionary_t, const char *,
+ int8_t *);
+bool prop_dictionary_get_uint8(prop_dictionary_t, const char *,
+ uint8_t *);
+bool prop_dictionary_set_int8(prop_dictionary_t, const char *,
+ int8_t);
+bool prop_dictionary_set_uint8(prop_dictionary_t, const char *,
+ uint8_t);
+
+bool prop_dictionary_get_int16(prop_dictionary_t, const char *,
+ int16_t *);
+bool prop_dictionary_get_uint16(prop_dictionary_t, const char *,
+ uint16_t *);
+bool prop_dictionary_set_int16(prop_dictionary_t, const char *,
+ int16_t);
+bool prop_dictionary_set_uint16(prop_dictionary_t, const char *,
+ uint16_t);
+
+bool prop_dictionary_get_int32(prop_dictionary_t, const char *,
+ int32_t *);
+bool prop_dictionary_get_uint32(prop_dictionary_t, const char *,
+ uint32_t *);
+bool prop_dictionary_set_int32(prop_dictionary_t, const char *,
+ int32_t);
+bool prop_dictionary_set_uint32(prop_dictionary_t, const char *,
+ uint32_t);
+
+bool prop_dictionary_get_int64(prop_dictionary_t, const char *,
+ int64_t *);
+bool prop_dictionary_get_uint64(prop_dictionary_t, const char *,
+ uint64_t *);
+bool prop_dictionary_set_int64(prop_dictionary_t, const char *,
+ int64_t);
+bool prop_dictionary_set_uint64(prop_dictionary_t, const char *,
+ uint64_t);
+
+bool prop_dictionary_get_cstring(prop_dictionary_t, const char *,
+ char **);
+bool prop_dictionary_set_cstring(prop_dictionary_t, const char *,
+ const char *);
+
+bool prop_dictionary_get_cstring_nocopy(prop_dictionary_t,
+ const char *,
+ const char **);
+bool prop_dictionary_set_cstring_nocopy(prop_dictionary_t,
+ const char *,
+ const char *);
+
+bool prop_dictionary_set_and_rel(prop_dictionary_t,
+ const char *,
+ prop_object_t);
+
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_DICTIONARY_H_ */
--- /dev/null
+/* $NetBSD: prop_ingest.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_INGEST_H_
+#define _PROPLIB_PROP_INGEST_H_
+
+#include <prop/prop_dictionary.h>
+
+typedef enum {
+ PROP_INGEST_ERROR_NO_ERROR = 0,
+ PROP_INGEST_ERROR_NO_KEY = 1,
+ PROP_INGEST_ERROR_WRONG_TYPE = 2,
+ PROP_INGEST_ERROR_HANDLER_FAILED = 3
+} prop_ingest_error_t;
+
+typedef enum {
+ PROP_INGEST_FLAG_OPTIONAL = 0x01
+} prop_ingest_flag_t;
+
+typedef struct _prop_ingest_context *prop_ingest_context_t;
+
+typedef bool (*prop_ingest_handler_t)(prop_ingest_context_t, prop_object_t);
+
+typedef struct {
+ const char *pite_key;
+ prop_type_t pite_type;
+ unsigned int pite_flags;
+ prop_ingest_handler_t pite_handler;
+} prop_ingest_table_entry;
+
+#define PROP_INGEST(key_, type_, handler_) \
+ { .pite_key = key_ , \
+ .pite_type = type_ , \
+ .pite_flags = 0 , \
+ .pite_handler = handler_ }
+
+#define PROP_INGEST_OPTIONAL(key_, type_, handler_) \
+ { .pite_key = key_ , \
+ .pite_type = type_ , \
+ .pite_flags = PROP_INGEST_FLAG_OPTIONAL , \
+ .pite_handler = handler_ }
+
+#define PROP_INGEST_END \
+ { .pite_key = NULL }
+
+__BEGIN_DECLS
+prop_ingest_context_t
+ prop_ingest_context_alloc(void *);
+void prop_ingest_context_free(prop_ingest_context_t);
+
+prop_ingest_error_t
+ prop_ingest_context_error(prop_ingest_context_t);
+prop_type_t prop_ingest_context_type(prop_ingest_context_t);
+const char * prop_ingest_context_key(prop_ingest_context_t);
+void * prop_ingest_context_private(prop_ingest_context_t);
+
+bool prop_dictionary_ingest(prop_dictionary_t,
+ const prop_ingest_table_entry[],
+ prop_ingest_context_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_INGEST_H_ */
--- /dev/null
+/* $NetBSD: prop_number.h,v 1.6 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_NUMBER_H_
+#define _PROPLIB_PROP_NUMBER_H_
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <stdint.h>
+#endif
+#include <prop/prop_object.h>
+
+typedef struct _prop_number *prop_number_t;
+
+__BEGIN_DECLS
+prop_number_t prop_number_create_integer(int64_t);
+prop_number_t prop_number_create_unsigned_integer(uint64_t);
+
+prop_number_t prop_number_copy(prop_number_t);
+
+int prop_number_size(prop_number_t);
+bool prop_number_unsigned(prop_number_t);
+
+int64_t prop_number_integer_value(prop_number_t);
+uint64_t prop_number_unsigned_integer_value(prop_number_t);
+
+bool prop_number_equals(prop_number_t, prop_number_t);
+bool prop_number_equals_integer(prop_number_t, int64_t);
+bool prop_number_equals_unsigned_integer(prop_number_t, uint64_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_NUMBER_H_ */
--- /dev/null
+/* $NetBSD: prop_object.h,v 1.8 2008/12/05 13:11:41 ad Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_OBJECT_H_
+#define _PROPLIB_PROP_OBJECT_H_
+
+#include <sys/types.h>
+
+#if !defined(_KERNEL) && !defined(_STANDALONE)
+#include <stdbool.h>
+#endif /* ! _KERNEL && ! _STANDALONE */
+
+typedef void *prop_object_t;
+
+typedef enum {
+ PROP_TYPE_UNKNOWN = 0x00000000,
+#ifndef _PROPLIB_ZFS_CONFLICT
+ PROP_TYPE_BOOL = 0x626f6f6c, /* 'bool' */
+ PROP_TYPE_NUMBER = 0x6e6d6272, /* 'nmbr' */
+ PROP_TYPE_STRING = 0x73746e67, /* 'stng' */
+ PROP_TYPE_DATA = 0x64617461, /* 'data' */
+ PROP_TYPE_ARRAY = 0x61726179, /* 'aray' */
+ PROP_TYPE_DICTIONARY = 0x64696374, /* 'dict' */
+ PROP_TYPE_DICT_KEYSYM = 0x646b6579 /* 'dkey' */
+#endif /* !_PROPLIB_ZFS_CONFLICT */
+} prop_type_t;
+
+__BEGIN_DECLS
+void prop_object_retain(prop_object_t);
+void prop_object_release(prop_object_t);
+
+prop_type_t prop_object_type(prop_object_t);
+
+bool prop_object_equals(prop_object_t, prop_object_t);
+bool prop_object_equals_with_error(prop_object_t, prop_object_t, bool *);
+
+typedef struct _prop_object_iterator *prop_object_iterator_t;
+
+prop_object_t prop_object_iterator_next(prop_object_iterator_t);
+void prop_object_iterator_reset(prop_object_iterator_t);
+void prop_object_iterator_release(prop_object_iterator_t);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_OBJECT_H_ */
--- /dev/null
+/* $NetBSD: prop_string.h,v 1.3 2008/04/28 20:22:51 martin Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROP_STRING_H_
+#define _PROPLIB_PROP_STRING_H_
+
+#include <prop/prop_object.h>
+
+typedef struct _prop_string *prop_string_t;
+
+__BEGIN_DECLS
+prop_string_t prop_string_create(void);
+prop_string_t prop_string_create_cstring(const char *);
+prop_string_t prop_string_create_cstring_nocopy(const char *);
+
+prop_string_t prop_string_copy(prop_string_t);
+prop_string_t prop_string_copy_mutable(prop_string_t);
+
+size_t prop_string_size(prop_string_t);
+bool prop_string_mutable(prop_string_t);
+
+char * prop_string_cstring(prop_string_t);
+const char * prop_string_cstring_nocopy(prop_string_t);
+
+bool prop_string_append(prop_string_t, prop_string_t);
+bool prop_string_append_cstring(prop_string_t, const char *);
+
+bool prop_string_equals(prop_string_t, prop_string_t);
+bool prop_string_equals_cstring(prop_string_t, const char *);
+__END_DECLS
+
+#endif /* _PROPLIB_PROP_STRING_H_ */
--- /dev/null
+/* $NetBSD: proplib.h,v 1.7 2009/09/13 18:45:10 pooka Exp $ */
+
+/*-
+ * Copyright (c) 2006 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PROPLIB_PROPLIB_H_
+#define _PROPLIB_PROPLIB_H_
+
+#include <prop/prop_array.h>
+#include <prop/prop_bool.h>
+#include <prop/prop_data.h>
+#include <prop/prop_dictionary.h>
+#include <prop/prop_number.h>
+#include <prop/prop_string.h>
+
+#include <prop/prop_ingest.h>
+
+#include <prop/plistref.h>
+
+#ifdef _KERNEL
+void prop_kern_init(void);
+#endif
+
+#endif /* _PROPLIB_PROPLIB_H_ */
+common/lib/libprop src/common/lib/libprop
common/lib/libc src/common/lib/libc
lib/nbsd_libc src/lib/libc
lib/nbsd_libm src/lib/libm