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