prop_string.c revision 1.9 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