xref: /netbsd-src/common/lib/libprop/prop_string.c (revision 2de962bd804263c16657f586aa00f1704045df8e)
1 /*	$NetBSD: prop_string.c,v 1.10 2008/04/28 20:22:53 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <prop/prop_string.h>
33 #include "prop_object_impl.h"
34 
35 struct _prop_string {
36 	struct _prop_object	ps_obj;
37 	union {
38 		char *		psu_mutable;
39 		const char *	psu_immutable;
40 	} ps_un;
41 #define	ps_mutable		ps_un.psu_mutable
42 #define	ps_immutable		ps_un.psu_immutable
43 	size_t			ps_size;	/* not including \0 */
44 	int			ps_flags;
45 };
46 
47 #define	PS_F_NOCOPY		0x01
48 
49 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
50 
51 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
52 		    "property string container object")
53 
54 static int		_prop_string_free(prop_stack_t, prop_object_t *);
55 static bool	_prop_string_externalize(
56 				struct _prop_object_externalize_context *,
57 				void *);
58 static bool	_prop_string_equals(prop_object_t, prop_object_t,
59 				void **, void **,
60 				prop_object_t *, prop_object_t *);
61 
62 static const struct _prop_object_type _prop_object_type_string = {
63 	.pot_type	=	PROP_TYPE_STRING,
64 	.pot_free	=	_prop_string_free,
65 	.pot_extern	=	_prop_string_externalize,
66 	.pot_equals	=	_prop_string_equals,
67 };
68 
69 #define	prop_object_is_string(x)	\
70 	((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
71 #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
72 
73 /* ARGSUSED */
74 static int
75 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
76 {
77 	prop_string_t ps = *obj;
78 
79 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
80 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
81 	_PROP_POOL_PUT(_prop_string_pool, ps);
82 
83 	return (_PROP_OBJECT_FREE_DONE);
84 }
85 
86 static bool
87 _prop_string_externalize(struct _prop_object_externalize_context *ctx,
88 			 void *v)
89 {
90 	prop_string_t ps = v;
91 
92 	if (ps->ps_size == 0)
93 		return (_prop_object_externalize_empty_tag(ctx, "string"));
94 
95 	if (_prop_object_externalize_start_tag(ctx, "string") == false ||
96 	    _prop_object_externalize_append_encoded_cstring(ctx,
97 	    					ps->ps_immutable) == false ||
98 	    _prop_object_externalize_end_tag(ctx, "string") == false)
99 		return (false);
100 
101 	return (true);
102 }
103 
104 /* ARGSUSED */
105 static bool
106 _prop_string_equals(prop_object_t v1, prop_object_t v2,
107     void **stored_pointer1, void **stored_pointer2,
108     prop_object_t *next_obj1, prop_object_t *next_obj2)
109 {
110 	prop_string_t str1 = v1;
111 	prop_string_t str2 = v2;
112 
113 	if (str1 == str2)
114 		return (_PROP_OBJECT_EQUALS_TRUE);
115 	if (str1->ps_size != str2->ps_size)
116 		return (_PROP_OBJECT_EQUALS_FALSE);
117 	if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
118 		return (_PROP_OBJECT_EQUALS_FALSE);
119 	else
120 		return (_PROP_OBJECT_EQUALS_TRUE);
121 }
122 
123 static prop_string_t
124 _prop_string_alloc(void)
125 {
126 	prop_string_t ps;
127 
128 	ps = _PROP_POOL_GET(_prop_string_pool);
129 	if (ps != NULL) {
130 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
131 
132 		ps->ps_mutable = NULL;
133 		ps->ps_size = 0;
134 		ps->ps_flags = 0;
135 	}
136 
137 	return (ps);
138 }
139 
140 /*
141  * prop_string_create --
142  *	Create an empty mutable string.
143  */
144 prop_string_t
145 prop_string_create(void)
146 {
147 
148 	return (_prop_string_alloc());
149 }
150 
151 /*
152  * prop_string_create_cstring --
153  *	Create a string that contains a copy of the provided C string.
154  */
155 prop_string_t
156 prop_string_create_cstring(const char *str)
157 {
158 	prop_string_t ps;
159 	char *cp;
160 	size_t len;
161 
162 	ps = _prop_string_alloc();
163 	if (ps != NULL) {
164 		len = strlen(str);
165 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
166 		if (cp == NULL) {
167 			prop_object_release(ps);
168 			return (NULL);
169 		}
170 		strcpy(cp, str);
171 		ps->ps_mutable = cp;
172 		ps->ps_size = len;
173 	}
174 	return (ps);
175 }
176 
177 /*
178  * prop_string_create_cstring_nocopy --
179  *	Create an immutable string that contains a refrence to the
180  *	provided C string.
181  */
182 prop_string_t
183 prop_string_create_cstring_nocopy(const char *str)
184 {
185 	prop_string_t ps;
186 
187 	ps = _prop_string_alloc();
188 	if (ps != NULL) {
189 		ps->ps_immutable = str;
190 		ps->ps_size = strlen(str);
191 		ps->ps_flags |= PS_F_NOCOPY;
192 	}
193 	return (ps);
194 }
195 
196 /*
197  * prop_string_copy --
198  *	Copy a string.  If the original string is immutable, then the
199  *	copy is also immutable and references the same external data.
200  */
201 prop_string_t
202 prop_string_copy(prop_string_t ops)
203 {
204 	prop_string_t ps;
205 
206 	if (! prop_object_is_string(ops))
207 		return (NULL);
208 
209 	ps = _prop_string_alloc();
210 	if (ps != NULL) {
211 		ps->ps_size = ops->ps_size;
212 		ps->ps_flags = ops->ps_flags;
213 		if (ops->ps_flags & PS_F_NOCOPY)
214 			ps->ps_immutable = ops->ps_immutable;
215 		else {
216 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
217 			if (cp == NULL) {
218 				prop_object_release(ps);
219 				return (NULL);
220 			}
221 			strcpy(cp, prop_string_contents(ops));
222 			ps->ps_mutable = cp;
223 		}
224 	}
225 	return (ps);
226 }
227 
228 /*
229  * prop_string_copy_mutable --
230  *	Copy a string, always returning a mutable copy.
231  */
232 prop_string_t
233 prop_string_copy_mutable(prop_string_t ops)
234 {
235 	prop_string_t ps;
236 	char *cp;
237 
238 	if (! prop_object_is_string(ops))
239 		return (NULL);
240 
241 	ps = _prop_string_alloc();
242 	if (ps != NULL) {
243 		ps->ps_size = ops->ps_size;
244 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
245 		if (cp == NULL) {
246 			prop_object_release(ps);
247 			return (NULL);
248 		}
249 		strcpy(cp, prop_string_contents(ops));
250 		ps->ps_mutable = cp;
251 	}
252 	return (ps);
253 }
254 
255 /*
256  * prop_string_size --
257  *	Return the size of the string, not including the terminating NUL.
258  */
259 size_t
260 prop_string_size(prop_string_t ps)
261 {
262 
263 	if (! prop_object_is_string(ps))
264 		return (0);
265 
266 	return (ps->ps_size);
267 }
268 
269 /*
270  * prop_string_mutable --
271  *	Return true if the string is a mutable string.
272  */
273 bool
274 prop_string_mutable(prop_string_t ps)
275 {
276 
277 	if (! prop_object_is_string(ps))
278 		return (false);
279 
280 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
281 }
282 
283 /*
284  * prop_string_cstring --
285  *	Return a copy of the contents of the string as a C string.
286  *	The string is allocated with the M_TEMP malloc type.
287  */
288 char *
289 prop_string_cstring(prop_string_t ps)
290 {
291 	char *cp;
292 
293 	if (! prop_object_is_string(ps))
294 		return (NULL);
295 
296 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
297 	if (cp != NULL)
298 		strcpy(cp, prop_string_contents(ps));
299 
300 	return (cp);
301 }
302 
303 /*
304  * prop_string_cstring_nocopy --
305  *	Return an immutable reference to the contents of the string
306  *	as a C string.
307  */
308 const char *
309 prop_string_cstring_nocopy(prop_string_t ps)
310 {
311 
312 	if (! prop_object_is_string(ps))
313 		return (NULL);
314 
315 	return (prop_string_contents(ps));
316 }
317 
318 /*
319  * prop_string_append --
320  *	Append the contents of one string to another.  Returns true
321  *	upon success.  The destination string must be mutable.
322  */
323 bool
324 prop_string_append(prop_string_t dst, prop_string_t src)
325 {
326 	char *ocp, *cp;
327 	size_t len;
328 
329 	if (! (prop_object_is_string(dst) &&
330 	       prop_object_is_string(src)))
331 		return (false);
332 
333 	if (dst->ps_flags & PS_F_NOCOPY)
334 		return (false);
335 
336 	len = dst->ps_size + src->ps_size;
337 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
338 	if (cp == NULL)
339 		return (false);
340 	sprintf(cp, "%s%s", prop_string_contents(dst),
341 		prop_string_contents(src));
342 	ocp = dst->ps_mutable;
343 	dst->ps_mutable = cp;
344 	dst->ps_size = len;
345 	if (ocp != NULL)
346 		_PROP_FREE(ocp, M_PROP_STRING);
347 
348 	return (true);
349 }
350 
351 /*
352  * prop_string_append_cstring --
353  *	Append a C string to a string.  Returns true upon success.
354  *	The destination string must be mutable.
355  */
356 bool
357 prop_string_append_cstring(prop_string_t dst, const char *src)
358 {
359 	char *ocp, *cp;
360 	size_t len;
361 
362 	if (! prop_object_is_string(dst))
363 		return (false);
364 
365 	_PROP_ASSERT(src != NULL);
366 
367 	if (dst->ps_flags & PS_F_NOCOPY)
368 		return (false);
369 
370 	len = dst->ps_size + strlen(src);
371 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
372 	if (cp == NULL)
373 		return (false);
374 	sprintf(cp, "%s%s", prop_string_contents(dst), src);
375 	ocp = dst->ps_mutable;
376 	dst->ps_mutable = cp;
377 	dst->ps_size = len;
378 	if (ocp != NULL)
379 		_PROP_FREE(ocp, M_PROP_STRING);
380 
381 	return (true);
382 }
383 
384 /*
385  * prop_string_equals --
386  *	Return true if two strings are equivalent.
387  */
388 bool
389 prop_string_equals(prop_string_t str1, prop_string_t str2)
390 {
391 	if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
392 		return (false);
393 
394 	return prop_object_equals(str1, str2);
395 }
396 
397 /*
398  * prop_string_equals_cstring --
399  *	Return true if the string is equivalent to the specified
400  *	C string.
401  */
402 bool
403 prop_string_equals_cstring(prop_string_t ps, const char *cp)
404 {
405 
406 	if (! prop_object_is_string(ps))
407 		return (false);
408 
409 	return (strcmp(prop_string_contents(ps), cp) == 0);
410 }
411 
412 /*
413  * _prop_string_internalize --
414  *	Parse a <string>...</string> and return the object created from the
415  *	external representation.
416  */
417 /* ARGSUSED */
418 bool
419 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
420     struct _prop_object_internalize_context *ctx)
421 {
422 	prop_string_t string;
423 	char *str;
424 	size_t len, alen;
425 
426 	if (ctx->poic_is_empty_element) {
427 		*obj = prop_string_create();
428 		return (true);
429 	}
430 
431 	/* No attributes recognized here. */
432 	if (ctx->poic_tagattr != NULL)
433 		return (true);
434 
435 	/* Compute the length of the result. */
436 	if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
437 						   NULL) == false)
438 		return (true);
439 
440 	str = _PROP_MALLOC(len + 1, M_PROP_STRING);
441 	if (str == NULL)
442 		return (true);
443 
444 	if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
445 						   &ctx->poic_cp) == false ||
446 	    alen != len) {
447 		_PROP_FREE(str, M_PROP_STRING);
448 		return (true);
449 	}
450 	str[len] = '\0';
451 
452 	if (_prop_object_internalize_find_tag(ctx, "string",
453 					      _PROP_TAG_TYPE_END) == false) {
454 		_PROP_FREE(str, M_PROP_STRING);
455 		return (true);
456 	}
457 
458 	string = _prop_string_alloc();
459 	if (string == NULL) {
460 		_PROP_FREE(str, M_PROP_STRING);
461 		return (true);
462 	}
463 
464 	string->ps_mutable = str;
465 	string->ps_size = len;
466 	*obj = string;
467 
468 	return (true);
469 }
470