1 /*        $NetBSD: prop_bool.c,v 1.21 2025/04/26 17:13:23 thorpej Exp $         */
2 
3 /*-
4  * Copyright (c) 2006, 2025 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_object_impl.h"
33 #include <prop/prop_bool.h>
34 
35 struct _prop_bool {
36           struct _prop_object pb_obj;
37           bool                          pb_value;
38 };
39 
40 static struct _prop_bool _prop_bool_true;
41 static struct _prop_bool _prop_bool_false;
42 
43 static const char truestr[] = "true";
44 static const char falsestr[] = "false";
45 
46 static const struct _prop_object_type_tags _prop_bool_true_type_tags = {
47           .xml_tag  =         truestr,
48           .json_open_tag      =         truestr,
49 };
50 static const struct _prop_object_type_tags _prop_bool_false_type_tags = {
51           .xml_tag  =         falsestr,
52           .json_open_tag      =         falsestr,
53 };
54 
55 static _prop_object_free_rv_t
56                     _prop_bool_free(prop_stack_t, prop_object_t *);
57 static bool         _prop_bool_externalize(
58                                         struct _prop_object_externalize_context *,
59                                         void *);
60 static _prop_object_equals_rv_t
61                     _prop_bool_equals(prop_object_t, prop_object_t,
62                                           void **, void **,
63                                           prop_object_t *, prop_object_t *);
64 
65 static const struct _prop_object_type _prop_object_type_bool = {
66           .pot_type =         PROP_TYPE_BOOL,
67           .pot_free =         _prop_bool_free,
68           .pot_extern         =         _prop_bool_externalize,
69           .pot_equals         =         _prop_bool_equals,
70 };
71 
72 #define   prop_object_is_bool(x)                  \
73           ((x) != NULL && (x)->pb_obj.po_type == &_prop_object_type_bool)
74 
75 /* ARGSUSED */
76 static _prop_object_free_rv_t
_prop_bool_free(prop_stack_t stack,prop_object_t * obj)77 _prop_bool_free(prop_stack_t stack, prop_object_t *obj)
78 {
79           /*
80            * This should never happen as we "leak" our initial reference
81            * count.
82            */
83 
84           /* XXX forced assertion failure? */
85           return (_PROP_OBJECT_FREE_DONE);
86 }
87 
88 static bool
_prop_bool_externalize(struct _prop_object_externalize_context * ctx,void * v)89 _prop_bool_externalize(struct _prop_object_externalize_context *ctx,
90                            void *v)
91 {
92           prop_bool_t pb = v;
93           const struct _prop_object_type_tags *tags =
94               pb->pb_value ? &_prop_bool_true_type_tags
95                                : &_prop_bool_false_type_tags;
96 
97           return _prop_object_externalize_empty_tag(ctx, tags);
98 }
99 
100 /* ARGSUSED */
101 static _prop_object_equals_rv_t
_prop_bool_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)102 _prop_bool_equals(prop_object_t v1, prop_object_t v2,
103     void **stored_pointer1, void **stored_pointer2,
104     prop_object_t *next_obj1, prop_object_t *next_obj2)
105 {
106           prop_bool_t b1 = v1;
107           prop_bool_t b2 = v2;
108 
109           if (! (prop_object_is_bool(b1) &&
110                  prop_object_is_bool(b2)))
111                     return (_PROP_OBJECT_EQUALS_FALSE);
112 
113           /*
114            * Since we only ever allocate one true and one false,
115            * save ourselves a couple of memory operations.
116            */
117           if (b1 == b2)
118                     return (_PROP_OBJECT_EQUALS_TRUE);
119           else
120                     return (_PROP_OBJECT_EQUALS_FALSE);
121 }
122 
_PROP_ONCE_DECL(_prop_bool_init_once)123 _PROP_ONCE_DECL(_prop_bool_init_once)
124 
125 static int
126 _prop_bool_init(void)
127 {
128 
129           _prop_object_init(&_prop_bool_true.pb_obj,
130               &_prop_object_type_bool);
131           _prop_bool_true.pb_value = true;
132 
133           _prop_object_init(&_prop_bool_false.pb_obj,
134               &_prop_object_type_bool);
135           _prop_bool_false.pb_value = false;
136 
137           return 0;
138 }
139 
140 static prop_bool_t
_prop_bool_alloc(bool val)141 _prop_bool_alloc(bool val)
142 {
143           prop_bool_t pb;
144 
145           _PROP_ONCE_RUN(_prop_bool_init_once, _prop_bool_init);
146           pb = val ? &_prop_bool_true : &_prop_bool_false;
147           prop_object_retain(pb);
148 
149           return (pb);
150 }
151 
152 /*
153  * prop_bool_create --
154  *        Create a prop_bool_t and initialize it with the
155  *        provided boolean value.
156  */
157 _PROP_EXPORT prop_bool_t
prop_bool_create(bool val)158 prop_bool_create(bool val)
159 {
160 
161           return (_prop_bool_alloc(val));
162 }
163 
164 /*
165  * prop_bool_copy --
166  *        Copy a prop_bool_t.
167  */
168 _PROP_EXPORT prop_bool_t
prop_bool_copy(prop_bool_t opb)169 prop_bool_copy(prop_bool_t opb)
170 {
171 
172           if (! prop_object_is_bool(opb))
173                     return (NULL);
174 
175           /*
176            * Because we only ever allocate one true and one false, this
177            * can be reduced to a simple retain operation.
178            */
179           prop_object_retain(opb);
180           return (opb);
181 }
182 
183 /*
184  * prop_bool_value --
185  *        Get the value of a prop_bool_t.
186  */
187 _PROP_EXPORT bool
prop_bool_value(prop_bool_t pb)188 prop_bool_value(prop_bool_t pb)
189 {
190 
191           if (! prop_object_is_bool(pb))
192                     return (false);
193 
194           return (pb->pb_value);
195 }
196 
197 /*
198  * prop_bool_true --
199  *        Historical alias for prop_bool_value().
200  */
201 _PROP_EXPORT bool
prop_bool_true(prop_bool_t pb)202 prop_bool_true(prop_bool_t pb)
203 {
204           return prop_bool_value(pb);
205 }
206 
207 /*
208  * prop_bool_equals --
209  *        Return true if the boolean values are equivalent.
210  */
211 _PROP_EXPORT bool
prop_bool_equals(prop_bool_t b1,prop_bool_t b2)212 prop_bool_equals(prop_bool_t b1, prop_bool_t b2)
213 {
214           if (!prop_object_is_bool(b1) || !prop_object_is_bool(b2))
215                     return (false);
216 
217           return (prop_object_equals(b1, b2));
218 }
219 
220 /*
221  * _prop_bool_internalize --
222  *        Parse a <true/> or <false/> and return the object created from
223  *        the external representation.
224  */
225 
226 /* ARGSUSED */
227 bool
_prop_bool_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)228 _prop_bool_internalize(prop_stack_t stack, prop_object_t *obj,
229     struct _prop_object_internalize_context *ctx)
230 {
231           bool val;
232 
233           /*
234            * N.B. For internalizing JSON, the layer above us has
235            * made it look like XML for this object type.
236            */
237 
238           /* No attributes, and it must be an empty element. */
239           if (ctx->poic_tagattr != NULL ||
240               ctx->poic_is_empty_element == false)
241                     return (true);
242 
243           if (_PROP_TAG_MATCH(ctx, truestr))
244                     val = true;
245           else {
246                     _PROP_ASSERT(_PROP_TAG_MATCH(ctx, falsestr));
247                     val = false;
248           }
249           *obj = prop_bool_create(val);
250           return (true);
251 }
252