You can specify the line terminator in foreign string conversions via the
:eol-style
parameter in the
external-format
argument.
By default foreign strings are assumed to have lines terminated according to platform conventions: Linefeed on Unix/Linux/MacOS, and Carriage-Return followed by Linefeed on Windows. That is,
eol-style
defaults to
:lf
and
:crlf
respectively. This means that unless you take care to specify the external format
:eol-style
parameter, you may get unexpected string length when returning a Lisp string.
Consider the following C code example on Windows:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
__declspec(dllexport) int __cdecl crlf_string(int length, char *string)
{
int ii;
int jj;
for (ii = 0; ii < length ; ii++)
if (ii % 3 == 1) {
string[ii] = 10;
printf("%d\n", ii);
} else
if ((ii > 0) && (ii % 3 == 0)) {
string[ii] = 13;
printf("%d\n", ii);
} else
if (ii % 3 == 2) {
string[ii] = 97 + rand() % 26 ;
printf("%d\n", ii);
}
string[length] = 0;
return length;
}
Call this C function from Lisp:
(fli:define-foreign-function (crlf-string
"crlf_string"
:source)
((length :int)
(return-string (:reference-return
(:ef-mb-string
:limit 256
:external-format :latin-1))))
:lambda-list (length &aux return-string)
:calling-convention :cdecl
:result-type :int)
(multiple-value-bind (length string)
(crlf-string 99)
(format t "~&C length ~D, Lisp string length ~D~%" length (length string)))
=>
C length 99, Lisp string length 67
Each two character CR LF sequence in the foreign string has been mapped to a single LF character in the Lisp string. If you want to return a Lisp string and not do line terminator conversion, then you must specify the eol-style as in this example:
(fli:define-foreign-function (crlf-string
"crlf_string"
:source)
((length :int)
(return-string (:reference-return
(:ef-mb-string
:limit 256
:external-format (:latin-1 :eol-style :lf)))))
:lambda-list (length &aux return-string)
:calling-convention :cdecl
:result-type :int)
(multiple-value-bind (length string)
(crlf-string 99)
(format t "~&C length ~D, Lisp string length ~D~%" length (length string)))
=>
C length 99, Lisp string length 99