prop_string.c revision 1.2 1 /* $NetBSD: prop_string.c,v 1.2 2006/05/18 03:05:19 thorpej 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)->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 _PROP_ASSERT(prop_object_is_string(str1));
113 _PROP_ASSERT(prop_object_is_string(str2));
114 if (str1 == str2)
115 return (TRUE);
116 if (str1->ps_size != str2->ps_size)
117 return (FALSE);
118 return (strcmp(prop_string_contents(str1),
119 prop_string_contents(str2)) == 0);
120 }
121
122 static prop_string_t
123 _prop_string_alloc(void)
124 {
125 prop_string_t ps;
126
127 ps = _PROP_POOL_GET(_prop_string_pool);
128 if (ps != NULL) {
129 _prop_object_init(&ps->ps_obj, &_prop_object_type_string);
130
131 ps->ps_mutable = NULL;
132 ps->ps_size = 0;
133 ps->ps_flags = 0;
134 }
135
136 return (ps);
137 }
138
139 /*
140 * prop_string_create --
141 * Create an empty mutable string.
142 */
143 prop_string_t
144 prop_string_create(void)
145 {
146
147 return (_prop_string_alloc());
148 }
149
150 /*
151 * prop_string_create_cstring --
152 * Create a string that contains a copy of the provided C string.
153 */
154 prop_string_t
155 prop_string_create_cstring(const char *str)
156 {
157 prop_string_t ps;
158 char *cp;
159 size_t len;
160
161 ps = _prop_string_alloc();
162 if (ps != NULL) {
163 len = strlen(str);
164 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
165 if (cp == NULL) {
166 _prop_string_free(ps);
167 return (NULL);
168 }
169 strcpy(cp, str);
170 ps->ps_mutable = cp;
171 ps->ps_size = len;
172 }
173 return (ps);
174 }
175
176 /*
177 * prop_string_create_cstring_nocopy --
178 * Create an immutable string that contains a refrence to the
179 * provided C string.
180 */
181 prop_string_t
182 prop_string_create_cstring_nocopy(const char *str)
183 {
184 prop_string_t ps;
185
186 ps = _prop_string_alloc();
187 if (ps != NULL) {
188 ps->ps_immutable = str;
189 ps->ps_size = strlen(str);
190 ps->ps_flags |= PS_F_NOCOPY;
191 }
192 return (ps);
193 }
194
195 /*
196 * prop_string_copy --
197 * Copy a string. If the original string is immutable, then the
198 * copy is also immutable and references the same external data.
199 */
200 prop_string_t
201 prop_string_copy(prop_string_t ops)
202 {
203 prop_string_t ps;
204
205 _PROP_ASSERT(prop_object_is_string(ops));
206
207 ps = _prop_string_alloc();
208 if (ps != NULL) {
209 ps->ps_size = ops->ps_size;
210 ps->ps_flags = ops->ps_flags;
211 if (ops->ps_flags & PS_F_NOCOPY)
212 ps->ps_immutable = ops->ps_immutable;
213 else {
214 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
215 if (cp == NULL) {
216 _prop_string_free(ps);
217 return (NULL);
218 }
219 strcpy(cp, prop_string_contents(ops));
220 ps->ps_mutable = cp;
221 }
222 }
223 return (ps);
224 }
225
226 /*
227 * prop_string_copy_mutable --
228 * Copy a string, always returning a mutable copy.
229 */
230 prop_string_t
231 prop_string_copy_mutable(prop_string_t ops)
232 {
233 prop_string_t ps;
234 char *cp;
235
236 _PROP_ASSERT(prop_object_is_string(ops));
237
238 ps = _prop_string_alloc();
239 if (ps != NULL) {
240 ps->ps_size = ops->ps_size;
241 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
242 if (cp == NULL) {
243 _prop_string_free(ps);
244 return (NULL);
245 }
246 strcpy(cp, prop_string_contents(ops));
247 ps->ps_mutable = cp;
248 }
249 return (ps);
250 }
251
252 /*
253 * prop_string_size --
254 * Return the size of the string, no including the terminating NUL.
255 */
256 size_t
257 prop_string_size(prop_string_t ps)
258 {
259
260 _PROP_ASSERT(prop_object_is_string(ps));
261 return (ps->ps_size);
262 }
263
264 /*
265 * prop_string_mutable --
266 * Return TRUE if the string is a mutable string.
267 */
268 boolean_t
269 prop_string_mutable(prop_string_t ps)
270 {
271
272 _PROP_ASSERT(prop_object_is_string(ps));
273 return ((ps->ps_flags & PS_F_NOCOPY) == 0);
274 }
275
276 /*
277 * prop_string_cstring --
278 * Return a copy of the contents of the string as a C string.
279 * The string is allocated with the M_TEMP malloc type.
280 */
281 char *
282 prop_string_cstring(prop_string_t ps)
283 {
284 char *cp;
285
286 _PROP_ASSERT(prop_object_is_string(ps));
287 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
288 if (cp != NULL)
289 strcpy(cp, prop_string_contents(ps));
290
291 return (cp);
292 }
293
294 /*
295 * prop_string_cstring_nocopy --
296 * Return an immutable reference to the contents of the string
297 * as a C string.
298 */
299 const char *
300 prop_string_cstring_nocopy(prop_string_t ps)
301 {
302
303 _PROP_ASSERT(prop_object_is_string(ps));
304 return (prop_string_contents(ps));
305 }
306
307 /*
308 * prop_string_append --
309 * Append the contents of one string to another. Returns TRUE
310 * upon success. The destination string must be mutable.
311 */
312 boolean_t
313 prop_string_append(prop_string_t dst, prop_string_t src)
314 {
315 char *ocp, *cp;
316 size_t len;
317
318 _PROP_ASSERT(prop_object_is_string(dst));
319 _PROP_ASSERT(prop_object_is_string(src));
320
321 if (dst->ps_flags & PS_F_NOCOPY)
322 return (FALSE);
323
324 len = dst->ps_size + src->ps_size;
325 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
326 if (cp == NULL)
327 return (FALSE);
328 sprintf(cp, "%s%s", prop_string_contents(dst),
329 prop_string_contents(src));
330 ocp = dst->ps_mutable;
331 dst->ps_mutable = cp;
332 dst->ps_size = len;
333 if (ocp != NULL)
334 _PROP_FREE(ocp, M_PROP_STRING);
335
336 return (TRUE);
337 }
338
339 /*
340 * prop_string_append_cstring --
341 * Append a C string to a string. Returns TRUE upon success.
342 * The destination string must be mutable.
343 */
344 boolean_t
345 prop_string_append_cstring(prop_string_t dst, const char *src)
346 {
347 char *ocp, *cp;
348 size_t len;
349
350 _PROP_ASSERT(src != NULL);
351 _PROP_ASSERT(prop_object_is_string(dst));
352
353 if (dst->ps_flags & PS_F_NOCOPY)
354 return (FALSE);
355
356 len = dst->ps_size + strlen(src);
357 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
358 if (cp == NULL)
359 return (FALSE);
360 sprintf(cp, "%s%s", prop_string_contents(dst), src);
361 ocp = dst->ps_mutable;
362 dst->ps_mutable = cp;
363 dst->ps_size = len;
364 if (ocp != NULL)
365 _PROP_FREE(ocp, M_PROP_STRING);
366
367 return (TRUE);
368 }
369
370 /*
371 * prop_string_equals --
372 * Return TRUE if two strings are equivalent.
373 */
374 boolean_t
375 prop_string_equals(prop_string_t str1, prop_string_t str2)
376 {
377
378 return (_prop_string_equals(str1, str2));
379 }
380
381 /*
382 * prop_string_equals_cstring --
383 * Return TRUE if the string is equivalent to the specified
384 * C string.
385 */
386 boolean_t
387 prop_string_equals_cstring(prop_string_t ps, const char *cp)
388 {
389
390 _PROP_ASSERT(prop_object_is_string(ps));
391 return (strcmp(prop_string_contents(ps), cp) == 0);
392 }
393
394 /*
395 * _prop_string_internalize --
396 * Parse a <string>...</string> and return the object created from the
397 * external representation.
398 */
399 prop_object_t
400 _prop_string_internalize(struct _prop_object_internalize_context *ctx)
401 {
402 prop_string_t string;
403 char *str;
404 size_t len, alen;
405
406 if (ctx->poic_is_empty_element)
407 return (prop_string_create());
408
409 /* No attributes recognized here. */
410 if (ctx->poic_tagattr != NULL)
411 return (NULL);
412
413 /* Compute the length of the result. */
414 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
415 NULL) == FALSE)
416 return (NULL);
417
418 str = _PROP_MALLOC(len + 1, M_PROP_STRING);
419 if (str == NULL)
420 return (NULL);
421
422 if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
423 &ctx->poic_cp) == FALSE ||
424 alen != len) {
425 _PROP_FREE(str, M_PROP_STRING);
426 return (NULL);
427 }
428 str[len] = '\0';
429
430 if (_prop_object_internalize_find_tag(ctx, "string",
431 _PROP_TAG_TYPE_END) == FALSE) {
432 _PROP_FREE(str, M_PROP_STRING);
433 return (NULL);
434 }
435
436 string = _prop_string_alloc();
437 if (string == NULL) {
438 _PROP_FREE(str, M_PROP_STRING);
439 return (NULL);
440 }
441
442 string->ps_mutable = str;
443 string->ps_size = len;
444
445 return (string);
446 }
447