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