From 6b6d114a21a24bee45291fa4af8899e108396c4a Mon Sep 17 00:00:00 2001 From: Ben Gras Date: Thu, 22 Dec 2011 17:42:19 +0100 Subject: [PATCH] import netbsd libprop --- common/lib/libprop/Makefile.inc | 9 + common/lib/libprop/prop_array.3 | 308 +++++ common/lib/libprop/prop_array.c | 911 +++++++++++++ common/lib/libprop/prop_array_util.3 | 228 ++++ common/lib/libprop/prop_array_util.c | 251 ++++ common/lib/libprop/prop_bool.3 | 82 ++ common/lib/libprop/prop_bool.c | 222 ++++ common/lib/libprop/prop_copyin_ioctl.9 | 194 +++ common/lib/libprop/prop_data.3 | 148 +++ common/lib/libprop/prop_data.c | 627 +++++++++ common/lib/libprop/prop_dictionary.3 | 353 +++++ common/lib/libprop/prop_dictionary.c | 1420 +++++++++++++++++++++ common/lib/libprop/prop_dictionary_util.3 | 200 +++ common/lib/libprop/prop_dictionary_util.c | 232 ++++ common/lib/libprop/prop_ingest.3 | 181 +++ common/lib/libprop/prop_ingest.c | 159 +++ common/lib/libprop/prop_kern.c | 612 +++++++++ common/lib/libprop/prop_number.3 | 210 +++ common/lib/libprop/prop_number.c | 592 +++++++++ common/lib/libprop/prop_object.3 | 141 ++ common/lib/libprop/prop_object.c | 1230 ++++++++++++++++++ common/lib/libprop/prop_object_impl.h | 436 +++++++ common/lib/libprop/prop_rb.c | 1057 +++++++++++++++ common/lib/libprop/prop_rb_impl.h | 154 +++ common/lib/libprop/prop_send_ioctl.3 | 151 +++ common/lib/libprop/prop_send_syscall.3 | 128 ++ common/lib/libprop/prop_stack.c | 118 ++ common/lib/libprop/prop_stack.h | 64 + common/lib/libprop/prop_string.3 | 193 +++ common/lib/libprop/prop_string.c | 471 +++++++ common/lib/libprop/proplib.3 | 139 ++ etc/mtree/minix.tree | 1 + lib/Makefile | 2 +- lib/libprop/Makefile | 191 +++ lib/libprop/shlib_version | 4 + nbsd_include/Makefile | 4 +- nbsd_include/prop/Makefile | 9 + nbsd_include/prop/plistref.h | 48 + nbsd_include/prop/prop_array.h | 163 +++ nbsd_include/prop/prop_bool.h | 48 + nbsd_include/prop/prop_data.h | 54 + nbsd_include/prop/prop_dictionary.h | 181 +++ nbsd_include/prop/prop_ingest.h | 90 ++ nbsd_include/prop/prop_number.h | 59 + nbsd_include/prop/prop_object.h | 72 ++ nbsd_include/prop/prop_string.h | 60 + nbsd_include/prop/proplib.h | 50 + tools/nbsd_ports | 1 + 48 files changed, 12256 insertions(+), 2 deletions(-) create mode 100644 common/lib/libprop/Makefile.inc create mode 100644 common/lib/libprop/prop_array.3 create mode 100644 common/lib/libprop/prop_array.c create mode 100644 common/lib/libprop/prop_array_util.3 create mode 100644 common/lib/libprop/prop_array_util.c create mode 100644 common/lib/libprop/prop_bool.3 create mode 100644 common/lib/libprop/prop_bool.c create mode 100644 common/lib/libprop/prop_copyin_ioctl.9 create mode 100644 common/lib/libprop/prop_data.3 create mode 100644 common/lib/libprop/prop_data.c create mode 100644 common/lib/libprop/prop_dictionary.3 create mode 100644 common/lib/libprop/prop_dictionary.c create mode 100644 common/lib/libprop/prop_dictionary_util.3 create mode 100644 common/lib/libprop/prop_dictionary_util.c create mode 100644 common/lib/libprop/prop_ingest.3 create mode 100644 common/lib/libprop/prop_ingest.c create mode 100644 common/lib/libprop/prop_kern.c create mode 100644 common/lib/libprop/prop_number.3 create mode 100644 common/lib/libprop/prop_number.c create mode 100644 common/lib/libprop/prop_object.3 create mode 100644 common/lib/libprop/prop_object.c create mode 100644 common/lib/libprop/prop_object_impl.h create mode 100644 common/lib/libprop/prop_rb.c create mode 100644 common/lib/libprop/prop_rb_impl.h create mode 100644 common/lib/libprop/prop_send_ioctl.3 create mode 100644 common/lib/libprop/prop_send_syscall.3 create mode 100644 common/lib/libprop/prop_stack.c create mode 100644 common/lib/libprop/prop_stack.h create mode 100644 common/lib/libprop/prop_string.3 create mode 100644 common/lib/libprop/prop_string.c create mode 100644 common/lib/libprop/proplib.3 create mode 100644 lib/libprop/Makefile create mode 100644 lib/libprop/shlib_version create mode 100644 nbsd_include/prop/Makefile create mode 100644 nbsd_include/prop/plistref.h create mode 100644 nbsd_include/prop/prop_array.h create mode 100644 nbsd_include/prop/prop_bool.h create mode 100644 nbsd_include/prop/prop_data.h create mode 100644 nbsd_include/prop/prop_dictionary.h create mode 100644 nbsd_include/prop/prop_ingest.h create mode 100644 nbsd_include/prop/prop_number.h create mode 100644 nbsd_include/prop/prop_object.h create mode 100644 nbsd_include/prop/prop_string.h create mode 100644 nbsd_include/prop/proplib.h diff --git a/common/lib/libprop/Makefile.inc b/common/lib/libprop/Makefile.inc new file mode 100644 index 000000000..65685934e --- /dev/null +++ b/common/lib/libprop/Makefile.inc @@ -0,0 +1,9 @@ +# $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 diff --git a/common/lib/libprop/prop_array.3 b/common/lib/libprop/prop_array.3 new file mode 100644 index 000000000..510d62070 --- /dev/null +++ b/common/lib/libprop/prop_array.3 @@ -0,0 +1,308 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_array.c b/common/lib/libprop/prop_array.c new file mode 100644 index 000000000..ecb6a8689 --- /dev/null +++ b/common/lib/libprop/prop_array.c @@ -0,0 +1,911 @@ +/* $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 +#include "prop_object_impl.h" + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#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 ... 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 */ diff --git a/common/lib/libprop/prop_array_util.3 b/common/lib/libprop/prop_array_util.3 new file mode 100644 index 000000000..89323a577 --- /dev/null +++ b/common/lib/libprop/prop_array_util.3 @@ -0,0 +1,228 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_array_util.c b/common/lib/libprop/prop_array_util.c new file mode 100644 index 000000000..8515bd5d3 --- /dev/null +++ b/common/lib/libprop/prop_array_util.c @@ -0,0 +1,251 @@ +/* $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 +#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; +} diff --git a/common/lib/libprop/prop_bool.3 b/common/lib/libprop/prop_bool.3 new file mode 100644 index 000000000..f56382dd7 --- /dev/null +++ b/common/lib/libprop/prop_bool.3 @@ -0,0 +1,82 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_bool.c b/common/lib/libprop/prop_bool.c new file mode 100644 index 000000000..d9e912b2c --- /dev/null +++ b/common/lib/libprop/prop_bool.c @@ -0,0 +1,222 @@ +/* $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 +#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 or 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); +} diff --git a/common/lib/libprop/prop_copyin_ioctl.9 b/common/lib/libprop/prop_copyin_ioctl.9 new file mode 100644 index 000000000..1ea482ca1 --- /dev/null +++ b/common/lib/libprop/prop_copyin_ioctl.9 @@ -0,0 +1,194 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_data.3 b/common/lib/libprop/prop_data.3 new file mode 100644 index 000000000..61acf46da --- /dev/null +++ b/common/lib/libprop/prop_data.3 @@ -0,0 +1,148 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_data.c b/common/lib/libprop/prop_data.c new file mode 100644 index 000000000..5ef9e35e3 --- /dev/null +++ b/common/lib/libprop/prop_data.c @@ -0,0 +1,627 @@ +/* $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 +#include "prop_object_impl.h" + +#if defined(_KERNEL) +#include +#elif defined(_STANDALONE) +#include +#include +#else +#include +#include +#include +#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 ... 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 + * (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); +} diff --git a/common/lib/libprop/prop_dictionary.3 b/common/lib/libprop/prop_dictionary.3 new file mode 100644 index 000000000..82743e34d --- /dev/null +++ b/common/lib/libprop/prop_dictionary.3 @@ -0,0 +1,353 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_dictionary.c b/common/lib/libprop/prop_dictionary.c new file mode 100644 index 000000000..8c2dcea9f --- /dev/null +++ b/common/lib/libprop/prop_dictionary.c @@ -0,0 +1,1420 @@ +/* $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 +#include +#include +#include "prop_object_impl.h" +#include "prop_rb_impl.h" + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#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 ... 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 */ diff --git a/common/lib/libprop/prop_dictionary_util.3 b/common/lib/libprop/prop_dictionary_util.3 new file mode 100644 index 000000000..b262357d9 --- /dev/null +++ b/common/lib/libprop/prop_dictionary_util.3 @@ -0,0 +1,200 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_dictionary_util.c b/common/lib/libprop/prop_dictionary_util.c new file mode 100644 index 000000000..65baf73cc --- /dev/null +++ b/common/lib/libprop/prop_dictionary_util.c @@ -0,0 +1,232 @@ +/* $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 +#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; +} diff --git a/common/lib/libprop/prop_ingest.3 b/common/lib/libprop/prop_ingest.3 new file mode 100644 index 000000000..ae29f22a3 --- /dev/null +++ b/common/lib/libprop/prop_ingest.3 @@ -0,0 +1,181 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_ingest.c b/common/lib/libprop/prop_ingest.c new file mode 100644 index 000000000..823d2c6c7 --- /dev/null +++ b/common/lib/libprop/prop_ingest.c @@ -0,0 +1,159 @@ +/* $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 +#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); +} diff --git a/common/lib/libprop/prop_kern.c b/common/lib/libprop/prop_kern.c new file mode 100644 index 000000000..eeda73336 --- /dev/null +++ b/common/lib/libprop/prop_kern.c @@ -0,0 +1,612 @@ +/* $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 +#include + +#include + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#include +#include +#include +#include + +#ifdef RUMP_ACTION +#include +#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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#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__ */ diff --git a/common/lib/libprop/prop_number.3 b/common/lib/libprop/prop_number.3 new file mode 100644 index 000000000..0b5e9cae8 --- /dev/null +++ b/common/lib/libprop/prop_number.3 @@ -0,0 +1,210 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_number.c b/common/lib/libprop/prop_number.c new file mode 100644 index 000000000..ba61b580f --- /dev/null +++ b/common/lib/libprop/prop_number.c @@ -0,0 +1,592 @@ +/* $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 +#include "prop_object_impl.h" +#include "prop_rb_impl.h" + +#if defined(_KERNEL) +#include +#elif defined(_STANDALONE) +#include +#include +#else +#include +#include +#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 ... 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); +} diff --git a/common/lib/libprop/prop_object.3 b/common/lib/libprop/prop_object.3 new file mode 100644 index 000000000..7df09ea01 --- /dev/null +++ b/common/lib/libprop/prop_object.3 @@ -0,0 +1,141 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_object.c b/common/lib/libprop/prop_object.c new file mode 100644 index 000000000..fd0f14de9 --- /dev/null +++ b/common/lib/libprop/prop_object.c @@ -0,0 +1,1230 @@ +/* $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 +#include "prop_object_impl.h" + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#include +#include +#include +#include +#include +#include +#endif +#include + +#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[] = +"\n" +"\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 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 . + */ + 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(" 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 */ diff --git a/common/lib/libprop/prop_rb_impl.h b/common/lib/libprop/prop_rb_impl.h new file mode 100644 index 000000000..682731fbf --- /dev/null +++ b/common/lib/libprop/prop_rb_impl.h @@ -0,0 +1,154 @@ +/* $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 . + * + * 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 + +/* + * 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 +#include +#include + +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_*/ diff --git a/common/lib/libprop/prop_send_ioctl.3 b/common/lib/libprop/prop_send_ioctl.3 new file mode 100644 index 000000000..22d34d51f --- /dev/null +++ b/common/lib/libprop/prop_send_ioctl.3 @@ -0,0 +1,151 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_send_syscall.3 b/common/lib/libprop/prop_send_syscall.3 new file mode 100644 index 000000000..4150fd2ac --- /dev/null +++ b/common/lib/libprop/prop_send_syscall.3 @@ -0,0 +1,128 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_stack.c b/common/lib/libprop/prop_stack.c new file mode 100644 index 000000000..a08118c2a --- /dev/null +++ b/common/lib/libprop/prop_stack.c @@ -0,0 +1,118 @@ +/* $NetBSD: prop_stack.c,v 1.2 2007/08/30 12:23:54 joerg Exp $ */ + +/*- + * Copyright (c) 2007 Joerg Sonnenberger . + * 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; +} diff --git a/common/lib/libprop/prop_stack.h b/common/lib/libprop/prop_stack.h new file mode 100644 index 000000000..dca99c152 --- /dev/null +++ b/common/lib/libprop/prop_stack.h @@ -0,0 +1,64 @@ +/* $NetBSD: prop_stack.h,v 1.2 2007/08/30 12:23:54 joerg Exp $ */ + +/*- + * Copyright (c) 2007 Joerg Sonnenberger . + * 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 + +#include + +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 diff --git a/common/lib/libprop/prop_string.3 b/common/lib/libprop/prop_string.3 new file mode 100644 index 000000000..4b9607108 --- /dev/null +++ b/common/lib/libprop/prop_string.3 @@ -0,0 +1,193 @@ +.\" $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 . diff --git a/common/lib/libprop/prop_string.c b/common/lib/libprop/prop_string.c new file mode 100644 index 000000000..4f9ed8860 --- /dev/null +++ b/common/lib/libprop/prop_string.c @@ -0,0 +1,471 @@ +/* $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 +#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 ... 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); +} diff --git a/common/lib/libprop/proplib.3 b/common/lib/libprop/proplib.3 new file mode 100644 index 000000000..1d92f8708 --- /dev/null +++ b/common/lib/libprop/proplib.3 @@ -0,0 +1,139 @@ +.\" $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. diff --git a/etc/mtree/minix.tree b/etc/mtree/minix.tree index f8f28a683..329abe152 100644 --- a/etc/mtree/minix.tree +++ b/etc/mtree/minix.tree @@ -61,6 +61,7 @@ 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 diff --git a/lib/Makefile b/lib/Makefile index a4c2127cb..8657b7964 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -24,7 +24,7 @@ SUBDIR= csu ${LIBCOMPAT_DIR} ${LIBC_DIR} libblockdriver libchardriver \ .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" diff --git a/lib/libprop/Makefile b/lib/libprop/Makefile new file mode 100644 index 000000000..0fd3d3f11 --- /dev/null +++ b/lib/libprop/Makefile @@ -0,0 +1,191 @@ +# $NetBSD: Makefile,v 1.19 2011/09/30 22:08:19 jym Exp $ + +.include + +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 diff --git a/lib/libprop/shlib_version b/lib/libprop/shlib_version new file mode 100644 index 000000000..cb5580554 --- /dev/null +++ b/lib/libprop/shlib_version @@ -0,0 +1,4 @@ +# $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 diff --git a/nbsd_include/Makefile b/nbsd_include/Makefile index 085a6d0ad..f5e5e19bb 100644 --- a/nbsd_include/Makefile +++ b/nbsd_include/Makefile @@ -67,7 +67,9 @@ INCSDIR= /usr/include .else SUBDIR= rpc .endif -.if !defined(__MINIX) +.if defined(__MINIX) +SUBDIR+= prop +.else SUBDIR+= ../common/include/prop .endif diff --git a/nbsd_include/prop/Makefile b/nbsd_include/prop/Makefile new file mode 100644 index 000000000..0efa775b8 --- /dev/null +++ b/nbsd_include/prop/Makefile @@ -0,0 +1,9 @@ +# $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 diff --git a/nbsd_include/prop/plistref.h b/nbsd_include/prop/plistref.h new file mode 100644 index 000000000..20755193c --- /dev/null +++ b/nbsd_include/prop/plistref.h @@ -0,0 +1,48 @@ +/* $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 + +/* + * 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_ */ diff --git a/nbsd_include/prop/prop_array.h b/nbsd_include/prop/prop_array.h new file mode 100644 index 000000000..d01a3e0d2 --- /dev/null +++ b/nbsd_include/prop/prop_array.h @@ -0,0 +1,163 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/prop_bool.h b/nbsd_include/prop/prop_bool.h new file mode 100644 index 000000000..f727ff491 --- /dev/null +++ b/nbsd_include/prop/prop_bool.h @@ -0,0 +1,48 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/prop_data.h b/nbsd_include/prop/prop_data.h new file mode 100644 index 000000000..ead37c55f --- /dev/null +++ b/nbsd_include/prop/prop_data.h @@ -0,0 +1,54 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/prop_dictionary.h b/nbsd_include/prop/prop_dictionary.h new file mode 100644 index 000000000..6cfef9fac --- /dev/null +++ b/nbsd_include/prop/prop_dictionary.h @@ -0,0 +1,181 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/prop_ingest.h b/nbsd_include/prop/prop_ingest.h new file mode 100644 index 000000000..f82a57de0 --- /dev/null +++ b/nbsd_include/prop/prop_ingest.h @@ -0,0 +1,90 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/prop_number.h b/nbsd_include/prop/prop_number.h new file mode 100644 index 000000000..a6a2a1491 --- /dev/null +++ b/nbsd_include/prop/prop_number.h @@ -0,0 +1,59 @@ +/* $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 +#endif +#include + +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_ */ diff --git a/nbsd_include/prop/prop_object.h b/nbsd_include/prop/prop_object.h new file mode 100644 index 000000000..e1203339c --- /dev/null +++ b/nbsd_include/prop/prop_object.h @@ -0,0 +1,72 @@ +/* $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 + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#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_ */ diff --git a/nbsd_include/prop/prop_string.h b/nbsd_include/prop/prop_string.h new file mode 100644 index 000000000..eb64e8773 --- /dev/null +++ b/nbsd_include/prop/prop_string.h @@ -0,0 +1,60 @@ +/* $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 + +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_ */ diff --git a/nbsd_include/prop/proplib.h b/nbsd_include/prop/proplib.h new file mode 100644 index 000000000..f136265de --- /dev/null +++ b/nbsd_include/prop/proplib.h @@ -0,0 +1,50 @@ +/* $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 +#include +#include +#include +#include +#include + +#include + +#include + +#ifdef _KERNEL +void prop_kern_init(void); +#endif + +#endif /* _PROPLIB_PROPLIB_H_ */ diff --git a/tools/nbsd_ports b/tools/nbsd_ports index a07753536..b8e43afae 100644 --- a/tools/nbsd_ports +++ b/tools/nbsd_ports @@ -1,3 +1,4 @@ +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 -- 2.44.0