comparison dyncallback/dyncallback.3 @ 579:1d4f0f516483

man pages: - dyncall(3): removal of unnecessary whitespace - dyncallback(3): added many more examples
author Tassilo Philipp
date Thu, 08 Sep 2022 17:36:20 +0200
parents fd7426080105
children
comparison
equal deleted inserted replaced
578:87b5f5d7af1f 579:1d4f0f516483
101 with an implicit NULL passed via the 101 with an implicit NULL passed via the
102 .Ar aggrs 102 .Ar aggrs
103 parameter, meaning it can only be used for callbacks that do not use any 103 parameter, meaning it can only be used for callbacks that do not use any
104 aggregate by value. 104 aggregate by value.
105 .Pp 105 .Pp
106 .Sy NOTE: 106 .Em NOTE :
107 C++ non-trivial aggregates (check with the std::is_trivial type trait) do not 107 C++ non-trivial aggregates (check with the std::is_trivial type trait) do not
108 use aggregate descriptions, so the respective pointers in the provided array 108 use aggregate descriptions, so the respective pointers in the provided array
109 must be NULL. See 109 must be NULL. See
110 .Xr dyncall 3 110 .Xr dyncall 3
111 for more information on C++ non-trivial aggregates. 111 for more information on C++ non-trivial aggregates.
157 argument can be done via 157 argument can be done via
158 .Fn dcbArgAggr , 158 .Fn dcbArgAggr ,
159 where 159 where
160 .Ar target 160 .Ar target
161 must point to memory large enough for the aggregate to be copied to, 161 must point to memory large enough for the aggregate to be copied to,
162 .Sy iff 162 .Em iff
163 the aggregate is trivial (see below for non-trivial C++ aggregates), in which case 163 the aggregate is trivial (see below for non-trivial C++ aggregates), in which case
164 .Ar target 164 .Ar target
165 is returned. 165 is returned.
166 .Pp 166 .Pp
167 To return a trivial aggregate by value, a helper function 167 To return a trivial aggregate by value, a helper function
188 which will make 188 which will make
189 .Ar result->p 189 .Ar result->p
190 point to (implicit, caller-provided) memory where the aggregate should be 190 point to (implicit, caller-provided) memory where the aggregate should be
191 copied to. 191 copied to.
192 192
193 .Sh EXAMPLE 193 .Sh EXAMPLES
194 Let's say, we want to create a callback object and call it. For simplicity, this 194 .Em Note :
195 example will omit passing it as a function pointer to a function (e.g. compar 195 for simplicity, none of the examples below do any error checking. Also, none of
196 in qsort(), etc.) and demonstrate calling it, directly. First, we need to define 196 them pass the callback object pointer as an argument to a function doing the
197 our callback handler - the following handler illustrates how to access the passed- 197 respective callback (e.g.
198 in arguments: 198 .Ar compar
199 in
200 .Xr qsort 3 ,
201 etc.), but demonstrate calling it, directly, for clarity.
202 .Pp
203 Let's say, we want to create a callback object and call it. First, we need to
204 define our callback handler - the following handler illustrates how to access
205 the passed-in arguments, optional userdata, and how to return values:
199 .Bd -literal -offset indent 206 .Bd -literal -offset indent
200 DCsigchar cbHandler(DCCallback* cb, 207 DCsigchar cbHandler(DCCallback* cb,
201 DCArgs* args, 208 DCArgs* args,
202 DCValue* result, 209 DCValue* result,
203 void* userdata) 210 void* userdata)
214 result->s = 1244; 221 result->s = 1244;
215 return 's'; 222 return 's';
216 } 223 }
217 .Ed 224 .Ed
218 .Pp 225 .Pp
219 Note that the return value of the handler is a signature character, not the 226 Note that the return value of the handler is a signature character, and not the
220 actual return value, itself. 227 actual return value, itself. Now, let's call it through a
221 Now, let's call it through a DCCallback object: 228 .Sy DCCallback
222 .Bd -literal -offset indent 229 object:
223 DCCallback* cb; 230 .Bd -literal -offset indent
224 short result = 0; 231 DCCallback* cb;
225 int userdata = 1337; 232 short result = 0;
226 cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata); 233 int userdata = 1337;
227 234 cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata);
228 /* call the callback object */ 235
229 result = ((short(*)(int, float, short, double, long long))cb) 236 /* call the callback object */
230 (123, 23.f, 3, 1.82, 9909ll); 237 result = ((short(*)(int, float, short, double, long long))cb)
231 238 (123, 23.f, 3, 1.82, 9909ll);
232 dcbFreeCallback(cb); 239
233 .Ed 240 dcbFreeCallback(cb);
241 .Ed
242 .Ss C/trivial aggregates by-value
243 Onto an example calling back a function which takes an aggregate
244 .Em "by value"
245 (note that this is only available on platforms where macro
246 .Dv DC__Feature_AggrByVal
247 is defined). E.g. with the following function
248 .Fn f
249 and
250 .Sy struct S :
251 .Bd -literal -offset indent
252 struct S { char x[3]; double y; };
253 int f(struct S, float);
254 .Ed
255 .Pp
256 the callback handler would look like:
257 .Bd -literal -offset indent
258 DCsigchar cbHandler(DCCallback* cb,
259 DCArgs* args,
260 DCValue* result,
261 void* userdata)
262 {
263 struct S arg1;
264 float arg2;
265 dcbArgAggr(args, (DCpointer)&arg1);
266 arg2 = dcbArgFloat(args);
267
268 /* ... */
269
270 result->i = 1;
271 return 'i';
272 }
273 .Ed
274 .Pp
275 and the callback object as well as the aggregate field/layout description are
276 set up (and the former called back) as follows:
277 .Bd -literal -offset indent
278 struct S s = { { 56, -23, 0 }, -6.28 };
279 int result;
280
281 DCCallback* cb;
282
283 DCaggr *a = dcNewAggr(2, sizeof(struct S));
284 dcAggrField(a, DC_SIGCHAR_CHAR, offsetof(struct S, x), 3);
285 dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
286 dcCloseAggr(a);
287
288 /* an array of DCaggr* must be passed as last arg, with one
289 * entry per 'A' signature character; we got only one, here
290 */
291 cb = dcbNewCallback2("Af)v", &cbHandler, NULL, &a);
292
293 /* call the callback object */
294 result = ((int(*)(struct S, float))cb)(s, 42.f);
295
296 dcbFreeCallback(cb);
297 dcFreeAggr(a);
298 .Ed
299 .Pp
300 Let's extend the last example, so that the callback function also returns
301 .Sy struct S
302 .Em "by value" .
303 The struct definition, function declaration and handler definition would be:
304 .Bd -literal -offset indent
305 /* callback function decl */
306 struct S f(struct S, float);
307
308 struct S { char x[3]; double y; };
309
310 DCsigchar cbHandler(DCCallback* cb,
311 DCArgs* args,
312 DCValue* result,
313 void* userdata)
314 {
315 struct S arg1, r;
316 float arg2;
317 dcbArgAggr(args, (DCpointer)&arg1);
318 arg2 = dcbArgFloat(args);
319
320 /* ... */
321
322 /* use helper to write aggregate return value to result */
323 dcbReturnAggr(args, result, (DCpointer)&r);
324 return 'A';
325 }
326 .Ed
327 .Pp
328 .Pp
329 and the callback object as well as the aggregate field/layout descriptions are
330 set up (and the former called back) as follows:
331 .Bd -literal -offset indent
332 struct S s = { { 33, 29, -1 }, 6.8 };
333 struct S result;
334
335 DCCallback* cb;
336
337 DCaggr *a = { dcNewAggr(2, sizeof(struct S)) };
338 dcAggrField(a, DC_SIGCHAR_CHAR, offsetof(struct S, x), 3);
339 dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
340 dcCloseAggr(a);
341
342 /* an array of DCaggr* must be passed as last arg, with one
343 * entry per 'A' signature character
344 */
345 cb = dcbNewCallback2("Af)A", &cbHandler, NULL, (DCaggr*[2]){a,a});
346
347 /* call the callback object */
348 result = ((struct S(*)(struct S, float))cb)(s, 42.f);
349
350 dcbFreeCallback(cb);
351 dcFreeAggr(a);
352 .Ed
353 .Ss C++
354 In our next example, let's look at setting up a
355 .Sy DCCallback
356 object to call back a simple C++ method (illustrating the need to specify the
357 thiscall calling convention). If the class and method is declared as:
358 .Bd -literal -offset indent
359 class Klass {
360 public:
361 virtual void Method(float, int);
362 };
363 .Ed
364 .Pp
365 the respective callback handler would be something along the lines of:
366 .Bd -literal -offset indent
367 DCsigchar cbHandler(DCCallback* cb,
368 DCArgs* args,
369 DCValue* result,
370 void* userdata)
371 {
372 Klass* thisptr = (Klass*)dcbArgPointer(args);
373 float arg1 = dcbArgFloat(args);
374 int arg2 = dcbArgInt(args);
375
376 /* ... */
377
378 return 'v';
379 }
380 .Ed
381 .Pp
382 and the callback object would be used as follows:
383 .Bd -literal -offset indent
384 DCCallback* cb;
385 cb = dcbNewCallback("_*pfi)v", &cbHandler, NULL);
386
387 /* HACK: this is a hack just for this example to force the compiler
388 * generating a thiscall, below (creates a fake vtable mimicking
389 * Klass, setting all of its possible entries to our callback handler;
390 */
391 DCpointer fakeClass[sizeof(Klass)/sizeof(DCpointer)];
392 for(int j=0; j<sizeof(Klass)/sizeof(DCpointer); ++j)
393 fakeClass[j] = &cb;
394
395 /* (this)call the callback object */
396 ((Klass*)&fakeClass)->Method(8, 23.f);
397
398 dcbFreeCallback(cb);
399 .Ed
400 .Pp
401 .Em NOTE :
402 In a real world scenario one would figure out the precise location of the vtable entry of
403 .Fn Klass::Method ,
404 of course; the above example omits this for simplicity.
234 .Sh CONFORMING TO 405 .Sh CONFORMING TO
235 The dyncallback library needs at least a c99 compiler with additional support 406 The dyncallback library needs at least a c99 compiler with additional support
236 for anonymous structs/unions (which were introduced officially in c11). Given 407 for anonymous structs/unions (which were introduced officially in c11). Given
237 that those are generally supported by pretty much all major c99 conforming 408 that those are generally supported by pretty much all major c99 conforming
238 compilers (as default extension), it should build fine with a c99 toolchain. 409 compilers (as default extension), it should build fine with a c99 toolchain.