Home | History | Annotate | Line # | Download | only in libprop
prop_string.c revision 1.8
      1 /*	$NetBSD: prop_string.c,v 1.8 2007/08/16 21:44:08 joerg 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 int		_prop_string_free(prop_stack_t, prop_object_t *);
     62 static bool	_prop_string_externalize(
     63 				struct _prop_object_externalize_context *,
     64 				void *);
     65 static bool	_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 /* ARGSUSED */
     79 static int
     80 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
     81 {
     82 	prop_string_t ps = *obj;
     83 
     84 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
     85 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
     86 	_PROP_POOL_PUT(_prop_string_pool, ps);
     87 
     88 	return (_PROP_OBJECT_FREE_DONE);
     89 }
     90 
     91 static bool
     92 _prop_string_externalize(struct _prop_object_externalize_context *ctx,
     93 			 void *v)
     94 {
     95 	prop_string_t ps = v;
     96 
     97 	if (ps->ps_size == 0)
     98 		return (_prop_object_externalize_empty_tag(ctx, "string"));
     99 
    100 	if (_prop_object_externalize_start_tag(ctx, "string") == false ||
    101 	    _prop_object_externalize_append_encoded_cstring(ctx,
    102 	    					ps->ps_immutable) == false ||
    103 	    _prop_object_externalize_end_tag(ctx, "string") == false)
    104 		return (false);
    105 
    106 	return (true);
    107 }
    108 
    109 static bool
    110 _prop_string_equals(void *v1, void *v2)
    111 {
    112 	prop_string_t str1 = v1;
    113 	prop_string_t str2 = v2;
    114 
    115 	if (! (prop_object_is_string(str1) &&
    116 	       prop_object_is_string(str2)))
    117 		return (false);
    118 
    119 	if (str1 == str2)
    120 		return (true);
    121 	if (str1->ps_size != str2->ps_size)
    122 		return (false);
    123 	return (strcmp(prop_string_contents(str1),
    124 		       prop_string_contents(str2)) == 0);
    125 }
    126 
    127 static prop_string_t
    128 _prop_string_alloc(void)
    129 {
    130 	prop_string_t ps;
    131 
    132 	ps = _PROP_POOL_GET(_prop_string_pool);
    133 	if (ps != NULL) {
    134 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
    135 
    136 		ps->ps_mutable = NULL;
    137 		ps->ps_size = 0;
    138 		ps->ps_flags = 0;
    139 	}
    140 
    141 	return (ps);
    142 }
    143 
    144 /*
    145  * prop_string_create --
    146  *	Create an empty mutable string.
    147  */
    148 prop_string_t
    149 prop_string_create(void)
    150 {
    151 
    152 	return (_prop_string_alloc());
    153 }
    154 
    155 /*
    156  * prop_string_create_cstring --
    157  *	Create a string that contains a copy of the provided C string.
    158  */
    159 prop_string_t
    160 prop_string_create_cstring(const char *str)
    161 {
    162 	prop_string_t ps;
    163 	char *cp;
    164 	size_t len;
    165 
    166 	ps = _prop_string_alloc();
    167 	if (ps != NULL) {
    168 		len = strlen(str);
    169 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    170 		if (cp == NULL) {
    171 			prop_object_release(ps);
    172 			return (NULL);
    173 		}
    174 		strcpy(cp, str);
    175 		ps->ps_mutable = cp;
    176 		ps->ps_size = len;
    177 	}
    178 	return (ps);
    179 }
    180 
    181 /*
    182  * prop_string_create_cstring_nocopy --
    183  *	Create an immutable string that contains a refrence to the
    184  *	provided C string.
    185  */
    186 prop_string_t
    187 prop_string_create_cstring_nocopy(const char *str)
    188 {
    189 	prop_string_t ps;
    190 
    191 	ps = _prop_string_alloc();
    192 	if (ps != NULL) {
    193 		ps->ps_immutable = str;
    194 		ps->ps_size = strlen(str);
    195 		ps->ps_flags |= PS_F_NOCOPY;
    196 	}
    197 	return (ps);
    198 }
    199 
    200 /*
    201  * prop_string_copy --
    202  *	Copy a string.  If the original string is immutable, then the
    203  *	copy is also immutable and references the same external data.
    204  */
    205 prop_string_t
    206 prop_string_copy(prop_string_t ops)
    207 {
    208 	prop_string_t ps;
    209 
    210 	if (! prop_object_is_string(ops))
    211 		return (NULL);
    212 
    213 	ps = _prop_string_alloc();
    214 	if (ps != NULL) {
    215 		ps->ps_size = ops->ps_size;
    216 		ps->ps_flags = ops->ps_flags;
    217 		if (ops->ps_flags & PS_F_NOCOPY)
    218 			ps->ps_immutable = ops->ps_immutable;
    219 		else {
    220 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    221 			if (cp == NULL) {
    222 				prop_object_release(ps);
    223 				return (NULL);
    224 			}
    225 			strcpy(cp, prop_string_contents(ops));
    226 			ps->ps_mutable = cp;
    227 		}
    228 	}
    229 	return (ps);
    230 }
    231 
    232 /*
    233  * prop_string_copy_mutable --
    234  *	Copy a string, always returning a mutable copy.
    235  */
    236 prop_string_t
    237 prop_string_copy_mutable(prop_string_t ops)
    238 {
    239 	prop_string_t ps;
    240 	char *cp;
    241 
    242 	if (! prop_object_is_string(ops))
    243 		return (NULL);
    244 
    245 	ps = _prop_string_alloc();
    246 	if (ps != NULL) {
    247 		ps->ps_size = ops->ps_size;
    248 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
    249 		if (cp == NULL) {
    250 			prop_object_release(ps);
    251 			return (NULL);
    252 		}
    253 		strcpy(cp, prop_string_contents(ops));
    254 		ps->ps_mutable = cp;
    255 	}
    256 	return (ps);
    257 }
    258 
    259 /*
    260  * prop_string_size --
    261  *	Return the size of the string, not including the terminating NUL.
    262  */
    263 size_t
    264 prop_string_size(prop_string_t ps)
    265 {
    266 
    267 	if (! prop_object_is_string(ps))
    268 		return (0);
    269 
    270 	return (ps->ps_size);
    271 }
    272 
    273 /*
    274  * prop_string_mutable --
    275  *	Return true if the string is a mutable string.
    276  */
    277 bool
    278 prop_string_mutable(prop_string_t ps)
    279 {
    280 
    281 	if (! prop_object_is_string(ps))
    282 		return (false);
    283 
    284 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
    285 }
    286 
    287 /*
    288  * prop_string_cstring --
    289  *	Return a copy of the contents of the string as a C string.
    290  *	The string is allocated with the M_TEMP malloc type.
    291  */
    292 char *
    293 prop_string_cstring(prop_string_t ps)
    294 {
    295 	char *cp;
    296 
    297 	if (! prop_object_is_string(ps))
    298 		return (NULL);
    299 
    300 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
    301 	if (cp != NULL)
    302 		strcpy(cp, prop_string_contents(ps));
    303 
    304 	return (cp);
    305 }
    306 
    307 /*
    308  * prop_string_cstring_nocopy --
    309  *	Return an immutable reference to the contents of the string
    310  *	as a C string.
    311  */
    312 const char *
    313 prop_string_cstring_nocopy(prop_string_t ps)
    314 {
    315 
    316 	if (! prop_object_is_string(ps))
    317 		return (NULL);
    318 
    319 	return (prop_string_contents(ps));
    320 }
    321 
    322 /*
    323  * prop_string_append --
    324  *	Append the contents of one string to another.  Returns true
    325  *	upon success.  The destination string must be mutable.
    326  */
    327 bool
    328 prop_string_append(prop_string_t dst, prop_string_t src)
    329 {
    330 	char *ocp, *cp;
    331 	size_t len;
    332 
    333 	if (! (prop_object_is_string(dst) &&
    334 	       prop_object_is_string(src)))
    335 		return (false);
    336 
    337 	if (dst->ps_flags & PS_F_NOCOPY)
    338 		return (false);
    339 
    340 	len = dst->ps_size + src->ps_size;
    341 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    342 	if (cp == NULL)
    343 		return (false);
    344 	sprintf(cp, "%s%s", prop_string_contents(dst),
    345 		prop_string_contents(src));
    346 	ocp = dst->ps_mutable;
    347 	dst->ps_mutable = cp;
    348 	dst->ps_size = len;
    349 	if (ocp != NULL)
    350 		_PROP_FREE(ocp, M_PROP_STRING);
    351 
    352 	return (true);
    353 }
    354 
    355 /*
    356  * prop_string_append_cstring --
    357  *	Append a C string to a string.  Returns true upon success.
    358  *	The destination string must be mutable.
    359  */
    360 bool
    361 prop_string_append_cstring(prop_string_t dst, const char *src)
    362 {
    363 	char *ocp, *cp;
    364 	size_t len;
    365 
    366 	if (! prop_object_is_string(dst))
    367 		return (false);
    368 
    369 	_PROP_ASSERT(src != NULL);
    370 
    371 	if (dst->ps_flags & PS_F_NOCOPY)
    372 		return (false);
    373 
    374 	len = dst->ps_size + strlen(src);
    375 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
    376 	if (cp == NULL)
    377 		return (false);
    378 	sprintf(cp, "%s%s", prop_string_contents(dst), src);
    379 	ocp = dst->ps_mutable;
    380 	dst->ps_mutable = cp;
    381 	dst->ps_size = len;
    382 	if (ocp != NULL)
    383 		_PROP_FREE(ocp, M_PROP_STRING);
    384 
    385 	return (true);
    386 }
    387 
    388 /*
    389  * prop_string_equals --
    390  *	Return true if two strings are equivalent.
    391  */
    392 bool
    393 prop_string_equals(prop_string_t str1, prop_string_t str2)
    394 {
    395 
    396 	return (_prop_string_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