Small fixes in readline ffi tutorial

This commit is contained in:
Edwin Brady 2020-03-03 23:35:19 +00:00
parent 1616879c3e
commit 0e98f6383f

View File

@ -33,7 +33,6 @@ completion:
:: ::
typedef char *rl_compentry_func_t (const char *, int); typedef char *rl_compentry_func_t (const char *, int);
rl_compentry_func_t * rl_completion_entry_function; rl_compentry_func_t * rl_completion_entry_function;
A completion function takes a ``String``, which is the text to complete, and A completion function takes a ``String``, which is the text to complete, and
@ -89,7 +88,7 @@ pointer (see Section :ref:`sect-ffi-string`):
We also need to provide a way to check whether the returned ``Ptr String`` is We also need to provide a way to check whether the returned ``Ptr String`` is
``NULL``. To do so, we'll write some glue code to convert back and forth ``NULL``. To do so, we'll write some glue code to convert back and forth
between ``Ptr String`` and ``String, in a file ``idris_readline.c`` and a between ``Ptr String`` and ``String``, in a file ``idris_readline.c`` and a
corresponding header ``idris_readline.h``. In ``idris_readline.h`` we have: corresponding header ``idris_readline.h``. In ``idris_readline.h`` we have:
:: ::
@ -119,10 +118,18 @@ Correspondingly, in ``idris_readline.c``:
return NULL; return NULL;
} }
Now, we can use ``prim_readline`` as follows, with a safe API: Now, we can use ``prim_readline`` as follows, with a safe API, checking
whether the result it returns is ``NULL`` or a concrete ``String``:
.. code-block:: idris .. code-block:: idris
%foreign (rlib "isNullString")
prim_isNullString : Ptr String -> Int
export
isNullString : Ptr String -> Bool
isNullString str = if prim_isNullString str == 0 then False else True
export export
readline : String -> IO (Maybe String) readline : String -> IO (Maybe String)
readline s readline s
@ -195,7 +202,7 @@ The function returns ``Nothing`` if there are no more completions, or
``Just str`` for some ``str`` if there is another one for the current ``Just str`` for some ``str`` if there is another one for the current
input. input.
We might hope that it's as simple as defining a function to assign the We might hope that it's a matter of defining a function to assign the
completion function... completion function...
:: ::
@ -222,8 +229,9 @@ the Readline library expects ``NULL`` when there are no more completions:
Just str => pure (mkString str) Just str => pure (mkString str)
So, we turn ``Nothing`` into ``nullString`` and ``Just str`` into ``mkString So, we turn ``Nothing`` into ``nullString`` and ``Just str`` into ``mkString
str``. Unfortunately, this doesn't quite work. Let's try it for the most basic str``. Unfortunately, this doesn't quite work. To see what goes wrong, let's
completion function that returns one completion no matter what the input: try it for the most basic completion function that returns one completion no
matter what the input:
.. code-block:: idris .. code-block:: idris
@ -240,14 +248,17 @@ completion function first:
main = do setCompletionFn testComplete main = do setCompletionFn testComplete
echoLoop echoLoop
Unfortunately, when we try running it, and hitting TAB before entering We see that there is a problem when we try running it, and hitting TAB before
anything, things go wrong: entering anything:
:: ::
Main> :exec main Main> :exec main
> free(): invalid pointer > free(): invalid pointer
The Idris code which sets up the completion is fine, but there is a problem
with the memory allocation in the C glue code.
This problem arises because we haven't thought carefully enough about which This problem arises because we haven't thought carefully enough about which
parts of our program are responsible for allocating and freeing strings. parts of our program are responsible for allocating and freeing strings.
When Idris calls a foreign function that returns a string, it copies the When Idris calls a foreign function that returns a string, it copies the