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