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