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