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