xref: /minix/common/lib/libprop/prop_string.c (revision 0a6a1f1d)
1 /*	$NetBSD: prop_string.c,v 1.12 2014/03/26 18:12:46 christos 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 _prop_object_free_rv_t
55 		_prop_string_free(prop_stack_t, prop_object_t *);
56 static bool	_prop_string_externalize(
57 				struct _prop_object_externalize_context *,
58 				void *);
59 static _prop_object_equals_rv_t
60 		_prop_string_equals(prop_object_t, prop_object_t,
61 				    void **, void **,
62 				    prop_object_t *, prop_object_t *);
63 
64 static const struct _prop_object_type _prop_object_type_string = {
65 	.pot_type	=	PROP_TYPE_STRING,
66 	.pot_free	=	_prop_string_free,
67 	.pot_extern	=	_prop_string_externalize,
68 	.pot_equals	=	_prop_string_equals,
69 };
70 
71 #define	prop_object_is_string(x)	\
72 	((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
73 #define	prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
74 
75 /* ARGSUSED */
76 static _prop_object_free_rv_t
_prop_string_free(prop_stack_t stack,prop_object_t * obj)77 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
78 {
79 	prop_string_t ps = *obj;
80 
81 	if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
82 	    	_PROP_FREE(ps->ps_mutable, M_PROP_STRING);
83 	_PROP_POOL_PUT(_prop_string_pool, ps);
84 
85 	return (_PROP_OBJECT_FREE_DONE);
86 }
87 
88 static bool
_prop_string_externalize(struct _prop_object_externalize_context * ctx,void * v)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 /* ARGSUSED */
107 static _prop_object_equals_rv_t
_prop_string_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)108 _prop_string_equals(prop_object_t v1, prop_object_t v2,
109     void **stored_pointer1, void **stored_pointer2,
110     prop_object_t *next_obj1, prop_object_t *next_obj2)
111 {
112 	prop_string_t str1 = v1;
113 	prop_string_t str2 = v2;
114 
115 	if (str1 == str2)
116 		return (_PROP_OBJECT_EQUALS_TRUE);
117 	if (str1->ps_size != str2->ps_size)
118 		return (_PROP_OBJECT_EQUALS_FALSE);
119 	if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
120 		return (_PROP_OBJECT_EQUALS_FALSE);
121 	else
122 		return (_PROP_OBJECT_EQUALS_TRUE);
123 }
124 
125 static prop_string_t
_prop_string_alloc(void)126 _prop_string_alloc(void)
127 {
128 	prop_string_t ps;
129 
130 	ps = _PROP_POOL_GET(_prop_string_pool);
131 	if (ps != NULL) {
132 		_prop_object_init(&ps->ps_obj, &_prop_object_type_string);
133 
134 		ps->ps_mutable = NULL;
135 		ps->ps_size = 0;
136 		ps->ps_flags = 0;
137 	}
138 
139 	return (ps);
140 }
141 
142 /*
143  * prop_string_create --
144  *	Create an empty mutable string.
145  */
146 prop_string_t
prop_string_create(void)147 prop_string_create(void)
148 {
149 
150 	return (_prop_string_alloc());
151 }
152 
153 /*
154  * prop_string_create_cstring --
155  *	Create a string that contains a copy of the provided C string.
156  */
157 prop_string_t
prop_string_create_cstring(const char * str)158 prop_string_create_cstring(const char *str)
159 {
160 	prop_string_t ps;
161 	char *cp;
162 	size_t len;
163 
164 	ps = _prop_string_alloc();
165 	if (ps != NULL) {
166 		len = strlen(str);
167 		cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
168 		if (cp == NULL) {
169 			prop_object_release(ps);
170 			return (NULL);
171 		}
172 		strcpy(cp, str);
173 		ps->ps_mutable = cp;
174 		ps->ps_size = len;
175 	}
176 	return (ps);
177 }
178 
179 /*
180  * prop_string_create_cstring_nocopy --
181  *	Create an immutable string that contains a refrence to the
182  *	provided C string.
183  */
184 prop_string_t
prop_string_create_cstring_nocopy(const char * str)185 prop_string_create_cstring_nocopy(const char *str)
186 {
187 	prop_string_t ps;
188 
189 	ps = _prop_string_alloc();
190 	if (ps != NULL) {
191 		ps->ps_immutable = str;
192 		ps->ps_size = strlen(str);
193 		ps->ps_flags |= PS_F_NOCOPY;
194 	}
195 	return (ps);
196 }
197 
198 /*
199  * prop_string_copy --
200  *	Copy a string.  If the original string is immutable, then the
201  *	copy is also immutable and references the same external data.
202  */
203 prop_string_t
prop_string_copy(prop_string_t ops)204 prop_string_copy(prop_string_t ops)
205 {
206 	prop_string_t ps;
207 
208 	if (! prop_object_is_string(ops))
209 		return (NULL);
210 
211 	ps = _prop_string_alloc();
212 	if (ps != NULL) {
213 		ps->ps_size = ops->ps_size;
214 		ps->ps_flags = ops->ps_flags;
215 		if (ops->ps_flags & PS_F_NOCOPY)
216 			ps->ps_immutable = ops->ps_immutable;
217 		else {
218 			char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
219 			if (cp == NULL) {
220 				prop_object_release(ps);
221 				return (NULL);
222 			}
223 			strcpy(cp, prop_string_contents(ops));
224 			ps->ps_mutable = cp;
225 		}
226 	}
227 	return (ps);
228 }
229 
230 /*
231  * prop_string_copy_mutable --
232  *	Copy a string, always returning a mutable copy.
233  */
234 prop_string_t
prop_string_copy_mutable(prop_string_t ops)235 prop_string_copy_mutable(prop_string_t ops)
236 {
237 	prop_string_t ps;
238 	char *cp;
239 
240 	if (! prop_object_is_string(ops))
241 		return (NULL);
242 
243 	ps = _prop_string_alloc();
244 	if (ps != NULL) {
245 		ps->ps_size = ops->ps_size;
246 		cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
247 		if (cp == NULL) {
248 			prop_object_release(ps);
249 			return (NULL);
250 		}
251 		strcpy(cp, prop_string_contents(ops));
252 		ps->ps_mutable = cp;
253 	}
254 	return (ps);
255 }
256 
257 /*
258  * prop_string_size --
259  *	Return the size of the string, not including the terminating NUL.
260  */
261 size_t
prop_string_size(prop_string_t ps)262 prop_string_size(prop_string_t ps)
263 {
264 
265 	if (! prop_object_is_string(ps))
266 		return (0);
267 
268 	return (ps->ps_size);
269 }
270 
271 /*
272  * prop_string_mutable --
273  *	Return true if the string is a mutable string.
274  */
275 bool
prop_string_mutable(prop_string_t ps)276 prop_string_mutable(prop_string_t ps)
277 {
278 
279 	if (! prop_object_is_string(ps))
280 		return (false);
281 
282 	return ((ps->ps_flags & PS_F_NOCOPY) == 0);
283 }
284 
285 /*
286  * prop_string_cstring --
287  *	Return a copy of the contents of the string as a C string.
288  *	The string is allocated with the M_TEMP malloc type.
289  */
290 char *
prop_string_cstring(prop_string_t ps)291 prop_string_cstring(prop_string_t ps)
292 {
293 	char *cp;
294 
295 	if (! prop_object_is_string(ps))
296 		return (NULL);
297 
298 	cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
299 	if (cp != NULL)
300 		strcpy(cp, prop_string_contents(ps));
301 
302 	return (cp);
303 }
304 
305 /*
306  * prop_string_cstring_nocopy --
307  *	Return an immutable reference to the contents of the string
308  *	as a C string.
309  */
310 const char *
prop_string_cstring_nocopy(prop_string_t ps)311 prop_string_cstring_nocopy(prop_string_t ps)
312 {
313 
314 	if (! prop_object_is_string(ps))
315 		return (NULL);
316 
317 	return (prop_string_contents(ps));
318 }
319 
320 /*
321  * prop_string_append --
322  *	Append the contents of one string to another.  Returns true
323  *	upon success.  The destination string must be mutable.
324  */
325 bool
prop_string_append(prop_string_t dst,prop_string_t src)326 prop_string_append(prop_string_t dst, prop_string_t src)
327 {
328 	char *ocp, *cp;
329 	size_t len;
330 
331 	if (! (prop_object_is_string(dst) &&
332 	       prop_object_is_string(src)))
333 		return (false);
334 
335 	if (dst->ps_flags & PS_F_NOCOPY)
336 		return (false);
337 
338 	len = dst->ps_size + src->ps_size;
339 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
340 	if (cp == NULL)
341 		return (false);
342 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst),
343 		prop_string_contents(src));
344 	ocp = dst->ps_mutable;
345 	dst->ps_mutable = cp;
346 	dst->ps_size = len;
347 	if (ocp != NULL)
348 		_PROP_FREE(ocp, M_PROP_STRING);
349 
350 	return (true);
351 }
352 
353 /*
354  * prop_string_append_cstring --
355  *	Append a C string to a string.  Returns true upon success.
356  *	The destination string must be mutable.
357  */
358 bool
prop_string_append_cstring(prop_string_t dst,const char * src)359 prop_string_append_cstring(prop_string_t dst, const char *src)
360 {
361 	char *ocp, *cp;
362 	size_t len;
363 
364 	if (! prop_object_is_string(dst))
365 		return (false);
366 
367 	_PROP_ASSERT(src != NULL);
368 
369 	if (dst->ps_flags & PS_F_NOCOPY)
370 		return (false);
371 
372 	len = dst->ps_size + strlen(src);
373 	cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
374 	if (cp == NULL)
375 		return (false);
376 	snprintf(cp, len + 1, "%s%s", prop_string_contents(dst), src);
377 	ocp = dst->ps_mutable;
378 	dst->ps_mutable = cp;
379 	dst->ps_size = len;
380 	if (ocp != NULL)
381 		_PROP_FREE(ocp, M_PROP_STRING);
382 
383 	return (true);
384 }
385 
386 /*
387  * prop_string_equals --
388  *	Return true if two strings are equivalent.
389  */
390 bool
prop_string_equals(prop_string_t str1,prop_string_t str2)391 prop_string_equals(prop_string_t str1, prop_string_t str2)
392 {
393 	if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
394 		return (false);
395 
396 	return prop_object_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
prop_string_equals_cstring(prop_string_t ps,const char * cp)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
_prop_string_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)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