Home | History | Annotate | Line # | Download | only in libprop
prop_string.c revision 1.18.2.1
      1  1.18.2.1  perseant /*	$NetBSD: prop_string.c,v 1.18.2.1 2025/08/02 05:18:35 perseant Exp $	*/
      2       1.1   thorpej 
      3       1.1   thorpej /*-
      4  1.18.2.1  perseant  * Copyright (c) 2006, 2020, 2025 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  *
     19       1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1   thorpej  */
     31       1.1   thorpej 
     32      1.13   thorpej #include "prop_object_impl.h"
     33       1.1   thorpej #include <prop/prop_string.h>
     34       1.1   thorpej 
     35      1.14   thorpej #include <sys/rbtree.h>
     36      1.14   thorpej #if defined(_KERNEL) || defined(_STANDALONE)
     37      1.14   thorpej #include <sys/stdarg.h>
     38      1.14   thorpej #else
     39      1.14   thorpej #include <stdarg.h>
     40      1.14   thorpej #endif /* _KERNEL || _STANDALONE */
     41      1.14   thorpej 
     42       1.1   thorpej struct _prop_string {
     43       1.1   thorpej 	struct _prop_object	ps_obj;
     44       1.1   thorpej 	union {
     45       1.1   thorpej 		char *		psu_mutable;
     46       1.1   thorpej 		const char *	psu_immutable;
     47       1.1   thorpej 	} ps_un;
     48       1.1   thorpej #define	ps_mutable		ps_un.psu_mutable
     49       1.1   thorpej #define	ps_immutable		ps_un.psu_immutable
     50       1.1   thorpej 	size_t			ps_size;	/* not including \0 */
     51      1.14   thorpej 	struct rb_node		ps_link;
     52       1.1   thorpej 	int			ps_flags;
     53       1.1   thorpej };
     54       1.1   thorpej 
     55       1.1   thorpej #define	PS_F_NOCOPY		0x01
     56      1.14   thorpej #define	PS_F_MUTABLE		0x02
     57       1.1   thorpej 
     58       1.1   thorpej _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
     59       1.1   thorpej _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
     60       1.1   thorpej 		    "property string container object")
     61       1.1   thorpej 
     62  1.18.2.1  perseant static const struct _prop_object_type_tags _prop_string_type_tags = {
     63  1.18.2.1  perseant 	.xml_tag		=	"string",
     64  1.18.2.1  perseant 	.json_open_tag		=	"\"",
     65  1.18.2.1  perseant 	.json_close_tag		=	"\"",
     66  1.18.2.1  perseant };
     67  1.18.2.1  perseant 
     68      1.11   thorpej static _prop_object_free_rv_t
     69      1.11   thorpej 		_prop_string_free(prop_stack_t, prop_object_t *);
     70       1.7   thorpej static bool	_prop_string_externalize(
     71       1.2   thorpej 				struct _prop_object_externalize_context *,
     72       1.2   thorpej 				void *);
     73      1.11   thorpej static _prop_object_equals_rv_t
     74      1.11   thorpej 		_prop_string_equals(prop_object_t, prop_object_t,
     75      1.11   thorpej 				    void **, void **,
     76      1.11   thorpej 				    prop_object_t *, prop_object_t *);
     77       1.2   thorpej 
     78       1.2   thorpej static const struct _prop_object_type _prop_object_type_string = {
     79       1.2   thorpej 	.pot_type	=	PROP_TYPE_STRING,
     80       1.2   thorpej 	.pot_free	=	_prop_string_free,
     81       1.2   thorpej 	.pot_extern	=	_prop_string_externalize,
     82       1.2   thorpej 	.pot_equals	=	_prop_string_equals,
     83       1.2   thorpej };
     84       1.2   thorpej 
     85       1.2   thorpej #define	prop_object_is_string(x)	\
     86       1.4   thorpej 	((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
     87       1.1   thorpej #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
     88       1.1   thorpej 
     89      1.14   thorpej /*
     90      1.14   thorpej  * In order to reduce memory usage, all immutable string objects are
     91      1.14   thorpej  * de-duplicated.
     92      1.14   thorpej  */
     93      1.14   thorpej 
     94      1.14   thorpej static int
     95      1.14   thorpej /*ARGSUSED*/
     96      1.14   thorpej _prop_string_rb_compare_nodes(void *ctx _PROP_ARG_UNUSED,
     97      1.14   thorpej 			      const void *n1, const void *n2)
     98      1.14   thorpej {
     99      1.14   thorpej 	const struct _prop_string * const ps1 = n1;
    100      1.14   thorpej 	const struct _prop_string * const ps2 = n2;
    101      1.14   thorpej 
    102      1.14   thorpej 	_PROP_ASSERT(ps1->ps_immutable != NULL);
    103      1.14   thorpej 	_PROP_ASSERT(ps2->ps_immutable != NULL);
    104      1.14   thorpej 
    105      1.14   thorpej 	return strcmp(ps1->ps_immutable, ps2->ps_immutable);
    106      1.14   thorpej }
    107      1.14   thorpej 
    108      1.14   thorpej static int
    109      1.14   thorpej /*ARGSUSED*/
    110      1.14   thorpej _prop_string_rb_compare_key(void *ctx _PROP_ARG_UNUSED,
    111      1.14   thorpej 			    const void *n, const void *v)
    112      1.14   thorpej {
    113      1.14   thorpej 	const struct _prop_string * const ps = n;
    114      1.14   thorpej 	const char * const cp = v;
    115      1.14   thorpej 
    116      1.14   thorpej 	_PROP_ASSERT(ps->ps_immutable != NULL);
    117      1.14   thorpej 
    118      1.14   thorpej 	return strcmp(ps->ps_immutable, cp);
    119      1.14   thorpej }
    120      1.14   thorpej 
    121      1.14   thorpej static const rb_tree_ops_t _prop_string_rb_tree_ops = {
    122      1.14   thorpej 	.rbto_compare_nodes = _prop_string_rb_compare_nodes,
    123      1.14   thorpej 	.rbto_compare_key = _prop_string_rb_compare_key,
    124      1.14   thorpej 	.rbto_node_offset = offsetof(struct _prop_string, ps_link),
    125      1.14   thorpej 	.rbto_context = NULL
    126      1.14   thorpej };
    127      1.14   thorpej 
    128      1.14   thorpej static struct rb_tree _prop_string_tree;
    129      1.14   thorpej 
    130      1.14   thorpej _PROP_ONCE_DECL(_prop_string_init_once)
    131      1.14   thorpej _PROP_MUTEX_DECL_STATIC(_prop_string_tree_mutex)
    132      1.14   thorpej 
    133      1.14   thorpej static int
    134      1.14   thorpej _prop_string_init(void)
    135      1.14   thorpej {
    136      1.14   thorpej 
    137      1.14   thorpej 	_PROP_MUTEX_INIT(_prop_string_tree_mutex);
    138      1.14   thorpej 	rb_tree_init(&_prop_string_tree,
    139      1.14   thorpej 		     &_prop_string_rb_tree_ops);
    140      1.17  riastrad 
    141      1.14   thorpej 	return 0;
    142      1.14   thorpej }
    143      1.14   thorpej 
    144       1.8     joerg /* ARGSUSED */
    145      1.11   thorpej static _prop_object_free_rv_t
    146       1.8     joerg _prop_string_free(prop_stack_t stack, prop_object_t *obj)
    147       1.1   thorpej {
    148       1.8     joerg 	prop_string_t ps = *obj;
    149       1.1   thorpej 
    150      1.14   thorpej 	if ((ps->ps_flags & PS_F_MUTABLE) == 0) {
    151      1.14   thorpej 		_PROP_MUTEX_LOCK(_prop_string_tree_mutex);
    152      1.14   thorpej 		/*
    153      1.14   thorpej 		 * Double-check the retain count now that we've
    154      1.16    andvar 		 * acquired the tree lock; holding this lock prevents
    155      1.14   thorpej 		 * new retains from coming in by finding it in the
    156      1.14   thorpej 		 * tree.
    157      1.14   thorpej 		 */
    158      1.14   thorpej 		if (_PROP_ATOMIC_LOAD(&ps->ps_obj.po_refcnt) == 0)
    159      1.14   thorpej 			rb_tree_remove_node(&_prop_string_tree, ps);
    160      1.14   thorpej 		else
    161      1.14   thorpej 			ps = NULL;
    162      1.14   thorpej 		_PROP_MUTEX_UNLOCK(_prop_string_tree_mutex);
    163      1.14   thorpej 
    164      1.14   thorpej 		if (ps == NULL)
    165      1.14   thorpej 			return (_PROP_OBJECT_FREE_DONE);
    166      1.14   thorpej 	}
    167      1.14   thorpej 
    168       1.1   thorpej 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
    169       1.1   thorpej 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
    170       1.8     joerg 	_PROP_POOL_PUT(_prop_string_pool, ps);
    171       1.8     joerg 
    172       1.8     joerg 	return (_PROP_OBJECT_FREE_DONE);
    173       1.1   thorpej }
    174       1.1   thorpej 
    175  1.18.2.1  perseant bool
    176  1.18.2.1  perseant _prop_string_externalize_internal(struct _prop_object_externalize_context *ctx,
    177  1.18.2.1  perseant 				  const struct _prop_object_type_tags *tags,
    178  1.18.2.1  perseant 				  const char *str)
    179  1.18.2.1  perseant {
    180  1.18.2.1  perseant 	if (_prop_extern_append_start_tag(ctx, tags, NULL) == false ||
    181  1.18.2.1  perseant 	    _prop_extern_append_encoded_cstring(ctx, str) == false ||
    182  1.18.2.1  perseant 	    _prop_extern_append_end_tag(ctx, tags) == false) {
    183  1.18.2.1  perseant 		return false;
    184  1.18.2.1  perseant 	}
    185  1.18.2.1  perseant 
    186  1.18.2.1  perseant 	return true;
    187  1.18.2.1  perseant }
    188  1.18.2.1  perseant 
    189       1.7   thorpej static bool
    190       1.1   thorpej _prop_string_externalize(struct _prop_object_externalize_context *ctx,
    191       1.1   thorpej 			 void *v)
    192       1.1   thorpej {
    193       1.1   thorpej 	prop_string_t ps = v;
    194       1.1   thorpej 
    195  1.18.2.1  perseant 	if (ps->ps_size == 0) {
    196  1.18.2.1  perseant 		return _prop_extern_append_empty_tag(ctx,
    197  1.18.2.1  perseant 		    &_prop_string_type_tags);
    198  1.18.2.1  perseant 	}
    199      1.17  riastrad 
    200  1.18.2.1  perseant 	return _prop_string_externalize_internal(ctx, &_prop_string_type_tags,
    201  1.18.2.1  perseant 	    ps->ps_immutable);
    202       1.1   thorpej }
    203       1.1   thorpej 
    204       1.9     joerg /* ARGSUSED */
    205      1.11   thorpej static _prop_object_equals_rv_t
    206       1.9     joerg _prop_string_equals(prop_object_t v1, prop_object_t v2,
    207       1.9     joerg     void **stored_pointer1, void **stored_pointer2,
    208       1.9     joerg     prop_object_t *next_obj1, prop_object_t *next_obj2)
    209       1.2   thorpej {
    210       1.2   thorpej 	prop_string_t str1 = v1;
    211       1.2   thorpej 	prop_string_t str2 = v2;
    212       1.2   thorpej 
    213       1.2   thorpej 	if (str1 == str2)
    214       1.9     joerg 		return (_PROP_OBJECT_EQUALS_TRUE);
    215       1.2   thorpej 	if (str1->ps_size != str2->ps_size)
    216       1.9     joerg 		return (_PROP_OBJECT_EQUALS_FALSE);
    217       1.9     joerg 	if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
    218       1.9     joerg 		return (_PROP_OBJECT_EQUALS_FALSE);
    219       1.9     joerg 	else
    220       1.9     joerg 		return (_PROP_OBJECT_EQUALS_TRUE);
    221       1.2   thorpej }
    222       1.2   thorpej 
    223       1.1   thorpej static prop_string_t
    224      1.14   thorpej _prop_string_alloc(int const flags)
    225       1.1   thorpej {
    226       1.1   thorpej 	prop_string_t ps;
    227       1.1   thorpej 
    228       1.1   thorpej 	ps = _PROP_POOL_GET(_prop_string_pool);
    229       1.1   thorpej 	if (ps != NULL) {
    230       1.2   thorpej 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
    231       1.1   thorpej 
    232       1.1   thorpej 		ps->ps_mutable = NULL;
    233       1.1   thorpej 		ps->ps_size = 0;
    234      1.14   thorpej 		ps->ps_flags = flags;
    235      1.14   thorpej 	}
    236      1.14   thorpej 
    237      1.14   thorpej 	return (ps);
    238      1.14   thorpej }
    239      1.14   thorpej 
    240      1.14   thorpej static prop_string_t
    241      1.14   thorpej _prop_string_instantiate(int const flags, const char * const str,
    242      1.14   thorpej     size_t const len)
    243      1.14   thorpej {
    244      1.14   thorpej 	prop_string_t ps;
    245      1.14   thorpej 
    246      1.14   thorpej 	_PROP_ONCE_RUN(_prop_string_init_once, _prop_string_init);
    247      1.14   thorpej 
    248      1.14   thorpej 	ps = _prop_string_alloc(flags);
    249      1.14   thorpej 	if (ps != NULL) {
    250      1.14   thorpej 		ps->ps_immutable = str;
    251      1.14   thorpej 		ps->ps_size = len;
    252      1.14   thorpej 
    253      1.14   thorpej 		if ((flags & PS_F_MUTABLE) == 0) {
    254      1.14   thorpej 			prop_string_t ops;
    255      1.14   thorpej 
    256      1.14   thorpej 			_PROP_MUTEX_LOCK(_prop_string_tree_mutex);
    257      1.14   thorpej 			ops = rb_tree_insert_node(&_prop_string_tree, ps);
    258      1.14   thorpej 			if (ops != ps) {
    259      1.14   thorpej 				/*
    260      1.14   thorpej 				 * Equivalent string object already exist;
    261      1.14   thorpej 				 * free the new one and return a reference
    262      1.14   thorpej 				 * to the existing object.
    263      1.14   thorpej 				 */
    264      1.14   thorpej 				prop_object_retain(ops);
    265      1.14   thorpej 				_PROP_MUTEX_UNLOCK(_prop_string_tree_mutex);
    266      1.18   thorpej 				if ((flags & PS_F_NOCOPY) == 0) {
    267      1.18   thorpej 					_PROP_FREE(ps->ps_mutable,
    268      1.18   thorpej 					    M_PROP_STRING);
    269      1.18   thorpej 				}
    270      1.14   thorpej 				_PROP_POOL_PUT(_prop_string_pool, ps);
    271      1.14   thorpej 				ps = ops;
    272      1.14   thorpej 			} else {
    273      1.14   thorpej 				_PROP_MUTEX_UNLOCK(_prop_string_tree_mutex);
    274      1.14   thorpej 			}
    275      1.14   thorpej 		}
    276      1.18   thorpej 	} else if ((flags & PS_F_NOCOPY) == 0) {
    277  1.18.2.1  perseant 		_PROP_FREE(_PROP_UNCONST(str), M_PROP_STRING);
    278       1.1   thorpej 	}
    279       1.1   thorpej 
    280       1.1   thorpej 	return (ps);
    281       1.1   thorpej }
    282       1.1   thorpej 
    283      1.14   thorpej _PROP_DEPRECATED(prop_string_create,
    284      1.14   thorpej     "this program uses prop_string_create(); all functions "
    285      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    286  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    287       1.1   thorpej prop_string_create(void)
    288       1.1   thorpej {
    289       1.1   thorpej 
    290      1.14   thorpej 	return (_prop_string_alloc(PS_F_MUTABLE));
    291       1.1   thorpej }
    292       1.1   thorpej 
    293      1.14   thorpej _PROP_DEPRECATED(prop_string_create_cstring,
    294      1.14   thorpej     "this program uses prop_string_create_cstring(); all functions "
    295      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    296  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    297       1.1   thorpej prop_string_create_cstring(const char *str)
    298       1.1   thorpej {
    299       1.1   thorpej 	prop_string_t ps;
    300       1.1   thorpej 	char *cp;
    301       1.1   thorpej 	size_t len;
    302       1.1   thorpej 
    303      1.14   thorpej 	_PROP_ASSERT(str != NULL);
    304      1.14   thorpej 
    305      1.14   thorpej 	ps = _prop_string_alloc(PS_F_MUTABLE);
    306       1.1   thorpej 	if (ps != NULL) {
    307       1.1   thorpej 		len = strlen(str);
    308       1.1   thorpej 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    309       1.1   thorpej 		if (cp == NULL) {
    310       1.8     joerg 			prop_object_release(ps);
    311       1.1   thorpej 			return (NULL);
    312       1.1   thorpej 		}
    313       1.1   thorpej 		strcpy(cp, str);
    314       1.1   thorpej 		ps->ps_mutable = cp;
    315       1.1   thorpej 		ps->ps_size = len;
    316       1.1   thorpej 	}
    317       1.1   thorpej 	return (ps);
    318       1.1   thorpej }
    319       1.1   thorpej 
    320      1.14   thorpej _PROP_DEPRECATED(prop_string_create_cstring_nocopy,
    321      1.14   thorpej     "this program uses prop_string_create_cstring_nocopy(), "
    322      1.14   thorpej     "which is deprecated; use prop_string_create_nocopy() instead.")
    323  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    324      1.14   thorpej prop_string_create_cstring_nocopy(const char *str)
    325      1.14   thorpej {
    326      1.14   thorpej 	return prop_string_create_nocopy(str);
    327      1.14   thorpej }
    328      1.14   thorpej 
    329       1.1   thorpej /*
    330      1.14   thorpej  * prop_string_create_format --
    331      1.14   thorpej  *	Create a string object using the provided format string.
    332       1.1   thorpej  */
    333  1.18.2.1  perseant _PROP_EXPORT prop_string_t __printflike(1, 2)
    334      1.14   thorpej prop_string_create_format(const char *fmt, ...)
    335       1.1   thorpej {
    336      1.14   thorpej 	char *str = NULL;
    337      1.14   thorpej 	int len;
    338      1.15  christos 	size_t nlen;
    339      1.14   thorpej 	va_list ap;
    340      1.14   thorpej 
    341      1.14   thorpej 	_PROP_ASSERT(fmt != NULL);
    342      1.14   thorpej 
    343      1.14   thorpej 	va_start(ap, fmt);
    344      1.14   thorpej 	len = vsnprintf(NULL, 0, fmt, ap);
    345      1.14   thorpej 	va_end(ap);
    346      1.14   thorpej 
    347      1.14   thorpej 	if (len < 0)
    348      1.14   thorpej 		return (NULL);
    349      1.15  christos 	nlen = len + 1;
    350      1.14   thorpej 
    351      1.15  christos 	str = _PROP_MALLOC(nlen, M_PROP_STRING);
    352      1.14   thorpej 	if (str == NULL)
    353      1.14   thorpej 		return (NULL);
    354      1.14   thorpej 
    355      1.14   thorpej 	va_start(ap, fmt);
    356      1.15  christos 	vsnprintf(str, nlen, fmt, ap);
    357      1.14   thorpej 	va_end(ap);
    358      1.14   thorpej 
    359      1.18   thorpej 	return _prop_string_instantiate(0, str, (size_t)len);
    360       1.1   thorpej }
    361       1.1   thorpej 
    362       1.1   thorpej /*
    363      1.14   thorpej  * prop_string_create_copy --
    364      1.14   thorpej  *	Create a string object by coping the provided constant string.
    365      1.14   thorpej  */
    366  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    367      1.14   thorpej prop_string_create_copy(const char *str)
    368      1.14   thorpej {
    369      1.14   thorpej 	return prop_string_create_format("%s", str);
    370      1.14   thorpej }
    371      1.14   thorpej 
    372      1.14   thorpej /*
    373      1.14   thorpej  * prop_string_create_nocopy --
    374      1.14   thorpej  *	Create a string object using the provided external constant
    375      1.14   thorpej  *	string.
    376      1.14   thorpej  */
    377  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    378      1.14   thorpej prop_string_create_nocopy(const char *str)
    379      1.14   thorpej {
    380      1.14   thorpej 
    381      1.14   thorpej 	_PROP_ASSERT(str != NULL);
    382      1.14   thorpej 
    383      1.14   thorpej 	return _prop_string_instantiate(PS_F_NOCOPY, str, strlen(str));
    384      1.14   thorpej }
    385      1.14   thorpej 
    386      1.14   thorpej /*
    387       1.1   thorpej  * prop_string_copy --
    388      1.14   thorpej  *	Copy a string.  This reduces to a retain in the common case.
    389      1.14   thorpej  *	Deprecated mutable string objects must be copied.
    390       1.1   thorpej  */
    391  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    392       1.1   thorpej prop_string_copy(prop_string_t ops)
    393       1.1   thorpej {
    394      1.14   thorpej 	char *cp;
    395       1.1   thorpej 
    396       1.3   thorpej 	if (! prop_object_is_string(ops))
    397       1.3   thorpej 		return (NULL);
    398       1.1   thorpej 
    399      1.14   thorpej 	if ((ops->ps_flags & PS_F_MUTABLE) == 0) {
    400      1.14   thorpej 		prop_object_retain(ops);
    401      1.14   thorpej 		return (ops);
    402       1.1   thorpej 	}
    403      1.14   thorpej 
    404      1.14   thorpej 	cp = _PROP_MALLOC(ops->ps_size + 1, M_PROP_STRING);
    405      1.14   thorpej 	if (cp == NULL)
    406      1.14   thorpej 		return NULL;
    407      1.17  riastrad 
    408      1.14   thorpej 	strcpy(cp, prop_string_contents(ops));
    409      1.14   thorpej 
    410      1.18   thorpej 	return _prop_string_instantiate(PS_F_MUTABLE, cp, ops->ps_size);
    411       1.1   thorpej }
    412       1.1   thorpej 
    413      1.14   thorpej _PROP_DEPRECATED(prop_string_copy_mutable,
    414      1.14   thorpej     "this program uses prop_string_copy_mutable(); all functions "
    415      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    416  1.18.2.1  perseant _PROP_EXPORT prop_string_t
    417       1.1   thorpej prop_string_copy_mutable(prop_string_t ops)
    418       1.1   thorpej {
    419       1.1   thorpej 	char *cp;
    420       1.1   thorpej 
    421       1.3   thorpej 	if (! prop_object_is_string(ops))
    422       1.3   thorpej 		return (NULL);
    423       1.1   thorpej 
    424      1.14   thorpej 	cp = _PROP_MALLOC(ops->ps_size + 1, M_PROP_STRING);
    425      1.14   thorpej 	if (cp == NULL)
    426      1.14   thorpej 		return NULL;
    427      1.17  riastrad 
    428      1.14   thorpej 	strcpy(cp, prop_string_contents(ops));
    429      1.14   thorpej 
    430      1.18   thorpej 	return _prop_string_instantiate(PS_F_MUTABLE, cp, ops->ps_size);
    431       1.1   thorpej }
    432       1.1   thorpej 
    433       1.1   thorpej /*
    434       1.1   thorpej  * prop_string_size --
    435       1.3   thorpej  *	Return the size of the string, not including the terminating NUL.
    436       1.1   thorpej  */
    437  1.18.2.1  perseant _PROP_EXPORT size_t
    438       1.1   thorpej prop_string_size(prop_string_t ps)
    439       1.1   thorpej {
    440       1.1   thorpej 
    441       1.3   thorpej 	if (! prop_object_is_string(ps))
    442       1.3   thorpej 		return (0);
    443       1.3   thorpej 
    444       1.1   thorpej 	return (ps->ps_size);
    445       1.1   thorpej }
    446       1.1   thorpej 
    447       1.1   thorpej /*
    448      1.14   thorpej  * prop_string_value --
    449      1.14   thorpej  *	Returns a pointer to the string object's value.  This pointer
    450      1.14   thorpej  *	remains valid only as long as the string object.
    451      1.14   thorpej  */
    452  1.18.2.1  perseant _PROP_EXPORT const char *
    453      1.14   thorpej prop_string_value(prop_string_t ps)
    454      1.14   thorpej {
    455      1.14   thorpej 
    456      1.14   thorpej 	if (! prop_object_is_string(ps))
    457      1.14   thorpej 		return (NULL);
    458      1.14   thorpej 
    459      1.14   thorpej 	if ((ps->ps_flags & PS_F_MUTABLE) == 0)
    460      1.14   thorpej 		return (ps->ps_immutable);
    461      1.17  riastrad 
    462      1.14   thorpej 	return (prop_string_contents(ps));
    463      1.14   thorpej }
    464      1.14   thorpej 
    465      1.14   thorpej /*
    466      1.14   thorpej  * prop_string_copy_value --
    467      1.14   thorpej  *	Copy the string object's value into the supplied buffer.
    468       1.1   thorpej  */
    469  1.18.2.1  perseant _PROP_EXPORT bool
    470      1.14   thorpej prop_string_copy_value(prop_string_t ps, void *buf, size_t buflen)
    471      1.14   thorpej {
    472      1.14   thorpej 
    473      1.14   thorpej 	if (! prop_object_is_string(ps))
    474      1.14   thorpej 		return (false);
    475      1.14   thorpej 
    476      1.14   thorpej 	if (buf == NULL || buflen < ps->ps_size + 1)
    477      1.14   thorpej 		return (false);
    478      1.17  riastrad 
    479      1.14   thorpej 	strcpy(buf, prop_string_contents(ps));
    480      1.14   thorpej 
    481      1.14   thorpej 	return (true);
    482      1.14   thorpej }
    483      1.14   thorpej 
    484      1.14   thorpej _PROP_DEPRECATED(prop_string_mutable,
    485      1.14   thorpej     "this program uses prop_string_mutable(); all functions "
    486      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    487  1.18.2.1  perseant _PROP_EXPORT bool
    488       1.1   thorpej prop_string_mutable(prop_string_t ps)
    489       1.1   thorpej {
    490       1.1   thorpej 
    491       1.3   thorpej 	if (! prop_object_is_string(ps))
    492       1.7   thorpej 		return (false);
    493       1.3   thorpej 
    494      1.14   thorpej 	return ((ps->ps_flags & PS_F_MUTABLE) != 0);
    495       1.1   thorpej }
    496       1.1   thorpej 
    497      1.14   thorpej _PROP_DEPRECATED(prop_string_cstring,
    498      1.14   thorpej     "this program uses prop_string_cstring(), "
    499      1.14   thorpej     "which is deprecated; use prop_string_copy_value() instead.")
    500  1.18.2.1  perseant _PROP_EXPORT char *
    501       1.1   thorpej prop_string_cstring(prop_string_t ps)
    502       1.1   thorpej {
    503       1.1   thorpej 	char *cp;
    504       1.1   thorpej 
    505       1.3   thorpej 	if (! prop_object_is_string(ps))
    506       1.3   thorpej 		return (NULL);
    507       1.3   thorpej 
    508       1.1   thorpej 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
    509       1.1   thorpej 	if (cp != NULL)
    510       1.1   thorpej 		strcpy(cp, prop_string_contents(ps));
    511      1.17  riastrad 
    512       1.1   thorpej 	return (cp);
    513       1.1   thorpej }
    514       1.1   thorpej 
    515      1.14   thorpej _PROP_DEPRECATED(prop_string_cstring_nocopy,
    516      1.14   thorpej     "this program uses prop_string_cstring_nocopy(), "
    517      1.14   thorpej     "which is deprecated; use prop_string_value() instead.")
    518  1.18.2.1  perseant _PROP_EXPORT const char *
    519       1.1   thorpej prop_string_cstring_nocopy(prop_string_t ps)
    520       1.1   thorpej {
    521       1.1   thorpej 
    522       1.3   thorpej 	if (! prop_object_is_string(ps))
    523       1.3   thorpej 		return (NULL);
    524       1.3   thorpej 
    525       1.1   thorpej 	return (prop_string_contents(ps));
    526       1.1   thorpej }
    527       1.1   thorpej 
    528      1.14   thorpej _PROP_DEPRECATED(prop_string_append,
    529      1.14   thorpej     "this program uses prop_string_append(); all functions "
    530      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    531  1.18.2.1  perseant _PROP_EXPORT bool
    532       1.1   thorpej prop_string_append(prop_string_t dst, prop_string_t src)
    533       1.1   thorpej {
    534       1.1   thorpej 	char *ocp, *cp;
    535       1.1   thorpej 	size_t len;
    536       1.1   thorpej 
    537       1.3   thorpej 	if (! (prop_object_is_string(dst) &&
    538       1.3   thorpej 	       prop_object_is_string(src)))
    539       1.7   thorpej 		return (false);
    540       1.1   thorpej 
    541      1.14   thorpej 	if ((dst->ps_flags & PS_F_MUTABLE) == 0)
    542       1.7   thorpej 		return (false);
    543       1.1   thorpej 
    544       1.1   thorpej 	len = dst->ps_size + src->ps_size;
    545       1.1   thorpej 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    546       1.1   thorpej 	if (cp == NULL)
    547       1.7   thorpej 		return (false);
    548      1.12  christos 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst),
    549       1.1   thorpej 		prop_string_contents(src));
    550       1.1   thorpej 	ocp = dst->ps_mutable;
    551       1.1   thorpej 	dst->ps_mutable = cp;
    552       1.1   thorpej 	dst->ps_size = len;
    553       1.1   thorpej 	if (ocp != NULL)
    554       1.1   thorpej 		_PROP_FREE(ocp, M_PROP_STRING);
    555      1.17  riastrad 
    556       1.7   thorpej 	return (true);
    557       1.1   thorpej }
    558       1.1   thorpej 
    559      1.14   thorpej _PROP_DEPRECATED(prop_string_append_cstring,
    560      1.14   thorpej     "this program uses prop_string_append_cstring(); all functions "
    561      1.14   thorpej     "supporting mutable prop_strings are deprecated.")
    562  1.18.2.1  perseant _PROP_EXPORT bool
    563       1.1   thorpej prop_string_append_cstring(prop_string_t dst, const char *src)
    564       1.1   thorpej {
    565       1.1   thorpej 	char *ocp, *cp;
    566       1.1   thorpej 	size_t len;
    567       1.1   thorpej 
    568       1.3   thorpej 	if (! prop_object_is_string(dst))
    569       1.7   thorpej 		return (false);
    570       1.3   thorpej 
    571       1.1   thorpej 	_PROP_ASSERT(src != NULL);
    572       1.1   thorpej 
    573      1.14   thorpej 	if ((dst->ps_flags & PS_F_MUTABLE) == 0)
    574       1.7   thorpej 		return (false);
    575      1.14   thorpej 
    576       1.1   thorpej 	len = dst->ps_size + strlen(src);
    577       1.1   thorpej 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    578       1.1   thorpej 	if (cp == NULL)
    579       1.7   thorpej 		return (false);
    580      1.12  christos 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst), src);
    581       1.1   thorpej 	ocp = dst->ps_mutable;
    582       1.1   thorpej 	dst->ps_mutable = cp;
    583       1.1   thorpej 	dst->ps_size = len;
    584       1.1   thorpej 	if (ocp != NULL)
    585       1.1   thorpej 		_PROP_FREE(ocp, M_PROP_STRING);
    586      1.17  riastrad 
    587       1.7   thorpej 	return (true);
    588       1.1   thorpej }
    589       1.1   thorpej 
    590       1.1   thorpej /*
    591       1.1   thorpej  * prop_string_equals --
    592       1.7   thorpej  *	Return true if two strings are equivalent.
    593       1.1   thorpej  */
    594  1.18.2.1  perseant _PROP_EXPORT bool
    595       1.1   thorpej prop_string_equals(prop_string_t str1, prop_string_t str2)
    596       1.1   thorpej {
    597       1.9     joerg 	if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
    598       1.9     joerg 		return (false);
    599       1.1   thorpej 
    600       1.9     joerg 	return prop_object_equals(str1, str2);
    601       1.1   thorpej }
    602       1.1   thorpej 
    603       1.1   thorpej /*
    604      1.14   thorpej  * prop_string_equals_string --
    605      1.14   thorpej  *	Return true if the string object is equivalent to the specified
    606       1.1   thorpej  *	C string.
    607       1.1   thorpej  */
    608  1.18.2.1  perseant _PROP_EXPORT bool
    609      1.14   thorpej prop_string_equals_string(prop_string_t ps, const char *cp)
    610       1.1   thorpej {
    611       1.1   thorpej 
    612       1.3   thorpej 	if (! prop_object_is_string(ps))
    613       1.7   thorpej 		return (false);
    614       1.3   thorpej 
    615       1.1   thorpej 	return (strcmp(prop_string_contents(ps), cp) == 0);
    616       1.1   thorpej }
    617       1.1   thorpej 
    618      1.14   thorpej _PROP_DEPRECATED(prop_string_equals_cstring,
    619      1.14   thorpej     "this program uses prop_string_equals_cstring(), "
    620      1.14   thorpej     "which is deprecated; prop_string_equals_string() instead.")
    621  1.18.2.1  perseant _PROP_EXPORT bool
    622      1.14   thorpej prop_string_equals_cstring(prop_string_t ps, const char *cp)
    623      1.14   thorpej {
    624      1.14   thorpej 	return prop_string_equals_string(ps, cp);
    625      1.14   thorpej }
    626      1.14   thorpej 
    627      1.14   thorpej /*
    628      1.14   thorpej  * prop_string_compare --
    629      1.14   thorpej  *	Compare two string objects, using strcmp() semantics.
    630      1.14   thorpej  */
    631  1.18.2.1  perseant _PROP_EXPORT int
    632      1.14   thorpej prop_string_compare(prop_string_t ps1, prop_string_t ps2)
    633      1.14   thorpej {
    634      1.14   thorpej 	if (!prop_object_is_string(ps1) || !prop_object_is_string(ps2))
    635      1.14   thorpej 		return (-666);	/* arbitrary */
    636      1.14   thorpej 
    637      1.14   thorpej 	return (strcmp(prop_string_contents(ps1),
    638      1.14   thorpej 		       prop_string_contents(ps2)));
    639      1.14   thorpej }
    640      1.14   thorpej 
    641      1.14   thorpej /*
    642      1.14   thorpej  * prop_string_compare_string --
    643      1.14   thorpej  *	Compare a string object to the specified C string, using
    644      1.14   thorpej  *	strcmp() semantics.
    645      1.14   thorpej  */
    646  1.18.2.1  perseant _PROP_EXPORT int
    647      1.14   thorpej prop_string_compare_string(prop_string_t ps, const char *cp)
    648      1.14   thorpej {
    649      1.14   thorpej 	if (!prop_object_is_string(ps))
    650      1.14   thorpej 		return (-666);	/* arbitrary */
    651      1.14   thorpej 
    652      1.14   thorpej 	return (strcmp(prop_string_contents(ps), cp));
    653      1.14   thorpej }
    654      1.14   thorpej 
    655       1.1   thorpej /*
    656       1.1   thorpej  * _prop_string_internalize --
    657       1.1   thorpej  *	Parse a <string>...</string> and return the object created from the
    658       1.1   thorpej  *	external representation.
    659       1.1   thorpej  */
    660       1.8     joerg /* ARGSUSED */
    661       1.8     joerg bool
    662       1.8     joerg _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
    663       1.8     joerg     struct _prop_object_internalize_context *ctx)
    664       1.1   thorpej {
    665       1.1   thorpej 	char *str;
    666       1.1   thorpej 	size_t len, alen;
    667       1.1   thorpej 
    668  1.18.2.1  perseant 	/*
    669  1.18.2.1  perseant 	 * N.B. for empty JSON strings, the layer above us has made it
    670  1.18.2.1  perseant 	 * look like XML.
    671  1.18.2.1  perseant 	 */
    672       1.8     joerg 	if (ctx->poic_is_empty_element) {
    673       1.8     joerg 		*obj = prop_string_create();
    674       1.8     joerg 		return (true);
    675       1.8     joerg 	}
    676      1.17  riastrad 
    677       1.1   thorpej 	/* No attributes recognized here. */
    678       1.1   thorpej 	if (ctx->poic_tagattr != NULL)
    679       1.8     joerg 		return (true);
    680       1.1   thorpej 
    681       1.1   thorpej 	/* Compute the length of the result. */
    682  1.18.2.1  perseant 	if (_prop_intern_decode_string(ctx, NULL, 0, &len, NULL) == false)
    683       1.8     joerg 		return (true);
    684      1.17  riastrad 
    685       1.1   thorpej 	str = _PROP_MALLOC(len + 1, M_PROP_STRING);
    686       1.1   thorpej 	if (str == NULL)
    687       1.8     joerg 		return (true);
    688      1.17  riastrad 
    689  1.18.2.1  perseant 	if (_prop_intern_decode_string(ctx, str, len, &alen,
    690  1.18.2.1  perseant 				       &ctx->poic_cp) == false ||
    691       1.1   thorpej 	    alen != len) {
    692       1.1   thorpej 		_PROP_FREE(str, M_PROP_STRING);
    693       1.8     joerg 		return (true);
    694       1.1   thorpej 	}
    695       1.1   thorpej 	str[len] = '\0';
    696       1.1   thorpej 
    697  1.18.2.1  perseant 	if (ctx->poic_format == PROP_FORMAT_JSON) {
    698  1.18.2.1  perseant 		if (*ctx->poic_cp != '"') {
    699  1.18.2.1  perseant 			_PROP_FREE(str, M_PROP_STRING);
    700  1.18.2.1  perseant 			return (true);
    701  1.18.2.1  perseant 		}
    702  1.18.2.1  perseant 		ctx->poic_cp++;
    703  1.18.2.1  perseant 	} else {
    704  1.18.2.1  perseant 		if (_prop_xml_intern_find_tag(ctx, "string",
    705       1.7   thorpej 					      _PROP_TAG_TYPE_END) == false) {
    706  1.18.2.1  perseant 			_PROP_FREE(str, M_PROP_STRING);
    707  1.18.2.1  perseant 			return (true);
    708  1.18.2.1  perseant 		}
    709       1.1   thorpej 	}
    710       1.1   thorpej 
    711      1.18   thorpej 	*obj = _prop_string_instantiate(0, str, len);
    712       1.8     joerg 	return (true);
    713       1.1   thorpej }
    714