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