Home | History | Annotate | Line # | Download | only in libprop
prop_number.c revision 1.11.4.1.2.1
      1  1.11.4.1.2.1      snj /*	$NetBSD: prop_number.c,v 1.11.4.1.2.1 2008/11/30 23:53:04 snj Exp $	*/
      2           1.1  thorpej 
      3           1.1  thorpej /*-
      4           1.1  thorpej  * Copyright (c) 2006 The NetBSD Foundation, Inc.
      5           1.1  thorpej  * All rights reserved.
      6           1.1  thorpej  *
      7           1.1  thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8           1.1  thorpej  * by Jason R. Thorpe.
      9           1.1  thorpej  *
     10           1.1  thorpej  * Redistribution and use in source and binary forms, with or without
     11           1.1  thorpej  * modification, are permitted provided that the following conditions
     12           1.1  thorpej  * are met:
     13           1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     14           1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     15           1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16           1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     17           1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     18           1.1  thorpej  * 3. All advertising materials mentioning features or use of this software
     19           1.1  thorpej  *    must display the following acknowledgement:
     20           1.1  thorpej  *      This product includes software developed by the NetBSD
     21           1.1  thorpej  *      Foundation, Inc. and its contributors.
     22           1.1  thorpej  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23           1.1  thorpej  *    contributors may be used to endorse or promote products derived
     24           1.1  thorpej  *    from this software without specific prior written permission.
     25           1.1  thorpej  *
     26           1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27           1.1  thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28           1.1  thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29           1.1  thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30           1.1  thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31           1.1  thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32           1.1  thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33           1.1  thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34           1.1  thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35           1.1  thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36           1.1  thorpej  * POSSIBILITY OF SUCH DAMAGE.
     37           1.1  thorpej  */
     38           1.1  thorpej 
     39           1.1  thorpej #include <prop/prop_number.h>
     40           1.1  thorpej #include "prop_object_impl.h"
     41           1.6  thorpej #include "prop_rb_impl.h"
     42           1.1  thorpej 
     43           1.1  thorpej #if defined(_KERNEL)
     44           1.1  thorpej #include <sys/systm.h>
     45           1.1  thorpej #elif defined(_STANDALONE)
     46           1.1  thorpej #include <sys/param.h>
     47           1.1  thorpej #include <lib/libkern/libkern.h>
     48           1.1  thorpej #else
     49           1.1  thorpej #include <errno.h>
     50           1.1  thorpej #include <stdlib.h>
     51           1.1  thorpej #endif
     52           1.1  thorpej 
     53           1.1  thorpej struct _prop_number {
     54           1.1  thorpej 	struct _prop_object	pn_obj;
     55           1.6  thorpej 	struct rb_node		pn_link;
     56           1.8  thorpej 	struct _prop_number_value {
     57           1.8  thorpej 		union {
     58           1.8  thorpej 			int64_t  pnu_signed;
     59           1.8  thorpej 			uint64_t pnu_unsigned;
     60           1.8  thorpej 		} pnv_un;
     61           1.8  thorpej #define	pnv_signed	pnv_un.pnu_signed
     62           1.8  thorpej #define	pnv_unsigned	pnv_un.pnu_unsigned
     63           1.8  thorpej 		unsigned int	pnv_is_unsigned	:1,
     64           1.8  thorpej 						:31;
     65           1.8  thorpej 	} pn_value;
     66           1.1  thorpej };
     67           1.1  thorpej 
     68           1.6  thorpej #define	RBNODE_TO_PN(n)							\
     69           1.6  thorpej 	((struct _prop_number *)					\
     70           1.6  thorpej 	 ((uintptr_t)n - offsetof(struct _prop_number, pn_link)))
     71           1.6  thorpej 
     72           1.1  thorpej _PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr")
     73           1.1  thorpej 
     74      1.11.4.1  xtraeme static int		_prop_number_free(prop_stack_t, prop_object_t *);
     75      1.11.4.1  xtraeme static bool	_prop_number_externalize(
     76           1.2  thorpej 				struct _prop_object_externalize_context *,
     77           1.2  thorpej 				void *);
     78      1.11.4.1  xtraeme static bool	_prop_number_equals(prop_object_t, prop_object_t,
     79      1.11.4.1  xtraeme 				    void **, void **,
     80      1.11.4.1  xtraeme 				    prop_object_t *, prop_object_t *);
     81           1.2  thorpej 
     82  1.11.4.1.2.1      snj static void _prop_number_lock(void);
     83  1.11.4.1.2.1      snj static void _prop_number_unlock(void);
     84  1.11.4.1.2.1      snj 
     85           1.2  thorpej static const struct _prop_object_type _prop_object_type_number = {
     86           1.2  thorpej 	.pot_type	=	PROP_TYPE_NUMBER,
     87           1.2  thorpej 	.pot_free	=	_prop_number_free,
     88           1.2  thorpej 	.pot_extern	=	_prop_number_externalize,
     89           1.2  thorpej 	.pot_equals	=	_prop_number_equals,
     90  1.11.4.1.2.1      snj 	.pot_lock       =       _prop_number_lock,
     91  1.11.4.1.2.1      snj 	.pot_unlock     =    	_prop_number_unlock,
     92           1.2  thorpej };
     93           1.2  thorpej 
     94           1.2  thorpej #define	prop_object_is_number(x)	\
     95           1.5  thorpej 	((x) != NULL && (x)->pn_obj.po_type == &_prop_object_type_number)
     96           1.1  thorpej 
     97           1.6  thorpej /*
     98           1.6  thorpej  * Number objects are immutable, and we are likely to have many number
     99           1.6  thorpej  * objects that have the same value.  So, to save memory, we unique'ify
    100           1.6  thorpej  * numbers so we only have one copy of each.
    101           1.6  thorpej  */
    102           1.6  thorpej 
    103           1.6  thorpej static int
    104           1.8  thorpej _prop_number_compare_values(const struct _prop_number_value *pnv1,
    105           1.8  thorpej 			    const struct _prop_number_value *pnv2)
    106           1.8  thorpej {
    107           1.8  thorpej 
    108           1.8  thorpej 	/* Signed numbers are sorted before unsigned numbers. */
    109           1.8  thorpej 
    110           1.8  thorpej 	if (pnv1->pnv_is_unsigned) {
    111           1.8  thorpej 		if (! pnv2->pnv_is_unsigned)
    112           1.8  thorpej 			return (1);
    113           1.8  thorpej 		if (pnv1->pnv_unsigned < pnv2->pnv_unsigned)
    114           1.8  thorpej 			return (-1);
    115           1.8  thorpej 		if (pnv1->pnv_unsigned > pnv2->pnv_unsigned)
    116           1.8  thorpej 			return (1);
    117           1.8  thorpej 		return (0);
    118           1.8  thorpej 	}
    119           1.8  thorpej 
    120           1.8  thorpej 	if (pnv2->pnv_is_unsigned)
    121           1.8  thorpej 		return (-1);
    122           1.8  thorpej 	if (pnv1->pnv_signed < pnv2->pnv_signed)
    123           1.8  thorpej 		return (-1);
    124           1.8  thorpej 	if (pnv1->pnv_signed > pnv2->pnv_signed)
    125           1.8  thorpej 		return (1);
    126           1.8  thorpej 	return (0);
    127           1.8  thorpej }
    128           1.8  thorpej 
    129           1.8  thorpej static int
    130           1.6  thorpej _prop_number_rb_compare_nodes(const struct rb_node *n1,
    131           1.6  thorpej 			      const struct rb_node *n2)
    132           1.6  thorpej {
    133           1.6  thorpej 	const prop_number_t pn1 = RBNODE_TO_PN(n1);
    134           1.6  thorpej 	const prop_number_t pn2 = RBNODE_TO_PN(n2);
    135           1.6  thorpej 
    136           1.8  thorpej 	return (_prop_number_compare_values(&pn1->pn_value, &pn2->pn_value));
    137           1.6  thorpej }
    138           1.6  thorpej 
    139           1.6  thorpej static int
    140           1.6  thorpej _prop_number_rb_compare_key(const struct rb_node *n,
    141           1.6  thorpej 			    const void *v)
    142           1.6  thorpej {
    143           1.6  thorpej 	const prop_number_t pn = RBNODE_TO_PN(n);
    144           1.8  thorpej 	const struct _prop_number_value *pnv = v;
    145           1.6  thorpej 
    146           1.8  thorpej 	return (_prop_number_compare_values(&pn->pn_value, pnv));
    147           1.6  thorpej }
    148           1.6  thorpej 
    149           1.6  thorpej static const struct rb_tree_ops _prop_number_rb_tree_ops = {
    150           1.6  thorpej 	.rbto_compare_nodes = _prop_number_rb_compare_nodes,
    151           1.6  thorpej 	.rbto_compare_key   = _prop_number_rb_compare_key,
    152           1.6  thorpej };
    153           1.6  thorpej 
    154           1.6  thorpej static struct rb_tree _prop_number_tree;
    155      1.11.4.1  xtraeme static bool _prop_number_tree_initialized;
    156           1.6  thorpej 
    157           1.7  thorpej _PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex)
    158           1.6  thorpej 
    159      1.11.4.1  xtraeme /* ARGSUSED */
    160      1.11.4.1  xtraeme static int
    161      1.11.4.1  xtraeme _prop_number_free(prop_stack_t stack, prop_object_t *obj)
    162           1.1  thorpej {
    163      1.11.4.1  xtraeme 	prop_number_t pn = *obj;
    164           1.6  thorpej 
    165           1.6  thorpej 	_prop_rb_tree_remove_node(&_prop_number_tree, &pn->pn_link);
    166           1.1  thorpej 
    167           1.6  thorpej 	_PROP_POOL_PUT(_prop_number_pool, pn);
    168      1.11.4.1  xtraeme 
    169      1.11.4.1  xtraeme 	return (_PROP_OBJECT_FREE_DONE);
    170           1.1  thorpej }
    171           1.1  thorpej 
    172  1.11.4.1.2.1      snj static void
    173  1.11.4.1.2.1      snj _prop_number_lock()
    174  1.11.4.1.2.1      snj {
    175  1.11.4.1.2.1      snj 	_PROP_MUTEX_LOCK(_prop_number_tree_mutex);
    176  1.11.4.1.2.1      snj }
    177  1.11.4.1.2.1      snj 
    178  1.11.4.1.2.1      snj static void
    179  1.11.4.1.2.1      snj _prop_number_unlock()
    180  1.11.4.1.2.1      snj {
    181  1.11.4.1.2.1      snj 	_PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
    182  1.11.4.1.2.1      snj }
    183  1.11.4.1.2.1      snj 
    184      1.11.4.1  xtraeme static bool
    185           1.1  thorpej _prop_number_externalize(struct _prop_object_externalize_context *ctx,
    186           1.1  thorpej 			 void *v)
    187           1.1  thorpej {
    188           1.1  thorpej 	prop_number_t pn = v;
    189           1.1  thorpej 	char tmpstr[32];
    190           1.1  thorpej 
    191           1.8  thorpej 	/*
    192           1.8  thorpej 	 * For unsigned numbers, we output in hex.  For signed numbers,
    193           1.8  thorpej 	 * we output in decimal.
    194           1.8  thorpej 	 */
    195           1.8  thorpej 	if (pn->pn_value.pnv_is_unsigned)
    196           1.8  thorpej 		sprintf(tmpstr, "0x%" PRIx64, pn->pn_value.pnv_unsigned);
    197           1.8  thorpej 	else
    198           1.8  thorpej 		sprintf(tmpstr, "%" PRIi64, pn->pn_value.pnv_signed);
    199           1.1  thorpej 
    200      1.11.4.1  xtraeme 	if (_prop_object_externalize_start_tag(ctx, "integer") == false ||
    201      1.11.4.1  xtraeme 	    _prop_object_externalize_append_cstring(ctx, tmpstr) == false ||
    202      1.11.4.1  xtraeme 	    _prop_object_externalize_end_tag(ctx, "integer") == false)
    203      1.11.4.1  xtraeme 		return (false);
    204           1.1  thorpej 
    205      1.11.4.1  xtraeme 	return (true);
    206           1.1  thorpej }
    207           1.1  thorpej 
    208      1.11.4.1  xtraeme /* ARGSUSED */
    209      1.11.4.1  xtraeme static bool
    210      1.11.4.1  xtraeme _prop_number_equals(prop_object_t v1, prop_object_t v2,
    211      1.11.4.1  xtraeme     void **stored_pointer1, void **stored_pointer2,
    212      1.11.4.1  xtraeme     prop_object_t *next_obj1, prop_object_t *next_obj2)
    213           1.2  thorpej {
    214           1.2  thorpej 	prop_number_t num1 = v1;
    215           1.2  thorpej 	prop_number_t num2 = v2;
    216           1.2  thorpej 
    217           1.6  thorpej 	/*
    218           1.6  thorpej 	 * There is only ever one copy of a number object at any given
    219           1.8  thorpej 	 * time, so we can reduce this to a simple pointer equality check
    220           1.8  thorpej 	 * in the common case.
    221           1.8  thorpej 	 */
    222           1.8  thorpej 	if (num1 == num2)
    223      1.11.4.1  xtraeme 		return (_PROP_OBJECT_EQUALS_TRUE);
    224           1.8  thorpej 
    225           1.8  thorpej 	/*
    226           1.8  thorpej 	 * If the numbers are the same signed-ness, then we know they
    227           1.8  thorpej 	 * cannot be equal because they would have had pointer equality.
    228           1.6  thorpej 	 */
    229           1.8  thorpej 	if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned)
    230      1.11.4.1  xtraeme 		return (_PROP_OBJECT_EQUALS_TRUE);
    231           1.8  thorpej 
    232           1.8  thorpej 	/*
    233           1.8  thorpej 	 * We now have one signed value and one unsigned value.  We can
    234           1.8  thorpej 	 * compare them iff:
    235           1.8  thorpej 	 *	- The unsigned value is not larger than the signed value
    236           1.8  thorpej 	 *	  can represent.
    237           1.8  thorpej 	 *	- The signed value is not smaller than the unsigned value
    238           1.8  thorpej 	 *	  can represent.
    239           1.8  thorpej 	 */
    240           1.8  thorpej 	if (num1->pn_value.pnv_is_unsigned) {
    241           1.8  thorpej 		/*
    242           1.8  thorpej 		 * num1 is unsigned and num2 is signed.
    243           1.8  thorpej 		 */
    244           1.8  thorpej 		if (num1->pn_value.pnv_unsigned > INT64_MAX)
    245      1.11.4.1  xtraeme 			return (_PROP_OBJECT_EQUALS_FALSE);
    246           1.8  thorpej 		if (num2->pn_value.pnv_signed < 0)
    247      1.11.4.1  xtraeme 			return (_PROP_OBJECT_EQUALS_FALSE);
    248           1.8  thorpej 	} else {
    249           1.8  thorpej 		/*
    250           1.8  thorpej 		 * num1 is signed and num2 is unsigned.
    251           1.8  thorpej 		 */
    252           1.8  thorpej 		if (num1->pn_value.pnv_signed < 0)
    253      1.11.4.1  xtraeme 			return (_PROP_OBJECT_EQUALS_FALSE);
    254           1.8  thorpej 		if (num2->pn_value.pnv_unsigned > INT64_MAX)
    255      1.11.4.1  xtraeme 			return (_PROP_OBJECT_EQUALS_FALSE);
    256           1.8  thorpej 	}
    257           1.8  thorpej 
    258      1.11.4.1  xtraeme 	if (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed)
    259      1.11.4.1  xtraeme 		return _PROP_OBJECT_EQUALS_TRUE;
    260      1.11.4.1  xtraeme 	else
    261      1.11.4.1  xtraeme 		return _PROP_OBJECT_EQUALS_FALSE;
    262           1.2  thorpej }
    263           1.2  thorpej 
    264           1.1  thorpej static prop_number_t
    265           1.8  thorpej _prop_number_alloc(const struct _prop_number_value *pnv)
    266           1.1  thorpej {
    267           1.6  thorpej 	prop_number_t opn, pn;
    268           1.6  thorpej 	struct rb_node *n;
    269           1.6  thorpej 
    270           1.6  thorpej 	/*
    271           1.6  thorpej 	 * Check to see if this already exists in the tree.  If it does,
    272           1.6  thorpej 	 * we just retain it and return it.
    273           1.6  thorpej 	 */
    274           1.6  thorpej 	_PROP_MUTEX_LOCK(_prop_number_tree_mutex);
    275           1.6  thorpej 	if (! _prop_number_tree_initialized) {
    276           1.6  thorpej 		_prop_rb_tree_init(&_prop_number_tree,
    277           1.6  thorpej 				   &_prop_number_rb_tree_ops);
    278      1.11.4.1  xtraeme 		_prop_number_tree_initialized = true;
    279           1.6  thorpej 	} else {
    280           1.8  thorpej 		n = _prop_rb_tree_find(&_prop_number_tree, pnv);
    281           1.6  thorpej 		if (n != NULL) {
    282           1.6  thorpej 			opn = RBNODE_TO_PN(n);
    283           1.6  thorpej 			prop_object_retain(opn);
    284           1.6  thorpej 			_PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
    285           1.6  thorpej 			return (opn);
    286           1.6  thorpej 		}
    287           1.6  thorpej 	}
    288           1.6  thorpej 	_PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
    289           1.6  thorpej 
    290           1.6  thorpej 	/*
    291           1.6  thorpej 	 * Not in the tree.  Create it now.
    292           1.6  thorpej 	 */
    293           1.1  thorpej 
    294           1.1  thorpej 	pn = _PROP_POOL_GET(_prop_number_pool);
    295           1.6  thorpej 	if (pn == NULL)
    296           1.6  thorpej 		return (NULL);
    297           1.6  thorpej 
    298           1.6  thorpej 	_prop_object_init(&pn->pn_obj, &_prop_object_type_number);
    299           1.1  thorpej 
    300           1.8  thorpej 	pn->pn_value = *pnv;
    301           1.6  thorpej 
    302           1.6  thorpej 	/*
    303           1.6  thorpej 	 * We dropped the mutex when we allocated the new object, so
    304           1.6  thorpej 	 * we have to check again if it is in the tree.
    305           1.6  thorpej 	 */
    306           1.6  thorpej 	_PROP_MUTEX_LOCK(_prop_number_tree_mutex);
    307           1.8  thorpej 	n = _prop_rb_tree_find(&_prop_number_tree, pnv);
    308           1.6  thorpej 	if (n != NULL) {
    309           1.6  thorpej 		opn = RBNODE_TO_PN(n);
    310           1.6  thorpej 		prop_object_retain(opn);
    311           1.6  thorpej 		_PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
    312           1.6  thorpej 		_PROP_POOL_PUT(_prop_number_pool, pn);
    313           1.6  thorpej 		return (opn);
    314           1.1  thorpej 	}
    315           1.6  thorpej 	_prop_rb_tree_insert_node(&_prop_number_tree, &pn->pn_link);
    316           1.6  thorpej 	_PROP_MUTEX_UNLOCK(_prop_number_tree_mutex);
    317           1.1  thorpej 	return (pn);
    318           1.1  thorpej }
    319           1.1  thorpej 
    320           1.1  thorpej /*
    321           1.1  thorpej  * prop_number_create_integer --
    322           1.1  thorpej  *	Create a prop_number_t and initialize it with the
    323           1.1  thorpej  *	provided integer value.
    324           1.1  thorpej  */
    325           1.1  thorpej prop_number_t
    326           1.8  thorpej prop_number_create_integer(int64_t val)
    327           1.1  thorpej {
    328           1.9  thorpej 	struct _prop_number_value pnv;
    329           1.9  thorpej 
    330           1.9  thorpej 	memset(&pnv, 0, sizeof(pnv));
    331           1.9  thorpej 	pnv.pnv_signed = val;
    332      1.11.4.1  xtraeme 	pnv.pnv_is_unsigned = false;
    333           1.1  thorpej 
    334           1.8  thorpej 	return (_prop_number_alloc(&pnv));
    335           1.8  thorpej }
    336           1.8  thorpej 
    337           1.8  thorpej /*
    338           1.8  thorpej  * prop_number_create_unsigned_integer --
    339           1.8  thorpej  *	Create a prop_number_t and initialize it with the
    340           1.8  thorpej  *	provided unsigned integer value.
    341           1.8  thorpej  */
    342           1.8  thorpej prop_number_t
    343           1.8  thorpej prop_number_create_unsigned_integer(uint64_t val)
    344           1.8  thorpej {
    345           1.9  thorpej 	struct _prop_number_value pnv;
    346           1.9  thorpej 
    347           1.9  thorpej 	memset(&pnv, 0, sizeof(pnv));
    348           1.9  thorpej 	pnv.pnv_unsigned = val;
    349      1.11.4.1  xtraeme 	pnv.pnv_is_unsigned = true;
    350           1.8  thorpej 
    351           1.8  thorpej 	return (_prop_number_alloc(&pnv));
    352           1.1  thorpej }
    353           1.1  thorpej 
    354           1.1  thorpej /*
    355           1.1  thorpej  * prop_number_copy --
    356           1.1  thorpej  *	Copy a prop_number_t.
    357           1.1  thorpej  */
    358           1.1  thorpej prop_number_t
    359           1.1  thorpej prop_number_copy(prop_number_t opn)
    360           1.1  thorpej {
    361           1.1  thorpej 
    362           1.4  thorpej 	if (! prop_object_is_number(opn))
    363           1.4  thorpej 		return (NULL);
    364           1.1  thorpej 
    365           1.6  thorpej 	/*
    366           1.6  thorpej 	 * Because we only ever allocate one object for any given
    367           1.6  thorpej 	 * value, this can be reduced to a simple retain operation.
    368           1.6  thorpej 	 */
    369           1.6  thorpej 	prop_object_retain(opn);
    370           1.6  thorpej 	return (opn);
    371           1.1  thorpej }
    372           1.1  thorpej 
    373           1.1  thorpej /*
    374           1.8  thorpej  * prop_number_unsigned --
    375      1.11.4.1  xtraeme  *	Returns true if the prop_number_t has an unsigned value.
    376           1.8  thorpej  */
    377      1.11.4.1  xtraeme bool
    378           1.8  thorpej prop_number_unsigned(prop_number_t pn)
    379           1.8  thorpej {
    380           1.8  thorpej 
    381           1.8  thorpej 	return (pn->pn_value.pnv_is_unsigned);
    382           1.8  thorpej }
    383           1.8  thorpej 
    384           1.8  thorpej /*
    385           1.1  thorpej  * prop_number_size --
    386           1.1  thorpej  *	Return the size, in bits, required to hold the value of
    387           1.1  thorpej  *	the specified number.
    388           1.1  thorpej  */
    389           1.1  thorpej int
    390           1.1  thorpej prop_number_size(prop_number_t pn)
    391           1.1  thorpej {
    392           1.8  thorpej 	struct _prop_number_value *pnv;
    393           1.1  thorpej 
    394           1.4  thorpej 	if (! prop_object_is_number(pn))
    395           1.4  thorpej 		return (0);
    396           1.4  thorpej 
    397           1.8  thorpej 	pnv = &pn->pn_value;
    398           1.8  thorpej 
    399           1.8  thorpej 	if (pnv->pnv_is_unsigned) {
    400           1.8  thorpej 		if (pnv->pnv_unsigned > UINT32_MAX)
    401           1.8  thorpej 			return (64);
    402           1.8  thorpej 		if (pnv->pnv_unsigned > UINT16_MAX)
    403           1.8  thorpej 			return (32);
    404           1.8  thorpej 		if (pnv->pnv_unsigned > UINT8_MAX)
    405           1.8  thorpej 			return (16);
    406           1.8  thorpej 		return (8);
    407           1.8  thorpej 	}
    408           1.8  thorpej 
    409           1.8  thorpej 	if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN)
    410           1.8  thorpej 	    	return (64);
    411           1.8  thorpej 	if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN)
    412           1.1  thorpej 		return (32);
    413           1.8  thorpej 	if (pnv->pnv_signed > INT8_MAX  || pnv->pnv_signed < INT8_MIN)
    414           1.1  thorpej 		return (16);
    415           1.1  thorpej 	return (8);
    416           1.1  thorpej }
    417           1.1  thorpej 
    418           1.1  thorpej /*
    419           1.1  thorpej  * prop_number_integer_value --
    420           1.1  thorpej  *	Get the integer value of a prop_number_t.
    421           1.1  thorpej  */
    422           1.8  thorpej int64_t
    423           1.8  thorpej prop_number_integer_value(prop_number_t pn)
    424           1.8  thorpej {
    425           1.8  thorpej 
    426           1.8  thorpej 	/*
    427           1.8  thorpej 	 * XXX Impossible to distinguish between "not a prop_number_t"
    428           1.8  thorpej 	 * XXX and "prop_number_t has a value of 0".
    429           1.8  thorpej 	 */
    430           1.8  thorpej 	if (! prop_object_is_number(pn))
    431           1.8  thorpej 		return (0);
    432           1.8  thorpej 
    433           1.8  thorpej 	return (pn->pn_value.pnv_signed);
    434           1.8  thorpej }
    435           1.8  thorpej 
    436           1.8  thorpej /*
    437           1.8  thorpej  * prop_number_unsigned_integer_value --
    438           1.8  thorpej  *	Get the unsigned integer value of a prop_number_t.
    439           1.8  thorpej  */
    440           1.3  thorpej uint64_t
    441           1.8  thorpej prop_number_unsigned_integer_value(prop_number_t pn)
    442           1.1  thorpej {
    443           1.1  thorpej 
    444           1.4  thorpej 	/*
    445           1.4  thorpej 	 * XXX Impossible to distinguish between "not a prop_number_t"
    446           1.4  thorpej 	 * XXX and "prop_number_t has a value of 0".
    447           1.4  thorpej 	 */
    448           1.4  thorpej 	if (! prop_object_is_number(pn))
    449           1.4  thorpej 		return (0);
    450           1.4  thorpej 
    451           1.8  thorpej 	return (pn->pn_value.pnv_unsigned);
    452           1.1  thorpej }
    453           1.1  thorpej 
    454           1.1  thorpej /*
    455           1.1  thorpej  * prop_number_equals --
    456      1.11.4.1  xtraeme  *	Return true if two numbers are equivalent.
    457           1.1  thorpej  */
    458      1.11.4.1  xtraeme bool
    459           1.1  thorpej prop_number_equals(prop_number_t num1, prop_number_t num2)
    460           1.1  thorpej {
    461      1.11.4.1  xtraeme 	if (!prop_object_is_number(num1) || !prop_object_is_number(num2))
    462      1.11.4.1  xtraeme 		return (false);
    463           1.1  thorpej 
    464      1.11.4.1  xtraeme 	return (prop_object_equals(num1, num2));
    465           1.1  thorpej }
    466           1.1  thorpej 
    467           1.1  thorpej /*
    468           1.1  thorpej  * prop_number_equals_integer --
    469      1.11.4.1  xtraeme  *	Return true if the number is equivalent to the specified integer.
    470           1.1  thorpej  */
    471      1.11.4.1  xtraeme bool
    472           1.8  thorpej prop_number_equals_integer(prop_number_t pn, int64_t val)
    473           1.1  thorpej {
    474           1.1  thorpej 
    475           1.4  thorpej 	if (! prop_object_is_number(pn))
    476      1.11.4.1  xtraeme 		return (false);
    477           1.4  thorpej 
    478           1.8  thorpej 	if (pn->pn_value.pnv_is_unsigned &&
    479           1.8  thorpej 	    (pn->pn_value.pnv_unsigned > INT64_MAX || val < 0))
    480      1.11.4.1  xtraeme 		return (false);
    481           1.8  thorpej 
    482           1.8  thorpej 	return (pn->pn_value.pnv_signed == val);
    483           1.8  thorpej }
    484           1.8  thorpej 
    485           1.8  thorpej /*
    486           1.8  thorpej  * prop_number_equals_unsigned_integer --
    487      1.11.4.1  xtraeme  *	Return true if the number is equivalent to the specified
    488           1.8  thorpej  *	unsigned integer.
    489           1.8  thorpej  */
    490      1.11.4.1  xtraeme bool
    491           1.8  thorpej prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val)
    492           1.8  thorpej {
    493           1.8  thorpej 
    494           1.8  thorpej 	if (! prop_object_is_number(pn))
    495      1.11.4.1  xtraeme 		return (false);
    496           1.8  thorpej 
    497           1.8  thorpej 	if (! pn->pn_value.pnv_is_unsigned &&
    498           1.8  thorpej 	    (pn->pn_value.pnv_signed < 0 || val > INT64_MAX))
    499      1.11.4.1  xtraeme 		return (false);
    500           1.8  thorpej 
    501           1.8  thorpej 	return (pn->pn_value.pnv_unsigned == val);
    502           1.8  thorpej }
    503           1.8  thorpej 
    504      1.11.4.1  xtraeme static bool
    505           1.8  thorpej _prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx,
    506           1.8  thorpej 				  struct _prop_number_value *pnv)
    507           1.8  thorpej {
    508           1.8  thorpej 	char *cp;
    509           1.8  thorpej 
    510           1.9  thorpej 	_PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) ==
    511           1.9  thorpej 		     sizeof(uint64_t));
    512           1.8  thorpej 
    513           1.8  thorpej #ifndef _KERNEL
    514           1.8  thorpej 	errno = 0;
    515           1.8  thorpej #endif
    516           1.8  thorpej 	pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0);
    517           1.8  thorpej #ifndef _KERNEL		/* XXX can't check for ERANGE in the kernel */
    518           1.8  thorpej 	if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE)
    519      1.11.4.1  xtraeme 		return (false);
    520           1.8  thorpej #endif
    521      1.11.4.1  xtraeme 	pnv->pnv_is_unsigned = true;
    522           1.8  thorpej 	ctx->poic_cp = cp;
    523           1.8  thorpej 
    524      1.11.4.1  xtraeme 	return (true);
    525           1.8  thorpej }
    526           1.8  thorpej 
    527      1.11.4.1  xtraeme static bool
    528           1.8  thorpej _prop_number_internalize_signed(struct _prop_object_internalize_context *ctx,
    529           1.8  thorpej 				struct _prop_number_value *pnv)
    530           1.8  thorpej {
    531           1.8  thorpej 	char *cp;
    532           1.8  thorpej 
    533           1.9  thorpej 	_PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t));
    534           1.8  thorpej 
    535           1.8  thorpej #ifndef _KERNEL
    536           1.8  thorpej 	errno = 0;
    537           1.8  thorpej #endif
    538           1.8  thorpej 	pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0);
    539           1.8  thorpej #ifndef _KERNEL		/* XXX can't check for ERANGE in the kernel */
    540           1.8  thorpej 	if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) &&
    541           1.8  thorpej 	    errno == ERANGE)
    542      1.11.4.1  xtraeme 	    	return (false);
    543           1.8  thorpej #endif
    544      1.11.4.1  xtraeme 	pnv->pnv_is_unsigned = false;
    545           1.8  thorpej 	ctx->poic_cp = cp;
    546           1.8  thorpej 
    547      1.11.4.1  xtraeme 	return (true);
    548           1.1  thorpej }
    549           1.1  thorpej 
    550           1.1  thorpej /*
    551           1.1  thorpej  * _prop_number_internalize --
    552           1.1  thorpej  *	Parse a <number>...</number> and return the object created from
    553           1.1  thorpej  *	the external representation.
    554           1.1  thorpej  */
    555      1.11.4.1  xtraeme /* ARGSUSED */
    556      1.11.4.1  xtraeme bool
    557      1.11.4.1  xtraeme _prop_number_internalize(prop_stack_t stack, prop_object_t *obj,
    558      1.11.4.1  xtraeme     struct _prop_object_internalize_context *ctx)
    559           1.1  thorpej {
    560           1.9  thorpej 	struct _prop_number_value pnv;
    561           1.9  thorpej 
    562           1.9  thorpej 	memset(&pnv, 0, sizeof(pnv));
    563           1.1  thorpej 
    564           1.1  thorpej 	/* No attributes, no empty elements. */
    565           1.1  thorpej 	if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element)
    566      1.11.4.1  xtraeme 		return (true);
    567           1.1  thorpej 
    568           1.8  thorpej 	/*
    569           1.8  thorpej 	 * If the first character is '-', then we treat as signed.
    570           1.8  thorpej 	 * If the first two characters are "0x" (i.e. the number is
    571           1.8  thorpej 	 * in hex), then we treat as unsigned.  Otherwise, we try
    572           1.8  thorpej 	 * signed first, and if that fails (presumably due to ERANGE),
    573           1.8  thorpej 	 * then we switch to unsigned.
    574           1.8  thorpej 	 */
    575           1.8  thorpej 	if (ctx->poic_cp[0] == '-') {
    576      1.11.4.1  xtraeme 		if (_prop_number_internalize_signed(ctx, &pnv) == false)
    577      1.11.4.1  xtraeme 			return (true);
    578           1.8  thorpej 	} else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') {
    579      1.11.4.1  xtraeme 		if (_prop_number_internalize_unsigned(ctx, &pnv) == false)
    580      1.11.4.1  xtraeme 			return (true);
    581           1.8  thorpej 	} else {
    582      1.11.4.1  xtraeme 		if (_prop_number_internalize_signed(ctx, &pnv) == false &&
    583      1.11.4.1  xtraeme 		    _prop_number_internalize_unsigned(ctx, &pnv) == false)
    584      1.11.4.1  xtraeme 		    	return (true);
    585           1.8  thorpej 	}
    586           1.8  thorpej 
    587           1.1  thorpej 	if (_prop_object_internalize_find_tag(ctx, "integer",
    588      1.11.4.1  xtraeme 					      _PROP_TAG_TYPE_END) == false)
    589      1.11.4.1  xtraeme 		return (true);
    590           1.1  thorpej 
    591      1.11.4.1  xtraeme 	*obj = _prop_number_alloc(&pnv);
    592      1.11.4.1  xtraeme 	return (true);
    593           1.1  thorpej }
    594