prop_bool.c revision 1.24 1 /* $NetBSD: prop_bool.c,v 1.24 2025/05/14 03:25:45 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
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
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_extern_append_empty_tag(ctx, tags);
98 }
99
100 /* ARGSUSED */
101 static _prop_object_equals_rv_t
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
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
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
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
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
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
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
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
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