prop_string.c revision 1.5 1 /* $NetBSD: prop_string.c,v 1.5 2006/10/18 14:49:21 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 * 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, (size_t)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