Home | History | Annotate | Line # | Download | only in libprop
prop_string.c revision 1.12
      1 /*	$NetBSD: prop_string.c,v 1.12 2014/03/26 18:12:46 christos Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2006 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/prop_string.h>
     33 #include "prop_object_impl.h"
     34 
     35 struct _prop_string {
     36 	struct _prop_object	ps_obj;
     37 	union {
     38 		char *		psu_mutable;
     39 		const char *	psu_immutable;
     40 	} ps_un;
     41 #define	ps_mutable		ps_un.psu_mutable
     42 #define	ps_immutable		ps_un.psu_immutable
     43 	size_t			ps_size;	/* not including \0 */
     44 	int			ps_flags;
     45 };
     46 
     47 #define	PS_F_NOCOPY		0x01
     48 
     49 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
     50 
     51 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
     52 		    "property string container object")
     53 
     54 static _prop_object_free_rv_t
     55 		_prop_string_free(prop_stack_t, prop_object_t *);
     56 static bool	_prop_string_externalize(
     57 				struct _prop_object_externalize_context *,
     58 				void *);
     59 static _prop_object_equals_rv_t
     60 		_prop_string_equals(prop_object_t, prop_object_t,
     61 				    void **, void **,
     62 				    prop_object_t *, prop_object_t *);
     63 
     64 static const struct _prop_object_type _prop_object_type_string = {
     65 	.pot_type	=	PROP_TYPE_STRING,
     66 	.pot_free	=	_prop_string_free,
     67 	.pot_extern	=	_prop_string_externalize,
     68 	.pot_equals	=	_prop_string_equals,
     69 };
     70 
     71 #define	prop_object_is_string(x)	\
     72 	((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
     73 #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
     74 
     75 /* ARGSUSED */
     76 static _prop_object_free_rv_t
     77 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
     78 {
     79 	prop_string_t ps = *obj;
     80 
     81 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
     82 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
     83 	_PROP_POOL_PUT(_prop_string_pool, ps);
     84 
     85 	return (_PROP_OBJECT_FREE_DONE);
     86 }
     87 
     88 static bool
     89 _prop_string_externalize(struct _prop_object_externalize_context *ctx,
     90 			 void *v)
     91 {
     92 	prop_string_t ps = v;
     93 
     94 	if (ps->ps_size == 0)
     95 		return (_prop_object_externalize_empty_tag(ctx, "string"));
     96 
     97 	if (_prop_object_externalize_start_tag(ctx, "string") == false ||
     98 	    _prop_object_externalize_append_encoded_cstring(ctx,
     99 	    					ps->ps_immutable) == false ||
    100 	    _prop_object_externalize_end_tag(ctx, "string") == false)
    101 		return (false);
    102 
    103 	return (true);
    104 }
    105 
    106 /* ARGSUSED */
    107 static _prop_object_equals_rv_t
    108 _prop_string_equals(prop_object_t v1, prop_object_t v2,
    109     void **stored_pointer1, void **stored_pointer2,
    110     prop_object_t *next_obj1, prop_object_t *next_obj2)
    111 {
    112 	prop_string_t str1 = v1;
    113 	prop_string_t str2 = v2;
    114 
    115 	if (str1 == str2)
    116 		return (_PROP_OBJECT_EQUALS_TRUE);
    117 	if (str1->ps_size != str2->ps_size)
    118 		return (_PROP_OBJECT_EQUALS_FALSE);
    119 	if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
    120 		return (_PROP_OBJECT_EQUALS_FALSE);
    121 	else
    122 		return (_PROP_OBJECT_EQUALS_TRUE);
    123 }
    124 
    125 static prop_string_t
    126 _prop_string_alloc(void)
    127 {
    128 	prop_string_t ps;
    129 
    130 	ps = _PROP_POOL_GET(_prop_string_pool);
    131 	if (ps != NULL) {
    132 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
    133 
    134 		ps->ps_mutable = NULL;
    135 		ps->ps_size = 0;
    136 		ps->ps_flags = 0;
    137 	}
    138 
    139 	return (ps);
    140 }
    141 
    142 /*
    143  * prop_string_create --
    144  *	Create an empty mutable string.
    145  */
    146 prop_string_t
    147 prop_string_create(void)
    148 {
    149 
    150 	return (_prop_string_alloc());
    151 }
    152 
    153 /*
    154  * prop_string_create_cstring --
    155  *	Create a string that contains a copy of the provided C string.
    156  */
    157 prop_string_t
    158 prop_string_create_cstring(const char *str)
    159 {
    160 	prop_string_t ps;
    161 	char *cp;
    162 	size_t len;
    163 
    164 	ps = _prop_string_alloc();
    165 	if (ps != NULL) {
    166 		len = strlen(str);
    167 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    168 		if (cp == NULL) {
    169 			prop_object_release(ps);
    170 			return (NULL);
    171 		}
    172 		strcpy(cp, str);
    173 		ps->ps_mutable = cp;
    174 		ps->ps_size = len;
    175 	}
    176 	return (ps);
    177 }
    178 
    179 /*
    180  * prop_string_create_cstring_nocopy --
    181  *	Create an immutable string that contains a refrence to the
    182  *	provided C string.
    183  */
    184 prop_string_t
    185 prop_string_create_cstring_nocopy(const char *str)
    186 {
    187 	prop_string_t ps;
    188 
    189 	ps = _prop_string_alloc();
    190 	if (ps != NULL) {
    191 		ps->ps_immutable = str;
    192 		ps->ps_size = strlen(str);
    193 		ps->ps_flags |= PS_F_NOCOPY;
    194 	}
    195 	return (ps);
    196 }
    197 
    198 /*
    199  * prop_string_copy --
    200  *	Copy a string.  If the original string is immutable, then the
    201  *	copy is also immutable and references the same external data.
    202  */
    203 prop_string_t
    204 prop_string_copy(prop_string_t ops)
    205 {
    206 	prop_string_t ps;
    207 
    208 	if (! prop_object_is_string(ops))
    209 		return (NULL);
    210 
    211 	ps = _prop_string_alloc();
    212 	if (ps != NULL) {
    213 		ps->ps_size = ops->ps_size;
    214 		ps->ps_flags = ops->ps_flags;
    215 		if (ops->ps_flags & PS_F_NOCOPY)
    216 			ps->ps_immutable = ops->ps_immutable;
    217 		else {
    218 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    219 			if (cp == NULL) {
    220 				prop_object_release(ps);
    221 				return (NULL);
    222 			}
    223 			strcpy(cp, prop_string_contents(ops));
    224 			ps->ps_mutable = cp;
    225 		}
    226 	}
    227 	return (ps);
    228 }
    229 
    230 /*
    231  * prop_string_copy_mutable --
    232  *	Copy a string, always returning a mutable copy.
    233  */
    234 prop_string_t
    235 prop_string_copy_mutable(prop_string_t ops)
    236 {
    237 	prop_string_t ps;
    238 	char *cp;
    239 
    240 	if (! prop_object_is_string(ops))
    241 		return (NULL);
    242 
    243 	ps = _prop_string_alloc();
    244 	if (ps != NULL) {
    245 		ps->ps_size = ops->ps_size;
    246 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    247 		if (cp == NULL) {
    248 			prop_object_release(ps);
    249 			return (NULL);
    250 		}
    251 		strcpy(cp, prop_string_contents(ops));
    252 		ps->ps_mutable = cp;
    253 	}
    254 	return (ps);
    255 }
    256 
    257 /*
    258  * prop_string_size --
    259  *	Return the size of the string, not including the terminating NUL.
    260  */
    261 size_t
    262 prop_string_size(prop_string_t ps)
    263 {
    264 
    265 	if (! prop_object_is_string(ps))
    266 		return (0);
    267 
    268 	return (ps->ps_size);
    269 }
    270 
    271 /*
    272  * prop_string_mutable --
    273  *	Return true if the string is a mutable string.
    274  */
    275 bool
    276 prop_string_mutable(prop_string_t ps)
    277 {
    278 
    279 	if (! prop_object_is_string(ps))
    280 		return (false);
    281 
    282 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
    283 }
    284 
    285 /*
    286  * prop_string_cstring --
    287  *	Return a copy of the contents of the string as a C string.
    288  *	The string is allocated with the M_TEMP malloc type.
    289  */
    290 char *
    291 prop_string_cstring(prop_string_t ps)
    292 {
    293 	char *cp;
    294 
    295 	if (! prop_object_is_string(ps))
    296 		return (NULL);
    297 
    298 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
    299 	if (cp != NULL)
    300 		strcpy(cp, prop_string_contents(ps));
    301 
    302 	return (cp);
    303 }
    304 
    305 /*
    306  * prop_string_cstring_nocopy --
    307  *	Return an immutable reference to the contents of the string
    308  *	as a C string.
    309  */
    310 const char *
    311 prop_string_cstring_nocopy(prop_string_t ps)
    312 {
    313 
    314 	if (! prop_object_is_string(ps))
    315 		return (NULL);
    316 
    317 	return (prop_string_contents(ps));
    318 }
    319 
    320 /*
    321  * prop_string_append --
    322  *	Append the contents of one string to another.  Returns true
    323  *	upon success.  The destination string must be mutable.
    324  */
    325 bool
    326 prop_string_append(prop_string_t dst, prop_string_t src)
    327 {
    328 	char *ocp, *cp;
    329 	size_t len;
    330 
    331 	if (! (prop_object_is_string(dst) &&
    332 	       prop_object_is_string(src)))
    333 		return (false);
    334 
    335 	if (dst->ps_flags & PS_F_NOCOPY)
    336 		return (false);
    337 
    338 	len = dst->ps_size + src->ps_size;
    339 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    340 	if (cp == NULL)
    341 		return (false);
    342 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst),
    343 		prop_string_contents(src));
    344 	ocp = dst->ps_mutable;
    345 	dst->ps_mutable = cp;
    346 	dst->ps_size = len;
    347 	if (ocp != NULL)
    348 		_PROP_FREE(ocp, M_PROP_STRING);
    349 
    350 	return (true);
    351 }
    352 
    353 /*
    354  * prop_string_append_cstring --
    355  *	Append a C string to a string.  Returns true upon success.
    356  *	The destination string must be mutable.
    357  */
    358 bool
    359 prop_string_append_cstring(prop_string_t dst, const char *src)
    360 {
    361 	char *ocp, *cp;
    362 	size_t len;
    363 
    364 	if (! prop_object_is_string(dst))
    365 		return (false);
    366 
    367 	_PROP_ASSERT(src != NULL);
    368 
    369 	if (dst->ps_flags & PS_F_NOCOPY)
    370 		return (false);
    371 
    372 	len = dst->ps_size + strlen(src);
    373 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    374 	if (cp == NULL)
    375 		return (false);
    376 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst), src);
    377 	ocp = dst->ps_mutable;
    378 	dst->ps_mutable = cp;
    379 	dst->ps_size = len;
    380 	if (ocp != NULL)
    381 		_PROP_FREE(ocp, M_PROP_STRING);
    382 
    383 	return (true);
    384 }
    385 
    386 /*
    387  * prop_string_equals --
    388  *	Return true if two strings are equivalent.
    389  */
    390 bool
    391 prop_string_equals(prop_string_t str1, prop_string_t str2)
    392 {
    393 	if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
    394 		return (false);
    395 
    396 	return prop_object_equals(str1, str2);
    397 }
    398 
    399 /*
    400  * prop_string_equals_cstring --
    401  *	Return true if the string is equivalent to the specified
    402  *	C string.
    403  */
    404 bool
    405 prop_string_equals_cstring(prop_string_t ps, const char *cp)
    406 {
    407 
    408 	if (! prop_object_is_string(ps))
    409 		return (false);
    410 
    411 	return (strcmp(prop_string_contents(ps), cp) == 0);
    412 }
    413 
    414 /*
    415  * _prop_string_internalize --
    416  *	Parse a <string>...</string> and return the object created from the
    417  *	external representation.
    418  */
    419 /* ARGSUSED */
    420 bool
    421 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
    422     struct _prop_object_internalize_context *ctx)
    423 {
    424 	prop_string_t string;
    425 	char *str;
    426 	size_t len, alen;
    427 
    428 	if (ctx->poic_is_empty_element) {
    429 		*obj = prop_string_create();
    430 		return (true);
    431 	}
    432 
    433 	/* No attributes recognized here. */
    434 	if (ctx->poic_tagattr != NULL)
    435 		return (true);
    436 
    437 	/* Compute the length of the result. */
    438 	if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
    439 						   NULL) == false)
    440 		return (true);
    441 
    442 	str = _PROP_MALLOC(len + 1, M_PROP_STRING);
    443 	if (str == NULL)
    444 		return (true);
    445 
    446 	if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
    447 						   &ctx->poic_cp) == false ||
    448 	    alen != len) {
    449 		_PROP_FREE(str, M_PROP_STRING);
    450 		return (true);
    451 	}
    452 	str[len] = '\0';
    453 
    454 	if (_prop_object_internalize_find_tag(ctx, "string",
    455 					      _PROP_TAG_TYPE_END) == false) {
    456 		_PROP_FREE(str, M_PROP_STRING);
    457 		return (true);
    458 	}
    459 
    460 	string = _prop_string_alloc();
    461 	if (string == NULL) {
    462 		_PROP_FREE(str, M_PROP_STRING);
    463 		return (true);
    464 	}
    465 
    466 	string->ps_mutable = str;
    467 	string->ps_size = len;
    468 	*obj = string;
    469 
    470 	return (true);
    471 }
    472