Mercurial > pub > dyncall > dyncall
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. |