TinyScheme Extensions Package

I created a package for LibreCMC / OpenWRT which seems to work well, though I have not had the chance yet to submit it to the official LibreCMC package repository. Here is my package commit:

https://gogs.librecmc.org/pi31415/librecmc-package-feed/commit/90ee4c484bfd46ff41358ee6668dab72985b061d

A build for for mips24_kc architecture is available here:

ftp://lavender.qlfiles.net/tinyscheme/tinyscheme-extensions_1.1-1_mips_24kc.ipk

That should install onto TPE-R1100, GL-AR150, GL-AR300M (NAND), and GL-AR300M16.

Here is a (trimmed down) sample program which comes with the TSX source code:

; load TinyScheme extension
(load-extension "/usr/lib/tinyscheme/tsx")

; get user's home dir from HOME environment var
(define homedir (getenv "HOME"))
(display "Listing contents of ") (display homedir) (newline)

; create directory stream to read dir entries
(define dirstream (open-dir-stream homedir))
(if (not dirstream)
 (begin
 (display "Unable to open home directory!! Check value of HOME environment var.")
 (quit)))

(let listentry ((entry (read-dir-entry dirstream)))
 (if (eof-object? entry)
 #t
 (begin
 (display entry)
 (newline)
 (listentry (read-dir-entry dirstream)))))

(close-dir-stream dirstream)

It lists the files in the home directory:

root@pathos:~# tinyscheme listhome.scm
Listing contents of /root
.
..
shellinabox_2.10-1_mips_24kc.ipk
luci-app-shellinabox_0.1-4_mips_24kc.ipk
tinyscheme-extensions_1.1-1_mips_24kc.ipk
tinyscheme-embedded_1.41-2_mips_24kc.ipk
srepl.scm
tinyscheme_1.41-2_mips_24kc.ipk
exercises
script.scm
zlib_1.2.11-1_mips_24kc.ipk
listhome.scm

Of course, this is a bit simpler:

(load-extension "/usr/lib/tinyscheme/tsx")
(system "ls ${HOME}")

As I mentioned previously, TinyScheme does not currently utilize ld.conf, so it is necessary to run (load-extension "/usr/lib/tinyscheme/tsx") with the full path to the TSX extension library.

 

TinyScheme Extensions

In my previous post I contemplated writing my own interface to more system functions, but then I discovered this had already been done:

TinyScheme Extensions

After installation of the library:

christopher@evenstar:~$ ls /usr/local/lib/ts/
tsx.so

christopher@evenstar:~$ tinyscheme 
TinyScheme 1.41

ts> (load-extension "/usr/local/lib/ts/tsx")
#t

ts> (system "grep 'model\ name' /proc/cpuinfo | head -n 1")
model name : Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz
0

One annoying detail here is that TinyScheme 1.41 does not use ld.so.conf paths to find the library (even though the documentation says it does). This means you must specify the full path to the extension library. Perhaps I could get this added into my own release of TinyScheme.

TinyScheme FFI

I started to experiment with using TinyScheme to control a libreCMC system, but then discovered that TinyScheme doesn’t actually come built-in with a system interface, other than basic input/output (from stdio.h). This is not really a deficiency, as TinyScheme was intended to be embedded in a variety of systems and applications. TinyScheme has a Foreign Function Interface (FFI) allowing us to turn C functions into scheme functions, so adding in more system functions should in principle be fairly simple.

One difficulty, though, is that the examples in the documentation did not actually match the FFI in the release. So, I had to spend some quality time in the header files. I was then able to modify the examples to work. This C program loads and runs a scheme file called myscheme.scm, while importing a C function called square, which, of course, squares a number:

#include "tinyscheme/scheme.h"
#include "tinyscheme/scheme-private.h"

pointer square(scheme *sc, pointer args) {
  if(args!=sc->NIL) {
    if(sc->vptr->is_number(sc->vptr->pair_car(args))) {
      double v=sc->vptr->rvalue(sc->vptr->pair_car(args));
      return sc->vptr->mk_real(sc,v*v);
    }
  }
  return sc->NIL;
}

int main() {
  scheme * sc;

  FILE *fptr;
  // initialize the scheme invironment
  sc = scheme_init_new();
  // set output to go to STDOUT by default
  scheme_set_output_port_file(sc, stdout);
  // Load the init file
  fptr = fopen("/usr/lib/tinyscheme/init.scm", "r");
  scheme_load_file(sc, fptr);
  fclose(fptr);

  // Import square fn
  sc->vptr->scheme_define(sc,
  sc->global_env,
  sc->vptr->mk_symbol(sc,"square"),
  sc->vptr->mk_foreign_func(sc, square));
 
  // Load my scheme program
  fptr = fopen("myscheme.scm", "r");
  scheme_load_file(sc, fptr);
  fclose(fptr);
  // de-initialize the scheme environment
  scheme_deinit(sc);
  return 0;
}

And here is the scheme program:

(display (square 4))
(newline)

And here is execution:

christopher@evenstar:~/Devel/embedded-ts$ gcc -o loader -DUSE_DL loader.c -ltinyscheme
christopher@evenstar:~/Devel/embedded-ts$ ./loader 
16.0

Next I should be able to add functions from <stdlib.h>, e.g., system() to call shell commands.