changeset 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 87b5f5d7af1f
children 2562c89d5bb5
files dyncall/dyncall.3 dyncallback/dyncallback.3
diffstat 2 files changed, 254 insertions(+), 83 deletions(-) [+]
line wrap: on
line diff
--- a/dyncall/dyncall.3	Thu Sep 08 16:15:52 2022 +0200
+++ b/dyncall/dyncall.3	Thu Sep 08 17:36:20 2022 +0200
@@ -294,14 +294,14 @@
 .Nm
 library, this function would be called as follows: 
 .Bd -literal -offset indent
-	double r;
-	DCCallVM* vm = dcNewCallVM(4096);
-	dcMode(vm, DC_CALL_C_DEFAULT);
-	dcReset(vm);
-	/* call: double sqrt(double x); */
-	dcArgDouble(vm, 4.2373);
-	r = dcCallDouble(vm, (DCpointer)&sqrt);
-	dcFree(vm);
+double r;
+DCCallVM* vm = dcNewCallVM(4096);
+dcMode(vm, DC_CALL_C_DEFAULT);
+dcReset(vm);
+/* call: double sqrt(double x); */
+dcArgDouble(vm, 4.2373);
+r = dcCallDouble(vm, (DCpointer)&sqrt);
+dcFree(vm);
 .Ed
 .Pp
 Note that the
@@ -317,18 +317,18 @@
 which requires a different initial mode, as well as a mode switch for the
 varargs part:
 .Bd -literal -offset indent
-	int n_written_chars, r;
-	/* initial callconv mode */
-	dcMode(vm, DC_CALL_C_ELLIPSIS);
-	dcReset(vm);
-	/* int printf(const char * restrict format, ...); */
-	dcArgPointer(vm, "my printf(%d) %s string%n");
-	/* switch mode for varargs part */
-	dcMode(vm, DC_CALL_C_ELLIPSIS_VARARGS);
-	dcArgInt(vm, 3);
-	dcArgPointer(vm, "format");
-	dcArgPointer(vm, &n_written_chars);
-	r = dcCallInt(vm, (DCpointer)&printf);
+int n_written_chars, r;
+/* initial callconv mode */
+dcMode(vm, DC_CALL_C_ELLIPSIS);
+dcReset(vm);
+/* int printf(const char * restrict format, ...); */
+dcArgPointer(vm, "my printf(%d) %s string%n");
+/* switch mode for varargs part */
+dcMode(vm, DC_CALL_C_ELLIPSIS_VARARGS);
+dcArgInt(vm, 3);
+dcArgPointer(vm, "format");
+dcArgPointer(vm, &n_written_chars);
+r = dcCallInt(vm, (DCpointer)&printf);
 .Ed
 .Pp
 .Ss C/trivial aggregates by-value
@@ -341,8 +341,8 @@
 to
 .Fn f :
 .Bd -literal -offset indent
-	struct S { char x[3]; double y; };
-	void f(int, struct S);
+struct S { char x[3]; double y; };
+void f(int, struct S);
 .Ed
 .Pp
 requires a
@@ -351,20 +351,20 @@
 .Sy struct S ,
 and is called as follows:
 .Bd -literal -offset indent
-	struct S s = { { 56, -23, 0 }, -6.28 };
+struct S s = { { 56, -23, 0 }, -6.28 };
 
-	DCaggr *a = dcNewAggr(2, sizeof(struct S));
-	dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
-	dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
-	dcCloseAggr(a);
+DCaggr *a = dcNewAggr(2, sizeof(struct S));
+dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
+dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
+dcCloseAggr(a);
 
-	dcMode(vm, DC_CALL_C_DEFAULT);
-	dcArgInt(vm, 999);
-	dcArgAggr(vm, a, &s);
+dcMode(vm, DC_CALL_C_DEFAULT);
+dcArgInt(vm, 999);
+dcArgAggr(vm, a, &s);
 
-	dcCallVoid(vm, (DCpointer)&f);
+dcCallVoid(vm, (DCpointer)&f);
 
-	dcFreeAggr(a);
+dcFreeAggr(a);
 .Ed
 .Pp
 Let's look at an example returning
@@ -373,7 +373,7 @@
 .Sy struct S
 from function:
 .Bd -literal -offset indent
