Home | History | Annotate | Line # | Download | only in libprop
prop_string.c revision 1.2
      1 /*	$NetBSD: prop_string.c,v 1.2 2006/05/18 03:05:19 thorpej 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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *      This product includes software developed by the NetBSD
     21  *      Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <prop/prop_string.h>
     40 #include "prop_object_impl.h"
     41 
     42 struct _prop_string {
     43 	struct _prop_object	ps_obj;
     44 	union {
     45 		char *		psu_mutable;
     46 		const char *	psu_immutable;
     47 	} ps_un;
     48 #define	ps_mutable		ps_un.psu_mutable
     49 #define	ps_immutable		ps_un.psu_immutable
     50 	size_t			ps_size;	/* not including \0 */
     51 	int			ps_flags;
     52 };
     53 
     54 #define	PS_F_NOCOPY		0x01
     55 
     56 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
     57 
     58 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
     59 		    "property string container object")
     60 
     61 static void		_prop_string_free(void *);
     62 static boolean_t	_prop_string_externalize(
     63 				struct _prop_object_externalize_context *,
     64 				void *);
     65 static boolean_t	_prop_string_equals(void *, void *);
     66 
     67 static const struct _prop_object_type _prop_object_type_string = {
     68 	.pot_type	=	PROP_TYPE_STRING,
     69 	.pot_free	=	_prop_string_free,
     70 	.pot_extern	=	_prop_string_externalize,
     71 	.pot_equals	=	_prop_string_equals,
     72 };
     73 
     74 #define	prop_object_is_string(x)	\
     75 	((x)->ps_obj.po_type == &_prop_object_type_string)
     76 #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
     77 
     78 static void
     79 _prop_string_free(void *v)
     80 {
     81 	prop_string_t ps = v;
     82 
     83 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
     84 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
     85 	_PROP_POOL_PUT(_prop_string_pool, v);
     86 }
     87 
     88 static boolean_t
     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 static boolean_t
    107 _prop_string_equals(void *v1, void *v2)
    108 {
    109 	prop_string_t str1 = v1;
    110 	prop_string_t str2 = v2;
    111 
    112 	_PROP_ASSERT(prop_object_is_string(str1));
    113 	_PROP_ASSERT(prop_object_is_string(str2));
    114 	if (str1 == str2)
    115 		return (TRUE);
    116 	if (str1->ps_size != str2->ps_size)
    117 		return (FALSE);
    118 	return (strcmp(prop_string_contents(str1),
    119 		       prop_string_contents(str2)) == 0);
    120 }
    121 
    122 static prop_string_t
    123 _prop_string_alloc(void)
    124 {
    125 	prop_string_t ps;
    126 
    127 	ps = _PROP_POOL_GET(_prop_string_pool);
    128 	if (ps != NULL) {
    129 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
    130 
    131 		ps->ps_mutable = NULL;
    132 		ps->ps_size = 0;
    133 		ps->ps_flags = 0;
    134 	}
    135 
    136 	return (ps);
    137 }
    138 
    139 /*
    140  * prop_string_create --
    141  *	Create an empty mutable string.
    142  */
    143 prop_string_t
    144 prop_string_create(void)
    145 {
    146 
    147 	return (_prop_string_alloc());
    148 }
    149 
    150 /*
    151  * prop_string_create_cstring --
    152  *	Create a string that contains a copy of the provided C string.
    153  */
    154 prop_string_t
    155 prop_string_create_cstring(const char *str)
    156 {
    157 	prop_string_t ps;
    158 	char *cp;
    159 	size_t len;
    160 
    161 	ps = _prop_string_alloc();
    162 	if (ps != NULL) {
    163 		len = strlen(str);
    164 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    165 		if (cp == NULL) {
    166 			_prop_string_free(ps);
    167 			return (NULL);
    168 		}
    169 		strcpy(cp, str);
    170 		ps->ps_mutable = cp;
    171 		ps->ps_size = len;
    172 	}
    173 	return (ps);
    174 }
    175 
    176 /*
    177  * prop_string_create_cstring_nocopy --
    178  *	Create an immutable string that contains a refrence to the
    179  *	provided C string.
    180  */
    181 prop_string_t
    182 prop_string_create_cstring_nocopy(const char *str)
    183 {
    184 	prop_string_t ps;
    185 
    186 	ps = _prop_string_alloc();
    187 	if (ps != NULL) {
    188 		ps->ps_immutable = str;
    189 		ps->ps_size = strlen(str);
    190 		ps->ps_flags |= PS_F_NOCOPY;
    191 	}
    192 	return (ps);
    193 }
    194 
    195 /*
    196  * prop_string_copy --
    197  *	Copy a string.  If the original string is immutable, then the
    198  *	copy is also immutable and references the same external data.
    199  */
    200 prop_string_t
    201 prop_string_copy(prop_string_t ops)
    202 {
    203 	prop_string_t ps;
    204 
    205 	_PROP_ASSERT(prop_object_is_string(ops));
    206 
    207 	ps = _prop_string_alloc();
    208 	if (ps != NULL) {
    209 		ps->ps_size = ops->ps_size;
    210 		ps->ps_flags = ops->ps_flags;
    211 		if (ops->ps_flags & PS_F_NOCOPY)
    212 			ps->ps_immutable = ops->ps_immutable;
    213 		else {
    214 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    215 			if (cp == NULL) {
    216 				_prop_string_free(ps);
    217 				return (NULL);
    218 			}
    219 			strcpy(cp, prop_string_contents(ops));
    220 			ps->ps_mutable = cp;
    221 		}
    222 	}
    223 	return (ps);
    224 }
    225 
    226 /*
    227  * prop_string_copy_mutable --
    228  *	Copy a string, always returning a mutable copy.
    229  */
    230 prop_string_t
    231 prop_string_copy_mutable(prop_string_t ops)
    232 {
    233 	prop_string_t ps;
    234 	char *cp;
    235 
    236 	_PROP_ASSERT(prop_object_is_string(ops));
    237 
    238 	ps = _prop_string_alloc();
    239 	if (ps != NULL) {
    240 		ps->ps_size = ops->ps_size;
    241 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    242 		if (cp == NULL) {
    243 			_prop_string_free(ps);
    244 			return (NULL);
    245 		}
    246 		strcpy(cp, prop_string_contents(ops));
    247 		ps->ps_mutable = cp;
    248 	}
    249 	return (ps);
    250 }
    251 
    252 /*
    253  * prop_string_size --
    254  *	Return the size of the string, no including the terminating NUL.
    255  */
    256 size_t
    257 prop_string_size(prop_string_t ps)
    258 {
    259 
    260 	_PROP_ASSERT(prop_object_is_string(ps));
    261 	return (ps->ps_size);
    262 }
    263 
    264 /*
    265  * prop_string_mutable --
    266  *	Return TRUE if the string is a mutable string.
    267  */
    268 boolean_t
    269 prop_string_mutable(prop_string_t ps)
    270 {
    271 
    272 	_PROP_ASSERT(prop_object_is_string(ps));
    273 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
    274 }
    275 
    276 /*
    277  * prop_string_cstring --
    278  *	Return a copy of the contents of the string as a C string.
    279  *	The string is allocated with the M_TEMP malloc type.
    280  */
    281 char *
    282 prop_string_cstring(prop_string_t ps)
    283 {
    284 	char *cp;
    285 
    286 	_PROP_ASSERT(prop_object_is_string(ps));
    287 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
    288 	if (cp != NULL)
    289 		strcpy(cp, prop_string_contents(ps));
    290 
    291 	return (cp);
    292 }
    293 
    294 /*
    295  * prop_string_cstring_nocopy --
    296  *	Return an immutable reference to the contents of the string
    297  *	as a C string.
    298  */
    299 const char *
    300 prop_string_cstring_nocopy(prop_string_t ps)
    301 {
    302 
    303 	_PROP_ASSERT(prop_object_is_string(ps));
    304 	return (prop_string_contents(ps));
    305 }
    306 
    307 /*
    308  * prop_string_append --
    309  *	Append the contents of one string to another.  Returns TRUE
    310  *	upon success.  The destination string must be mutable.
    311  */
    312 boolean_t
    313 prop_string_append(prop_string_t dst, prop_string_t src)
    314 {
    315 	char *ocp, *cp;
    316 	size_t len;
    317 
    318 	_PROP_ASSERT(prop_object_is_string(dst));
    319 	_PROP_ASSERT(prop_object_is_string(src));
    320 
    321 	if (dst->ps_flags & PS_F_NOCOPY)
    322 		return (FALSE);
    323 
    324 	len = dst->ps_size + src->ps_size;
    325 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    326 	if (cp == NULL)
    327 		return (FALSE);
    328 	sprintf(cp, "%s%s", prop_string_contents(dst),
    329 		prop_string_contents(src));
    330 	ocp = dst->ps_mutable;
    331 	dst->ps_mutable = cp;
    332 	dst->ps_size = len;
    333 	if (ocp != NULL)
    334 		_PROP_FREE(ocp, M_PROP_STRING);
    335 
    336 	return (TRUE);
    337 }
    338 
    339 /*
    340  * prop_string_append_cstring --
    341  *	Append a C string to a string.  Returns TRUE upon success.
    342  *	The destination string must be mutable.
    343  */
    344 boolean_t
    345 prop_string_append_cstring(prop_string_t dst, const char *src)
    346 {
    347 	char *ocp, *cp;
    348 	size_t len;
    349 
    350 	_PROP_ASSERT(src != NULL);
    351 	_PROP_ASSERT(prop_object_is_string(dst));
    352 
    353 	if (dst->ps_flags & PS_F_NOCOPY)
    354 		return (FALSE);
    355 
    356 	len = dst->ps_size + strlen(src);
    357 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    358 	if (cp == NULL)
    359 		return (FALSE);
    360 	sprintf(cp, "%s%s", prop_string_contents(dst), src);
    361 	ocp = dst->ps_mutable;
    362 	dst->ps_mutable = cp;
    363 	dst->ps_size = len;
    364 	if (ocp != NULL)
    365 		_PROP_FREE(ocp, M_PROP_STRING);
    366 
    367 	return (TRUE);
    368 }
    369 
    370 /*
    371  * prop_string_equals --
    372  *	Return TRUE if two strings are equivalent.
    373  */
    374 boolean_t
    375 prop_string_equals(prop_string_t str1, prop_string_t str2)
    376 {
    377 
    378 	return (_prop_string_equals(str1, str2));
    379 }
    380 
    381 /*
    382  * prop_string_equals_cstring --
    383  *	Return TRUE if the string is equivalent to the specified
    384  *	C string.
    385  */
    386 boolean_t
    387 prop_string_equals_cstring(prop_string_t ps, const char *cp)
    388 {
    389 
    390 	_PROP_ASSERT(prop_object_is_string(ps));
    391 	return (strcmp(prop_string_contents(ps), cp) == 0);
    392 }
    393 
    394 /*
    395  * _prop_string_internalize --
    396  *	Parse a <string>...</string> and return the object created from the
    397  *	external representation.
    398  */
    399 prop_object_t
    400 _prop_string_internalize(struct _prop_object_internalize_context *ctx)
    401 {
    402 	prop_string_t string;
    403 	char *str;
    404 	size_t len, alen;
    405 
    406 	if (ctx->poic_is_empty_element)
    407 		return (prop_string_create());
    408 
    409 	/* No attributes recognized here. */
    410 	if (ctx->poic_tagattr != NULL)
    411 		return (NULL);
    412 
    413 	/* Compute the length of the result. */
    414 	if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
    415 						   NULL) == FALSE)
    416 		return (NULL);
    417 
    418 	str = _PROP_MALLOC(len + 1, M_PROP_STRING);
    419 	if (str == NULL)
    420 		return (NULL);
    421 
    422 	if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
    423 						   &ctx->poic_cp) == FALSE ||
    424 	    alen != len) {
    425 		_PROP_FREE(str, M_PROP_STRING);
    426 		return (NULL);
    427 	}
    428 	str[len] = '\0';
    429 
    430 	if (_prop_object_internalize_find_tag(ctx, "string",
    431 					      _PROP_TAG_TYPE_END) == FALSE) {
    432 		_PROP_FREE(str, M_PROP_STRING);
    433 		return (NULL);
    434 	}
    435 
    436 	string = _prop_string_alloc();
    437 	if (string == NULL) {
    438 		_PROP_FREE(str, M_PROP_STRING);
    439 		return (NULL);
    440 	}
    441 
    442 	string->ps_mutable = str;
    443 	string->ps_size = len;
    444 
    445 	return (string);
    446 }
    447