xref: /minix3/common/lib/libprop/prop_string.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: prop_string.c,v 1.12 2014/03/26 18:12:46 christos 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_string.h>
336b6d114aSBen Gras #include "prop_object_impl.h"
346b6d114aSBen Gras 
356b6d114aSBen Gras struct _prop_string {
366b6d114aSBen Gras 	struct _prop_object	ps_obj;
376b6d114aSBen Gras 	union {
386b6d114aSBen Gras 		char *		psu_mutable;
396b6d114aSBen Gras 		const char *	psu_immutable;
406b6d114aSBen Gras 	} ps_un;
416b6d114aSBen Gras #define	ps_mutable		ps_un.psu_mutable
426b6d114aSBen Gras #define	ps_immutable		ps_un.psu_immutable
436b6d114aSBen Gras 	size_t			ps_size;	/* not including \0 */
446b6d114aSBen Gras 	int			ps_flags;
456b6d114aSBen Gras };
466b6d114aSBen Gras 
476b6d114aSBen Gras #define	PS_F_NOCOPY		0x01
486b6d114aSBen Gras 
496b6d114aSBen Gras _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
506b6d114aSBen Gras 
516b6d114aSBen Gras _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
526b6d114aSBen Gras 		    "property string container object")
536b6d114aSBen Gras 
546b6d114aSBen Gras static _prop_object_free_rv_t
556b6d114aSBen Gras 		_prop_string_free(prop_stack_t, prop_object_t *);
566b6d114aSBen Gras static bool	_prop_string_externalize(
576b6d114aSBen Gras 				struct _prop_object_externalize_context *,
586b6d114aSBen Gras 				void *);
596b6d114aSBen Gras static _prop_object_equals_rv_t
606b6d114aSBen Gras 		_prop_string_equals(prop_object_t, prop_object_t,
616b6d114aSBen Gras 				    void **, void **,
626b6d114aSBen Gras 				    prop_object_t *, prop_object_t *);
636b6d114aSBen Gras 
646b6d114aSBen Gras static const struct _prop_object_type _prop_object_type_string = {
656b6d114aSBen Gras 	.pot_type	=	PROP_TYPE_STRING,
666b6d114aSBen Gras 	.pot_free	=	_prop_string_free,
676b6d114aSBen Gras 	.pot_extern	=	_prop_string_externalize,
686b6d114aSBen Gras 	.pot_equals	=	_prop_string_equals,
696b6d114aSBen Gras };
706b6d114aSBen Gras 
716b6d114aSBen Gras #define	prop_object_is_string(x)	\
726b6d114aSBen Gras 	((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
736b6d114aSBen Gras #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
746b6d114aSBen Gras 
756b6d114aSBen Gras /* ARGSUSED */
766b6d114aSBen Gras static _prop_object_free_rv_t
_prop_string_free(prop_stack_t stack,prop_object_t * obj)776b6d114aSBen Gras _prop_string_free(prop_stack_t stack, prop_object_t *obj)
786b6d114aSBen Gras {
796b6d114aSBen Gras 	prop_string_t ps = *obj;
806b6d114aSBen Gras 
816b6d114aSBen Gras 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
826b6d114aSBen Gras 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
836b6d114aSBen Gras 	_PROP_POOL_PUT(_prop_string_pool, ps);
846b6d114aSBen Gras 
856b6d114aSBen Gras 	return (_PROP_OBJECT_FREE_DONE);
866b6d114aSBen Gras }
876b6d114aSBen Gras 
886b6d114aSBen Gras static bool
_prop_string_externalize(struct _prop_object_externalize_context * ctx,void * v)896b6d114aSBen Gras _prop_string_externalize(struct _prop_object_externalize_context *ctx,
906b6d114aSBen Gras 			 void *v)
916b6d114aSBen Gras {
926b6d114aSBen Gras 	prop_string_t ps = v;
936b6d114aSBen Gras 
946b6d114aSBen Gras 	if (ps->ps_size == 0)
956b6d114aSBen Gras 		return (_prop_object_externalize_empty_tag(ctx, "string"));
966b6d114aSBen Gras 
976b6d114aSBen Gras 	if (_prop_object_externalize_start_tag(ctx, "string") == false ||
986b6d114aSBen Gras 	    _prop_object_externalize_append_encoded_cstring(ctx,
996b6d114aSBen Gras 	    					ps->ps_immutable) == false ||
1006b6d114aSBen Gras 	    _prop_object_externalize_end_tag(ctx, "string") == false)
1016b6d114aSBen Gras 		return (false);
1026b6d114aSBen Gras 
1036b6d114aSBen Gras 	return (true);
1046b6d114aSBen Gras }
1056b6d114aSBen Gras 
1066b6d114aSBen Gras /* ARGSUSED */
1076b6d114aSBen Gras static _prop_object_equals_rv_t
_prop_string_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)1086b6d114aSBen Gras _prop_string_equals(prop_object_t v1, prop_object_t v2,
1096b6d114aSBen Gras     void **stored_pointer1, void **stored_pointer2,
1106b6d114aSBen Gras     prop_object_t *next_obj1, prop_object_t *next_obj2)
1116b6d114aSBen Gras {
1126b6d114aSBen Gras 	prop_string_t str1 = v1;
1136b6d114aSBen Gras 	prop_string_t str2 = v2;
1146b6d114aSBen Gras 
1156b6d114aSBen Gras 	if (str1 == str2)
1166b6d114aSBen Gras 		return (_PROP_OBJECT_EQUALS_TRUE);
1176b6d114aSBen Gras 	if (str1->ps_size != str2->ps_size)
1186b6d114aSBen Gras 		return (_PROP_OBJECT_EQUALS_FALSE);
1196b6d114aSBen Gras 	if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
1206b6d114aSBen Gras 		return (_PROP_OBJECT_EQUALS_FALSE);
1216b6d114aSBen Gras 	else
1226b6d114aSBen Gras 		return (_PROP_OBJECT_EQUALS_TRUE);
1236b6d114aSBen Gras }
1246b6d114aSBen Gras 
1256b6d114aSBen Gras static prop_string_t
_prop_string_alloc(void)1266b6d114aSBen Gras _prop_string_alloc(void)
1276b6d114aSBen Gras {
1286b6d114aSBen Gras 	prop_string_t ps;
1296b6d114aSBen Gras 
1306b6d114aSBen Gras 	ps = _PROP_POOL_GET(_prop_string_pool);
1316b6d114aSBen Gras 	if (ps != NULL) {
1326b6d114aSBen Gras 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
1336b6d114aSBen Gras 
1346b6d114aSBen Gras 		ps->ps_mutable = NULL;
1356b6d114aSBen Gras 		ps->ps_size = 0;
1366b6d114aSBen Gras 		ps->ps_flags = 0;
1376b6d114aSBen Gras 	}
1386b6d114aSBen Gras 
1396b6d114aSBen Gras 	return (ps);
1406b6d114aSBen Gras }
1416b6d114aSBen Gras 
1426b6d114aSBen Gras /*
1436b6d114aSBen Gras  * prop_string_create --
1446b6d114aSBen Gras  *	Create an empty mutable string.
1456b6d114aSBen Gras  */
1466b6d114aSBen Gras prop_string_t
prop_string_create(void)1476b6d114aSBen Gras prop_string_create(void)
1486b6d114aSBen Gras {
1496b6d114aSBen Gras 
1506b6d114aSBen Gras 	return (_prop_string_alloc());
1516b6d114aSBen Gras }
1526b6d114aSBen Gras 
1536b6d114aSBen Gras /*
1546b6d114aSBen Gras  * prop_string_create_cstring --
1556b6d114aSBen Gras  *	Create a string that contains a copy of the provided C string.
1566b6d114aSBen Gras  */
1576b6d114aSBen Gras prop_string_t
prop_string_create_cstring(const char * str)1586b6d114aSBen Gras prop_string_create_cstring(const char *str)
1596b6d114aSBen Gras {
1606b6d114aSBen Gras 	prop_string_t ps;
1616b6d114aSBen Gras 	char *cp;
1626b6d114aSBen Gras 	size_t len;
1636b6d114aSBen Gras 
1646b6d114aSBen Gras 	ps = _prop_string_alloc();
1656b6d114aSBen Gras 	if (ps != NULL) {
1666b6d114aSBen Gras 		len = strlen(str);
1676b6d114aSBen Gras 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
1686b6d114aSBen Gras 		if (cp == NULL) {
1696b6d114aSBen Gras 			prop_object_release(ps);
1706b6d114aSBen Gras 			return (NULL);
1716b6d114aSBen Gras 		}
1726b6d114aSBen Gras 		strcpy(cp, str);
1736b6d114aSBen Gras 		ps->ps_mutable = cp;
1746b6d114aSBen Gras 		ps->ps_size = len;
1756b6d114aSBen Gras 	}
1766b6d114aSBen Gras 	return (ps);
1776b6d114aSBen Gras }
1786b6d114aSBen Gras 
1796b6d114aSBen Gras /*
1806b6d114aSBen Gras  * prop_string_create_cstring_nocopy --
1816b6d114aSBen Gras  *	Create an immutable string that contains a refrence to the
1826b6d114aSBen Gras  *	provided C string.
1836b6d114aSBen Gras  */
1846b6d114aSBen Gras prop_string_t
prop_string_create_cstring_nocopy(const char * str)1856b6d114aSBen Gras prop_string_create_cstring_nocopy(const char *str)
1866b6d114aSBen Gras {
1876b6d114aSBen Gras 	prop_string_t ps;
1886b6d114aSBen Gras 
1896b6d114aSBen Gras 	ps = _prop_string_alloc();
1906b6d114aSBen Gras 	if (ps != NULL) {
1916b6d114aSBen Gras 		ps->ps_immutable = str;
1926b6d114aSBen Gras 		ps->ps_size = strlen(str);
1936b6d114aSBen Gras 		ps->ps_flags |= PS_F_NOCOPY;
1946b6d114aSBen Gras 	}
1956b6d114aSBen Gras 	return (ps);
1966b6d114aSBen Gras }
1976b6d114aSBen Gras 
1986b6d114aSBen Gras /*
1996b6d114aSBen Gras  * prop_string_copy --
2006b6d114aSBen Gras  *	Copy a string.  If the original string is immutable, then the
2016b6d114aSBen Gras  *	copy is also immutable and references the same external data.
2026b6d114aSBen Gras  */
2036b6d114aSBen Gras prop_string_t
prop_string_copy(prop_string_t ops)2046b6d114aSBen Gras prop_string_copy(prop_string_t ops)
2056b6d114aSBen Gras {
2066b6d114aSBen Gras 	prop_string_t ps;
2076b6d114aSBen Gras 
2086b6d114aSBen Gras 	if (! prop_object_is_string(ops))
2096b6d114aSBen Gras 		return (NULL);
2106b6d114aSBen Gras 
2116b6d114aSBen Gras 	ps = _prop_string_alloc();
2126b6d114aSBen Gras 	if (ps != NULL) {
2136b6d114aSBen Gras 		ps->ps_size = ops->ps_size;
2146b6d114aSBen Gras 		ps->ps_flags = ops->ps_flags;
2156b6d114aSBen Gras 		if (ops->ps_flags & PS_F_NOCOPY)
2166b6d114aSBen Gras 			ps->ps_immutable = ops->ps_immutable;
2176b6d114aSBen Gras 		else {
2186b6d114aSBen Gras 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
2196b6d114aSBen Gras 			if (cp == NULL) {
2206b6d114aSBen Gras 				prop_object_release(ps);
2216b6d114aSBen Gras 				return (NULL);
2226b6d114aSBen Gras 			}
2236b6d114aSBen Gras 			strcpy(cp, prop_string_contents(ops));
2246b6d114aSBen Gras 			ps->ps_mutable = cp;
2256b6d114aSBen Gras 		}
2266b6d114aSBen Gras 	}
2276b6d114aSBen Gras 	return (ps);
2286b6d114aSBen Gras }
2296b6d114aSBen Gras 
2306b6d114aSBen Gras /*
2316b6d114aSBen Gras  * prop_string_copy_mutable --
2326b6d114aSBen Gras  *	Copy a string, always returning a mutable copy.
2336b6d114aSBen Gras  */
2346b6d114aSBen Gras prop_string_t
prop_string_copy_mutable(prop_string_t ops)2356b6d114aSBen Gras prop_string_copy_mutable(prop_string_t ops)
2366b6d114aSBen Gras {
2376b6d114aSBen Gras 	prop_string_t ps;
2386b6d114aSBen Gras 	char *cp;
2396b6d114aSBen Gras 
2406b6d114aSBen Gras 	if (! prop_object_is_string(ops))
2416b6d114aSBen Gras 		return (NULL);
2426b6d114aSBen Gras 
2436b6d114aSBen Gras 	ps = _prop_string_alloc();
2446b6d114aSBen Gras 	if (ps != NULL) {
2456b6d114aSBen Gras 		ps->ps_size = ops->ps_size;
2466b6d114aSBen Gras 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
2476b6d114aSBen Gras 		if (cp == NULL) {
2486b6d114aSBen Gras 			prop_object_release(ps);
2496b6d114aSBen Gras 			return (NULL);
2506b6d114aSBen Gras 		}
2516b6d114aSBen Gras 		strcpy(cp, prop_string_contents(ops));
2526b6d114aSBen Gras 		ps->ps_mutable = cp;
2536b6d114aSBen Gras 	}
2546b6d114aSBen Gras 	return (ps);
2556b6d114aSBen Gras }
2566b6d114aSBen Gras 
2576b6d114aSBen Gras /*
2586b6d114aSBen Gras  * prop_string_size --
2596b6d114aSBen Gras  *	Return the size of the string, not including the terminating NUL.
2606b6d114aSBen Gras  */
2616b6d114aSBen Gras size_t
prop_string_size(prop_string_t ps)2626b6d114aSBen Gras prop_string_size(prop_string_t ps)
2636b6d114aSBen Gras {
2646b6d114aSBen Gras 
2656b6d114aSBen Gras 	if (! prop_object_is_string(ps))
2666b6d114aSBen Gras 		return (0);
2676b6d114aSBen Gras 
2686b6d114aSBen Gras 	return (ps->ps_size);
2696b6d114aSBen Gras }
2706b6d114aSBen Gras 
2716b6d114aSBen Gras /*
2726b6d114aSBen Gras  * prop_string_mutable --
2736b6d114aSBen Gras  *	Return true if the string is a mutable string.
2746b6d114aSBen Gras  */
2756b6d114aSBen Gras bool
prop_string_mutable(prop_string_t ps)2766b6d114aSBen Gras prop_string_mutable(prop_string_t ps)
2776b6d114aSBen Gras {
2786b6d114aSBen Gras 
2796b6d114aSBen Gras 	if (! prop_object_is_string(ps))
2806b6d114aSBen Gras 		return (false);
2816b6d114aSBen Gras 
2826b6d114aSBen Gras 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
2836b6d114aSBen Gras }
2846b6d114aSBen Gras 
2856b6d114aSBen Gras /*
2866b6d114aSBen Gras  * prop_string_cstring --
2876b6d114aSBen Gras  *	Return a copy of the contents of the string as a C string.
2886b6d114aSBen Gras  *	The string is allocated with the M_TEMP malloc type.
2896b6d114aSBen Gras  */
2906b6d114aSBen Gras char *
prop_string_cstring(prop_string_t ps)2916b6d114aSBen Gras prop_string_cstring(prop_string_t ps)
2926b6d114aSBen Gras {
2936b6d114aSBen Gras 	char *cp;
2946b6d114aSBen Gras 
2956b6d114aSBen Gras 	if (! prop_object_is_string(ps))
2966b6d114aSBen Gras 		return (NULL);
2976b6d114aSBen Gras 
2986b6d114aSBen Gras 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
2996b6d114aSBen Gras 	if (cp != NULL)
3006b6d114aSBen Gras 		strcpy(cp, prop_string_contents(ps));
3016b6d114aSBen Gras 
3026b6d114aSBen Gras 	return (cp);
3036b6d114aSBen Gras }
3046b6d114aSBen Gras 
3056b6d114aSBen Gras /*
3066b6d114aSBen Gras  * prop_string_cstring_nocopy --
3076b6d114aSBen Gras  *	Return an immutable reference to the contents of the string
3086b6d114aSBen Gras  *	as a C string.
3096b6d114aSBen Gras  */
3106b6d114aSBen Gras const char *
prop_string_cstring_nocopy(prop_string_t ps)3116b6d114aSBen Gras prop_string_cstring_nocopy(prop_string_t ps)
3126b6d114aSBen Gras {
3136b6d114aSBen Gras 
3146b6d114aSBen Gras 	if (! prop_object_is_string(ps))
3156b6d114aSBen Gras 		return (NULL);
3166b6d114aSBen Gras 
3176b6d114aSBen Gras 	return (prop_string_contents(ps));
3186b6d114aSBen Gras }
3196b6d114aSBen Gras 
3206b6d114aSBen Gras /*
3216b6d114aSBen Gras  * prop_string_append --
3226b6d114aSBen Gras  *	Append the contents of one string to another.  Returns true
3236b6d114aSBen Gras  *	upon success.  The destination string must be mutable.
3246b6d114aSBen Gras  */
3256b6d114aSBen Gras bool
prop_string_append(prop_string_t dst,prop_string_t src)3266b6d114aSBen Gras prop_string_append(prop_string_t dst, prop_string_t src)
3276b6d114aSBen Gras {
3286b6d114aSBen Gras 	char *ocp, *cp;
3296b6d114aSBen Gras 	size_t len;
3306b6d114aSBen Gras 
3316b6d114aSBen Gras 	if (! (prop_object_is_string(dst) &&
3326b6d114aSBen Gras 	       prop_object_is_string(src)))
3336b6d114aSBen Gras 		return (false);
3346b6d114aSBen Gras 
3356b6d114aSBen Gras 	if (dst->ps_flags & PS_F_NOCOPY)
3366b6d114aSBen Gras 		return (false);
3376b6d114aSBen Gras 
3386b6d114aSBen Gras 	len = dst->ps_size + src->ps_size;
3396b6d114aSBen Gras 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
3406b6d114aSBen Gras 	if (cp == NULL)
3416b6d114aSBen Gras 		return (false);
342*0a6a1f1dSLionel Sambuc 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst),
3436b6d114aSBen Gras 		prop_string_contents(src));
3446b6d114aSBen Gras 	ocp = dst->ps_mutable;
3456b6d114aSBen Gras 	dst->ps_mutable = cp;
3466b6d114aSBen Gras 	dst->ps_size = len;
3476b6d114aSBen Gras 	if (ocp != NULL)
3486b6d114aSBen Gras 		_PROP_FREE(ocp, M_PROP_STRING);
3496b6d114aSBen Gras 
3506b6d114aSBen Gras 	return (true);
3516b6d114aSBen Gras }
3526b6d114aSBen Gras 
3536b6d114aSBen Gras /*
3546b6d114aSBen Gras  * prop_string_append_cstring --
3556b6d114aSBen Gras  *	Append a C string to a string.  Returns true upon success.
3566b6d114aSBen Gras  *	The destination string must be mutable.
3576b6d114aSBen Gras  */
3586b6d114aSBen Gras bool
prop_string_append_cstring(prop_string_t dst,const char * src)3596b6d114aSBen Gras prop_string_append_cstring(prop_string_t dst, const char *src)
3606b6d114aSBen Gras {
3616b6d114aSBen Gras 	char *ocp, *cp;
3626b6d114aSBen Gras 	size_t len;
3636b6d114aSBen Gras 
3646b6d114aSBen Gras 	if (! prop_object_is_string(dst))
3656b6d114aSBen Gras 		return (false);
3666b6d114aSBen Gras 
3676b6d114aSBen Gras 	_PROP_ASSERT(src != NULL);
3686b6d114aSBen Gras 
3696b6d114aSBen Gras 	if (dst->ps_flags & PS_F_NOCOPY)
3706b6d114aSBen Gras 		return (false);
3716b6d114aSBen Gras 
3726b6d114aSBen Gras 	len = dst->ps_size + strlen(src);
3736b6d114aSBen Gras 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
3746b6d114aSBen Gras 	if (cp == NULL)
3756b6d114aSBen Gras 		return (false);
376*0a6a1f1dSLionel Sambuc 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst), src);
3776b6d114aSBen Gras 	ocp = dst->ps_mutable;
3786b6d114aSBen Gras 	dst->ps_mutable = cp;
3796b6d114aSBen Gras 	dst->ps_size = len;
3806b6d114aSBen Gras 	if (ocp != NULL)
3816b6d114aSBen Gras 		_PROP_FREE(ocp, M_PROP_STRING);
3826b6d114aSBen Gras 
3836b6d114aSBen Gras 	return (true);
3846b6d114aSBen Gras }
3856b6d114aSBen Gras 
3866b6d114aSBen Gras /*
3876b6d114aSBen Gras  * prop_string_equals --
3886b6d114aSBen Gras  *	Return true if two strings are equivalent.
3896b6d114aSBen Gras  */
3906b6d114aSBen Gras bool
prop_string_equals(prop_string_t str1,prop_string_t str2)3916b6d114aSBen Gras prop_string_equals(prop_string_t str1, prop_string_t str2)
3926b6d114aSBen Gras {
3936b6d114aSBen Gras 	if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
3946b6d114aSBen Gras 		return (false);
3956b6d114aSBen Gras 
3966b6d114aSBen Gras 	return prop_object_equals(str1, str2);
3976b6d114aSBen Gras }
3986b6d114aSBen Gras 
3996b6d114aSBen Gras /*
4006b6d114aSBen Gras  * prop_string_equals_cstring --
4016b6d114aSBen Gras  *	Return true if the string is equivalent to the specified
4026b6d114aSBen Gras  *	C string.
4036b6d114aSBen Gras  */
4046b6d114aSBen Gras bool
prop_string_equals_cstring(prop_string_t ps,const char * cp)4056b6d114aSBen Gras prop_string_equals_cstring(prop_string_t ps, const char *cp)
4066b6d114aSBen Gras {
4076b6d114aSBen Gras 
4086b6d114aSBen Gras 	if (! prop_object_is_string(ps))
4096b6d114aSBen Gras 		return (false);
4106b6d114aSBen Gras 
4116b6d114aSBen Gras 	return (strcmp(prop_string_contents(ps), cp) == 0);
4126b6d114aSBen Gras }
4136b6d114aSBen Gras 
4146b6d114aSBen Gras /*
4156b6d114aSBen Gras  * _prop_string_internalize --
4166b6d114aSBen Gras  *	Parse a <string>...</string> and return the object created from the
4176b6d114aSBen Gras  *	external representation.
4186b6d114aSBen Gras  */
4196b6d114aSBen Gras /* ARGSUSED */
4206b6d114aSBen Gras bool
_prop_string_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)4216b6d114aSBen Gras _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
4226b6d114aSBen Gras     struct _prop_object_internalize_context *ctx)
4236b6d114aSBen Gras {
4246b6d114aSBen Gras 	prop_string_t string;
4256b6d114aSBen Gras 	char *str;
4266b6d114aSBen Gras 	size_t len, alen;
4276b6d114aSBen Gras 
4286b6d114aSBen Gras 	if (ctx->poic_is_empty_element) {
4296b6d114aSBen Gras 		*obj = prop_string_create();
4306b6d114aSBen Gras 		return (true);
4316b6d114aSBen Gras 	}
4326b6d114aSBen Gras 
4336b6d114aSBen Gras 	/* No attributes recognized here. */
4346b6d114aSBen Gras 	if (ctx->poic_tagattr != NULL)
4356b6d114aSBen Gras 		return (true);
4366b6d114aSBen Gras 
4376b6d114aSBen Gras 	/* Compute the length of the result. */
4386b6d114aSBen Gras 	if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
4396b6d114aSBen Gras 						   NULL) == false)
4406b6d114aSBen Gras 		return (true);
4416b6d114aSBen Gras 
4426b6d114aSBen Gras 	str = _PROP_MALLOC(len + 1, M_PROP_STRING);
4436b6d114aSBen Gras 	if (str == NULL)
4446b6d114aSBen Gras 		return (true);
4456b6d114aSBen Gras 
4466b6d114aSBen Gras 	if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
4476b6d114aSBen Gras 						   &ctx->poic_cp) == false ||
4486b6d114aSBen Gras 	    alen != len) {
4496b6d114aSBen Gras 		_PROP_FREE(str, M_PROP_STRING);
4506b6d114aSBen Gras 		return (true);
4516b6d114aSBen Gras 	}
4526b6d114aSBen Gras 	str[len] = '\0';
4536b6d114aSBen Gras 
4546b6d114aSBen Gras 	if (_prop_object_internalize_find_tag(ctx, "string",
4556b6d114aSBen Gras 					      _PROP_TAG_TYPE_END) == false) {
4566b6d114aSBen Gras 		_PROP_FREE(str, M_PROP_STRING);
4576b6d114aSBen Gras 		return (true);
4586b6d114aSBen Gras 	}
4596b6d114aSBen Gras 
4606b6d114aSBen Gras 	string = _prop_string_alloc();
4616b6d114aSBen Gras 	if (string == NULL) {
4626b6d114aSBen Gras 		_PROP_FREE(str, M_PROP_STRING);
4636b6d114aSBen Gras 		return (true);
4646b6d114aSBen Gras 	}
4656b6d114aSBen Gras 
4666b6d114aSBen Gras 	string->ps_mutable = str;
4676b6d114aSBen Gras 	string->ps_size = len;
4686b6d114aSBen Gras 	*obj = string;
4696b6d114aSBen Gras 
4706b6d114aSBen Gras 	return (true);
4716b6d114aSBen Gras }
472