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