<astyle="font-size: 120%"href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023"title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a>
📕 <ahref="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<divid="content"
<p>The ANSI Common Lisp standard doesn’t mention this topic. So almost everything that can be said here depends on your OS and your implementation.</p>
<p><aname="clisp-gethost"></a></p>
<h3id="example-calling-gethostname-from-clisp">Example: Calling ‘gethostname’ from CLISP</h3>
<p>Note: You should read the <ahref="http://clisp.sourceforge.net/impnotes.html#dffi">relevant chapter</a> from the CLISP implementation notes before you proceed.</p>
<p><code>int gethostname(char *name, int len)</code> follows a typical pattern of C “out”-parameter convention - it expects a pointer to a buffer it’s going to fill. So you must view this parameter as either <code>:OUT</code> or <code>:IN-OUT</code>. Additionally, one must tell the function the size of the buffer. Here <code>len</code> is just an <code>:IN</code> parameter. Sometimes this will be an <code>:IN-OUT</code> parameter, returning the number of bytes actually filled in.</p>
<p>So <code>name</code> is actually a pointer to an array of up to <code>len</code> characters, regardless of what the poor “<code>char *</code>” C prototype says, to be used like a C string (0-termination). How many elements are in the array? Luckily, in our case, you can find it out without calculating the <code>sizeof()</code> a C structure. It’s a hostname that will be returned. The Solaris 2.x manpage says “Host names are limited to MAXHOSTNAMELEN characters, currently 256.”</p>
<p>Also, in the present example, you can use allocation <code>:ALLOCA</code>, like you’d do in C: stack-allocate a temporary. Why make things worse when using Lisp than when using C?</p>
<p>This yields the following useful signature for your foreign function:</p>
;; :out or :in-out parameters are returned via multiple values
(gethostname 256)
(if (zerop success) name
(error ... ; errno may be set
...))))
</code></pre>
<p><aname="alisp-gethost"></a></p>
<h3id="example-calling-gethostname-from-allegro-cl">Example: Calling ‘gethostname’ from Allegro CL</h3>
<p>This is how the same example above would be written in Allegro Common Lisp version 6 and above. ACL doesn’t explicitly distinguish between <code>input</code> and <code>output</code> arguments. The way to declare an argument as <code>output</code> (i.e., modifiable by C) is to use an array, since arrays are passed by reference and C therefore receives a pointer to a memory location (which is what it expects). In this case things are made even easier by the fact that <code>gethostname()</code> expects an array of char, and a <code>SIMPLE-ARRAY</code> of <code>CHARACTER</code> represents essentially the same thing in Lisp. The foreign function definition is therefore the following:</p>
<p>Let’s read this line by line: this form defines a Lisp function called <code>C-GET-HOSTNAME</code> that calls the C function <code>gethostname()</code>. It takes two arguments: the first one, called <code>NAME</code>, is a pointer to a char (<code>*char</code> in C), and a <code>SIMPLE-ARRAY</code> of characters in Lisp; the second one is called <code>LEN</code>, and is an integer. The function returns an integer value.</p>
<p>This function creates the <code>NAME</code> array, calls <code>C-GET-HOSTNAME</code> to fill it and then checks the returned value. If the value is zero, then the call was successful, and we return the contents of <code>NAME</code> up to the first 0 character (the string terminator in C), otherwise we signal an error. Note that, unlike the previous example, we allocate the string in Lisp, and we rely on the Lisp garbage collector to get rid of it after the function terminates. Here is a usage example:</p>
<pre><codeclass="language-lisp">* (get-hostname)
"terminus"
</code></pre>
<p>Working with strings is, in general, easier than the previous example showed. Let’s say you want to call <code>getenv()</code> from Lisp to access the value of an environment variable. <code>getenv()</code> takes a string argument (the variable name) and returns another string (the variable value). To be more precise, the argument is a <em>pointer</em> to a sequence of characters that should have been allocated by the caller, and the return value is a pointer to an already-existing sequence of chars (in the environment). Here is the definition of <code>C-GETENV</code>:</p>
<p>The argument in this case is still a pointer to char in C, but we can declare it a <code>STRING</code> to Lisp. The return value is a pointer, so we declare it as integer. Finally, the <code>:STRINGS-CONVERT</code> keyword argument specifies that ACL should automatically translate the Lisp string passed as the first argument into a C string. Here is how it’s used:</p>
<p>If you are surprised by the return value, just remember that <code>C-GETENV</code> returns a pointer, and we must tell Lisp how to interpret the contents of the memory location pointed to by it. Since in this case we know that it will point to a C string, we can use the <code>FF:NATIVE-TO-STRING</code> function to convert it to a Lisp string:</p>
<p>(The second and third values are the number of characters and bytes copied, respectively). One caveat: if you ask for the value of a non-existent variable, <code>C-GETENV</code> will return 0, and <code>NATIVE-TO-STRING</code> will fail. So a safer example would be:</p>