1 /*
2  * Copyright (c) 2008-2012 Hypertriton, Inc. <http://hypertriton.com/>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
18  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <agar/core/core.h>
27 
28 #include <string.h>
29 
30 const AG_VariableTypeInfo agVariableTypes[] = {
31 	{ AG_VARIABLE_NULL,		0,	"NULL",		AG_VARIABLE_NULL,		-1,	0 },
32 	/*
33 	 * Primitive types
34 	 */
35 	{ AG_VARIABLE_UINT,		0,	"Uint",		AG_VARIABLE_UINT,		0,	sizeof(Uint) },
36 	{ AG_VARIABLE_P_UINT,		1,	"Uint *",	AG_VARIABLE_UINT,		0,	sizeof(Uint) },
37 	{ AG_VARIABLE_INT,		0,	"int",		AG_VARIABLE_INT,		1,	sizeof(int) },
38 	{ AG_VARIABLE_P_INT,		1,	"int *",	AG_VARIABLE_INT,		1,	sizeof(int) },
39 	{ AG_VARIABLE_UINT8,		0,	"Uint8",	AG_VARIABLE_UINT8,		2,	1 },
40 	{ AG_VARIABLE_P_UINT8,		1,	"Uint8 *",	AG_VARIABLE_UINT8,		2,	1 },
41 	{ AG_VARIABLE_SINT8,		0,	"Sint8",	AG_VARIABLE_SINT8,		3,	1 },
42 	{ AG_VARIABLE_P_SINT8,		1,	"Sint8 *",	AG_VARIABLE_SINT8,		3,	1 },
43 	{ AG_VARIABLE_UINT16,		0,	"Uint16",	AG_VARIABLE_UINT16,		4,	2 },
44 	{ AG_VARIABLE_P_UINT16,		1,	"Uint16 *",	AG_VARIABLE_UINT16,		4,	2 },
45 	{ AG_VARIABLE_SINT16,		0,	"Sint16",	AG_VARIABLE_SINT16,		5,	2 },
46 	{ AG_VARIABLE_P_SINT16,		1,	"Sint16 *",	AG_VARIABLE_SINT16,		5,	2 },
47 	{ AG_VARIABLE_UINT32,		0,	"Uint32",	AG_VARIABLE_UINT32,		6,	4 },
48 	{ AG_VARIABLE_P_UINT32,		1,	"Uint32 *" ,	AG_VARIABLE_UINT32,		6,	4 },
49 	{ AG_VARIABLE_SINT32,		0,	"Sint32",	AG_VARIABLE_SINT32,		7,	4 },
50 	{ AG_VARIABLE_P_SINT32,		1,	"Sint32 *",	AG_VARIABLE_SINT32,		7,	4 },
51 	{ AG_VARIABLE_UINT64,		0,	"Uint64",	AG_VARIABLE_UINT64,		8,	sizeof(Uint64) },
52 	{ AG_VARIABLE_P_UINT64,		1,	"Uint64 *",	AG_VARIABLE_UINT64,		8,	sizeof(Uint64) },
53 	{ AG_VARIABLE_SINT64,		0,	"Sint64",	AG_VARIABLE_SINT64,		9,	sizeof(Sint64) },
54 	{ AG_VARIABLE_P_SINT64,		1,	"Sint64 *",	AG_VARIABLE_SINT64,		9,	sizeof(Sint64) },
55 	{ AG_VARIABLE_FLOAT,		0,	"float",	AG_VARIABLE_FLOAT,		10,	sizeof(float) },
56 	{ AG_VARIABLE_P_FLOAT,		1,	"float *",	AG_VARIABLE_FLOAT,		10,	sizeof(float) },
57 	{ AG_VARIABLE_DOUBLE,		0,	"double",	AG_VARIABLE_DOUBLE,		11,	sizeof(double) },
58 	{ AG_VARIABLE_P_DOUBLE,		1,	"double *",	AG_VARIABLE_DOUBLE,		11,	sizeof(double) },
59 	{ AG_VARIABLE_LONG_DOUBLE,	0,	"long double",	AG_VARIABLE_LONG_DOUBLE,	12,	sizeof(long double) },
60 	{ AG_VARIABLE_P_LONG_DOUBLE,	1,	"long double *",AG_VARIABLE_LONG_DOUBLE,	12,	sizeof(long double) },
61 	{ AG_VARIABLE_STRING,		0,	"Str",		AG_VARIABLE_STRING,		13,	sizeof(char *) },
62 	{ AG_VARIABLE_P_STRING,		1,	"Str *",	AG_VARIABLE_STRING,		13,	sizeof(char *) },
63 	{ AG_VARIABLE_CONST_STRING,	0,	"Const Str",	AG_VARIABLE_CONST_STRING, 	13,	sizeof(const char *) },
64 	{ AG_VARIABLE_P_CONST_STRING,	1,	"Const Str *",	AG_VARIABLE_CONST_STRING, 	13,	sizeof(const char *) },
65 	{ AG_VARIABLE_POINTER,		0,	"Ptr",		AG_VARIABLE_POINTER,		-1,	sizeof(void *) },
66 	{ AG_VARIABLE_P_POINTER,	1,	"Ptr *",	AG_VARIABLE_POINTER,		-1,	sizeof(void *) },
67 	{ AG_VARIABLE_CONST_POINTER,	0,	"Const Ptr",	AG_VARIABLE_CONST_POINTER,	-1,	sizeof(const void *) },
68 	{ AG_VARIABLE_P_CONST_POINTER,	1,	"Const Ptr *",	AG_VARIABLE_CONST_POINTER,	-1,	sizeof(const void *) },
69 	/*
70 	 * Bitmask-specific types
71 	 */
72 	{ AG_VARIABLE_P_FLAG,		1,	"Flag *",	AG_VARIABLE_P_FLAG,		-1,	sizeof(int) },
73 	{ AG_VARIABLE_P_FLAG8,		1,	"Flag8 *",	AG_VARIABLE_P_FLAG8,		-1,	1 },
74 	{ AG_VARIABLE_P_FLAG16,		1,	"Flag16 *",	AG_VARIABLE_P_FLAG16,		-1,	2 },
75 	{ AG_VARIABLE_P_FLAG32,		1,	"Flag32 *",	AG_VARIABLE_P_FLAG32,		-1,	4 },
76 	/*
77 	 * Agar-Core specific types
78 	 */
79 	{ AG_VARIABLE_P_OBJECT,		1,	"Object *",	AG_VARIABLE_P_OBJECT,		-1,	sizeof(void *) },
80 	{ AG_VARIABLE_P_TEXT,		1,	"Text *",	AG_VARIABLE_P_TEXT,		-1,	sizeof(void *) },
81 	{ AG_VARIABLE_P_VARIABLE,	1,	"Variable *",	AG_VARIABLE_P_VARIABLE,		-1,	sizeof(void *) },
82 };
83 
84 /*
85  * Duplicate a Variable. Pointer references are preserved; internally
86  * allocated strings are duplicated (references to string buffers are
87  * preserved).
88  */
89 int
AG_CopyVariable(AG_Variable * Vdst,const AG_Variable * Vsrc)90 AG_CopyVariable(AG_Variable *Vdst, const AG_Variable *Vsrc)
91 {
92 	memcpy(Vdst, Vsrc, sizeof(AG_Variable));
93 
94 	if (Vsrc->type == AG_VARIABLE_STRING &&
95 	    Vsrc->info.size == 0) {
96 		if ((Vdst->data.s = TryStrdup(Vsrc->data.s)) == NULL)
97 			return (-1);
98 	}
99 	return (0);
100 }
101 
102 /*
103  * Duplicate a Variable with dereference. Pointer references are converted to
104  * immediate values and strings are duplicated unconditionally.
105  */
106 int
AG_DerefVariable(AG_Variable * Vdst,const AG_Variable * Vsrc)107 AG_DerefVariable(AG_Variable *Vdst, const AG_Variable *Vsrc)
108 {
109 	memcpy(Vdst, Vsrc, sizeof(AG_Variable));
110 
111 	switch (Vsrc->type) {
112 	case AG_VARIABLE_P_UINT:	Vdst->type = AG_VARIABLE_UINT;		Vdst->data.u = *(Uint *)Vsrc->data.p;		break;
113 	case AG_VARIABLE_P_INT:		Vdst->type = AG_VARIABLE_INT;		Vdst->data.i = *(int *)Vsrc->data.p;		break;
114 	case AG_VARIABLE_P_UINT8:	Vdst->type = AG_VARIABLE_UINT8;		Vdst->data.u8 = *(Uint8 *)Vsrc->data.p;		break;
115 	case AG_VARIABLE_P_SINT8:	Vdst->type = AG_VARIABLE_SINT8;		Vdst->data.s8 = *(Sint8 *)Vsrc->data.p;		break;
116 	case AG_VARIABLE_P_UINT16:	Vdst->type = AG_VARIABLE_UINT16;	Vdst->data.u16 = *(Uint16 *)Vsrc->data.p;	break;
117 	case AG_VARIABLE_P_SINT16:	Vdst->type = AG_VARIABLE_SINT16;	Vdst->data.s16 = *(Sint16 *)Vsrc->data.p;	break;
118 	case AG_VARIABLE_P_UINT32:	Vdst->type = AG_VARIABLE_UINT32;	Vdst->data.u32 = *(Uint32 *)Vsrc->data.p;	break;
119 	case AG_VARIABLE_P_SINT32:	Vdst->type = AG_VARIABLE_SINT32;	Vdst->data.s32 = *(Sint32 *)Vsrc->data.p;	break;
120 #ifdef HAVE_64BIT
121 	case AG_VARIABLE_P_UINT64:	Vdst->type = AG_VARIABLE_UINT64;	Vdst->data.u64 = *(Uint64 *)Vsrc->data.p;	break;
122 	case AG_VARIABLE_P_SINT64:	Vdst->type = AG_VARIABLE_SINT64;	Vdst->data.s64 = *(Sint64 *)Vsrc->data.p;	break;
123 #endif
124 	case AG_VARIABLE_P_FLOAT:	Vdst->type = AG_VARIABLE_FLOAT;		Vdst->data.flt = *(float *)Vsrc->data.p;	break;
125 	case AG_VARIABLE_P_DOUBLE:	Vdst->type = AG_VARIABLE_DOUBLE;	Vdst->data.dbl = *(double *)Vsrc->data.p;	break;
126 #ifdef HAVE_LONG_DOUBLE
127 	case AG_VARIABLE_P_LONG_DOUBLE:	Vdst->type = AG_VARIABLE_LONG_DOUBLE;	Vdst->data.ldbl = *(long double *)Vsrc->data.p;	break;
128 #endif
129 	case AG_VARIABLE_P_POINTER:	Vdst->type = AG_VARIABLE_POINTER;	Vdst->data.p = *(void **)Vsrc->data.p;		break;
130 	case AG_VARIABLE_STRING:
131 	case AG_VARIABLE_P_STRING:
132 		if ((Vdst->data.s = TryStrdup(Vsrc->data.s)) == NULL) {
133 			return (-1);
134 		}
135 		Vdst->info.size = 0;
136 		break;
137 	default:
138 		break;
139 	}
140 	return (0);
141 }
142 
143 /* Compare two variables (without dereference). */
144 int
AG_CompareVariables(const AG_Variable * a,const AG_Variable * b)145 AG_CompareVariables(const AG_Variable *a, const AG_Variable *b)
146 {
147 	size_t size;
148 
149 	if (a->type != b->type) {
150 		return (1);
151 	}
152 	size = agVariableTypes[a->type].size;
153 	if (size == 0) {
154 		return (1);
155 	} else {
156 		return memcmp((const void *)&a->data, (const void *)&b->data,
157 		    agVariableTypes[a->type].size);
158 	}
159 }
160 
161 /* Evaluate the value of a variable from any associated function. */
162 int
AG_EvalVariable(void * pObj,AG_Variable * V)163 AG_EvalVariable(void *pObj, AG_Variable *V)
164 {
165 	AG_Object *obj = pObj;
166 	char evName[AG_EVENT_NAME_MAX];
167 	AG_Event *ev;
168 
169 	if (V->fn.fnVoid == NULL)
170 		return (0);
171 
172 	AG_Strlcpy(evName, "get-", sizeof(evName));
173 	AG_Strlcat(evName, V->name, sizeof(evName));
174 	TAILQ_FOREACH(ev, &obj->events, events) {
175 		if (strcmp(evName, ev->name) == 0)
176 			break;
177 	}
178 	if (ev == NULL) {
179 		AG_SetError("Missing get-%s event", V->name);
180 		return (-1);
181 	}
182 	switch (V->type) {
183 	case AG_VARIABLE_UINT:		V->data.u = V->fn.fnUint(ev);		break;
184 	case AG_VARIABLE_INT:		V->data.i = V->fn.fnInt(ev);		break;
185 	case AG_VARIABLE_UINT8:		V->data.u8 = V->fn.fnUint8(ev);		break;
186 	case AG_VARIABLE_SINT8:		V->data.s8 = V->fn.fnSint8(ev);		break;
187 	case AG_VARIABLE_UINT16:	V->data.u16 = V->fn.fnUint16(ev);	break;
188 	case AG_VARIABLE_SINT16:	V->data.s16 = V->fn.fnSint16(ev);	break;
189 	case AG_VARIABLE_UINT32:	V->data.u32 = V->fn.fnUint32(ev);	break;
190 	case AG_VARIABLE_SINT32:	V->data.s32 = V->fn.fnSint32(ev);	break;
191 #ifdef HAVE_64BIT
192 	case AG_VARIABLE_UINT64:	V->data.u64 = V->fn.fnUint64(ev);	break;
193 	case AG_VARIABLE_SINT64:	V->data.s64 = V->fn.fnSint64(ev);	break;
194 #endif
195 	case AG_VARIABLE_FLOAT:		V->data.flt = V->fn.fnFloat(ev);	break;
196 	case AG_VARIABLE_DOUBLE:	V->data.dbl = V->fn.fnDouble(ev);	break;
197 #ifdef HAVE_LONG_DOUBLE
198 	case AG_VARIABLE_LONG_DOUBLE:	V->data.ldbl = V->fn.fnLongDouble(ev);	break;
199 #endif
200 	case AG_VARIABLE_POINTER:	V->data.p = V->fn.fnPointer(ev);	break;
201 	case AG_VARIABLE_CONST_POINTER:	V->data.Cp = V->fn.fnConstPointer(ev);	break;
202 	case AG_VARIABLE_STRING:
203 	case AG_VARIABLE_CONST_STRING:
204 		V->fn.fnString(ev, V->data.s, V->info.size);
205 		break;
206 	default:
207 		break;
208 	}
209 	return (0);
210 }
211 
212 /*
213  * Print the specified variable to fixed-size buffer. The Variable must be
214  * locked, and must have been previously evaluated if associated with a
215  * function.
216  */
217 static void
AG_PrintFlagsVariable(char * s,size_t len,Uint32 val,AG_Variable * V)218 AG_PrintFlagsVariable(char *s, size_t len, Uint32 val, AG_Variable *V)
219 {
220 	Snprintf(s, len, "%s", (val & V->info.bitmask)?"Set":"UnSet");
221 }
222 
223 void
AG_PrintVariable(char * s,size_t len,AG_Variable * V)224 AG_PrintVariable(char *s, size_t len, AG_Variable *V)
225 {
226 	Uint val;
227 
228 	switch (V->type) {
229 	case AG_VARIABLE_UINT:		StrlcpyUint(s, V->data.u, len);				break;
230 	case AG_VARIABLE_P_UINT:	StrlcpyUint(s, *(Uint *)V->data.p, len);		break;
231 	case AG_VARIABLE_INT:		StrlcpyInt(s, V->data.i, len);				break;
232 	case AG_VARIABLE_P_INT:		StrlcpyInt(s, *(int *)V->data.p, len);			break;
233 	case AG_VARIABLE_UINT8:		StrlcpyUint(s, (Uint)V->data.u8, len);			break;
234 	case AG_VARIABLE_P_UINT8:	StrlcpyUint(s, (Uint)*(Uint8 *)V->data.p, len);		break;
235 	case AG_VARIABLE_SINT8:		StrlcpyInt(s, (int)V->data.s8, len);			break;
236 	case AG_VARIABLE_P_SINT8:	StrlcpyInt(s, (int)*(Sint8 *)V->data.p, len);		break;
237 	case AG_VARIABLE_UINT16:	StrlcpyUint(s, (Uint)V->data.u16, len);			break;
238 	case AG_VARIABLE_P_UINT16:	StrlcpyUint(s, (Uint)*(Uint16 *)V->data.p, len);	break;
239 	case AG_VARIABLE_SINT16:	StrlcpyInt(s, (int)V->data.s16, len);			break;
240 	case AG_VARIABLE_P_SINT16:	StrlcpyInt(s, (int)*(Sint16 *)V->data.p, len);		break;
241 	case AG_VARIABLE_UINT32:	Snprintf(s, len, "%lu", (Ulong)V->data.u32);		break;
242 	case AG_VARIABLE_P_UINT32:	Snprintf(s, len, "%lu", (Ulong)*(Uint32 *)V->data.p);	break;
243 	case AG_VARIABLE_SINT32:	Snprintf(s, len, "%ld", (long)V->data.s32);		break;
244 	case AG_VARIABLE_P_SINT32:	Snprintf(s, len, "%ld", (long)*(Sint32 *)V->data.p);	break;
245 #ifdef HAVE_64BIT
246 	case AG_VARIABLE_SINT64:	Snprintf(s, len, "%lld", (long long)V->data.s64);		break;
247 	case AG_VARIABLE_P_SINT64:	Snprintf(s, len, "%lld", (long long)*(Sint64 *)V->data.p);	break;
248 	case AG_VARIABLE_UINT64:	Snprintf(s, len, "%llu", (unsigned long long)V->data.u64);		break;
249 	case AG_VARIABLE_P_UINT64:	Snprintf(s, len, "%llu", (unsigned long long)*(Sint64 *)V->data.p);	break;
250 #endif
251 	case AG_VARIABLE_FLOAT:		Snprintf(s, len, "%.2f", V->data.flt);			break;
252 	case AG_VARIABLE_P_FLOAT:	Snprintf(s, len, "%.2f", *(float *)V->data.p);		break;
253 	case AG_VARIABLE_DOUBLE:	Snprintf(s, len, "%.2f", V->data.dbl);			break;
254 	case AG_VARIABLE_P_DOUBLE:	Snprintf(s, len, "%.2f", *(double *)V->data.p);		break;
255 #ifdef HAVE_LONG_DOUBLE
256 	case AG_VARIABLE_P_LONG_DOUBLE:	Snprintf(s, len, "%.2Lf", *(long double *)V->data.p);	break;
257 #endif
258 	case AG_VARIABLE_STRING:
259 	case AG_VARIABLE_CONST_STRING:
260 		Strlcpy(s, V->data.s, len);
261 		break;
262 	case AG_VARIABLE_P_STRING:
263 	case AG_VARIABLE_P_CONST_STRING:
264 		Strlcpy(s, V->data.s, len);
265 		break;
266 	case AG_VARIABLE_POINTER:
267 	case AG_VARIABLE_CONST_POINTER:
268 		Snprintf(s, len, "%p", V->data.p);
269 		break;
270 	case AG_VARIABLE_P_POINTER:
271 	case AG_VARIABLE_P_CONST_POINTER:
272 		Snprintf(s, len, "%p", *(void **)V->data.p);
273 		break;
274 	case AG_VARIABLE_P_FLAG:
275 		val = *(Uint *)V->data.p;
276 		AG_PrintFlagsVariable(s, len, val, V);
277 		break;
278 	case AG_VARIABLE_P_FLAG8:
279 		val = *(Uint8 *)V->data.p;
280 		AG_PrintFlagsVariable(s, len, val, V);
281 		break;
282 	case AG_VARIABLE_P_FLAG16:
283 		val = *(Uint16 *)V->data.p;
284 		AG_PrintFlagsVariable(s, len, val, V);
285 		break;
286 	case AG_VARIABLE_P_FLAG32:
287 		val = *(Uint32 *)V->data.p;
288 		AG_PrintFlagsVariable(s, len, val, V);
289 		break;
290 	default:
291 		s[0] = '?';
292 		s[1] = '\0';
293 		break;
294 	}
295 }
296 
297 /*
298  * Lookup a variable by name and return a generic pointer to its current value.
299  * If the variable is a reference, the target is accessed. If the variable is
300  * function-defined, that function is invoked.
301  *
302  * The variable is returned locked. Returns NULL if the variable is undefined.
303  */
304 AG_Variable *
AG_GetVariable(void * pObj,const char * name,...)305 AG_GetVariable(void *pObj, const char *name, ...)
306 {
307 	AG_Object *obj = pObj;
308 	void **p;
309 	AG_Variable *V;
310 	va_list ap;
311 
312 	va_start(ap, name);
313 	p = va_arg(ap, void **);
314 	va_end(ap);
315 
316 	AG_ObjectLock(obj);
317 	if ((V = AG_GetVariableLocked(obj, name)) == NULL) {
318 		goto fail;
319 	}
320 	if (V->fn.fnVoid != NULL) {
321 		AG_EvalVariable(obj, V);
322 	}
323 	if (p != NULL) {
324 		*p = (agVariableTypes[V->type].indirLvl > 0) ?
325 		    V->data.p : &V->data;
326 	}
327 	AG_ObjectUnlock(obj);
328 	return (V);
329 fail:
330 	AG_ObjectUnlock(obj);
331 	return (NULL);
332 }
333 
334 /*
335  * Search for a variable from an a "object-name:prop-name" string,
336  * relative to the specified VFS. Returns the Variable locked.
337  */
338 AG_Variable *
AG_GetVariableVFS(void * vfsRoot,const char * varPath)339 AG_GetVariableVFS(void *vfsRoot, const char *varPath)
340 {
341 	char sb[AG_OBJECT_PATH_MAX+65];
342 	char *s = &sb[0], *objName, *varName;
343 	void *obj;
344 	AG_Variable *V;
345 
346 	Strlcpy(sb, varPath, sizeof(sb));
347 	objName = Strsep(&s, ":");
348 	varName = Strsep(&s, ":");
349 	if (objName == NULL || varName == NULL ||
350 	    objName[0] == '\0' || varName[0] == '\0') {
351 		AG_SetError(_("Invalid variable path: %s"), varPath);
352 		return (NULL);
353 	}
354 	if ((obj = AG_ObjectFindS(vfsRoot, objName)) == NULL) {
355 		return (NULL);
356 	}
357 	if ((V = AG_GetVariableLocked(obj, varName)) == NULL) {
358 		return (NULL);
359 	}
360 	if (V->fn.fnVoid != NULL) {
361 		AG_EvalVariable(obj, V);
362 	}
363 	return (V);
364 }
365 
366 /* Unset a variable */
367 void
AG_Unset(void * pObj,const char * name)368 AG_Unset(void *pObj, const char *name)
369 {
370 	AG_Object *obj = pObj;
371 	AG_Variable *V;
372 
373 	TAILQ_FOREACH(V, &obj->vars, vars) {
374 		if (strcmp(V->name, name) == 0) {
375 			TAILQ_REMOVE(&obj->vars, V, vars);
376 			AG_FreeVariable(V);
377 			free(V);
378 			break;
379 		}
380 	}
381 }
382 
383 /* Body of AG_GetFoo() routines. */
384 #undef  FN_VARIABLE_GET
385 #define FN_VARIABLE_GET(_memb,_fn,_type,_getfn)			\
386 	_type rv;						\
387 	AG_Variable *V;						\
388 								\
389 	if ((V = AG_GetVariableLocked(obj,name)) == NULL) {	\
390 		Debug(obj, "No such variable: %s\n", name);	\
391 		return (_type)(0);				\
392 	}							\
393 	if (V->fn._fn != NULL) {				\
394 		_getfn(obj, V);					\
395 	}							\
396 	if (agVariableTypes[V->type].indirLvl > 0) {		\
397 		rv = *(_type *)V->data.p;			\
398 	} else {						\
399 		rv = V->data._memb;				\
400 	}							\
401 	AG_UnlockVariable(V);					\
402 	return (rv)						\
403 
404 /* Body of AG_SetFoo() routines. */
405 #undef  FN_VARIABLE_SET
406 #define FN_VARIABLE_SET(_memb,_type,ntype)			\
407 	AG_Variable *V;						\
408 								\
409 	AG_ObjectLock(obj);					\
410 	V = AG_FetchVariable(obj, name, ntype);			\
411 	if (agVariableTypes[V->type].indirLvl > 0) {		\
412 		*(_type *)V->data.p = v;			\
413 	} else {						\
414 		V->data._memb = v;				\
415 	}							\
416 	AG_ObjectUnlock(obj);					\
417 	return (V)
418 
419 /* Body of AG_BindFoo() routines. */
420 #undef  FN_VARIABLE_BIND
421 #define FN_VARIABLE_BIND(ntype)					\
422 	AG_Variable *V;						\
423 								\
424 	AG_ObjectLock(obj);					\
425 	V = AG_FetchVariableOfType(obj, name, ntype);		\
426 	V->data.p = (void *)v;					\
427 	AG_PostEvent(NULL, obj, "bound", "%p", V);		\
428 	AG_ObjectUnlock(obj);					\
429 	return (V)
430 
431 /* Body of AG_BindFooFn() routines. */
432 #undef  FN_VARIABLE_BIND_FN
433 #define FN_VARIABLE_BIND_FN(_memb,ntype)			\
434 	char evName[AG_EVENT_NAME_MAX];				\
435 	AG_Event *ev;						\
436 	AG_Variable *V;						\
437 								\
438 	Strlcpy(evName, "get-", sizeof(evName));		\
439 	Strlcat(evName, name, sizeof(evName));			\
440 	AG_ObjectLock(obj);					\
441 	V = AG_FetchVariableOfType(obj, name, ntype);		\
442 	V->fn._memb = fn;					\
443 	ev = AG_SetEvent(obj, evName, NULL, NULL);		\
444 	AG_EVENT_GET_ARGS(ev, fmt);				\
445 	AG_PostEvent(NULL, obj, "bound", "%p", V);		\
446 	AG_ObjectUnlock(obj);					\
447 	return (V)
448 
449 /* Body of AG_BindFooMp() routines. */
450 #undef  FN_VARIABLE_BIND_MP
451 #define FN_VARIABLE_BIND_MP(ntype)				\
452 	AG_Variable *V;						\
453 								\
454 	AG_ObjectLock(obj);					\
455 	V = AG_FetchVariableOfType(obj, name, ntype);		\
456 	V->mutex = mutex;					\
457 	V->data.p = (void *)v;					\
458 	AG_PostEvent(NULL, obj, "bound", "%p", V);		\
459 	AG_ObjectUnlock(obj);					\
460 	return (V)
461 
462 /*
463  * Body of our internal GetFooFn() routines which are invoked when
464  * a function must be evaluated. We store the function arguments into
465  * a "get-foo" event to avoid growing the AG_Variable structure.
466  */
467 #define FN_VARIABLE_GETFN(_field,_fname) do {			\
468 	char evName[AG_EVENT_NAME_MAX];				\
469 	AG_Event *ev;						\
470 								\
471 	Strlcpy(evName, "get-", sizeof(evName));		\
472 	Strlcat(evName, V->name, sizeof(evName));		\
473 	AG_ObjectLock(obj);					\
474 	TAILQ_FOREACH(ev, &OBJECT(obj)->events, events) {	\
475 		if (strcmp(evName, ev->name) == 0)		\
476 			break;					\
477 	}							\
478 	if (ev != NULL) {					\
479 		V->data._field = V->fn._fname(ev);		\
480 	}							\
481 	AG_ObjectUnlock(obj);					\
482 } while (0)
483 
484 
485 /*
486  * Unsigned integer
487  */
488 static void
GetUintFn(void * obj,AG_Variable * V)489 GetUintFn(void *obj, AG_Variable *V)
490 {
491 	FN_VARIABLE_GETFN(u, fnUint);
492 }
493 Uint
AG_GetUint(void * obj,const char * name)494 AG_GetUint(void *obj, const char *name)
495 {
496 	FN_VARIABLE_GET(u, fnUint, Uint, GetUintFn);
497 }
498 AG_Variable *
AG_SetUint(void * obj,const char * name,Uint v)499 AG_SetUint(void *obj, const char *name, Uint v)
500 {
501 	FN_VARIABLE_SET(u, Uint, AG_VARIABLE_UINT);
502 }
503 void
AG_InitUint(AG_Variable * V,Uint v)504 AG_InitUint(AG_Variable *V, Uint v)
505 {
506 	AG_InitVariable(V, AG_VARIABLE_UINT);
507 	V->name[0] = '\0';
508 	V->data.u = v;
509 }
510 AG_Variable *
AG_BindUint(void * obj,const char * name,Uint * v)511 AG_BindUint(void *obj, const char *name, Uint *v)
512 {
513 	FN_VARIABLE_BIND(AG_VARIABLE_P_UINT);
514 }
515 AG_Variable *
AG_BindUintFn(void * obj,const char * name,AG_UintFn fn,const char * fmt,...)516 AG_BindUintFn(void *obj, const char *name, AG_UintFn fn, const char *fmt, ...)
517 {
518 	FN_VARIABLE_BIND_FN(fnUint, AG_VARIABLE_UINT);
519 }
520 AG_Variable *
AG_BindUintMp(void * obj,const char * name,Uint * v,AG_Mutex * mutex)521 AG_BindUintMp(void *obj, const char *name, Uint *v, AG_Mutex *mutex)
522 {
523 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_UINT);
524 }
525 
526 /*
527  * Signed integer
528  */
529 static void
GetIntFn(void * obj,AG_Variable * V)530 GetIntFn(void *obj, AG_Variable *V)
531 {
532 	FN_VARIABLE_GETFN(i, fnInt);
533 }
534 int
AG_GetInt(void * obj,const char * name)535 AG_GetInt(void *obj, const char *name)
536 {
537 	FN_VARIABLE_GET(i, fnInt, int, GetIntFn);
538 }
539 AG_Variable *
AG_SetInt(void * obj,const char * name,int v)540 AG_SetInt(void *obj, const char *name, int v)
541 {
542 	FN_VARIABLE_SET(i, int, AG_VARIABLE_INT);
543 }
544 void
AG_InitInt(AG_Variable * V,int v)545 AG_InitInt(AG_Variable *V, int v)
546 {
547 	AG_InitVariable(V, AG_VARIABLE_INT);
548 	V->name[0] = '\0';
549 	V->data.i = v;
550 }
551 AG_Variable *
AG_BindInt(void * obj,const char * name,int * v)552 AG_BindInt(void *obj, const char *name, int *v)
553 {
554 	FN_VARIABLE_BIND(AG_VARIABLE_P_INT);
555 }
556 AG_Variable *
AG_BindIntFn(void * obj,const char * name,AG_IntFn fn,const char * fmt,...)557 AG_BindIntFn(void *obj, const char *name, AG_IntFn fn, const char *fmt, ...)
558 {
559 	FN_VARIABLE_BIND_FN(fnInt, AG_VARIABLE_INT);
560 }
561 AG_Variable *
AG_BindIntMp(void * obj,const char * name,int * v,AG_Mutex * mutex)562 AG_BindIntMp(void *obj, const char *name, int *v, AG_Mutex *mutex)
563 {
564 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_INT);
565 }
566 
567 /*
568  * Unsigned 8-bit integer
569  */
570 static void
GetUint8Fn(void * obj,AG_Variable * V)571 GetUint8Fn(void *obj, AG_Variable *V)
572 {
573 	FN_VARIABLE_GETFN(u8, fnUint8);
574 }
575 Uint8
AG_GetUint8(void * obj,const char * name)576 AG_GetUint8(void *obj, const char *name)
577 {
578 	FN_VARIABLE_GET(u8, fnUint8, Uint8, GetUint8Fn);
579 }
580 AG_Variable *
AG_SetUint8(void * obj,const char * name,Uint8 v)581 AG_SetUint8(void *obj, const char *name, Uint8 v)
582 {
583 	FN_VARIABLE_SET(u8, Uint8, AG_VARIABLE_UINT8);
584 }
585 void
AG_InitUint8(AG_Variable * V,Uint8 v)586 AG_InitUint8(AG_Variable *V, Uint8 v)
587 {
588 	AG_InitVariable(V, AG_VARIABLE_UINT8);
589 	V->name[0] = '\0';
590 	V->data.u8 = v;
591 }
592 AG_Variable *
AG_BindUint8(void * obj,const char * name,Uint8 * v)593 AG_BindUint8(void *obj, const char *name, Uint8 *v)
594 {
595 	FN_VARIABLE_BIND(AG_VARIABLE_P_UINT8);
596 }
597 AG_Variable *
AG_BindUint8Fn(void * obj,const char * name,AG_Uint8Fn fn,const char * fmt,...)598 AG_BindUint8Fn(void *obj, const char *name, AG_Uint8Fn fn, const char *fmt, ...)
599 {
600 	FN_VARIABLE_BIND_FN(fnUint8, AG_VARIABLE_UINT8);
601 }
602 AG_Variable *
AG_BindUint8Mp(void * obj,const char * name,Uint8 * v,AG_Mutex * mutex)603 AG_BindUint8Mp(void *obj, const char *name, Uint8 *v, AG_Mutex *mutex)
604 {
605 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_UINT8);
606 }
607 
608 /*
609  * Signed 8-bit integer
610  */
611 static void
GetSint8Fn(void * obj,AG_Variable * V)612 GetSint8Fn(void *obj, AG_Variable *V)
613 {
614 	FN_VARIABLE_GETFN(s8, fnSint8);
615 }
616 Sint8
AG_GetSint8(void * obj,const char * name)617 AG_GetSint8(void *obj, const char *name)
618 {
619 	FN_VARIABLE_GET(s8, fnSint8, Sint8, GetSint8Fn);
620 }
621 AG_Variable *
AG_SetSint8(void * obj,const char * name,Sint8 v)622 AG_SetSint8(void *obj, const char *name, Sint8 v)
623 {
624 	FN_VARIABLE_SET(s8, Sint8, AG_VARIABLE_SINT8);
625 }
626 void
AG_InitSint8(AG_Variable * V,Sint8 v)627 AG_InitSint8(AG_Variable *V, Sint8 v)
628 {
629 	AG_InitVariable(V, AG_VARIABLE_SINT8);
630 	V->name[0] = '\0';
631 	V->data.s8 = v;
632 }
633 AG_Variable *
AG_BindSint8(void * obj,const char * name,Sint8 * v)634 AG_BindSint8(void *obj, const char *name, Sint8 *v)
635 {
636 	FN_VARIABLE_BIND(AG_VARIABLE_P_SINT8);
637 }
638 AG_Variable *
AG_BindSint8Fn(void * obj,const char * name,AG_Sint8Fn fn,const char * fmt,...)639 AG_BindSint8Fn(void *obj, const char *name, AG_Sint8Fn fn, const char *fmt, ...)
640 {
641 	FN_VARIABLE_BIND_FN(fnSint8, AG_VARIABLE_SINT8);
642 }
643 AG_Variable *
AG_BindSint8Mp(void * obj,const char * name,Sint8 * v,AG_Mutex * mutex)644 AG_BindSint8Mp(void *obj, const char *name, Sint8 *v, AG_Mutex *mutex)
645 {
646 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_SINT8);
647 }
648 
649 /*
650  * Unsigned 16-bit integer
651  */
652 static void
GetUint16Fn(void * obj,AG_Variable * V)653 GetUint16Fn(void *obj, AG_Variable *V)
654 {
655 	FN_VARIABLE_GETFN(u16, fnUint16);
656 }
657 Uint16
AG_GetUint16(void * obj,const char * name)658 AG_GetUint16(void *obj, const char *name)
659 {
660 	FN_VARIABLE_GET(u16, fnUint16, Uint16, GetUint16Fn);
661 }
662 AG_Variable *
AG_SetUint16(void * obj,const char * name,Uint16 v)663 AG_SetUint16(void *obj, const char *name, Uint16 v)
664 {
665 	FN_VARIABLE_SET(u16, Uint16, AG_VARIABLE_UINT16);
666 }
667 void
AG_InitUint16(AG_Variable * V,Uint16 v)668 AG_InitUint16(AG_Variable *V, Uint16 v)
669 {
670 	AG_InitVariable(V, AG_VARIABLE_UINT16);
671 	V->name[0] = '\0';
672 	V->data.u16 = v;
673 }
674 AG_Variable *
AG_BindUint16(void * obj,const char * name,Uint16 * v)675 AG_BindUint16(void *obj, const char *name, Uint16 *v)
676 {
677 	FN_VARIABLE_BIND(AG_VARIABLE_P_UINT16);
678 }
679 AG_Variable *
AG_BindUint16Fn(void * obj,const char * name,AG_Uint16Fn fn,const char * fmt,...)680 AG_BindUint16Fn(void *obj, const char *name, AG_Uint16Fn fn, const char *fmt, ...)
681 {
682 	FN_VARIABLE_BIND_FN(fnUint16, AG_VARIABLE_UINT16);
683 }
684 AG_Variable *
AG_BindUint16Mp(void * obj,const char * name,Uint16 * v,AG_Mutex * mutex)685 AG_BindUint16Mp(void *obj, const char *name, Uint16 *v, AG_Mutex *mutex)
686 {
687 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_UINT16);
688 }
689 
690 /*
691  * Signed 16-bit integer
692  */
693 static void
GetSint16Fn(void * obj,AG_Variable * V)694 GetSint16Fn(void *obj, AG_Variable *V)
695 {
696 	FN_VARIABLE_GETFN(s16, fnSint16);
697 }
698 Sint16
AG_GetSint16(void * obj,const char * name)699 AG_GetSint16(void *obj, const char *name)
700 {
701 	FN_VARIABLE_GET(s16, fnSint16, Sint16, GetSint16Fn);
702 }
703 AG_Variable *
AG_SetSint16(void * obj,const char * name,Sint16 v)704 AG_SetSint16(void *obj, const char *name, Sint16 v)
705 {
706 	FN_VARIABLE_SET(s16, Sint16, AG_VARIABLE_SINT16);
707 }
708 void
AG_InitSint16(AG_Variable * V,Sint16 v)709 AG_InitSint16(AG_Variable *V, Sint16 v)
710 {
711 	AG_InitVariable(V, AG_VARIABLE_SINT16);
712 	V->name[0] = '\0';
713 	V->data.s16 = v;
714 }
715 AG_Variable *
AG_BindSint16(void * obj,const char * name,Sint16 * v)716 AG_BindSint16(void *obj, const char *name, Sint16 *v)
717 {
718 	FN_VARIABLE_BIND(AG_VARIABLE_P_SINT16);
719 }
720 AG_Variable *
AG_BindSint16Fn(void * obj,const char * name,AG_Sint16Fn fn,const char * fmt,...)721 AG_BindSint16Fn(void *obj, const char *name, AG_Sint16Fn fn, const char *fmt, ...)
722 {
723 	FN_VARIABLE_BIND_FN(fnSint16, AG_VARIABLE_SINT16);
724 }
725 AG_Variable *
AG_BindSint16Mp(void * obj,const char * name,Sint16 * v,AG_Mutex * mutex)726 AG_BindSint16Mp(void *obj, const char *name, Sint16 *v, AG_Mutex *mutex)
727 {
728 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_SINT16);
729 }
730 
731 /*
732  * Unsigned 32-bit integer
733  */
734 static void
GetUint32Fn(void * obj,AG_Variable * V)735 GetUint32Fn(void *obj, AG_Variable *V)
736 {
737 	FN_VARIABLE_GETFN(u32, fnUint32);
738 }
739 Uint32
AG_GetUint32(void * obj,const char * name)740 AG_GetUint32(void *obj, const char *name)
741 {
742 	FN_VARIABLE_GET(u32, fnUint32, Uint32, GetUint32Fn);
743 }
744 AG_Variable *
AG_SetUint32(void * obj,const char * name,Uint32 v)745 AG_SetUint32(void *obj, const char *name, Uint32 v)
746 {
747 	FN_VARIABLE_SET(u32, Uint32, AG_VARIABLE_UINT32);
748 }
749 void
AG_InitUint32(AG_Variable * V,Uint32 v)750 AG_InitUint32(AG_Variable *V, Uint32 v)
751 {
752 	AG_InitVariable(V, AG_VARIABLE_UINT32);
753 	V->name[0] = '\0';
754 	V->data.u32 = v;
755 }
756 AG_Variable *
AG_BindUint32(void * obj,const char * name,Uint32 * v)757 AG_BindUint32(void *obj, const char *name, Uint32 *v)
758 {
759 	FN_VARIABLE_BIND(AG_VARIABLE_P_UINT32);
760 }
761 AG_Variable *
AG_BindUint32Fn(void * obj,const char * name,AG_Uint32Fn fn,const char * fmt,...)762 AG_BindUint32Fn(void *obj, const char *name, AG_Uint32Fn fn, const char *fmt, ...)
763 {
764 	FN_VARIABLE_BIND_FN(fnUint32, AG_VARIABLE_UINT32);
765 }
766 AG_Variable *
AG_BindUint32Mp(void * obj,const char * name,Uint32 * v,AG_Mutex * mutex)767 AG_BindUint32Mp(void *obj, const char *name, Uint32 *v, AG_Mutex *mutex)
768 {
769 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_UINT32);
770 }
771 
772 /*
773  * Signed 32-bit integer
774  */
775 static void
GetSint32Fn(void * obj,AG_Variable * V)776 GetSint32Fn(void *obj, AG_Variable *V)
777 {
778 	FN_VARIABLE_GETFN(s32, fnSint32);
779 }
780 Sint32
AG_GetSint32(void * obj,const char * name)781 AG_GetSint32(void *obj, const char *name)
782 {
783 	FN_VARIABLE_GET(s32, fnSint32, Sint32, GetSint32Fn);
784 }
785 AG_Variable *
AG_SetSint32(void * obj,const char * name,Sint32 v)786 AG_SetSint32(void *obj, const char *name, Sint32 v)
787 {
788 	FN_VARIABLE_SET(s32, Sint32, AG_VARIABLE_SINT32);
789 }
790 void
AG_InitSint32(AG_Variable * V,Sint32 v)791 AG_InitSint32(AG_Variable *V, Sint32 v)
792 {
793 	AG_InitVariable(V, AG_VARIABLE_SINT32);
794 	V->name[0] = '\0';
795 	V->data.s32 = v;
796 }
797 AG_Variable *
AG_BindSint32(void * obj,const char * name,Sint32 * v)798 AG_BindSint32(void *obj, const char *name, Sint32 *v)
799 {
800 	FN_VARIABLE_BIND(AG_VARIABLE_P_SINT32);
801 }
802 AG_Variable *
AG_BindSint32Fn(void * obj,const char * name,AG_Sint32Fn fn,const char * fmt,...)803 AG_BindSint32Fn(void *obj, const char *name, AG_Sint32Fn fn, const char *fmt, ...)
804 {
805 	FN_VARIABLE_BIND_FN(fnSint32, AG_VARIABLE_SINT32);
806 }
807 AG_Variable *
AG_BindSint32Mp(void * obj,const char * name,Sint32 * v,AG_Mutex * mutex)808 AG_BindSint32Mp(void *obj, const char *name, Sint32 *v, AG_Mutex *mutex)
809 {
810 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_SINT32);
811 }
812 
813 #ifdef HAVE_64BIT
814 /*
815  * Unsigned 64-bit integer
816  */
817 static void
GetUint64Fn(void * obj,AG_Variable * V)818 GetUint64Fn(void *obj, AG_Variable *V)
819 {
820 	FN_VARIABLE_GETFN(u64, fnUint64);
821 }
822 Uint64
AG_GetUint64(void * obj,const char * name)823 AG_GetUint64(void *obj, const char *name)
824 {
825 	FN_VARIABLE_GET(u64, fnUint64, Uint64, GetUint64Fn);
826 }
827 AG_Variable *
AG_SetUint64(void * obj,const char * name,Uint64 v)828 AG_SetUint64(void *obj, const char *name, Uint64 v)
829 {
830 	FN_VARIABLE_SET(u64, Uint64, AG_VARIABLE_UINT64);
831 }
832 void
AG_InitUint64(AG_Variable * V,Uint64 v)833 AG_InitUint64(AG_Variable *V, Uint64 v)
834 {
835 	AG_InitVariable(V, AG_VARIABLE_UINT64);
836 	V->name[0] = '\0';
837 	V->data.u64 = v;
838 }
839 AG_Variable *
AG_BindUint64(void * obj,const char * name,Uint64 * v)840 AG_BindUint64(void *obj, const char *name, Uint64 *v)
841 {
842 	FN_VARIABLE_BIND(AG_VARIABLE_P_UINT64);
843 }
844 AG_Variable *
AG_BindUint64Fn(void * obj,const char * name,AG_Uint64Fn fn,const char * fmt,...)845 AG_BindUint64Fn(void *obj, const char *name, AG_Uint64Fn fn, const char *fmt, ...)
846 {
847 	FN_VARIABLE_BIND_FN(fnUint64, AG_VARIABLE_UINT64);
848 }
849 AG_Variable *
AG_BindUint64Mp(void * obj,const char * name,Uint64 * v,AG_Mutex * mutex)850 AG_BindUint64Mp(void *obj, const char *name, Uint64 *v, AG_Mutex *mutex)
851 {
852 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_UINT64);
853 }
854 
855 /*
856  * Signed 64-bit integer
857  */
858 static void
GetSint64Fn(void * obj,AG_Variable * V)859 GetSint64Fn(void *obj, AG_Variable *V)
860 {
861 	FN_VARIABLE_GETFN(s64, fnSint64);
862 }
863 Sint64
AG_GetSint64(void * obj,const char * name)864 AG_GetSint64(void *obj, const char *name)
865 {
866 	FN_VARIABLE_GET(s64, fnSint64, Sint64, GetSint64Fn);
867 }
868 AG_Variable *
AG_SetSint64(void * obj,const char * name,Sint64 v)869 AG_SetSint64(void *obj, const char *name, Sint64 v)
870 {
871 	FN_VARIABLE_SET(s64, Sint64, AG_VARIABLE_SINT64);
872 }
873 void
AG_InitSint64(AG_Variable * V,Sint64 v)874 AG_InitSint64(AG_Variable *V, Sint64 v)
875 {
876 	AG_InitVariable(V, AG_VARIABLE_SINT64);
877 	V->name[0] = '\0';
878 	V->data.s64 = v;
879 }
880 AG_Variable *
AG_BindSint64(void * obj,const char * name,Sint64 * v)881 AG_BindSint64(void *obj, const char *name, Sint64 *v)
882 {
883 	FN_VARIABLE_BIND(AG_VARIABLE_P_SINT64);
884 }
885 AG_Variable *
AG_BindSint64Fn(void * obj,const char * name,AG_Sint64Fn fn,const char * fmt,...)886 AG_BindSint64Fn(void *obj, const char *name, AG_Sint64Fn fn, const char *fmt, ...)
887 {
888 	FN_VARIABLE_BIND_FN(fnSint64, AG_VARIABLE_SINT64);
889 }
890 AG_Variable *
AG_BindSint64Mp(void * obj,const char * name,Sint64 * v,AG_Mutex * mutex)891 AG_BindSint64Mp(void *obj, const char *name, Sint64 *v, AG_Mutex *mutex)
892 {
893 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_SINT64);
894 }
895 #endif /* HAVE_64BIT */
896 
897 /*
898  * Single-precision floating-point number.
899  */
900 static void
GetFloatFn(void * obj,AG_Variable * V)901 GetFloatFn(void *obj, AG_Variable *V)
902 {
903 	FN_VARIABLE_GETFN(flt, fnFloat);
904 }
905 float
AG_GetFloat(void * obj,const char * name)906 AG_GetFloat(void *obj, const char *name)
907 {
908 	FN_VARIABLE_GET(flt, fnFloat, float, GetFloatFn);
909 }
910 AG_Variable *
AG_SetFloat(void * obj,const char * name,float v)911 AG_SetFloat(void *obj, const char *name, float v)
912 {
913 	FN_VARIABLE_SET(flt, float, AG_VARIABLE_FLOAT);
914 }
915 void
AG_InitFloat(AG_Variable * V,float v)916 AG_InitFloat(AG_Variable *V, float v)
917 {
918 	AG_InitVariable(V, AG_VARIABLE_FLOAT);
919 	V->name[0] = '\0';
920 	V->data.flt = v;
921 }
922 AG_Variable *
AG_BindFloat(void * obj,const char * name,float * v)923 AG_BindFloat(void *obj, const char *name, float *v)
924 {
925 	FN_VARIABLE_BIND(AG_VARIABLE_P_FLOAT);
926 }
927 AG_Variable *
AG_BindFloatFn(void * obj,const char * name,AG_FloatFn fn,const char * fmt,...)928 AG_BindFloatFn(void *obj, const char *name, AG_FloatFn fn, const char *fmt, ...)
929 {
930 	FN_VARIABLE_BIND_FN(fnFloat, AG_VARIABLE_FLOAT);
931 }
932 AG_Variable *
AG_BindFloatMp(void * obj,const char * name,float * v,AG_Mutex * mutex)933 AG_BindFloatMp(void *obj, const char *name, float *v, AG_Mutex *mutex)
934 {
935 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_FLOAT);
936 }
937 
938 /*
939  * Double-precision floating-point number.
940  */
941 static void
GetDoubleFn(void * obj,AG_Variable * V)942 GetDoubleFn(void *obj, AG_Variable *V)
943 {
944 	FN_VARIABLE_GETFN(dbl, fnDouble);
945 }
946 double
AG_GetDouble(void * obj,const char * name)947 AG_GetDouble(void *obj, const char *name)
948 {
949 	FN_VARIABLE_GET(dbl, fnDouble, double, GetDoubleFn);
950 }
951 AG_Variable *
AG_SetDouble(void * obj,const char * name,double v)952 AG_SetDouble(void *obj, const char *name, double v)
953 {
954 	FN_VARIABLE_SET(dbl, double, AG_VARIABLE_DOUBLE);
955 }
956 void
AG_InitDouble(AG_Variable * V,double v)957 AG_InitDouble(AG_Variable *V, double v)
958 {
959 	AG_InitVariable(V, AG_VARIABLE_DOUBLE);
960 	V->name[0] = '\0';
961 	V->data.dbl = v;
962 }
963 AG_Variable *
AG_BindDouble(void * obj,const char * name,double * v)964 AG_BindDouble(void *obj, const char *name, double *v)
965 {
966 	FN_VARIABLE_BIND(AG_VARIABLE_P_DOUBLE);
967 }
968 AG_Variable *
AG_BindDoubleFn(void * obj,const char * name,AG_DoubleFn fn,const char * fmt,...)969 AG_BindDoubleFn(void *obj, const char *name, AG_DoubleFn fn, const char *fmt, ...)
970 {
971 	FN_VARIABLE_BIND_FN(fnDouble, AG_VARIABLE_DOUBLE);
972 }
973 AG_Variable *
AG_BindDoubleMp(void * obj,const char * name,double * v,AG_Mutex * mutex)974 AG_BindDoubleMp(void *obj, const char *name, double *v, AG_Mutex *mutex)
975 {
976 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_DOUBLE);
977 }
978 
979 #ifdef HAVE_LONG_DOUBLE
980 /*
981  * Quad-precision floating-point number.
982  */
983 static void
GetLongDoubleFn(void * obj,AG_Variable * V)984 GetLongDoubleFn(void *obj, AG_Variable *V)
985 {
986 	FN_VARIABLE_GETFN(ldbl, fnLongDouble);
987 }
988 long double
AG_GetLongDouble(void * obj,const char * name)989 AG_GetLongDouble(void *obj, const char *name)
990 {
991 	FN_VARIABLE_GET(ldbl, fnLongDouble, long double, GetLongDoubleFn);
992 }
993 AG_Variable *
AG_SetLongDouble(void * obj,const char * name,long double v)994 AG_SetLongDouble(void *obj, const char *name, long double v)
995 {
996 	FN_VARIABLE_SET(ldbl, long double, AG_VARIABLE_LONG_DOUBLE);
997 }
998 void
AG_InitLongDouble(AG_Variable * V,long double v)999 AG_InitLongDouble(AG_Variable *V, long double v)
1000 {
1001 	AG_InitVariable(V, AG_VARIABLE_LONG_DOUBLE);
1002 	V->name[0] = '\0';
1003 	V->data.ldbl = v;
1004 }
1005 AG_Variable *
AG_BindLongDouble(void * obj,const char * name,long double * v)1006 AG_BindLongDouble(void *obj, const char *name, long double *v)
1007 {
1008 	FN_VARIABLE_BIND(AG_VARIABLE_P_LONG_DOUBLE);
1009 }
1010 AG_Variable *
AG_BindLongDoubleFn(void * obj,const char * name,AG_LongDoubleFn fn,const char * fmt,...)1011 AG_BindLongDoubleFn(void *obj, const char *name, AG_LongDoubleFn fn, const char *fmt, ...)
1012 {
1013 	FN_VARIABLE_BIND_FN(fnLongDouble, AG_VARIABLE_LONG_DOUBLE);
1014 }
1015 AG_Variable *
AG_BindLongDoubleMp(void * obj,const char * name,long double * v,AG_Mutex * mutex)1016 AG_BindLongDoubleMp(void *obj, const char *name, long double *v, AG_Mutex *mutex)
1017 {
1018 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_LONG_DOUBLE);
1019 }
1020 #endif /* HAVE_LONG_DOUBLE */
1021 
1022 /*
1023  * Pointer routines.
1024  */
1025 static void
GetPointerFn(void * obj,AG_Variable * V)1026 GetPointerFn(void *obj, AG_Variable *V)
1027 {
1028 	FN_VARIABLE_GETFN(p, fnPointer);
1029 }
1030 void *
AG_GetPointer(void * obj,const char * name)1031 AG_GetPointer(void *obj, const char *name)
1032 {
1033 	FN_VARIABLE_GET(p, fnPointer, void *, GetPointerFn);
1034 }
1035 AG_Variable *
AG_SetPointer(void * obj,const char * name,void * v)1036 AG_SetPointer(void *obj, const char *name, void *v)
1037 {
1038 	FN_VARIABLE_SET(p, void *, AG_VARIABLE_POINTER);
1039 }
1040 void
AG_InitPointer(AG_Variable * V,void * v)1041 AG_InitPointer(AG_Variable *V, void *v)
1042 {
1043 	AG_InitVariable(V, AG_VARIABLE_POINTER);
1044 	V->name[0] = '\0';
1045 	V->data.p = v;
1046 }
1047 AG_Variable *
AG_BindPointer(void * obj,const char * name,void ** v)1048 AG_BindPointer(void *obj, const char *name, void **v)
1049 {
1050 	FN_VARIABLE_BIND(AG_VARIABLE_P_POINTER);
1051 }
1052 AG_Variable *
AG_BindPointerFn(void * obj,const char * name,AG_PointerFn fn,const char * fmt,...)1053 AG_BindPointerFn(void *obj, const char *name, AG_PointerFn fn, const char *fmt, ...)
1054 {
1055 	FN_VARIABLE_BIND_FN(fnPointer, AG_VARIABLE_POINTER);
1056 }
1057 AG_Variable *
AG_BindPointerMp(void * obj,const char * name,void ** v,AG_Mutex * mutex)1058 AG_BindPointerMp(void *obj, const char *name, void **v, AG_Mutex *mutex)
1059 {
1060 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_POINTER);
1061 	return (V);
1062 }
1063 
1064 /*
1065  * AG_Text routines.
1066  */
1067 static void
GetTextFn(void * obj,AG_Variable * V)1068 GetTextFn(void *obj, AG_Variable *V)
1069 {
1070 	FN_VARIABLE_GETFN(p, fnText);
1071 }
1072 AG_Text *
AG_GetText(void * obj,const char * name)1073 AG_GetText(void *obj, const char *name)
1074 {
1075 	FN_VARIABLE_GET(p, fnText, void *, GetTextFn);
1076 }
1077 AG_Variable *
AG_SetText(void * obj,const char * name,AG_Text * v)1078 AG_SetText(void *obj, const char *name, AG_Text *v)
1079 {
1080 	FN_VARIABLE_SET(p, void *, AG_VARIABLE_P_TEXT);
1081 }
1082 void
AG_InitText(AG_Variable * V,AG_Text * v)1083 AG_InitText(AG_Variable *V, AG_Text *v)
1084 {
1085 	AG_InitVariable(V, AG_VARIABLE_P_TEXT);
1086 	V->name[0] = '\0';
1087 	V->data.p = v;
1088 }
1089 AG_Variable *
AG_BindText(void * obj,const char * name,AG_Text * v)1090 AG_BindText(void *obj, const char *name, AG_Text *v)
1091 {
1092 	FN_VARIABLE_BIND(AG_VARIABLE_P_TEXT);
1093 }
1094 AG_Variable *
AG_BindTextFn(void * obj,const char * name,AG_TextFn fn,const char * fmt,...)1095 AG_BindTextFn(void *obj, const char *name, AG_TextFn fn, const char *fmt, ...)
1096 {
1097 	FN_VARIABLE_BIND_FN(fnText, AG_VARIABLE_P_TEXT);
1098 }
1099 AG_Variable *
AG_BindTextMp(void * obj,const char * name,AG_Text * v,AG_Mutex * mutex)1100 AG_BindTextMp(void *obj, const char *name, AG_Text *v, AG_Mutex *mutex)
1101 {
1102 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_TEXT);
1103 	return (V);
1104 }
1105 
1106 
1107 /*
1108  * Const pointer routines.
1109  */
1110 static void
GetConstPointerFn(void * obj,AG_Variable * V)1111 GetConstPointerFn(void *obj, AG_Variable *V)
1112 {
1113 	FN_VARIABLE_GETFN(Cp, fnConstPointer);
1114 }
1115 const void *
AG_GetConstPointer(void * obj,const char * name)1116 AG_GetConstPointer(void *obj, const char *name)
1117 {
1118 	FN_VARIABLE_GET(Cp, fnConstPointer, const void *, GetConstPointerFn);
1119 }
1120 AG_Variable *
AG_SetConstPointer(void * obj,const char * name,const void * v)1121 AG_SetConstPointer(void *obj, const char *name, const void *v)
1122 {
1123 	FN_VARIABLE_SET(Cp, const void *, AG_VARIABLE_CONST_POINTER);
1124 }
1125 void
AG_InitConstPointer(AG_Variable * V,const void * v)1126 AG_InitConstPointer(AG_Variable *V, const void *v)
1127 {
1128 	AG_InitVariable(V, AG_VARIABLE_CONST_POINTER);
1129 	V->name[0] = '\0';
1130 	V->data.Cp = v;
1131 }
1132 AG_Variable *
AG_BindConstPointer(void * obj,const char * name,const void ** v)1133 AG_BindConstPointer(void *obj, const char *name, const void **v)
1134 {
1135 	FN_VARIABLE_BIND(AG_VARIABLE_P_CONST_POINTER);
1136 }
1137 AG_Variable *
AG_BindConstPointerFn(void * obj,const char * name,AG_ConstPointerFn fn,const char * fmt,...)1138 AG_BindConstPointerFn(void *obj, const char *name, AG_ConstPointerFn fn, const char *fmt, ...)
1139 {
1140 	FN_VARIABLE_BIND_FN(fnConstPointer, AG_VARIABLE_CONST_POINTER);
1141 }
1142 AG_Variable *
AG_BindConstPointerMp(void * obj,const char * name,const void ** v,AG_Mutex * mutex)1143 AG_BindConstPointerMp(void *obj, const char *name, const void **v,
1144     AG_Mutex *mutex)
1145 {
1146 	FN_VARIABLE_BIND_MP(AG_VARIABLE_P_CONST_POINTER);
1147 }
1148 
1149 /*
1150  * String get/set routines.
1151  */
1152 static size_t
GetStringFn(void * obj,AG_Variable * V,char * dst,size_t dstSize)1153 GetStringFn(void *obj, AG_Variable *V, char *dst, size_t dstSize)
1154 {
1155 	char evName[AG_EVENT_NAME_MAX];
1156 	AG_Event *ev;
1157 	size_t rv;
1158 
1159 	Strlcpy(evName, "get-", sizeof(evName));
1160 	Strlcat(evName, V->name, sizeof(evName));
1161 
1162 	AG_ObjectLock(obj);
1163 	TAILQ_FOREACH(ev, &OBJECT(obj)->events, events) {
1164 		if (strcmp(evName, ev->name) == 0)
1165 			break;
1166 	}
1167 	rv = (V->fn.fnString != NULL) ?
1168 	      V->fn.fnString(ev, dst, dstSize) : 0;
1169 	AG_ObjectUnlock(obj);
1170 	return (rv);
1171 }
1172 size_t
AG_GetString(void * pObj,const char * name,char * dst,size_t dstSize)1173 AG_GetString(void *pObj, const char *name, char *dst, size_t dstSize)
1174 {
1175 	AG_Object *obj = pObj;
1176 	AG_Variable *V;
1177 	size_t rv;
1178 
1179 	if ((V = AG_GetVariableLocked(obj, name)) == NULL) {
1180 		return (0);
1181 	}
1182 	if (V->fn.fnString != NULL) {
1183 		rv = GetStringFn(obj, V, dst, dstSize);
1184 	} else {
1185 		Strlcpy(dst, V->data.s, dstSize);
1186 		rv = strlen(V->data.s);
1187 	}
1188 	AG_UnlockVariable(V);
1189 	return (rv);
1190 }
1191 char *
AG_GetStringDup(void * pObj,const char * name)1192 AG_GetStringDup(void *pObj, const char *name)
1193 {
1194 	AG_Object *obj = pObj;
1195 	AG_Variable *V;
1196 	char *s;
1197 
1198 	if ((V = AG_GetVariableLocked(obj, name)) == NULL) {
1199 		return (NULL);
1200 	}
1201 	if (V->fn.fnString != NULL) {
1202 		if ((s = TryMalloc(V->info.size)) == NULL) {
1203 			goto fail;
1204 		}
1205 		(void)GetStringFn(obj, V, s, V->info.size);
1206 	} else {
1207 		s = TryStrdup(V->data.s);
1208 	}
1209 	AG_UnlockVariable(V);
1210 	return (s);
1211 fail:
1212 	AG_UnlockVariable(V);
1213 	return (NULL);
1214 }
1215 /* Return a direct pointer to a string buffer (not free-threaded). */
1216 char *
AG_GetStringP(void * pObj,const char * name)1217 AG_GetStringP(void *pObj, const char *name)
1218 {
1219 	AG_Object *obj = pObj;
1220 	AG_Variable *V;
1221 	char *s;
1222 
1223 	if ((V = AG_GetVariableLocked(obj, name)) == NULL) {
1224 		return (NULL);
1225 	}
1226 	s = V->data.s;
1227 	AG_UnlockVariable(V);
1228 	return (s);
1229 }
1230 
1231 /*
1232  * Set the value of a string variable. If the variable exists as a reference
1233  * to a fixed-size buffer, the string is copied to the buffer. Otherwise, the
1234  * string is duplicated.
1235  */
1236 AG_Variable *
AG_SetString(void * pObj,const char * name,const char * s)1237 AG_SetString(void *pObj, const char *name, const char *s)
1238 {
1239 	AG_Object *obj = pObj;
1240 	AG_Variable *V;
1241 
1242 	AG_ObjectLock(obj);
1243 	TAILQ_FOREACH(V, &obj->vars, vars) {
1244 		if (strcmp(V->name, name) == 0)
1245 			break;
1246 	}
1247 	if (V == NULL) {
1248 		V = Malloc(sizeof(AG_Variable));
1249 		AG_InitVariable(V, AG_VARIABLE_STRING);
1250 		Strlcpy(V->name, name, sizeof(V->name));
1251 		TAILQ_INSERT_TAIL(&obj->vars, V, vars);
1252 
1253 		V->info.size = 0;				/* Allocated */
1254 		V->data.s = Strdup(s);
1255 	} else {
1256 		switch (V->type) {
1257 		case AG_VARIABLE_STRING:
1258 			if (V->data.s != NULL && V->info.size == 0) {
1259 				free(V->data.s);
1260 			}
1261 			V->data.s = Strdup(s);
1262 			V->info.size = 0;
1263 			break;
1264 		case AG_VARIABLE_P_STRING:
1265 			AG_LockVariable(V);
1266 			Strlcpy(V->data.s, s, V->info.size);
1267 			AG_UnlockVariable(V);
1268 			break;
1269 		default:
1270 			AG_FreeVariable(V);
1271 			AG_InitVariable(V, AG_VARIABLE_STRING);
1272 			V->info.size = 0;			/* Allocated */
1273 			V->data.s = Strdup(s);
1274 			break;
1275 		}
1276 	}
1277 	AG_ObjectUnlock(obj);
1278 	return (V);
1279 }
1280 void
AG_InitString(AG_Variable * V,const char * v)1281 AG_InitString(AG_Variable *V, const char *v)
1282 {
1283 	AG_InitVariable(V, AG_VARIABLE_STRING);
1284 	V->name[0] = '\0';
1285 	V->data.s = Strdup(v);
1286 	V->info.size = 0;
1287 }
1288 void
AG_InitStringNODUP(AG_Variable * V,char * v)1289 AG_InitStringNODUP(AG_Variable *V, char *v)
1290 {
1291 	AG_InitVariable(V, AG_VARIABLE_STRING);
1292 	V->name[0] = '\0';
1293 	V->data.s = v;
1294 	V->info.size = 0;
1295 }
1296 
1297 /*
1298  * Variant of AG_SetString() where the string argument is taken to be
1299  * a dynamically-allocated string buffer which does not need to be
1300  * duplicated. The provided buffer will be freed automatically with
1301  * the parent object.
1302  */
1303 AG_Variable *
AG_SetStringNODUP(void * obj,const char * name,char * s)1304 AG_SetStringNODUP(void *obj, const char *name, char *s)
1305 {
1306 	AG_Variable *V;
1307 
1308 	AG_ObjectLock(obj);
1309 	V = AG_FetchVariable(obj, name, AG_VARIABLE_STRING);
1310 	switch (V->type) {
1311 	case AG_VARIABLE_STRING:
1312 		if (V->data.s != NULL && V->info.size == 0) {
1313 			free(V->data.s);
1314 		}
1315 		V->data.s = s;
1316 		V->info.size = 0;
1317 		break;
1318 	case AG_VARIABLE_P_STRING:
1319 		AG_LockVariable(V);
1320 		Strlcpy(V->data.s, s, V->info.size);
1321 		AG_UnlockVariable(V);
1322 		break;
1323 	default:
1324 		AG_FreeVariable(V);
1325 		AG_InitVariable(V, AG_VARIABLE_STRING);
1326 		V->data.s = s;
1327 		V->info.size = 0;			/* Allocated */
1328 		break;
1329 	}
1330 	AG_ObjectUnlock(obj);
1331 	return (V);
1332 }
1333 
1334 AG_Variable *
AG_PrtString(void * obj,const char * name,const char * fmt,...)1335 AG_PrtString(void *obj, const char *name, const char *fmt, ...)
1336 {
1337 	va_list ap;
1338 	char *s;
1339 
1340 	va_start(ap, fmt);
1341 	Vasprintf(&s, fmt, ap);
1342 	va_end(ap);
1343 
1344 	return AG_SetStringNODUP(obj, name, s);
1345 }
1346 AG_Variable *
AG_BindString(void * obj,const char * name,char * buf,size_t bufSize)1347 AG_BindString(void *obj, const char *name, char *buf, size_t bufSize)
1348 {
1349 	AG_Variable *V;
1350 
1351 	AG_ObjectLock(obj);
1352 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_STRING);
1353 	V->data.s = buf;
1354 	V->info.size = bufSize;
1355 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1356 	AG_ObjectUnlock(obj);
1357 	return (V);
1358 }
1359 AG_Variable *
AG_BindStringFn(void * obj,const char * name,AG_StringFn fn,const char * fmt,...)1360 AG_BindStringFn(void *obj, const char *name, AG_StringFn fn, const char *fmt, ...)
1361 {
1362 	FN_VARIABLE_BIND_FN(fnString, AG_VARIABLE_STRING);
1363 }
1364 AG_Variable *
AG_BindStringMp(void * obj,const char * name,char * v,size_t size,AG_Mutex * mutex)1365 AG_BindStringMp(void *obj, const char *name, char *v, size_t size,
1366     AG_Mutex *mutex)
1367 {
1368 	AG_Variable *V;
1369 
1370 	AG_ObjectLock(obj);
1371 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_STRING);
1372 	V->mutex = mutex;
1373 	V->data.s = v;
1374 	V->info.size = size;
1375 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1376 	AG_ObjectUnlock(obj);
1377 	return (V);
1378 }
1379 AG_Variable *
AG_SetConstString(void * obj,const char * name,const char * v)1380 AG_SetConstString(void *obj, const char *name, const char *v)
1381 {
1382 	AG_Variable *V;
1383 
1384 	AG_ObjectLock(obj);
1385 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_CONST_STRING);
1386 	V->data.Cs = v;
1387 	V->info.size = strlen(v)+1;
1388 	AG_ObjectUnlock(obj);
1389 	return (V);
1390 }
1391 AG_Variable *
AG_BindConstString(void * obj,const char * name,const char ** v)1392 AG_BindConstString(void *obj, const char *name, const char **v)
1393 {
1394 	AG_Variable *V;
1395 
1396 	AG_ObjectLock(obj);
1397 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_CONST_STRING);
1398 	V->data.Cs = (const char *)v;
1399 	V->info.size = strlen(*v)+1;
1400 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1401 	AG_ObjectUnlock(obj);
1402 	return (V);
1403 }
1404 AG_Variable *
AG_BindConstStringMp(void * obj,const char * name,const char ** v,AG_Mutex * mutex)1405 AG_BindConstStringMp(void *obj, const char *name, const char **v,
1406     AG_Mutex *mutex)
1407 {
1408 	AG_Variable *V;
1409 
1410 	AG_ObjectLock(obj);
1411 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_CONST_STRING);
1412 	V->mutex = mutex;
1413 	V->data.Cs = (const char *)v;
1414 	V->info.size = strlen(*v)+1;
1415 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1416 	AG_ObjectUnlock(obj);
1417 	return (V);
1418 }
1419 
1420 /*
1421  * Bitwise flag routines.
1422  */
1423 AG_Variable *
AG_BindFlag(void * obj,const char * name,Uint * v,Uint bitmask)1424 AG_BindFlag(void *obj, const char *name, Uint *v, Uint bitmask)
1425 {
1426 	AG_Variable *V;
1427 
1428 	AG_ObjectLock(obj);
1429 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG);
1430 	V->data.p = v;
1431 	V->info.bitmask = bitmask;
1432 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1433 	AG_ObjectUnlock(obj);
1434 	return (V);
1435 }
1436 AG_Variable *
AG_BindFlagMp(void * obj,const char * name,Uint * v,Uint bitmask,AG_Mutex * mutex)1437 AG_BindFlagMp(void *obj, const char *name, Uint *v, Uint bitmask,
1438     AG_Mutex *mutex)
1439 {
1440 	AG_Variable *V;
1441 
1442 	AG_ObjectLock(obj);
1443 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG);
1444 	V->mutex = mutex;
1445 	V->data.p = v;
1446 	V->info.bitmask = bitmask;
1447 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1448 	AG_ObjectUnlock(obj);
1449 	return (V);
1450 }
1451 AG_Variable *
AG_BindFlag8(void * obj,const char * name,Uint8 * v,Uint8 bitmask)1452 AG_BindFlag8(void *obj, const char *name, Uint8 *v, Uint8 bitmask)
1453 {
1454 	AG_Variable *V;
1455 
1456 	AG_ObjectLock(obj);
1457 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG8);
1458 	V->data.p = v;
1459 	V->info.bitmask = bitmask;
1460 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1461 	AG_ObjectUnlock(obj);
1462 	return (V);
1463 }
1464 AG_Variable *
AG_BindFlag8Mp(void * obj,const char * name,Uint8 * v,Uint8 bitmask,AG_Mutex * mutex)1465 AG_BindFlag8Mp(void *obj, const char *name, Uint8 *v, Uint8 bitmask,
1466     AG_Mutex *mutex)
1467 {
1468 	AG_Variable *V;
1469 
1470 	AG_ObjectLock(obj);
1471 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG8);
1472 	V->mutex = mutex;
1473 	V->data.p = v;
1474 	V->info.bitmask = bitmask;
1475 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1476 	AG_ObjectUnlock(obj);
1477 	return (V);
1478 }
1479 AG_Variable *
AG_BindFlag16(void * obj,const char * name,Uint16 * v,Uint16 bitmask)1480 AG_BindFlag16(void *obj, const char *name, Uint16 *v, Uint16 bitmask)
1481 {
1482 	AG_Variable *V;
1483 
1484 	AG_ObjectLock(obj);
1485 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG16);
1486 	V->data.p = v;
1487 	V->info.bitmask = bitmask;
1488 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1489 	AG_ObjectUnlock(obj);
1490 	return (V);
1491 }
1492 AG_Variable *
AG_BindFlag16Mp(void * obj,const char * name,Uint16 * v,Uint16 bitmask,AG_Mutex * mutex)1493 AG_BindFlag16Mp(void *obj, const char *name, Uint16 *v, Uint16 bitmask,
1494     AG_Mutex *mutex)
1495 {
1496 	AG_Variable *V;
1497 
1498 	AG_ObjectLock(obj);
1499 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG16);
1500 	V->mutex = mutex;
1501 	V->data.p = v;
1502 	V->info.bitmask = bitmask;
1503 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1504 	AG_ObjectUnlock(obj);
1505 	return (V);
1506 }
1507 AG_Variable *
AG_BindFlag32(void * obj,const char * name,Uint32 * v,Uint32 bitmask)1508 AG_BindFlag32(void *obj, const char *name, Uint32 *v, Uint32 bitmask)
1509 {
1510 	AG_Variable *V;
1511 
1512 	AG_ObjectLock(obj);
1513 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG32);
1514 	V->data.p = v;
1515 	V->info.bitmask = bitmask;
1516 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1517 	AG_ObjectUnlock(obj);
1518 	return (V);
1519 }
1520 AG_Variable *
AG_BindFlag32Mp(void * obj,const char * name,Uint32 * v,Uint32 bitmask,AG_Mutex * mutex)1521 AG_BindFlag32Mp(void *obj, const char *name, Uint32 *v, Uint32 bitmask,
1522     AG_Mutex *mutex)
1523 {
1524 	AG_Variable *V;
1525 
1526 	AG_ObjectLock(obj);
1527 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_FLAG32);
1528 	V->mutex = mutex;
1529 	V->data.p = v;
1530 	V->info.bitmask = bitmask;
1531 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1532 	AG_ObjectUnlock(obj);
1533 	return (V);
1534 }
1535 
1536 /* Create a Variable->Variable reference. */
1537 AG_Variable *
AG_BindVariable(void * obj,const char * name,void * tgtObj,const char * tgtKey)1538 AG_BindVariable(void *obj, const char *name, void *tgtObj, const char *tgtKey)
1539 {
1540 	AG_Variable *V;
1541 	char *keyDup;
1542 
1543 	if ((keyDup = TryStrdup(tgtKey)) == NULL)
1544 		return (NULL);
1545 
1546 	AG_ObjectLock(obj);
1547 	V = AG_FetchVariableOfType(obj, name, AG_VARIABLE_P_VARIABLE);
1548 	V->data.p = tgtObj;
1549 	V->info.ref.key = keyDup;
1550 	V->info.ref.var = NULL;
1551 	AG_PostEvent(NULL, obj, "bound", "%p", V);
1552 	AG_ObjectUnlock(obj);
1553 	return (V);
1554 }
1555 
1556 /* Substitute variable references of the form "$(foo)" in a string. */
1557 void
AG_VariableSubst(void * obj,const char * s,char * dst,size_t len)1558 AG_VariableSubst(void *obj, const char *s, char *dst, size_t len)
1559 {
1560 	char key[AG_VARIABLE_NAME_MAX], val[64];
1561 	const char *c, *cEnd;
1562 	AG_Variable *V;
1563 	size_t kLen;
1564 
1565 	if (len < 1) {
1566 		return;
1567 	}
1568 	AG_ObjectLock(obj);
1569 	dst[0] = '\0';
1570 	for (c = &s[0]; *c != '\0'; ) {
1571 		if (c[0] == '$' && c[1] == '(' &&
1572 		    (cEnd = strchr(&c[2], ')')) != NULL) {
1573 			if ((kLen = cEnd-&c[1]) >= sizeof(key)) {
1574 				c = &cEnd[1];
1575 				continue;
1576 			}
1577 			memcpy(key, &c[2], kLen);
1578 			key[kLen-1] = '\0';
1579 			if (strcmp(key, "name") == 0) {
1580 				Strlcat(dst, OBJECT(obj)->name, len);
1581 			} else if (strcmp(key, "class") == 0) {
1582 				Strlcat(dst, OBJECT(obj)->cls->name, len);
1583 			} else {
1584 				if ((V = AG_GetVariableLocked(obj, key)) != NULL) {
1585 					AG_PrintVariable(val, sizeof(val), V);
1586 					Strlcat(dst, val, len);
1587 					AG_UnlockVariable(V);
1588 				}
1589 #if 0
1590 				} else {
1591 					Strlcat(dst, "$(", len);
1592 					Strlcat(dst, key, len);
1593 					Strlcat(dst, ")", len);
1594 				}
1595 #endif
1596 			}
1597 			c = cEnd+1;
1598 			continue;
1599 		}
1600 		val[0] = *c;
1601 		val[1] = '\0';
1602 		Strlcat(dst, val, len);
1603 		c++;
1604 	}
1605 	AG_ObjectUnlock(obj);
1606 }
1607 
1608 /*
1609  * AG_ListSet(): Construct a list of AG_Variables from varargs arguments.
1610  */
1611 #undef AG_VARIABLE_SETARG
1612 #define AG_VARIABLE_SETARG(V,t,pt,dmemb,dtype,vtype,ival,fnmemb,fntype)	\
1613 	if (pFlag) {							\
1614 		(V)->type = (pt);					\
1615 	} else {							\
1616 		(V)->type = (t);					\
1617 		if (fnFlag) {						\
1618 			(V)->data.dmemb = (ival);			\
1619 			(V)->fn.fnmemb = va_arg(ap, fntype);		\
1620 		} else {						\
1621 			(V)->data.dmemb = (dtype)va_arg(ap, vtype);	\
1622 		}							\
1623 	} while (0)
1624 
1625 #undef AG_VARIABLE_SETARG_STRING
1626 #define AG_VARIABLE_SETARG_STRING(V,t,pt,dmemb,dtype,ival,fnmemb,fntype) \
1627 	if (pFlag) {							\
1628 		(V)->type = (pt);					\
1629 	} else {							\
1630 		(V)->type = (t);					\
1631 		if (fnFlag) {						\
1632 			(V)->data.dmemb = (ival);			\
1633 			(V)->fn.fnmemb = va_arg(ap, fntype);		\
1634 			(V)->info.size = 0;				\
1635 		} else {						\
1636 			(V)->data.dmemb = va_arg(ap, dtype);		\
1637 			(V)->info.size = strlen((V)->data.dmemb)+1;	\
1638 		}							\
1639 	} while (0)
1640 
1641 #undef AG_VARIABLE_SETARG_STRING_BUFFER
1642 #define AG_VARIABLE_SETARG_STRING_BUFFER(V,t,pt,dmemb,dtype,ival,fnmemb,fntype) \
1643 	if (pFlag) {							\
1644 		(V)->type = (pt);					\
1645 	} else {							\
1646 		(V)->type = (t);					\
1647 		if (fnFlag) {						\
1648 			(V)->data.dmemb = (ival);			\
1649 			(V)->fn.fnmemb = va_arg(ap, fntype);		\
1650 			(V)->info.size = 0;				\
1651 		} else {						\
1652 			(V)->data.dmemb = va_arg(ap, dtype);		\
1653 			(V)->info.size = va_arg(ap, size_t);		\
1654 		}							\
1655 	} while (0)
1656 
1657 AG_List *
AG_ListSet(const char * fmt,...)1658 AG_ListSet(const char *fmt, ...)
1659 {
1660 	va_list ap;
1661 	AG_List *L;
1662 	int *argSizes = NULL, *argSizesNew;
1663 	const char *fmtSpec;
1664 	int nArgs = 0;
1665 
1666 	if ((L = AG_ListNew()) == NULL) {
1667 		return (NULL);
1668 	}
1669 	va_start(ap, fmt);
1670 	for (fmtSpec = fmt; *fmtSpec != '\0'; ) {
1671 		const char *c;
1672 		int pFlag = 0, fnFlag = 0, lFlag = 0, LFlag = 0, isExtended = 0;
1673 		int fmtChars, inFmt = 0;
1674 		AG_Variable V;
1675 
1676 		for (c = &fmtSpec[0], fmtChars = 0;
1677 		     *c != '\0';
1678 		     c++) {
1679 			if (*c == '%') { inFmt = 1; }
1680 			if (inFmt) { fmtChars++; }
1681 			if (*c == '%') {
1682 				continue;
1683 			} else if (*c == '*' && c[1] != '\0') {
1684 				pFlag++;
1685 			} else if (*c == 'l' && c[1] != '\0') {
1686 				lFlag++;
1687 			} else if (*c == 'L' && c[1] != '\0') {
1688 				LFlag++;
1689 			} else if (*c == 'F' && c[1] != '\0') {
1690 				fnFlag++;
1691 			} else if (*c == '[' && c[1] != '\0') {
1692 				isExtended++;
1693 				break;
1694 			} else if (inFmt && strchr("*Csdiufgp]", *c)) {
1695 				break;
1696 			} else if (strchr(".0123456789", *c)) {
1697 				continue;
1698 			} else {
1699 				inFmt = 0;
1700 			}
1701 		}
1702 		fmtSpec += fmtChars;
1703 		if (*c == '\0') { break; }
1704 		if (!inFmt) { continue;	}
1705 
1706 		if ((argSizesNew = TryRealloc(argSizes, (nArgs+1)*sizeof(int)))
1707 		    == NULL) {
1708 			goto fail;
1709 		}
1710 		argSizes = argSizesNew;
1711 		argSizes[nArgs++] = fmtChars;
1712 
1713 		V.type = AG_VARIABLE_NULL;
1714 		V.name[0] = '\0';
1715 		V.mutex = NULL;
1716 		V.fn.fnVoid = NULL;
1717 		V.info.bitmask = 0;
1718 
1719 		if (pFlag) {
1720 			V.data.p = va_arg(ap, void *);
1721 		}
1722 		if (isExtended) {
1723 			c++;
1724 			if (c[0] == 's') {
1725 				if (c[1] == '3' && c[2] == '2') {
1726 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_SINT32, AG_VARIABLE_P_SINT32,
1727 					    s32, Sint32, int, 0, fnSint32, AG_Sint32Fn);
1728 #ifdef HAVE_64BIT
1729 				} else if (c[1] == '6' && c[2] == '4') {
1730 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_SINT64, AG_VARIABLE_P_SINT64,
1731 					    s64, Sint64, long long, 0LL, fnSint64, AG_Sint64Fn);
1732 #endif
1733 				} else if (c[1] == '1' && c[2] == '6') {
1734 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_SINT16, AG_VARIABLE_P_SINT16,
1735 					    s16, Sint16, int, 0, fnSint16, AG_Sint16Fn);
1736 				} else if (c[1] == '8') {
1737 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_SINT8, AG_VARIABLE_P_SINT8,
1738 					    s8, Sint8, int, 0, fnSint8, AG_Sint8Fn);
1739 				}
1740 			} else if (c[0] == 'u') {
1741 				if (c[1] == '3' && c[2] == '2') {
1742 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT32, AG_VARIABLE_P_UINT32,
1743 					    u32, Uint32, Uint, 0, fnUint32, AG_Uint32Fn);
1744 #ifdef HAVE_64BIT
1745 				} else if (c[1] == '6' && c[2] == '4') {
1746 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT64, AG_VARIABLE_P_UINT64,
1747 					    u64, Uint64, unsigned long long, 0ULL, fnSint64, AG_Sint64Fn);
1748 #endif
1749 				} else if (c[1] == '1' && c[2] == '6') {
1750 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT16, AG_VARIABLE_P_UINT16,
1751 					    u16, Uint16, Uint, 0, fnUint16, AG_Uint16Fn);
1752 				} else if (c[1] == '8') {
1753 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT8, AG_VARIABLE_P_UINT8,
1754 					    u8, Uint8, int, 0, fnUint8, AG_Uint8Fn);
1755 				}
1756 			} else if (c[0] == 'C') {
1757 				switch (c[1]) {
1758 				case 'p':
1759 					AG_VARIABLE_SETARG(&V, AG_VARIABLE_CONST_POINTER, AG_VARIABLE_P_CONST_POINTER,
1760 					    Cp, const void *, const void *, NULL, fnConstPointer, AG_ConstPointerFn);
1761 					break;
1762 				case 's':
1763 					AG_VARIABLE_SETARG_STRING(&V, AG_VARIABLE_CONST_STRING, AG_VARIABLE_P_CONST_STRING,
1764 					    Cs, const char *, NULL, fnString, AG_StringFn);
1765 					break;
1766 				}
1767 			} else if (c[0] == 'B') {
1768 				AG_VARIABLE_SETARG_STRING_BUFFER(&V, AG_VARIABLE_STRING,	AG_VARIABLE_P_STRING,
1769 				    s, char *, NULL, fnString, AG_StringFn);
1770 			}
1771 			break;
1772 		}
1773 		switch (c[0]) {
1774 		case 'p':
1775 			AG_VARIABLE_SETARG(&V, AG_VARIABLE_POINTER, AG_VARIABLE_P_POINTER,
1776 			    p, void *, void *, NULL, fnPointer, AG_PointerFn);
1777 			break;
1778 		case 's':
1779 			AG_VARIABLE_SETARG_STRING(&V, AG_VARIABLE_STRING, AG_VARIABLE_P_STRING,
1780 			    s, char *, NULL, fnString, AG_StringFn);
1781 			break;
1782 		case 't':
1783 			V.type = AG_VARIABLE_P_TEXT;
1784 			break;
1785 		case 'd':
1786 		case 'i':
1787 			if (lFlag == 0) {
1788 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_INT, AG_VARIABLE_P_INT,
1789 				    i, int, int, 0, fnInt, AG_IntFn);
1790 			} else {
1791 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_SINT32, AG_VARIABLE_P_SINT32,
1792 				    s32, Sint32, Sint32, 0, fnSint32, AG_Sint32Fn);
1793 			}
1794 			break;
1795 		case 'u':
1796 			if (lFlag == 0) {
1797 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT, AG_VARIABLE_P_UINT,
1798 				    u, Uint, Uint, 0, fnUint, AG_UintFn);
1799 			} else {
1800 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_UINT32, AG_VARIABLE_P_UINT32,
1801 				    u32, Uint32, Uint32, 0, fnUint32, AG_Uint32Fn);
1802 			}
1803 			break;
1804 		case 'f':
1805 		case 'g':
1806 			if (lFlag) {
1807 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_DOUBLE, AG_VARIABLE_P_DOUBLE,
1808 				    dbl, double, double, 0.0, fnDouble, AG_DoubleFn);
1809 #ifdef HAVE_LONG_DOUBLE
1810 			} else if (LFlag) {
1811 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_LONG_DOUBLE, AG_VARIABLE_P_LONG_DOUBLE,
1812 				    ldbl, long double, long double, 0.0L, fnLongDouble, AG_LongDoubleFn);
1813 #endif
1814 			} else {
1815 				AG_VARIABLE_SETARG(&V, AG_VARIABLE_FLOAT, AG_VARIABLE_P_FLOAT,
1816 				    flt, float, double, 0.0f, fnFloat, AG_FloatFn);
1817 			}
1818 			break;
1819 		}
1820 		AG_ListAppend(L, &V);
1821 	}
1822 	va_end(ap);
1823 	return (L);
1824 fail:
1825 	va_end(ap);
1826 	AG_ListDestroy(L);
1827 	free(argSizes);
1828 	return (NULL);
1829 }
1830