1/* $NetBSD: prop_number.c,v 1.34 2022/08/03 21:13:46 riastradh Exp $ */ 2 3/*- 4 * Copyright (c) 2006, 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#include "prop_object_impl.h" 33#include <prop/prop_number.h> 34#include <sys/rbtree.h> 35 36#if defined(_KERNEL) 37#include <sys/systm.h> 38#elif defined(_STANDALONE) 39#include <sys/param.h> 40#include <lib/libkern/libkern.h> 41#else 42#include <errno.h> 43#include <limits.h> 44#include <stdlib.h> 45#endif 46 47struct _prop_number_value { 48 union { 49 int64_t pnu_signed; 50 uint64_t pnu_unsigned; 51 } pnv_un; 52#define pnv_signed pnv_un.pnu_signed 53#define pnv_unsigned pnv_un.pnu_unsigned 54 unsigned int pnv_is_unsigned :1, 55 :31; 56}; 57 58struct _prop_number { 59 struct _prop_object pn_obj; 60 struct rb_node pn_link; 61 struct _prop_number_value pn_value; 62}; 63 64_PROP_POOL_INIT(_prop_number_pool, sizeof(struct _prop_number), "propnmbr") 65 66static _prop_object_free_rv_t 67 _prop_number_free(prop_stack_t, prop_object_t *); 68static bool _prop_number_externalize( 69 struct _prop_object_externalize_context *, 70 void *); 71static _prop_object_equals_rv_t 72 _prop_number_equals(prop_object_t, prop_object_t, 73 void **, void **, 74 prop_object_t *, prop_object_t *); 75 76static void _prop_number_lock(void); 77static void _prop_number_unlock(void); 78 79static const struct _prop_object_type _prop_object_type_number = { 80 .pot_type = PROP_TYPE_NUMBER, 81 .pot_free = _prop_number_free, 82 .pot_extern = _prop_number_externalize, 83 .pot_equals = _prop_number_equals, 84 .pot_lock = _prop_number_lock, 85 .pot_unlock = _prop_number_unlock, 86}; 87 88#define prop_object_is_number(x) \ 89 ((x) != NULL && (x)->pn_obj.po_type == &_prop_object_type_number) 90 91/* 92 * Number objects are immutable, and we are likely to have many number 93 * objects that have the same value. So, to save memory, we unique'ify 94 * numbers so we only have one copy of each. 95 */ 96 97static int 98_prop_number_compare_values(const struct _prop_number_value *pnv1, 99 const struct _prop_number_value *pnv2) 100{ 101 102 /* Signed numbers are sorted before unsigned numbers. */ 103 104 if (pnv1->pnv_is_unsigned) { 105 if (! pnv2->pnv_is_unsigned) 106 return (1); 107 if (pnv1->pnv_unsigned < pnv2->pnv_unsigned) 108 return (-1); 109 if (pnv1->pnv_unsigned > pnv2->pnv_unsigned) 110 return (1); 111 return (0); 112 } 113 114 if (pnv2->pnv_is_unsigned) 115 return (-1); 116 if (pnv1->pnv_signed < pnv2->pnv_signed) 117 return (-1); 118 if (pnv1->pnv_signed > pnv2->pnv_signed) 119 return (1); 120 return (0); 121} 122 123static int 124/*ARGSUSED*/ 125_prop_number_rb_compare_nodes(void *ctx _PROP_ARG_UNUSED, 126 const void *n1, const void *n2) 127{ 128 const struct _prop_number *pn1 = n1; 129 const struct _prop_number *pn2 = n2; 130 131 return _prop_number_compare_values(&pn1->pn_value, &pn2->pn_value); 132} 133 134static int 135/*ARGSUSED*/ 136_prop_number_rb_compare_key(void *ctx _PROP_ARG_UNUSED, 137 const void *n, const void *v) 138{ 139 const struct _prop_number *pn = n; 140 const struct _prop_number_value *pnv = v; 141 142 return _prop_number_compare_values(&pn->pn_value, pnv); 143} 144 145static const rb_tree_ops_t _prop_number_rb_tree_ops = { 146 .rbto_compare_nodes = _prop_number_rb_compare_nodes, 147 .rbto_compare_key = _prop_number_rb_compare_key, 148 .rbto_node_offset = offsetof(struct _prop_number, pn_link), 149 .rbto_context = NULL 150}; 151 152static struct rb_tree _prop_number_tree; 153_PROP_MUTEX_DECL_STATIC(_prop_number_tree_mutex) 154 155/* ARGSUSED */ 156static _prop_object_free_rv_t 157_prop_number_free(prop_stack_t stack, prop_object_t *obj) 158{ 159 prop_number_t pn = *obj; 160 161 rb_tree_remove_node(&_prop_number_tree, pn); 162 163 _PROP_POOL_PUT(_prop_number_pool, pn); 164 165 return (_PROP_OBJECT_FREE_DONE); 166} 167 168_PROP_ONCE_DECL(_prop_number_init_once) 169 170static int 171_prop_number_init(void) 172{ 173 174 _PROP_MUTEX_INIT(_prop_number_tree_mutex); 175 rb_tree_init(&_prop_number_tree, &_prop_number_rb_tree_ops); 176 return 0; 177} 178 179static void 180_prop_number_lock(void) 181{ 182 /* XXX: init necessary? */ 183 _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init); 184 _PROP_MUTEX_LOCK(_prop_number_tree_mutex); 185} 186 187static void 188_prop_number_unlock(void) 189{ 190 _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); 191} 192 193static bool 194_prop_number_externalize(struct _prop_object_externalize_context *ctx, 195 void *v) 196{ 197 prop_number_t pn = v; 198 char tmpstr[32]; 199 200 /* 201 * For unsigned numbers, we output in hex. For signed numbers, 202 * we output in decimal. 203 */ 204 if (pn->pn_value.pnv_is_unsigned) 205 snprintf(tmpstr, sizeof(tmpstr), "0x%" PRIx64, 206 pn->pn_value.pnv_unsigned); 207 else 208 snprintf(tmpstr, sizeof(tmpstr), "%" PRIi64, 209 pn->pn_value.pnv_signed); 210 211 if (_prop_object_externalize_start_tag(ctx, "integer") == false || 212 _prop_object_externalize_append_cstring(ctx, tmpstr) == false || 213 _prop_object_externalize_end_tag(ctx, "integer") == false) 214 return (false); 215 216 return (true); 217} 218 219/* ARGSUSED */ 220static _prop_object_equals_rv_t 221_prop_number_equals(prop_object_t v1, prop_object_t v2, 222 void **stored_pointer1, void **stored_pointer2, 223 prop_object_t *next_obj1, prop_object_t *next_obj2) 224{ 225 prop_number_t num1 = v1; 226 prop_number_t num2 = v2; 227 228 /* 229 * There is only ever one copy of a number object at any given 230 * time, so we can reduce this to a simple pointer equality check 231 * in the common case. 232 */ 233 if (num1 == num2) 234 return (_PROP_OBJECT_EQUALS_TRUE); 235 236 /* 237 * If the numbers are the same signed-ness, then we know they 238 * cannot be equal because they would have had pointer equality. 239 */ 240 if (num1->pn_value.pnv_is_unsigned == num2->pn_value.pnv_is_unsigned) 241 return (_PROP_OBJECT_EQUALS_FALSE); 242 243 /* 244 * We now have one signed value and one unsigned value. We can 245 * compare them iff: 246 * - The unsigned value is not larger than the signed value 247 * can represent. 248 * - The signed value is not smaller than the unsigned value 249 * can represent. 250 */ 251 if (num1->pn_value.pnv_is_unsigned) { 252 /* 253 * num1 is unsigned and num2 is signed. 254 */ 255 if (num1->pn_value.pnv_unsigned > INTMAX_MAX) 256 return (_PROP_OBJECT_EQUALS_FALSE); 257 if (num2->pn_value.pnv_signed < 0) 258 return (_PROP_OBJECT_EQUALS_FALSE); 259 } else { 260 /* 261 * num1 is signed and num2 is unsigned. 262 */ 263 if (num1->pn_value.pnv_signed < 0) 264 return (_PROP_OBJECT_EQUALS_FALSE); 265 if (num2->pn_value.pnv_unsigned > INTMAX_MAX) 266 return (_PROP_OBJECT_EQUALS_FALSE); 267 } 268 269 if (num1->pn_value.pnv_signed == num2->pn_value.pnv_signed) 270 return _PROP_OBJECT_EQUALS_TRUE; 271 else 272 return _PROP_OBJECT_EQUALS_FALSE; 273} 274 275static prop_number_t 276_prop_number_alloc(const struct _prop_number_value *pnv) 277{ 278 prop_number_t opn, pn, rpn; 279 280 _PROP_ONCE_RUN(_prop_number_init_once, _prop_number_init); 281 282 /* 283 * Check to see if this already exists in the tree. If it does, 284 * we just retain it and return it. 285 */ 286 _PROP_MUTEX_LOCK(_prop_number_tree_mutex); 287 opn = rb_tree_find_node(&_prop_number_tree, pnv); 288 if (opn != NULL) { 289 prop_object_retain(opn); 290 _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); 291 return (opn); 292 } 293 _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); 294 295 /* 296 * Not in the tree. Create it now. 297 */ 298 299 pn = _PROP_POOL_GET(_prop_number_pool); 300 if (pn == NULL) 301 return (NULL); 302 303 _prop_object_init(&pn->pn_obj, &_prop_object_type_number); 304 305 pn->pn_value = *pnv; 306 307 /* 308 * We dropped the mutex when we allocated the new object, so 309 * we have to check again if it is in the tree. 310 */ 311 _PROP_MUTEX_LOCK(_prop_number_tree_mutex); 312 opn = rb_tree_find_node(&_prop_number_tree, pnv); 313 if (opn != NULL) { 314 prop_object_retain(opn); 315 _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); 316 _PROP_POOL_PUT(_prop_number_pool, pn); 317 return (opn); 318 } 319 rpn = rb_tree_insert_node(&_prop_number_tree, pn); 320 _PROP_ASSERT(rpn == pn); 321 _PROP_MUTEX_UNLOCK(_prop_number_tree_mutex); 322 return (rpn); 323} 324 325/* 326 * prop_number_create_signed -- 327 * Create a prop_number_t and initialize it with the 328 * provided signed value. 329 */ 330prop_number_t 331prop_number_create_signed(intmax_t val) 332{ 333 struct _prop_number_value pnv; 334 335 memset(&pnv, 0, sizeof(pnv)); 336 pnv.pnv_signed = val; 337 pnv.pnv_is_unsigned = false; 338 339 return (_prop_number_alloc(&pnv)); 340} 341 342_PROP_DEPRECATED(prop_number_create_integer, 343 "this program uses prop_number_create_integer(), " 344 "which is deprecated; use prop_number_create_signed() instead.") 345prop_number_t 346prop_number_create_integer(int64_t val) 347{ 348 return prop_number_create_signed(val); 349} 350 351/* 352 * prop_number_create_unsigned -- 353 * Create a prop_number_t and initialize it with the 354 * provided unsigned value. 355 */ 356prop_number_t 357prop_number_create_unsigned(uintmax_t val) 358{ 359 struct _prop_number_value pnv; 360 361 memset(&pnv, 0, sizeof(pnv)); 362 pnv.pnv_unsigned = val; 363 pnv.pnv_is_unsigned = true; 364 365 return (_prop_number_alloc(&pnv)); 366} 367 368_PROP_DEPRECATED(prop_number_create_unsigned_integer, 369 "this program uses prop_number_create_unsigned_integer(), " 370 "which is deprecated; use prop_number_create_unsigned() instead.") 371prop_number_t 372prop_number_create_unsigned_integer(uint64_t val) 373{ 374 return prop_number_create_unsigned(val); 375} 376 377/* 378 * prop_number_copy -- 379 * Copy a prop_number_t. 380 */ 381prop_number_t 382prop_number_copy(prop_number_t opn) 383{ 384 385 if (! prop_object_is_number(opn)) 386 return (NULL); 387 388 /* 389 * Because we only ever allocate one object for any given 390 * value, this can be reduced to a simple retain operation. 391 */ 392 prop_object_retain(opn); 393 return (opn); 394} 395 396/* 397 * prop_number_unsigned -- 398 * Returns true if the prop_number_t has an unsigned value. 399 */ 400bool 401prop_number_unsigned(prop_number_t pn) 402{ 403 404 return (pn->pn_value.pnv_is_unsigned); 405} 406 407/* 408 * prop_number_size -- 409 * Return the size, in bits, required to hold the value of 410 * the specified number. 411 */ 412int 413prop_number_size(prop_number_t pn) 414{ 415 struct _prop_number_value *pnv; 416 417 if (! prop_object_is_number(pn)) 418 return (0); 419 420 pnv = &pn->pn_value; 421 422 if (pnv->pnv_is_unsigned) { 423 if (pnv->pnv_unsigned > UINT32_MAX) 424 return (64); 425 if (pnv->pnv_unsigned > UINT16_MAX) 426 return (32); 427 if (pnv->pnv_unsigned > UINT8_MAX) 428 return (16); 429 return (8); 430 } 431 432 if (pnv->pnv_signed > INT32_MAX || pnv->pnv_signed < INT32_MIN) 433 return (64); 434 if (pnv->pnv_signed > INT16_MAX || pnv->pnv_signed < INT16_MIN) 435 return (32); 436 if (pnv->pnv_signed > INT8_MAX || pnv->pnv_signed < INT8_MIN) 437 return (16); 438 return (8); 439} 440 441/* 442 * prop_number_signed_value -- 443 * Get the signed value of a prop_number_t. 444 */ 445intmax_t 446prop_number_signed_value(prop_number_t pn) 447{ 448 449 /* 450 * XXX Impossible to distinguish between "not a prop_number_t" 451 * XXX and "prop_number_t has a value of 0". 452 */ 453 if (! prop_object_is_number(pn)) 454 return (0); 455 456 return (pn->pn_value.pnv_signed); 457} 458 459_PROP_DEPRECATED(prop_number_integer_value, 460 "this program uses prop_number_integer_value(), " 461 "which is deprecated; use prop_number_signed_value() instead.") 462int64_t 463prop_number_integer_value(prop_number_t pn) 464{ 465 return prop_number_signed_value(pn); 466} 467 468/* 469 * prop_number_unsigned_value -- 470 * Get the unsigned value of a prop_number_t. 471 */ 472uintmax_t 473prop_number_unsigned_value(prop_number_t pn) 474{ 475 476 /* 477 * XXX Impossible to distinguish between "not a prop_number_t" 478 * XXX and "prop_number_t has a value of 0". 479 */ 480 if (! prop_object_is_number(pn)) 481 return (0); 482 483 return (pn->pn_value.pnv_unsigned); 484} 485 486_PROP_DEPRECATED(prop_number_unsigned_integer_value, 487 "this program uses prop_number_unsigned_integer_value(), " 488 "which is deprecated; use prop_number_unsigned_value() instead.") 489uint64_t 490prop_number_unsigned_integer_value(prop_number_t pn) 491{ 492 return prop_number_unsigned_value(pn); 493} 494 495/* 496 * prop_number_[...]_value -- 497 * Retrieve the bounds-checked value as the specified type. 498 * Returns true if successful. 499 */ 500#define TEMPLATE(name, typ, minv, maxv) \ 501bool \ 502prop_number_ ## name ## _value(prop_number_t pn, typ * const valp) \ 503{ \ 504 \ 505 if (! prop_object_is_number(pn)) \ 506 return (false); \ 507 \ 508 if (pn->pn_value.pnv_is_unsigned) { \ 509 if (pn->pn_value.pnv_unsigned > (maxv)) \ 510 return (false); \ 511 *valp = (typ) pn->pn_value.pnv_unsigned; \ 512 } else { \ 513 if ((pn->pn_value.pnv_signed > 0 && \ 514 (uintmax_t)pn->pn_value.pnv_signed > (maxv)) || \ 515 pn->pn_value.pnv_signed < (minv)) \ 516 return (false); \ 517 *valp = (typ) pn->pn_value.pnv_signed; \ 518 } \ 519 \ 520 return (true); \ 521} 522TEMPLATE(schar, signed char, SCHAR_MIN, SCHAR_MAX) 523TEMPLATE(short, short, SHRT_MIN, SHRT_MAX) 524TEMPLATE(int, int, INT_MIN, INT_MAX) 525TEMPLATE(long, long, LONG_MIN, LONG_MAX) 526TEMPLATE(longlong, long long, LLONG_MIN, LLONG_MAX) 527TEMPLATE(intptr, intptr_t, INTPTR_MIN, INTPTR_MAX) 528TEMPLATE(int8, int8_t, INT8_MIN, INT8_MAX) 529TEMPLATE(int16, int16_t, INT16_MIN, INT16_MAX) 530TEMPLATE(int32, int32_t, INT32_MIN, INT32_MAX) 531TEMPLATE(int64, int64_t, INT64_MIN, INT64_MAX) 532 533TEMPLATE(uchar, unsigned char, 0, UCHAR_MAX) 534TEMPLATE(ushort, unsigned short, 0, USHRT_MAX) 535TEMPLATE(uint, unsigned int, 0, UINT_MAX) 536TEMPLATE(ulong, unsigned long, 0, ULONG_MAX) 537TEMPLATE(ulonglong, unsigned long long, 0, ULLONG_MAX) 538TEMPLATE(uintptr, uintptr_t, 0, UINTPTR_MAX) 539TEMPLATE(uint8, uint8_t, 0, UINT8_MAX) 540TEMPLATE(uint16, uint16_t, 0, UINT16_MAX) 541TEMPLATE(uint32, uint32_t, 0, UINT32_MAX) 542TEMPLATE(uint64, uint64_t, 0, UINT64_MAX) 543 544#undef TEMPLATE 545 546/* 547 * prop_number_equals -- 548 * Return true if two numbers are equivalent. 549 */ 550bool 551prop_number_equals(prop_number_t num1, prop_number_t num2) 552{ 553 if (!prop_object_is_number(num1) || !prop_object_is_number(num2)) 554 return (false); 555 556 return (prop_object_equals(num1, num2)); 557} 558 559/* 560 * prop_number_equals_signed -- 561 * Return true if the number is equivalent to the specified signed 562 * value. 563 */ 564bool 565prop_number_equals_signed(prop_number_t pn, intmax_t val) 566{ 567 568 if (! prop_object_is_number(pn)) 569 return (false); 570 571 if (pn->pn_value.pnv_is_unsigned && 572 (pn->pn_value.pnv_unsigned > INTMAX_MAX || val < 0)) 573 return (false); 574 575 return (pn->pn_value.pnv_signed == val); 576} 577 578_PROP_DEPRECATED(prop_number_equals_integer, 579 "this program uses prop_number_equals_integer(), " 580 "which is deprecated; use prop_number_equals_signed() instead.") 581bool 582prop_number_equals_integer(prop_number_t pn, int64_t val) 583{ 584 return prop_number_equals_signed(pn, val); 585} 586 587/* 588 * prop_number_equals_unsigned -- 589 * Return true if the number is equivalent to the specified 590 * unsigned value. 591 */ 592bool 593prop_number_equals_unsigned(prop_number_t pn, uintmax_t val) 594{ 595 596 if (! prop_object_is_number(pn)) 597 return (false); 598 599 if (! pn->pn_value.pnv_is_unsigned && 600 (pn->pn_value.pnv_signed < 0 || val > INT64_MAX)) 601 return (false); 602 603 return (pn->pn_value.pnv_unsigned == val); 604} 605 606_PROP_DEPRECATED(prop_number_equals_unsigned_integer, 607 "this program uses prop_number_equals_unsigned_integer(), " 608 "which is deprecated; use prop_number_equals_unsigned() instead.") 609bool 610prop_number_equals_unsigned_integer(prop_number_t pn, uint64_t val) 611{ 612 return prop_number_equals_unsigned(pn, val); 613} 614 615static bool 616_prop_number_internalize_unsigned(struct _prop_object_internalize_context *ctx, 617 struct _prop_number_value *pnv) 618{ 619 char *cp; 620 621 _PROP_ASSERT(/*CONSTCOND*/sizeof(unsigned long long) == 622 sizeof(uint64_t)); 623 624#ifndef _KERNEL 625 errno = 0; 626#endif 627 pnv->pnv_unsigned = (uint64_t) strtoull(ctx->poic_cp, &cp, 0); 628#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */ 629 if (pnv->pnv_unsigned == UINT64_MAX && errno == ERANGE) 630 return (false); 631#endif 632 pnv->pnv_is_unsigned = true; 633 ctx->poic_cp = cp; 634 635 return (true); 636} 637 638static bool 639_prop_number_internalize_signed(struct _prop_object_internalize_context *ctx, 640 struct _prop_number_value *pnv) 641{ 642 char *cp; 643 644 _PROP_ASSERT(/*CONSTCOND*/sizeof(long long) == sizeof(int64_t)); 645 646#ifndef _KERNEL 647 errno = 0; 648#endif 649 pnv->pnv_signed = (int64_t) strtoll(ctx->poic_cp, &cp, 0); 650#ifndef _KERNEL /* XXX can't check for ERANGE in the kernel */ 651 if ((pnv->pnv_signed == INT64_MAX || pnv->pnv_signed == INT64_MIN) && 652 errno == ERANGE) 653 return (false); 654#endif 655 pnv->pnv_is_unsigned = false; 656 ctx->poic_cp = cp; 657 658 return (true); 659} 660 661/* 662 * _prop_number_internalize -- 663 * Parse a <number>...</number> and return the object created from 664 * the external representation. 665 */ 666/* ARGSUSED */ 667bool 668_prop_number_internalize(prop_stack_t stack, prop_object_t *obj, 669 struct _prop_object_internalize_context *ctx) 670{ 671 struct _prop_number_value pnv; 672 673 memset(&pnv, 0, sizeof(pnv)); 674 675 /* No attributes, no empty elements. */ 676 if (ctx->poic_tagattr != NULL || ctx->poic_is_empty_element) 677 return (true); 678 679 /* 680 * If the first character is '-', then we treat as signed. 681 * If the first two characters are "0x" (i.e. the number is 682 * in hex), then we treat as unsigned. Otherwise, we try 683 * signed first, and if that fails (presumably due to ERANGE), 684 * then we switch to unsigned. 685 */ 686 if (ctx->poic_cp[0] == '-') { 687 if (_prop_number_internalize_signed(ctx, &pnv) == false) 688 return (true); 689 } else if (ctx->poic_cp[0] == '0' && ctx->poic_cp[1] == 'x') { 690 if (_prop_number_internalize_unsigned(ctx, &pnv) == false) 691 return (true); 692 } else { 693 if (_prop_number_internalize_signed(ctx, &pnv) == false && 694 _prop_number_internalize_unsigned(ctx, &pnv) == false) 695 return (true); 696 } 697 698 if (_prop_object_internalize_find_tag(ctx, "integer", 699 _PROP_TAG_TYPE_END) == false) 700 return (true); 701 702 *obj = _prop_number_alloc(&pnv); 703 return (true); 704} 705