-	struct S g(int, short);
+struct S g(int, short);
 .Ed
 .Pp
 Omitting creation of the
@@ -381,23 +381,23 @@
 .Ar *a
 description, for simplicity:
 .Bd -literal -offset indent
-	struct S s;
+struct S s;
 
-	dcMode(vm, DC_CALL_C_DEFAULT);
+dcMode(vm, DC_CALL_C_DEFAULT);
 
-	/* needed when returning aggrs by value, *before* pushing args */
-	dcBeginCallAggr(vm, a);
+/* needed when returning aggrs by value, *before* pushing args */
+dcBeginCallAggr(vm, a);
 
-	dcArgInt(vm, 9);
-	dcArgShort(vm, 7);
+dcArgInt(vm, 9);
+dcArgShort(vm, 7);
 
-	dcCallAggr(vm, (DCpointer)&g, a, &s);
+dcCallAggr(vm, (DCpointer)&g, a, &s);
 .Ed
 .Ss C++
 In our next example, let's look at calling a simple C++ method, with the method
 declaration being:
 .Bd -literal -offset indent
-	virtual void Klass::Method(float, int);
+virtual void Klass::Method(float, int);
 .Ed
 .Pp
 To keep the example simple, let's assume we have a pointer to this virtual
@@ -406,39 +406,39 @@
 (e.g. grabbed from the instance's vtable), and a pointer to the instance in var
 .Ar thisptr :
 .Bd -literal -offset indent
-	/* thiscall calling convention */
-	dcMode(vm, DC_CALL_C_DEFAULT_THIS);
-	dcReset(vm);
-	/* C++ methods use this-ptr as first/hidden argument */
-	dcArgPointer(vm, thisptr);
-	dcArgFloat(vm, 2.3f);
-	dcArgInt(vm, -19);
-	dcCallVoid(vm, (DCpointer)mptr);
+/* thiscall calling convention */
+dcMode(vm, DC_CALL_C_DEFAULT_THIS);
+dcReset(vm);
+/* C++ methods use this-ptr as first/hidden argument */
+dcArgPointer(vm, thisptr);
+dcArgFloat(vm, 2.3f);
+dcArgInt(vm, -19);
+dcCallVoid(vm, (DCpointer)mptr);
 .Ed
 .Pp
 Extending the last example to a vararg method would need some more
 .Xr dcMode 3
 calls. E.g.:
 .Bd -literal -offset indent
-	virtual void Klass::Method(float, int, ...);
+virtual void Klass::Method(float, int, ...);
 .Ed
 .Pp
 would be called as follows:
 .Bd -literal -offset indent
-	/* thiscall calling convention (to pass this-ptr) */
-	dcMode(vm, DC_CALL_C_DEFAULT_THIS);
-	dcReset(vm);
-	/* C++ methods use this-ptr as first/hidden argument */
-	dcArgPointer(vm, thisptr);
-	/* fixed part of arguments */
-	dcMode(vm, DC_CALL_C_ELLIPSIS);
-	dcArgFloat(vm, 2.3f);
-	dcArgInt(vm, -19);
-	/* variable part of arguments */
-	dcMode(vm, DC_CALL_C_ELLIPSIS_VARARGS);
-	dcArgInt(vm, 7);
-	dcArgDouble(vm, 7.99);
-	dcCallVoid(vm, (DCpointer)mptr);
+/* thiscall calling convention (to pass this-ptr) */
+dcMode(vm, DC_CALL_C_DEFAULT_THIS);
+dcReset(vm);
+/* C++ methods use this-ptr as first/hidden argument */
+dcArgPointer(vm, thisptr);
+/* fixed part of arguments */
+dcMode(vm, DC_CALL_C_ELLIPSIS);
+dcArgFloat(vm, 2.3f);
+dcArgInt(vm, -19);
+/* variable part of arguments */
+dcMode(vm, DC_CALL_C_ELLIPSIS_VARARGS);
+dcArgInt(vm, 7);
+dcArgDouble(vm, 7.99);
+dcCallVoid(vm, (DCpointer)mptr);
 .Ed
 .Pp
 .Sh CONFORMING TO
--- a/dyncallback/dyncallback.3	Thu Sep 08 16:15:52 2022 +0200
+++ b/dyncallback/dyncallback.3	Thu Sep 08 17:36:20 2022 +0200
@@ -103,7 +103,7 @@
 parameter, meaning it can only be used for callbacks that do not use any
 aggregate by value.
 .Pp
-.Sy NOTE:
+.Em NOTE :
 C++ non-trivial aggregates (check with the std::is_trivial type trait) do not
 use aggregate descriptions, so the respective pointers in the provided array
 must be NULL. See
@@ -159,7 +159,7 @@
 where
 .Ar target
 must point to memory large enough for the aggregate to be copied to,
-.Sy iff
+.Em iff
 the aggregate is trivial (see below for non-trivial C++ aggregates), in which case
 .Ar target
 is returned.
@@ -190,12 +190,19 @@
 point to (implicit, caller-provided) memory where the aggregate should be
 copied to.
 
-.Sh EXAMPLE
-Let's say, we want to create a callback object and call it. For simplicity, this
-example will omit passing it as a function pointer to a function (e.g. compar
-in qsort(), etc.) and demonstrate calling it, directly. First, we need to define
-our callback handler - the following handler illustrates how to access the passed-
-in arguments:
+.Sh EXAMPLES
+.Em Note :
+for simplicity, none of the examples below do any error checking. Also, none of
+them pass the callback object pointer as an argument to a function doing the
+respective callback (e.g.
+.Ar compar
+in
+.Xr qsort 3 ,
+etc.), but demonstrate calling it, directly, for clarity.
+.Pp
+Let's say, we want to create a callback object and call it. First, we need to
+define our callback handler - the following handler illustrates how to access
+the passed-in arguments, optional userdata, and how to return values:
 .Bd -literal -offset indent
 DCsigchar cbHandler(DCCallback* cb,
                     DCArgs*     args,
@@ -216,21 +223,185 @@
 }
 .Ed
 .Pp
-Note that the return value of the handler is a signature character, not the
-actual return value, itself.
-Now, let's call it through a DCCallback object:
+Note that the return value of the handler is a signature character, and not the
+actual return value, itself.  Now, let's call it through a
+.Sy DCCallback
+object:
+.Bd -literal -offset indent
+DCCallback* cb;
+short result = 0;
+int userdata = 1337;
+cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata);
+
+/* call the callback object */
+result = ((short(*)(int, float, short, double, long long))cb)
+  (123, 23.f, 3, 1.82, 9909ll);
+
+dcbFreeCallback(cb);
+.Ed
+.Ss C/trivial aggregates by-value
+Onto an example calling back a function which takes an aggregate
+.Em "by value"
+(note that this is only available on platforms where macro
+.Dv DC__Feature_AggrByVal
+is defined). E.g. with the following function
+.Fn f
+and
+.Sy struct S :
+.Bd -literal -offset indent
+struct S { char x[3]; double y; };
+int f(struct S, float);
+.Ed
+.Pp
+the callback handler would look like:
+.Bd -literal -offset indent
+DCsigchar cbHandler(DCCallback* cb,
+                    DCArgs*     args,
+                    DCValue*    result,
+                    void*       userdata)
+{
+  struct S arg1;
+  float arg2;
+  dcbArgAggr(args, (DCpointer)&arg1);
+  arg2 = dcbArgFloat(args);
+
+  /* ... */
+
+  result->i = 1;
+  return 'i';
+}
+.Ed
+.Pp
+and the callback object as well as the aggregate field/layout description are
+set up (and the former called back) as follows:
+.Bd -literal -offset indent
+struct S s = { { 56, -23, 0 }, -6.28 };
+int result;
+
+DCCallback* cb;
+
+DCaggr *a = dcNewAggr(2, sizeof(struct S));
+dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
+dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
+dcCloseAggr(a);
+
+/* an array of DCaggr* must be passed as last arg, with one
+ * entry per 'A' signature character; we got only one, here
+ */
+cb = dcbNewCallback2("Af)v", &cbHandler, NULL, &a);
+
+/* call the callback object */
+result = ((int(*)(struct S, float))cb)(s, 42.f);
+
+dcbFreeCallback(cb);
+dcFreeAggr(a);
+.Ed
+.Pp
+Let's extend the last example, so that the callback function also returns
+.Sy struct S
+.Em "by value" .
+The struct definition, function declaration and handler definition would be:
 .Bd -literal -offset indent
