mdoc.local: Indent with spaces like everywhere else.
[dragonfly.git] / common / lib / libprop / prop_string.c
1 /*      $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 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  *
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 _prop_object_free_rv_t
55                 _prop_string_free(prop_stack_t, prop_object_t *);
56 static bool     _prop_string_externalize(
57                                 struct _prop_object_externalize_context *,
58                                 void *);
59 static _prop_object_equals_rv_t
60                 _prop_string_equals(prop_object_t, prop_object_t,
61                                     void **, void **,
62                                     prop_object_t *, prop_object_t *);
63
64 static const struct _prop_object_type _prop_object_type_string = {
65         .pot_type       =       PROP_TYPE_STRING,
66         .pot_free       =       _prop_string_free,
67         .pot_extern     =       _prop_string_externalize,
68         .pot_equals     =       _prop_string_equals,
69 };
70
71 #define prop_object_is_string(x)        \
72         ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
73 #define prop_string_contents(x)  ((x)->ps_immutable ? (x)->ps_immutable : "")
74
75 /* ARGSUSED */
76 static _prop_object_free_rv_t
77 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
78 {
79         prop_string_t ps = *obj;
80
81         if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
82                 _PROP_FREE(ps->ps_mutable, M_PROP_STRING);
83         _PROP_POOL_PUT(_prop_string_pool, ps);
84
85         return (_PROP_OBJECT_FREE_DONE);
86 }
87
88 static bool
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 /* ARGSUSED */
107 static _prop_object_equals_rv_t
108 _prop_string_equals(prop_object_t v1, prop_object_t v2,
109     void **stored_pointer1, void **stored_pointer2,
110     prop_object_t *next_obj1, prop_object_t *next_obj2)
111 {
112         prop_string_t str1 = v1;
113         prop_string_t str2 = v2;
114
115         if (str1 == str2)
116                 return (_PROP_OBJECT_EQUALS_TRUE);
117         if (str1->ps_size != str2->ps_size)
118                 return (_PROP_OBJECT_EQUALS_FALSE);
119         if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
120                 return (_PROP_OBJECT_EQUALS_FALSE);
121         else
122                 return (_PROP_OBJECT_EQUALS_TRUE);
123 }
124
125 static prop_string_t
126 _prop_string_alloc(void)
127 {
128         prop_string_t ps;
129
130         ps = _PROP_POOL_GET(_prop_string_pool);
131         if (ps != NULL) {
132                 _prop_object_init(&ps->ps_obj, &_prop_object_type_string);
133
134                 ps->ps_mutable = NULL;
135                 ps->ps_size = 0;
136                 ps->ps_flags = 0;
137         }
138
139         return (ps);
140 }
141
142 /*
143  * prop_string_create --
144  *      Create an empty mutable string.
145  */
146 prop_string_t
147 prop_string_create(void)
148 {
149
150         return (_prop_string_alloc());
151 }
152
153 /*
154  * prop_string_create_cstring --
155  *      Create a string that contains a copy of the provided C string.
156  */
157 prop_string_t
158 prop_string_create_cstring(const char *str)
159 {
160         prop_string_t ps;
161         char *cp;
162         size_t len;
163
164         ps = _prop_string_alloc();
165         if (ps != NULL) {
166                 len = strlen(str);
167                 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
168                 if (cp == NULL) {
169                         prop_object_release(ps);
170                         return (NULL);
171                 }
172                 strcpy(cp, str);
173                 ps->ps_mutable = cp;
174                 ps->ps_size = len;
175         }
176         return (ps);
177 }
178
179 /*
180  * prop_string_create_cstring_nocopy --
181  *      Create an immutable string that contains a refrence to the
182  *      provided C string.
183  */
184 prop_string_t
185 prop_string_create_cstring_nocopy(const char *str)
186 {
187         prop_string_t ps;
188         
189         ps = _prop_string_alloc();
190         if (ps != NULL) {
191                 ps->ps_immutable = str;
192                 ps->ps_size = strlen(str);
193                 ps->ps_flags |= PS_F_NOCOPY;
194         }
195         return (ps);
196 }
197
198 /*
199  * prop_string_copy --
200  *      Copy a string.  If the original string is immutable, then the
201  *      copy is also immutable and references the same external data.
202  */
203 prop_string_t
204 prop_string_copy(prop_string_t ops)
205 {
206         prop_string_t ps;
207
208         if (! prop_object_is_string(ops))
209                 return (NULL);
210
211         ps = _prop_string_alloc();
212         if (ps != NULL) {
213                 ps->ps_size = ops->ps_size;
214                 ps->ps_flags = ops->ps_flags;
215                 if (ops->ps_flags & PS_F_NOCOPY)
216                         ps->ps_immutable = ops->ps_immutable;
217                 else {
218                         char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
219                         if (cp == NULL) {
220                                 prop_object_release(ps);
221                                 return (NULL);
222                         }
223                         strcpy(cp, prop_string_contents(ops));
224                         ps->ps_mutable = cp;
225                 }
226         }
227         return (ps);
228 }
229
230 /*
231  * prop_string_copy_mutable --
232  *      Copy a string, always returning a mutable copy.
233  */
234 prop_string_t
235 prop_string_copy_mutable(prop_string_t ops)
236 {
237         prop_string_t ps;
238         char *cp;
239
240         if (! prop_object_is_string(ops))
241                 return (NULL);
242
243         ps = _prop_string_alloc();
244         if (ps != NULL) {
245                 ps->ps_size = ops->ps_size;
246                 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
247                 if (cp == NULL) {
248                         prop_object_release(ps);
249                         return (NULL);
250                 }
251                 strcpy(cp, prop_string_contents(ops));
252                 ps->ps_mutable = cp;
253         }
254         return (ps);
255 }
256
257 /*
258  * prop_string_size --
259  *      Return the size of the string, not including the terminating NUL.
260  */
261 size_t
262 prop_string_size(prop_string_t ps)
263 {
264
265         if (! prop_object_is_string(ps))
266                 return (0);
267
268         return (ps->ps_size);
269 }
270
271 /*
272  * prop_string_mutable --
273  *      Return true if the string is a mutable string.
274  */
275 bool
276 prop_string_mutable(prop_string_t ps)
277 {
278
279         if (! prop_object_is_string(ps))
280                 return (false);
281
282         return ((ps->ps_flags & PS_F_NOCOPY) == 0);
283 }
284
285 /*
286  * prop_string_cstring --
287  *      Return a copy of the contents of the string as a C string.
288  *      The string is allocated with the M_TEMP malloc type.
289  */
290 char *
291 prop_string_cstring(prop_string_t ps)
292 {
293         char *cp;
294
295         if (! prop_object_is_string(ps))
296                 return (NULL);
297
298         cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
299         if (cp != NULL)
300                 strcpy(cp, prop_string_contents(ps));
301         
302         return (cp);
303 }
304
305 /*
306  * prop_string_cstring_nocopy --
307  *      Return an immutable reference to the contents of the string
308  *      as a C string.
309  */
310 const char *
311 prop_string_cstring_nocopy(prop_string_t ps)
312 {
313
314         if (! prop_object_is_string(ps))
315                 return (NULL);
316
317         return (prop_string_contents(ps));
318 }
319
320 /*
321  * prop_string_append --
322  *      Append the contents of one string to another.  Returns true
323  *      upon success.  The destination string must be mutable.
324  */
325 bool
326 prop_string_append(prop_string_t dst, prop_string_t src)
327 {
328         char *ocp, *cp;
329         size_t len;
330
331         if (! (prop_object_is_string(dst) &&
332                prop_object_is_string(src)))
333                 return (false);
334
335         if (dst->ps_flags & PS_F_NOCOPY)
336                 return (false);
337
338         len = dst->ps_size + src->ps_size;
339         cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
340         if (cp == NULL)
341                 return (false);
342         sprintf(cp, "%s%s", prop_string_contents(dst),
343                 prop_string_contents(src));
344         ocp = dst->ps_mutable;
345         dst->ps_mutable = cp;
346         dst->ps_size = len;
347         if (ocp != NULL)
348                 _PROP_FREE(ocp, M_PROP_STRING);
349         
350         return (true);
351 }
352
353 /*
354  * prop_string_append_cstring --
355  *      Append a C string to a string.  Returns true upon success.
356  *      The destination string must be mutable.
357  */
358 bool
359 prop_string_append_cstring(prop_string_t dst, const char *src)
360 {
361         char *ocp, *cp;
362         size_t len;
363
364         if (! prop_object_is_string(dst))
365                 return (false);
366
367         _PROP_ASSERT(src != NULL);
368
369         if (dst->ps_flags & PS_F_NOCOPY)
370                 return (false);
371         
372         len = dst->ps_size + strlen(src);
373         cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
374         if (cp == NULL)
375                 return (false);
376         sprintf(cp, "%s%s", prop_string_contents(dst), src);
377         ocp = dst->ps_mutable;
378         dst->ps_mutable = cp;
379         dst->ps_size = len;
380         if (ocp != NULL)
381                 _PROP_FREE(ocp, M_PROP_STRING);
382         
383         return (true);
384 }
385
386 /*
387  * prop_string_equals --
388  *      Return true if two strings are equivalent.
389  */
390 bool
391 prop_string_equals(prop_string_t str1, prop_string_t str2)
392 {
393         if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
394                 return (false);
395
396         return prop_object_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 }