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