-  DCCallback* cb;
-  short result = 0;
-  int userdata = 1337;
-  cb = dcbNewCallback("ifsdl)s", &cbHandler, &userdata);
+/* callback function decl */
+struct S f(struct S, float);
+
+struct S { char x[3]; double y; };
+
+DCsigchar cbHandler(DCCallback* cb,
+                    DCArgs*     args,
+                    DCValue*    result,
+                    void*       userdata)
+{
+  struct S arg1, r;
+  float arg2;
+  dcbArgAggr(args, (DCpointer)&arg1);
+  arg2 = dcbArgFloat(args);
+
+  /* ... */
+
+  /* use helper to write aggregate return value to result */
+  dcbReturnAggr(args, result, (DCpointer)&r);
+  return 'A';
+}
+.Ed
+.Pp
+.Pp
+and the callback object as well as the aggregate field/layout descriptions are
+set up (and the former called back) as follows:
+.Bd -literal -offset indent
+struct S s = { { 33, 29, -1 }, 6.8 };
+struct S result;
+
+DCCallback* cb;
+
+DCaggr *a = { dcNewAggr(2, sizeof(struct S)) };
+dcAggrField(a, DC_SIGCHAR_CHAR,   offsetof(struct S, x), 3);
+dcAggrField(a, DC_SIGCHAR_DOUBLE, offsetof(struct S, y), 1);
+dcCloseAggr(a);
+
+/* an array of DCaggr* must be passed as last arg, with one
+ * entry per 'A' signature character
+ */
+cb = dcbNewCallback2("Af)A", &cbHandler, NULL, (DCaggr*[2]){a,a});
+
+/* call the callback object */
+result = ((struct S(*)(struct S, float))cb)(s, 42.f);
 
