xref: /netbsd-src/common/lib/libprop/prop_string.c (revision 267197ec1eebfcb9810ea27a89625b6ddf68e3e7)
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