xref: /netbsd-src/common/lib/libprop/prop_bool.c (revision 466a16a118933bd295a8a104f095714fadf9cf68)
1 /*	$NetBSD: prop_bool.c,v 1.16 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_bool.h>
33 #include "prop_object_impl.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 _PROP_MUTEX_DECL_STATIC(_prop_bool_initialized_mutex)
44 static bool	_prop_bool_initialized;
45 
46 static _prop_object_free_rv_t
47 		_prop_bool_free(prop_stack_t, prop_object_t *);
48 static bool	_prop_bool_externalize(
49 				struct _prop_object_externalize_context *,
50 				void *);
51 static _prop_object_equals_rv_t
52 		_prop_bool_equals(prop_object_t, prop_object_t,
53 				  void **, void **,
54 				  prop_object_t *, prop_object_t *);
55 
56 static const struct _prop_object_type _prop_object_type_bool = {
57 	.pot_type	=	PROP_TYPE_BOOL,
58 	.pot_free	=	_prop_bool_free,
59 	.pot_extern	=	_prop_bool_externalize,
60 	.pot_equals	=	_prop_bool_equals,
61 };
62 
63 #define	prop_object_is_bool(x)		\
64 	((x) != NULL && (x)->pb_obj.po_type == &_prop_object_type_bool)
65 
66 /* ARGSUSED */
67 static _prop_object_free_rv_t
68 _prop_bool_free(prop_stack_t stack, prop_object_t *obj)
69 {
70 	/*
71 	 * This should never happen as we "leak" our initial reference
72 	 * count.
73 	 */
74 
75 	/* XXX forced assertion failure? */
76 	return (_PROP_OBJECT_FREE_DONE);
77 }
78 
79 static bool
80 _prop_bool_externalize(struct _prop_object_externalize_context *ctx,
81 		       void *v)
82 {
83 	prop_bool_t pb = v;
84 
85 	return (_prop_object_externalize_empty_tag(ctx,
86 	    pb->pb_value ? "true" : "false"));
87 }
88 
89 /* ARGSUSED */
90 static _prop_object_equals_rv_t
91 _prop_bool_equals(prop_object_t v1, prop_object_t v2,
92     void **stored_pointer1, void **stored_pointer2,
93     prop_object_t *next_obj1, prop_object_t *next_obj2)
94 {
95 	prop_bool_t b1 = v1;
96 	prop_bool_t b2 = v2;
97 
98 	if (! (prop_object_is_bool(b1) &&
99 	       prop_object_is_bool(b2)))
100 		return (_PROP_OBJECT_EQUALS_FALSE);
101 
102 	/*
103 	 * Since we only ever allocate one true and one false,
104 	 * save ourselves a couple of memory operations.
105 	 */
106 	if (b1 == b2)
107 		return (_PROP_OBJECT_EQUALS_TRUE);
108 	else
109 		return (_PROP_OBJECT_EQUALS_FALSE);
110 }
111 
112 static prop_bool_t
113 _prop_bool_alloc(bool val)
114 {
115 	prop_bool_t pb;
116 
117 	if (! _prop_bool_initialized) {
118 		_PROP_MUTEX_LOCK(_prop_bool_initialized_mutex);
119 		if (! _prop_bool_initialized) {
120 			_prop_object_init(&_prop_bool_true.pb_obj,
121 					  &_prop_object_type_bool);
122 			_prop_bool_true.pb_value = true;
123 
124 			_prop_object_init(&_prop_bool_false.pb_obj,
125 					  &_prop_object_type_bool);
126 			_prop_bool_false.pb_value = false;
127 
128 			_prop_bool_initialized = true;
129 		}
130 		_PROP_MUTEX_UNLOCK(_prop_bool_initialized_mutex);
131 	}
132 
133 	pb = val ? &_prop_bool_true : &_prop_bool_false;
134 	prop_object_retain(pb);
135 
136 	return (pb);
137 }
138 
139 /*
140  * prop_bool_create --
141  *	Create a prop_bool_t and initialize it with the
142  *	provided boolean value.
143  */
144 prop_bool_t
145 prop_bool_create(bool val)
146 {
147 
148 	return (_prop_bool_alloc(val));
149 }
150 
151 /*
152  * prop_bool_copy --
153  *	Copy a prop_bool_t.
154  */
155 prop_bool_t
156 prop_bool_copy(prop_bool_t opb)
157 {
158 
159 	if (! prop_object_is_bool(opb))
160 		return (NULL);
161 
162 	/*
163 	 * Because we only ever allocate one true and one false, this
164 	 * can be reduced to a simple retain operation.
165 	 */
166 	prop_object_retain(opb);
167 	return (opb);
168 }
169 
170 /*
171  * prop_bool_true --
172  *	Get the value of a prop_bool_t.
173  */
174 bool
175 prop_bool_true(prop_bool_t pb)
176 {
177 
178 	if (! prop_object_is_bool(pb))
179 		return (false);
180 
181 	return (pb->pb_value);
182 }
183 
184 /*
185  * prop_bool_equals --
186  *	Return true if the boolean values are equivalent.
187  */
188 bool
189 prop_bool_equals(prop_bool_t b1, prop_bool_t b2)
190 {
191 	if (!prop_object_is_bool(b1) || !prop_object_is_bool(b2))
192 		return (false);
193 
194 	return (prop_object_equals(b1, b2));
195 }
196 
197 /*
198  * _prop_bool_internalize --
199  *	Parse a <true/> or <false/> and return the object created from
200  *	the external representation.
201  */
202 
203 /* ARGSUSED */
204 bool
205 _prop_bool_internalize(prop_stack_t stack, prop_object_t *obj,
206     struct _prop_object_internalize_context *ctx)
207 {
208 	bool val;
209 
210 	/* No attributes, and it must be an empty element. */
211 	if (ctx->poic_tagattr != NULL ||
212 	    ctx->poic_is_empty_element == false)
213 	    	return (true);
214 
215 	if (_PROP_TAG_MATCH(ctx, "true"))
216 		val = true;
217 	else {
218 		_PROP_ASSERT(_PROP_TAG_MATCH(ctx, "false"));
219 		val = false;
220 	}
221 	*obj = prop_bool_create(val);
222 	return (true);
223 }
224