-  /* call the callback object */
-  result = ((short(*)(int, float, short, double, long long))cb)
-    (123, 23.f, 3, 1.82, 9909ll);
+dcbFreeCallback(cb);
+dcFreeAggr(a);
+.Ed
+.Ss C++
+In our next example, let's look at setting up a
+.Sy DCCallback
+object to call back a simple C++ method (illustrating the need to specify the
+thiscall calling convention). If the class and method is declared as:
+.Bd -literal -offset indent
+class Klass {
+public:
+	virtual void Method(float, int);
+};
+.Ed
+.Pp
+the respective callback handler would be something along the lines of:
+.Bd -literal -offset indent
+DCsigchar cbHandler(DCCallback* cb,
+                    DCArgs*     args,
+                    DCValue*    result,
+                    void*       userdata)
+{
+  Klass*    thisptr = (Klass*)dcbArgPointer(args);
+  float     arg1 = dcbArgFloat(args);
+  int       arg2 = dcbArgInt(args);
+
+  /* ... */
 
-  dcbFreeCallback(cb);
+  return 'v';
+}
 .Ed
+.Pp
+and the callback object would be used as follows:
+.Bd -literal -offset indent
+DCCallback* cb;
+cb = dcbNewCallback("_*pfi)v", &cbHandler, NULL);
+
+/* HACK: this is a hack just for this example to force the compiler
+ * generating a thiscall, below (creates a fake vtable mimicking
+ * Klass, setting all of its possible entries to our callback handler;
+ */
+DCpointer fakeClass[sizeof(Klass)/sizeof(DCpointer)];
+for(int j=0; j<sizeof(Klass)/sizeof(DCpointer); ++j)
+	fakeClass[j] = &cb;
+
+/* (this)call the callback object */
+((Klass*)&fakeClass)->Method(8, 23.f);
+
+dcbFreeCallback(cb);
+.Ed
+.Pp
+.Em NOTE :
+In a real world scenario one would figure out the precise location of the vtable entry of
+.Fn Klass::Method ,
+of course; the above example omits this for simplicity.
 .Sh CONFORMING TO
 The dyncallback library needs at least a c99 compiler with additional support
 for anonymous structs/unions (which were introduced officially in c11). Given