On Mon, Jun 02, 2008 at 03:42:19PM +1000, konrad Zielinski wrote:
> Yes I do have a specific question:

Great! :-)

> Symbols referring to a shared library contain a colon "lib:sym"
> My Question is How do you do this interplay and what are it's limitations

The internal mechanism in the interpreter works like this:

When an expression like (lib:sym 'arg1 'arg2 ...) is called, 'lib:sym'
is just a normal symbol. If this symbol has no function definition yet,
the interpreter drops into the "undefined" error handler (see
"src/main.c:602"). If this handler finds out, however, that the
undefined symbol contains a colon in its name, it splits the name at the
colon, tries to locate a shared object file (library) using the first
part as a file name (with dlopen()), and a symbol in that file using the
second part (with dlsym()).

If successful, a pointer to the library code is stored as a function
definition in 'lib:sym'. After that, all calls to (lib:sym ...) work
just like a normal function call, without any speed penalties.

> * how do I embed C code in a picolisp file

You need to load "lib/gcc.l" in your lisp source. Then, to write an
inline C code segment, you call the 'gcc' function with at least three

   1. A name to be used for a temporary library name (any name unique
      for this application is all right).

   2. An optional list of other libraries to link with.

   3. One or more symbols to receive the function definitions (i.e. the
      functions defined in that inline segment.

The 'gcc' function will pass all following source text to the C
compiler, until a dummy comment of the form '/**/' (must be exactly one
slash, two asterisks, and a slash) is encountered. Then it stops, and
normal Lisp interpretation continues.

The C code in that segment can be written just like the C code in the
picoLisp kernel. "pico.h" is already included automatically.

There are a few examples in the release tarball: In lines 11 through 25
of "misc/fibo.l", "misc/crc.l", and lines 9 through 23 of "rcsim/tone".

As additional examples, I'll attach "radius.l" (radius authentication)
and "fam.l" (interface to 'famd', I did some experiments but I don't
remember how far that worked).

Considering SDL, Jon Kleiser's experiments with OpenGL might be
interesting for you: <http://folk.uio.no/jkleiser/pico/gl/>

> * what do I do to call it.

There is nothing special. Called just like any other lisp function.

> * how are arguments and return values passed between the two languages

This can be the tricky part. Especially when you want to pass not only
numbers but other data like symbols and lists. It depends on the
application. All arguments and values have to be converted to be
understood by C, and boxed into s-exprs to be understood by Lisp.

> * is there tools for modifying c structs from inside pico lisp

Nothing generic out of the box. It would be nice to invent something,
but I never needed it until now.

> * It's great that you can call functions from libraries but how do you
> tell the interpreter that you want to access a library?

If you want to call a pre-fabricated library, it works just the same way
as the inline mechanism, using the colon syntax.

There are already several libraries included in the standard picoLisp
release ('ext', 'ht', and 'z3d' to be exact). 'z3d' is used, for
example, by the flight simulator demo, and 'ext' for several purposes).

In this case, the library must be placed into the local "lib/"
directory. Then simply call the function

   : (ext:Sin (/ 314159 2) 100000)  # 100000 is the scale factor
   -> 100000

I hope this helps for a first intro. As I said, the tricky part is
writing non-trivial C functions, as soon as non-scalar Lisp date need to
be passed around. I'll help you if you have a concrete case.

- Alex
# 04feb07abu
# (c) Software Lab. Alexander Burger

`(info "/usr/lib/libradiusclient-ng.so")

# 'libradiusclient' is installed
(load "lib/gcc.l")

(gcc "radius" '("/usr/lib/libradiusclient-ng.so") 'rcAuth)

#include        <radiusclient-ng.h>

// (rcAuth 'nm 'pw) -> flg
any rcAuth(any ex) {
   any x, y;
   VALUE_PAIR *send, *received;
   UINT4 service;
   char msg[4096];
   rc_handle *rh;

   x = evSym(cdr(ex));
   y = evSym(cddr(ex));
      char nm[bufSize(x)];
      char pw[bufSize(y)];

      bufString(x, nm);
      bufString(y, pw);

      if ((rh = rc_read_config("/etc/radiusclient-ng/radiusclient.conf")) == 
         return Nil;
      if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0)
         return Nil;
      send = NULL;
      if (rc_avpair_add(rh, &send, PW_USER_NAME, nm, -1, 0) == NULL)
         return Nil;
      if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, pw, -1, 0) == NULL)
         return Nil;
      service = PW_AUTHENTICATE_ONLY;
      if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL)
         return Nil;
      return rc_auth(rh, 0, send, &received, msg) == OK_RC? T : Nil;
# 04sep06abu
# (c) Software Lab. Alexander Burger

(load "lib/gcc.l")

(gcc "fam" '("-lfam") 'famOpen 'famDir 'famEvent 'famClose)

# include <fam.h>

static FAMConnection Fc;

// (famOpen) -> num | NIL
any famOpen(any x __attribute__((unused))) {
   if (FAMOpen2(&Fc, "picolisp"))
      return Nil;
   return boxCnt(FAMCONNECTION_GETFD(&Fc));

// (famDir 'any) -> flg
any famDir(any x) {
   x = evSym(cdr(x));
      char nm[bufSize(x)];
      FAMRequest fr;

      bufString(x, nm);
      return FAMMonitorDirectory(&Fc, nm, &fr, NULL)? Nil : T;

// (famEvent 'new 'chg 'del) -> any
any famEvent(any ex) {
   any x;
   cell c1;
   FAMEvent fe;

   if (FAMNextEvent(&Fc,&fe) < 0 || fe.code<FAMChanged || fe.code>FAMEndExist) 
      return Nil;
   switch (fe.code) {
   case FAMCreated:
      Push(c1, mkStr(fe.filename));
      x = cdr(ex),  x = apply(ex, EVAL(car(x)), NO, 1, &c1);
      return x;
   case FAMChanged:
      Push(c1, mkStr(fe.filename));
      x = cddr(ex),  x = apply(ex, EVAL(car(x)), NO, 1, &c1);
      return x;
   case FAMDeleted:
      Push(c1, mkStr(fe.filename));
      x = cdddr(ex),  x = apply(ex, EVAL(car(x)), NO, 1, &c1);
      return x;
   return Nil;

// (famClose) -> flg
any famClose(any x __attribute__((unused))) {
   return FAMClose(&Fc)? Nil : T;


(task (famOpen)
      '((Nm) (println 'new Nm))
      '((Nm) (println 'chg Nm))
      '((Nm) (println 'del Nm)) ) )
(famDir "/usr/abu")
(famDir "/usr/abu/pico")

Reply via email to