1*0a6a1f1dSLionel Sambuc /* $NetBSD: prop_number.c,v 1.27 2014/09/05 05:19:24 matt Exp $ */
26b6d114aSBen Gras
36b6d114aSBen Gras /*-
46b6d114aSBen Gras * Copyright (c) 2006 The NetBSD Foundation, Inc.
56b6d114aSBen Gras * All rights reserved.
66b6d114aSBen Gras *
76b6d114aSBen Gras * This code is derived from software contributed to The NetBSD Foundation
86b6d114aSBen Gras * by Jason R. Thorpe.
96b6d114aSBen Gras *
106b6d114aSBen Gras * Redistribution and use in source and binary forms, with or without
116b6d114aSBen Gras * modification, are permitted provided that the following conditions
126b6d114aSBen Gras * are met:
136b6d114aSBen Gras * 1. Redistributions of source code must retain the above copyright
146b6d114aSBen Gras * notice, this list of conditions and the following disclaimer.
156b6d114aSBen Gras * 2. Redistributions in binary form must reproduce the above copyright
166b6d114aSBen Gras * notice, this list of conditions and the following disclaimer in the
176b6d114aSBen Gras * documentation and/or other materials provided with the distribution.
186b6d114aSBen Gras *
196b6d114aSBen Gras * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
206b6d114aSBen Gras * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
216b6d114aSBen Gras * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
226b6d114aSBen Gras * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
236b6d114aSBen Gras * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246b6d114aSBen Gras * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
256b6d114aSBen Gras * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
266b6d114aSBen Gras * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
276b6d114aSBen Gras * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
286b6d114aSBen Gras * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
296b6d114aSBen Gras * POSSIBILITY OF SUCH DAMAGE.
306b6d114aSBen Gras */
316b6d114aSBen Gras
326b6d114aSBen Gras #include <prop/prop_number.h>
336b6d114aSBen Gras #include "prop_object_impl.h"
346b6d114aSBen Gras #include "prop_rb_impl.h"
356b6d114aSBen Gras
366b6d114aSBen Gras #if defined(_KERNEL)
376b6d114aSBen Gras #include <sys/systm.h>
386b6d114aSBen Gras #elif defined(_STANDALONE)
396b6d114aSBen Gras #include <sys/param.h>
406b6d114aSBen Gras #include <lib/libkern/libkern.h>
416b6d114aSBen Gras #else
426b6d114aSBen Gras #include <errno.h>
436b6d114aSBen Gras #include <stdlib.h>
446b6d114aSBen Gras #endif
456b6d114aSBen Gras
466b6d114aSBen Gras struct _prop_number_value {
476b6d114aSBen Gras union {
486b6d114aSBen Gras int64_t pnu_signed;
496b6d114aSBen Gras uint64_t pnu_unsigned;
506b6d114aSBen Gras } pnv_un;
516b6d114aSBen Gras #define pnv_signed pnv_un.pnu_signed
526b6d114aSBen Gras #define pnv_unsigned pnv_un.pnu_unsigned
536b6d114aSBen Gras unsigned int pnv_is_unsigned :1,
546b6d114aSBen Gras :31;
55*0a6a1f1dSLionel Sambuc };
56*0a6a1f1dSLionel Sambuc
57*0a6a1f1dSLionel Sambuc struct _prop_number {
58*0a6a1f1dSLionel Sambuc struct _prop_object pn_obj;
59*0a6a1f1dSLionel Sambuc struct rb_node pn_link;
60*0a6a1f1dSLionel Sambuc struct _prop_number_value pn_value;
616b6d114aSBen Gras };
626b6d114aSBen Gras
636b6d114aSBen Gras _PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr")
646b6d114aSBen Gras
656b6d114aSBen Gras static _prop_object_free_rv_t
666b6d114aSBen Gras _prop_number_free(prop_stack_t, prop_object_t *);
676b6d114aSBen Gras static bool _prop_number_externalize(
686b6d114aSBen Gras struct _prop_object_externalize_context *,
696b6d114aSBen Gras void *);
706b6d114aSBen Gras static _prop_object_equals_rv_t
716b6d114aSBen Gras _prop_number_equals(prop_object_t, prop_object_t,
726b6d114aSBen Gras void **, void **,
736b6d114aSBen Gras prop_object_t *, prop_object_t *);
746b6d114aSBen Gras
756b6d114aSBen Gras static void _prop_number_lock(void);
766b6d114aSBen Gras static void _prop_number_unlock(void);
776b6d114aSBen Gras
786b6d114aSBen Gras static const struct _prop_object_type _prop_object_type_number = {
796b6d114aSBen Gras .pot_type = PROP_TYPE_NUMBER,
806b6d114aSBen Gras .pot_free = _prop_number_free,
816b6d114aSBen Gras .pot_extern = _prop_number_externalize,
826b6d114aSBen Gras .pot_equals = _prop_number_equals,
836b6d114aSBen Gras .pot_lock = _prop_number_lock,
846b6d114aSBen Gras .pot_unlock = _prop_number_unlock,
856b6d114aSBen Gras };
866b6d114aSBen Gras
876b6d114aSBen Gras #define prop_object_is_number(x) \
886b6d114aSBen Gras ((x) != NULL && (x)->pn_obj.po_type == &_prop_object_type_number)
896b6d114aSBen Gras
906b6d114aSBen Gras /*
916b6d114aSBen Gras * Number objects are immutable, and we are likely to have many number
926b6d114aSBen Gras * objects that have the same value. So, to save memory, we unique'ify
936b6d114aSBen Gras * numbers so we only have one copy of each.
946b6d114aSBen Gras */
956b6d114aSBen Gras
966b6d114aSBen Gras static int
_prop_number_compare_values(const struct _prop_number_value * pnv1,const struct _prop_number_value * pnv2)976b6d114aSBen Gras _prop_number_compare_values(const struct _prop_number_value *pnv1,
986b6d114aSBen Gras const struct _prop_number_value *pnv2)
996b6d114aSBen Gras {
1006b6d114aSBen Gras
1016b6d114aSBen Gras /* Signed numbers are sorted before unsigned numbers. */
1026b6d114aSBen Gras
1036b6d114aSBen Gras if (pnv1->pnv_is_unsigned) {
1046b6d114aSBen Gras if (! pnv2->pnv_is_unsigned)
1056b6d114aSBen Gras return (1);
1066b6d114aSBen Gras if (pnv1->pnv_unsigned < pnv2->pnv_unsigned)
1076b6d114aSBen Gras return (-1);
1086b6d114aSBen Gras if (pnv1->pnv_unsigned > pnv2->pnv_unsigned)
1096b6d114aSBen Gras return (1);
1106b6d114aSBen Gras return (0);
1116b6d114aSBen Gras }
1126b6d114aSBen Gras
1136b6d114aSBen Gras if (pnv2->pnv_is_unsigned)
1146b6d114aSBen Gras return (-1);
1156b6d114aSBen Gras if (pnv1->pnv_signed < pnv2->pnv_signed)
1166b6d114aSBen Gras return (-1);
1176b6d114aSBen Gras if (pnv1->pnv_signed > pnv2->pnv_signed)
1186b6d114aSBen Gras return (1);
1196b6d114aSBen Gras return (0);
1206b6d114aSBen Gras }
1216b6d114aSBen Gras
1226b6d114aSBen Gras static int
1236b6d114aSBen Gras /*ARGSUSED*/
_prop_number_rb_compare_nodes(void * ctx _PROP_ARG_UNUSED,const void * n1,const void * n2)124f14fb602SLionel Sambuc _prop_number_rb_compare_nodes(void *ctx _PROP_ARG_UNUSED,
1256b6d114aSBen Gras const void *n1, const void *n2)
1266b6d114aSBen Gras {
1276b6d114aSBen Gras const struct _prop_number *pn1 = n1;
1286b6d114aSBen Gras const struct _prop_number *pn2 = n2;
1296b6d114aSBen Gras
1306b6d114aSBen Gras return _prop_number_compare_values(&pn1->pn_value, &pn2->pn_value);
1316b6d114aSBen Gras }
1326b6d114aSBen Gras
1336b6d114aSBen Gras static int
1346b6d114aSBen Gras /*ARGSUSED*/
_prop_number_rb_compare_key(void * ctx _PROP_ARG_UNUSED,const void * n,const void * v)135f14fb602SLionel Sambuc _prop_number_rb_compare_key(void *ctx _PROP_ARG_UNUSED,
136f14fb602SLionel Sambuc const void *n, const void *v)
1376b6d114aSBen Gras {
1386b6d114aSBen Gras const struct _prop_number *pn = n;
1396b6d114aSBen Gras const struct _prop_number_value *pnv = v;
1406b6d114aSBen Gras
1416b6d114aSBen Gras return _prop_number_compare_values(&pn->pn_value, pnv);
1426b6d114aSBen Gras }
1436b6d114aSBen Gras
1446b6d114aSBen Gras static const rb_tree_ops_t _prop_number_rb_tree_ops = {
1456b6d114aSBen Gras .rbto_compare_nodes = _prop_number_rb_compare_nodes,
1466b6d114aSBen Gras .rbto_compare_key = _prop_number_rb_compare_key,
1476b6d114aSBen Gras .rbto_node_offset = offsetof(struct _prop_number, pn_link),
1486b6d114aSBen Gras .rbto_context = NULL
1496b6d114aSBen Gras };
1506b6d114aSBen Gras
1516b6d114aSBen Gras static struct rb_tree _prop_number_tree;
_PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex)1526b6d114aSBen Gras _PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex)
1536b6d114aSBen Gras
1546b6d114aSBen Gras /* ARGSUSED */
1556b6d114aSBen Gras static _prop_object_free_rv_t
1566b6d114aSBen Gras _prop_number_free(prop_stack_t stack, prop_object_t *obj)
1576b6d114aSBen Gras {
1586b6d114aSBen Gras prop_number_t pn = *obj;
1596b6d114aSBen Gras
1606b6d114aSBen Gras _prop_rb_tree_remove_node(&_prop_number_tree, pn);
1616b6d114aSBen Gras
1626b6d114aSBen Gras _PROP_POOL_PUT(_prop_number_pool, pn);
1636b6d114aSBen Gras
1646b6d114aSBen Gras return (_PROP_OBJECT_FREE_DONE);
1656b6d114aSBen Gras }
1666b6d114aSBen Gras
_PROP_ONCE_DECL(_prop_number_init_once)1676b6d114aSBen Gras _PROP_ONCE_DECL(_prop_number_init_once)
1686b6d114aSBen Gras
1696b6d114aSBen Gras static int
1706b6d114aSBen Gras _prop_number_init(void)
1716b6d114aSBen Gras {
1726b6d114aSBen Gras
1736b6d114aSBen Gras _PROP_MUTEX_INIT(_prop_number_tree_mutex);
1746b6d114aSBen Gras _prop_rb_tree_init(&_prop_number_tree, &_prop_number_rb_tree_ops);
1756b6d114aSBen Gras return 0;
1766b6d114aSBen Gras }
1776b6d114aSBen Gras
1786b6d114aSBen Gras static void
_prop_number_lock(void)1796b6d114aSBen Gras _prop_number_lock(void)
1806b6d114aSBen Gras {
1816b6d114aSBen Gras /* XXX: init necessary? */
1826b6d114aSBen Gras _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init);
1836b6d114aSBen Gras _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
1846b6d114aSBen Gras }
1856b6d114aSBen Gras
1866b6d114aSBen Gras static void
_prop_number_unlock(void)1876b6d114aSBen Gras _prop_number_unlock(void)
1886b6d114aSBen Gras {
1896b6d114aSBen Gras _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
1906b6d114aSBen Gras }
1916b6d114aSBen Gras
1926b6d114aSBen Gras static bool
_prop_number_externalize(struct _prop_object_externalize_context * ctx,void * v)1936b6d114aSBen Gras _prop_number_externalize(struct _prop_object_externalize_context *ctx,
1946b6d114aSBen Gras void *v)
1956b6d114aSBen Gras {
1966b6d114aSBen Gras prop_number_t pn = v;
1976b6d114aSBen Gras char tmpstr[32];
1986b6d114aSBen Gras
1996b6d114aSBen Gras /*
2006b6d114aSBen Gras * For unsigned numbers, we output in hex. For signed numbers,
2016b6d114aSBen Gras * we output in decimal.
2026b6d114aSBen Gras */
2036b6d114aSBen Gras if (pn->pn_value.pnv_is_unsigned)
204*0a6a1f1dSLionel Sambuc snprintf(tmpstr, sizeof(tmpstr), "0x%" PRIx64,
205*0a6a1f1dSLionel Sambuc pn->pn_value.pnv_unsigned);
2066b6d114aSBen Gras else
207*0a6a1f1dSLionel Sambuc snprintf(tmpstr, sizeof(tmpstr), "%" PRIi64,
208*0a6a1f1dSLionel Sambuc pn->pn_value.pnv_signed);
2096b6d114aSBen Gras
2106b6d114aSBen Gras if (_prop_object_externalize_start_tag(ctx, "integer") == false ||
2116b6d114aSBen Gras _prop_object_externalize_append_cstring(ctx, tmpstr) == false ||
2126b6d114aSBen Gras _prop_object_externalize_end_tag(ctx, "integer") == false)
2136b6d114aSBen Gras return (false);
2146b6d114aSBen Gras
2156b6d114aSBen Gras return (true);
2166b6d114aSBen Gras }
2176b6d114aSBen Gras
2186b6d114aSBen Gras /* ARGSUSED */
2196b6d114aSBen Gras 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)2206b6d114aSBen Gras _prop_number_equals(prop_object_t v1, prop_object_t v2,
2216b6d114aSBen Gras void **stored_pointer1, void **stored_pointer2,
2226b6d114aSBen Gras prop_object_t *next_obj1, prop_object_t *next_obj2)
2236b6d114aSBen Gras {
2246b6d114aSBen Gras prop_number_t num1 = v1;
2256b6d114aSBen Gras prop_number_t num2 = v2;
2266b6d114aSBen Gras
2276b6d114aSBen Gras /*
2286b6d114aSBen Gras * There is only ever one copy of a number object at any given
2296b6d114aSBen Gras * time, so we can reduce this to a simple pointer equality check
2306b6d114aSBen Gras * in the common case.
2316b6d114aSBen Gras */
2326b6d114aSBen Gras if (num1 == num2)
2336b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_TRUE);
2346b6d114aSBen Gras
2356b6d114aSBen Gras /*
2366b6d114aSBen Gras * If the numbers are the same signed-ness, then we know they
2376b6d114aSBen Gras * cannot be equal because they would have had pointer equality.
2386b6d114aSBen Gras */
2396b6d114aSBen Gras if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned)
2406b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_FALSE);
2416b6d114aSBen Gras
2426b6d114aSBen Gras /*
2436b6d114aSBen Gras * We now have one signed value and one unsigned value. We can
2446b6d114aSBen Gras * compare them iff:
2456b6d114aSBen Gras * - The unsigned value is not larger than the signed value
2466b6d114aSBen Gras * can represent.
2476b6d114aSBen Gras * - The signed value is not smaller than the unsigned value
2486b6d114aSBen Gras * can represent.
2496b6d114aSBen Gras */
2506b6d114aSBen Gras if (num1->pn_value.pnv_is_unsigned) {
2516b6d114aSBen Gras /*
2526b6d114aSBen Gras * num1 is unsigned and num2 is signed.
2536b6d114aSBen Gras */
2546b6d114aSBen Gras if (num1->pn_value.pnv_unsigned > INT64_MAX)
2556b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_FALSE);
2566b6d114aSBen Gras if (num2->pn_value.pnv_signed < 0)
2576b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_FALSE);
2586b6d114aSBen Gras } else {
2596b6d114aSBen Gras /*
2606b6d114aSBen Gras * num1 is signed and num2 is unsigned.
2616b6d114aSBen Gras */
2626b6d114aSBen Gras if (num1->pn_value.pnv_signed < 0)
2636b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_FALSE);
2646b6d114aSBen Gras if (num2->pn_value.pnv_unsigned > INT64_MAX)
2656b6d114aSBen Gras return (_PROP_OBJECT_EQUALS_FALSE);
2666b6d114aSBen Gras }
2676b6d114aSBen Gras
2686b6d114aSBen Gras if (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed)
2696b6d114aSBen Gras return _PROP_OBJECT_EQUALS_TRUE;
2706b6d114aSBen Gras else
2716b6d114aSBen Gras return _PROP_OBJECT_EQUALS_FALSE;
2726b6d114aSBen Gras }
2736b6d114aSBen Gras
2746b6d114aSBen Gras static prop_number_t
_prop_number_alloc(const struct _prop_number_value * pnv)2756b6d114aSBen Gras _prop_number_alloc(const struct _prop_number_value *pnv)
2766b6d114aSBen Gras {
2776b6d114aSBen Gras prop_number_t opn, pn, rpn;
2786b6d114aSBen Gras
2796b6d114aSBen Gras _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init);
2806b6d114aSBen Gras
2816b6d114aSBen Gras /*
2826b6d114aSBen Gras * Check to see if this already exists in the tree. If it does,
2836b6d114aSBen Gras * we just retain it and return it.
2846b6d114aSBen Gras */
2856b6d114aSBen Gras _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
2866b6d114aSBen Gras opn = _prop_rb_tree_find(&_prop_number_tree, pnv);
2876b6d114aSBen Gras if (opn != NULL) {
2886b6d114aSBen Gras prop_object_retain(opn);
2896b6d114aSBen Gras _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
2906b6d114aSBen Gras return (opn);
2916b6d114aSBen Gras }
2926b6d114aSBen Gras _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
2936b6d114aSBen Gras
2946b6d114aSBen Gras /*
2956b6d114aSBen Gras * Not in the tree. Create it now.
2966b6d114aSBen Gras */
2976b6d114aSBen Gras
2986b6d114aSBen Gras pn = _PROP_POOL_GET(_prop_number_pool);
2996b6d114aSBen Gras if (pn == NULL)
3006b6d114aSBen Gras return (NULL);
3016b6d114aSBen Gras
3026b6d114aSBen Gras _prop_object_init(&pn->pn_obj, &_prop_object_type_number);
3036b6d114aSBen Gras
3046b6d114aSBen Gras pn->pn_value = *pnv;
3056b6d114aSBen Gras
3066b6d114aSBen Gras /*
3076b6d114aSBen Gras * We dropped the mutex when we allocated the new object, so
3086b6d114aSBen Gras * we have to check again if it is in the tree.
3096b6d114aSBen Gras */
3106b6d114aSBen Gras _PROP_MUTEX_LOCK(_prop_number_tree_mutex);
3116b6d114aSBen Gras opn = _prop_rb_tree_find(&_prop_number_tree, pnv);
3126b6d114aSBen Gras if (opn != NULL) {
3136b6d114aSBen Gras prop_object_retain(opn);
3146b6d114aSBen Gras _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
3156b6d114aSBen Gras _PROP_POOL_PUT(_prop_number_pool, pn);
3166b6d114aSBen Gras return (opn);
3176b6d114aSBen Gras }
3186b6d114aSBen Gras rpn = _prop_rb_tree_insert_node(&_prop_number_tree, pn);
3196b6d114aSBen Gras _PROP_ASSERT(rpn == pn);
3206b6d114aSBen Gras _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
32184d9c625SLionel Sambuc return (rpn);
3226b6d114aSBen Gras }
3236b6d114aSBen Gras
3246b6d114aSBen Gras /*
3256b6d114aSBen Gras * prop_number_create_integer --
3266b6d114aSBen Gras * Create a prop_number_t and initialize it with the
3276b6d114aSBen Gras * provided integer value.
3286b6d114aSBen Gras */
3296b6d114aSBen Gras prop_number_t
prop_number_create_integer(int64_t val)3306b6d114aSBen Gras prop_number_create_integer(int64_t val)
3316b6d114aSBen Gras {
3326b6d114aSBen Gras struct _prop_number_value pnv;
3336b6d114aSBen Gras
3346b6d114aSBen Gras memset(&pnv, 0, sizeof(pnv));
3356b6d114aSBen Gras pnv.pnv_signed = val;
3366b6d114aSBen Gras pnv.pnv_is_unsigned = false;
3376b6d114aSBen Gras
3386b6d114aSBen Gras return (_prop_number_alloc(&pnv));
3396b6d114aSBen Gras }
3406b6d114aSBen Gras
3416b6d114aSBen Gras /*
3426b6d114aSBen Gras * prop_number_create_unsigned_integer --
3436b6d114aSBen Gras * Create a prop_number_t and initialize it with the
3446b6d114aSBen Gras * provided unsigned integer value.
3456b6d114aSBen Gras */
3466b6d114aSBen Gras prop_number_t
prop_number_create_unsigned_integer(uint64_t val)3476b6d114aSBen Gras prop_number_create_unsigned_integer(uint64_t val)
3486b6d114aSBen Gras {
3496b6d114aSBen Gras struct _prop_number_value pnv;
3506b6d114aSBen Gras
3516b6d114aSBen Gras memset(&pnv, 0, sizeof(pnv));
3526b6d114aSBen Gras pnv.pnv_unsigned = val;
3536b6d114aSBen Gras pnv.pnv_is_unsigned = true;
3546b6d114aSBen Gras
3556b6d114aSBen Gras return (_prop_number_alloc(&pnv));
3566b6d114aSBen Gras }
3576b6d114aSBen Gras
3586b6d114aSBen Gras /*
3596b6d114aSBen Gras * prop_number_copy --
3606b6d114aSBen Gras * Copy a prop_number_t.
3616b6d114aSBen Gras */
3626b6d114aSBen Gras prop_number_t
prop_number_copy(prop_number_t opn)3636b6d114aSBen Gras prop_number_copy(prop_number_t opn)
3646b6d114aSBen Gras {
3656b6d114aSBen Gras
3666b6d114aSBen Gras if (! prop_object_is_number(opn))
3676b6d114aSBen Gras return (NULL);
3686b6d114aSBen Gras
3696b6d114aSBen Gras /*
3706b6d114aSBen Gras * Because we only ever allocate one object for any given
3716b6d114aSBen Gras * value, this can be reduced to a simple retain operation.
3726b6d114aSBen Gras */
3736b6d114aSBen Gras prop_object_retain(opn);
3746b6d114aSBen Gras return (opn);
3756b6d114aSBen Gras }
3766b6d114aSBen Gras
3776b6d114aSBen Gras /*
3786b6d114aSBen Gras * prop_number_unsigned --
3796b6d114aSBen Gras * Returns true if the prop_number_t has an unsigned value.
3806b6d114aSBen Gras */
3816b6d114aSBen Gras bool
prop_number_unsigned(prop_number_t pn)3826b6d114aSBen Gras prop_number_unsigned(prop_number_t pn)
3836b6d114aSBen Gras {
3846b6d114aSBen Gras
3856b6d114aSBen Gras return (pn->pn_value.pnv_is_unsigned);
3866b6d114aSBen Gras }
3876b6d114aSBen Gras
3886b6d114aSBen Gras /*
3896b6d114aSBen Gras * prop_number_size --
3906b6d114aSBen Gras * Return the size, in bits, required to hold the value of
3916b6d114aSBen Gras * the specified number.
3926b6d114aSBen Gras */
3936b6d114aSBen Gras int
prop_number_size(prop_number_t pn)3946b6d114aSBen Gras prop_number_size(prop_number_t pn)
3956b6d114aSBen Gras {
3966b6d114aSBen Gras struct _prop_number_value *pnv;
3976b6d114aSBen Gras
3986b6d114aSBen Gras if (! prop_object_is_number(pn))
3996b6d114aSBen Gras return (0);
4006b6d114aSBen Gras
4016b6d114aSBen Gras pnv = &pn->pn_value;
4026b6d114aSBen Gras
4036b6d114aSBen Gras if (pnv->pnv_is_unsigned) {
4046b6d114aSBen Gras if (pnv->pnv_unsigned > UINT32_MAX)
4056b6d114aSBen Gras return (64);
4066b6d114aSBen Gras if (pnv->pnv_unsigned > UINT16_MAX)
4076b6d114aSBen Gras return (32);
4086b6d114aSBen Gras if (pnv->pnv_unsigned > UINT8_MAX)
4096b6d114aSBen Gras return (16);
4106b6d114aSBen Gras return (8);
4116b6d114aSBen Gras }
4126b6d114aSBen Gras
4136b6d114aSBen Gras if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN)
4146b6d114aSBen Gras return (64);
4156b6d114aSBen Gras if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN)
4166b6d114aSBen Gras return (32);
4176b6d114aSBen Gras if (pnv->pnv_signed > INT8_MAX || pnv->pnv_signed < INT8_MIN)
4186b6d114aSBen Gras return (16);
4196b6d114aSBen Gras return (8);
4206b6d114aSBen Gras }
4216b6d114aSBen Gras
4226b6d114aSBen Gras /*
4236b6d114aSBen Gras * prop_number_integer_value --
4246b6d114aSBen Gras * Get the integer value of a prop_number_t.
4256b6d114aSBen Gras */
4266b6d114aSBen Gras int64_t
prop_number_integer_value(prop_number_t pn)4276b6d114aSBen Gras prop_number_integer_value(prop_number_t pn)
4286b6d114aSBen Gras {
4296b6d114aSBen Gras
4306b6d114aSBen Gras /*
4316b6d114aSBen Gras * XXX Impossible to distinguish between "not a prop_number_t"
4326b6d114aSBen Gras * XXX and "prop_number_t has a value of 0".
4336b6d114aSBen Gras */
4346b6d114aSBen Gras if (! prop_object_is_number(pn))
4356b6d114aSBen Gras return (0);
4366b6d114aSBen Gras
4376b6d114aSBen Gras return (pn->pn_value.pnv_signed);
4386b6d114aSBen Gras }
4396b6d114aSBen Gras
4406b6d114aSBen Gras /*
4416b6d114aSBen Gras * prop_number_unsigned_integer_value --
4426b6d114aSBen Gras * Get the unsigned integer value of a prop_number_t.
4436b6d114aSBen Gras */
4446b6d114aSBen Gras uint64_t
prop_number_unsigned_integer_value(prop_number_t pn)4456b6d114aSBen Gras prop_number_unsigned_integer_value(prop_number_t pn)
4466b6d114aSBen Gras {
4476b6d114aSBen Gras
4486b6d114aSBen Gras /*
4496b6d114aSBen Gras * XXX Impossible to distinguish between "not a prop_number_t"
4506b6d114aSBen Gras * XXX and "prop_number_t has a value of 0".
4516b6d114aSBen Gras */
4526b6d114aSBen Gras if (! prop_object_is_number(pn))
4536b6d114aSBen Gras return (0);
4546b6d114aSBen Gras
4556b6d114aSBen Gras return (pn->pn_value.pnv_unsigned);
4566b6d114aSBen Gras }
4576b6d114aSBen Gras
4586b6d114aSBen Gras /*
4596b6d114aSBen Gras * prop_number_equals --
4606b6d114aSBen Gras * Return true if two numbers are equivalent.
4616b6d114aSBen Gras */
4626b6d114aSBen Gras bool
prop_number_equals(prop_number_t num1,prop_number_t num2)4636b6d114aSBen Gras prop_number_equals(prop_number_t num1, prop_number_t num2)
4646b6d114aSBen Gras {
4656b6d114aSBen Gras if (!prop_object_is_number(num1) || !prop_object_is_number(num2))
4666b6d114aSBen Gras return (false);
4676b6d114aSBen Gras
4686b6d114aSBen Gras return (prop_object_equals(num1, num2));
4696b6d114aSBen Gras }
4706b6d114aSBen Gras
4716b6d114aSBen Gras /*
4726b6d114aSBen Gras * prop_number_equals_integer --
4736b6d114aSBen Gras * Return true if the number is equivalent to the specified integer.
4746b6d114aSBen Gras */
4756b6d114aSBen Gras bool
prop_number_equals_integer(prop_number_t pn,int64_t val)4766b6d114aSBen Gras prop_number_equals_integer(prop_number_t pn, int64_t val)
4776b6d114aSBen Gras {
4786b6d114aSBen Gras
4796b6d114aSBen Gras if (! prop_object_is_number(pn))
4806b6d114aSBen Gras return (false);
4816b6d114aSBen Gras
4826b6d114aSBen Gras if (pn->pn_value.pnv_is_unsigned &&
4836b6d114aSBen Gras (pn->pn_value.pnv_unsigned > INT64_MAX || val < 0))
4846b6d114aSBen Gras return (false);
4856b6d114aSBen Gras
4866b6d114aSBen Gras return (pn->pn_value.pnv_signed == val);
4876b6d114aSBen Gras }
4886b6d114aSBen Gras
4896b6d114aSBen Gras /*
4906b6d114aSBen Gras * prop_number_equals_unsigned_integer --
4916b6d114aSBen Gras * Return true if the number is equivalent to the specified
4926b6d114aSBen Gras * unsigned integer.
4936b6d114aSBen Gras */
4946b6d114aSBen Gras bool
prop_number_equals_unsigned_integer(prop_number_t pn,uint64_t val)4956b6d114aSBen Gras prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val)
4966b6d114aSBen Gras {
4976b6d114aSBen Gras
4986b6d114aSBen Gras if (! prop_object_is_number(pn))
4996b6d114aSBen Gras return (false);
5006b6d114aSBen Gras
5016b6d114aSBen Gras if (! pn->pn_value.pnv_is_unsigned &&
5026b6d114aSBen Gras (pn->pn_value.pnv_signed < 0 || val > INT64_MAX))
5036b6d114aSBen Gras return (false);
5046b6d114aSBen Gras
5056b6d114aSBen Gras return (pn->pn_value.pnv_unsigned == val);
5066b6d114aSBen Gras }
5076b6d114aSBen Gras
5086b6d114aSBen Gras static bool
_prop_number_internalize_unsigned(struct _prop_object_internalize_context * ctx,struct _prop_number_value * pnv)5096b6d114aSBen Gras _prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
5106b6d114aSBen Gras struct _prop_number_value *pnv)
5116b6d114aSBen Gras {
5126b6d114aSBen Gras char *cp;
5136b6d114aSBen Gras
5146b6d114aSBen Gras _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) ==
5156b6d114aSBen Gras sizeof(uint64_t));
5166b6d114aSBen Gras
5176b6d114aSBen Gras #ifndef _KERNEL
5186b6d114aSBen Gras errno = 0;
5196b6d114aSBen Gras #endif
5206b6d114aSBen Gras pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
5216b6d114aSBen Gras #ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
5226b6d114aSBen Gras if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
5236b6d114aSBen Gras return (false);
5246b6d114aSBen Gras #endif
5256b6d114aSBen Gras pnv->pnv_is_unsigned = true;
5266b6d114aSBen Gras ctx->poic_cp = cp;
5276b6d114aSBen Gras
5286b6d114aSBen Gras return (true);
5296b6d114aSBen Gras }
5306b6d114aSBen Gras
5316b6d114aSBen Gras static bool
_prop_number_internalize_signed(struct _prop_object_internalize_context * ctx,struct _prop_number_value * pnv)5326b6d114aSBen Gras _prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
5336b6d114aSBen Gras struct _prop_number_value *pnv)
5346b6d114aSBen Gras {
5356b6d114aSBen Gras char *cp;
5366b6d114aSBen Gras
5376b6d114aSBen Gras _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t));
5386b6d114aSBen Gras
5396b6d114aSBen Gras #ifndef _KERNEL
5406b6d114aSBen Gras errno = 0;
5416b6d114aSBen Gras #endif
5426b6d114aSBen Gras pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
5436b6d114aSBen Gras #ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */
5446b6d114aSBen Gras if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
5456b6d114aSBen Gras errno == ERANGE)
5466b6d114aSBen Gras return (false);
5476b6d114aSBen Gras #endif
5486b6d114aSBen Gras pnv->pnv_is_unsigned = false;
5496b6d114aSBen Gras ctx->poic_cp = cp;
5506b6d114aSBen Gras
5516b6d114aSBen Gras return (true);
5526b6d114aSBen Gras }
5536b6d114aSBen Gras
5546b6d114aSBen Gras /*
5556b6d114aSBen Gras * _prop_number_internalize --
5566b6d114aSBen Gras * Parse a <number>...</number> and return the object created from
5576b6d114aSBen Gras * the external representation.
5586b6d114aSBen Gras */
5596b6d114aSBen Gras /* ARGSUSED */
5606b6d114aSBen Gras bool
_prop_number_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)5616b6d114aSBen Gras _prop_number_internalize(prop_stack_t stack, prop_object_t *obj,
5626b6d114aSBen Gras struct _prop_object_internalize_context *ctx)
5636b6d114aSBen Gras {
5646b6d114aSBen Gras struct _prop_number_value pnv;
5656b6d114aSBen Gras
5666b6d114aSBen Gras memset(&pnv, 0, sizeof(pnv));
5676b6d114aSBen Gras
5686b6d114aSBen Gras /* No attributes, no empty elements. */
5696b6d114aSBen Gras if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
5706b6d114aSBen Gras return (true);
5716b6d114aSBen Gras
5726b6d114aSBen Gras /*
5736b6d114aSBen Gras * If the first character is '-', then we treat as signed.
5746b6d114aSBen Gras * If the first two characters are "0x" (i.e. the number is
5756b6d114aSBen Gras * in hex), then we treat as unsigned. Otherwise, we try
5766b6d114aSBen Gras * signed first, and if that fails (presumably due to ERANGE),
5776b6d114aSBen Gras * then we switch to unsigned.
5786b6d114aSBen Gras */
5796b6d114aSBen Gras if (ctx->poic_cp[0] == '-') {
5806b6d114aSBen Gras if (_prop_number_internalize_signed(ctx, &pnv) == false)
5816b6d114aSBen Gras return (true);
5826b6d114aSBen Gras } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
5836b6d114aSBen Gras if (_prop_number_internalize_unsigned(ctx, &pnv) == false)
5846b6d114aSBen Gras return (true);
5856b6d114aSBen Gras } else {
5866b6d114aSBen Gras if (_prop_number_internalize_signed(ctx, &pnv) == false &&
5876b6d114aSBen Gras _prop_number_internalize_unsigned(ctx, &pnv) == false)
5886b6d114aSBen Gras return (true);
5896b6d114aSBen Gras }
5906b6d114aSBen Gras
5916b6d114aSBen Gras if (_prop_object_internalize_find_tag(ctx, "integer",
5926b6d114aSBen Gras _PROP_TAG_TYPE_END) == false)
5936b6d114aSBen Gras return (true);
5946b6d114aSBen Gras
5956b6d114aSBen Gras *obj = _prop_number_alloc(&pnv);
5966b6d114aSBen Gras return (true);
5976b6d114aSBen Gras }
598