I wasn't referring to the management of APL memory,
but rather native memory used when calling functions through the
FFI.
As an example, I've been recently working on integrating
GSSAPI in Emacs (I've previously integrated the same library
in Common Lisp), and as an example, let's take a look at a
typical C function call in GSSAPI:
A simple function is gss_display_name() which is used to
retrieve the name of a principal as a string, given the
principal object (returned from a previous function call).
Here is the signature:
OM_uint32 gss_display_name(
OM_uint32
*minor_status,
name_t
input_name,
gss_buffer_desc
*output_name_buffer,
gss_OID
*output_name_type);
Here's how you use the function, assuming the name is in
the variable ‘name’:
gss_buffer_desc
out;
gss_OID out_type;
int minor;
int major =
gss_display_name(&minor, name, &out,
&out_type);
if(GSS_ERROR(major)) {
// there was an error, and
the details about the error can be found in major and
minor
}
// The name is now available
in a string located at out.value with the length
out.length
// Making this extra
complicated is that out.value is not nul-terminated.
char *name_as_string =
malloc(out.length + 1);
strncpy(name_as_string,
out.value, out.length);
name_as_string[out.length] = 0;
// We now have the name as a
string in the variable name_as_string.
// There are some other API
calls needed to release the memory allocated by the call
to gss_display_name
// but I'm ignoring that for
the purpose of the example.
All right, with this in mind, we'll have to figure out an
APL API that allows me to do this, and even more complex
stuff. It's possible, but not easy. Here's an attempt at
doing so that I'm just typing out as I see it just to have
something discuss around:
⍝ The size of a gss_buffer_desc consists of 2
pointers,
⍝ which makes it 16 bytes on 64-bit platforms and 8
bytes
⍝ on 32-bit platforms.
gss_buffer_desc_size ← 16
out ← ⎕FFI_Alloc
gss_buffer_desc_size
⍝ The gss_OID type is just a pointer, so 8 bytes on
64-bit platforms
gss_OID_size ← 8
out_type ←
⎕FFI_Alloc gss_OID_size
minor ← ⎕FFI_Alloc
4 ⍝ 32-bit number
⍝ We need to specify the datatype of the return value,
so we'll use an
⍝ axis argument for that.
major ←
'gss_display_name' ⎕FFI_Call minor[Type_Int32] name out
out_type
⍝ The C macro GSS_ERROR expands to some bit-fiddling,
⍝ but it's nothing we can't deal with in APL. There is
⍝ an error if any of the most-significant 16 bits are
set.
is_error ← 0 ≠
+/((32⍴2)⊤4294901760) ∧ (32⍴2)⊤major
⍝ Extract a pointer from 8 bytes after the top of the
struct that out points to
out_value ← 8
⎕FFI_Dereference_Pointer out
⍝ Extract a 64-bit number from the top of the struct
out_length ← 0
⎕FFI_Dereference_Int64 out
⍝ Construct an APL string from an array of UTF-8
characters.
⍝ The idea here is that the left argument specifies
the number of bytes to
⍝ copy, and if the function is called monadically it
will simply copy
⍝ until a terminating NUL byte.
name_as_string ←
out_length ⎕FFI_MakeString out_value
⍝ Finally, free the memory we allocated previously
⎕FFI_Free out
⎕FFI_Free out_type
I don't think this can be made much simpler, and this is a
reasonably simple real-world example of C API's that one
needs to call. I've adopted this example from my Common Lisp
code, and if you want to look at how it's done there you're
welcome to look at that code:
https://github.com/lokedhs/cl-gss/blob/master/src/cl-gss.lisp#L136
Regards,
Elias