Re: using guile like a awk filter in a C program.

Pierre Lindenbaum <[email protected]>
Newsgroups gmane.lisp.guile.user
Message-ID <[email protected]>
> I want to call scheme from C.
>
> The C loop scans the binary data and a scheme script would be used to accept/reject a record. Something like
>
>
>         ./my-c-program --filter '(and (is-male?) (is-german?) )' persons.data > male_from_germany.data
>
>
>>> - furthermore, what's the best practice to include the user's script in
>>> a larger script that would include the definitions of `variant-is-snp?`
>>> , `variant-allele-count`, etc...
>> Maybe modules?

Ok , this it what I got so far. I tested my idea with a C program scanning a stream of integers on stdin . I put  the C code and the Makefile below (or you can read it at https://gist.github.com/lindenb/7b7793ced81fc3a4a566333f5149d65a ) :

The invocation looks like:

seq 1 100 | ./a.out '(= (modulo (_get) 7) 0)'
7
14
21
28
35
42
49
56
63
70
77
84
91
98

where (_get) returns the current integer.

Is it the correct way to initialize the script ?

it looks ugly. Currently the user just define the 'filter' part and then I include this string in a larger code. Ant how should I design this if I want to include modules, custom functions,...  ?

Furthermore, I'd like to include a module that would be embedded in the C code , in a big const string to avoid any external file, it it possible ?


Thank you for your suggestions

Pierre


/***************** C code ************************************************/

#include <stdio.h>
#include <libguile.h>


struct Global {
     /** inputstream */
     FILE* in;
     /** currrent value */
     int value;
     /** contains script as string */
     char buffer[2048];
     };

static struct Global global;

/** retrieve the next record, return #t on success */
static SCM _next () {
   int ret = fscanf(global.in,"%d", &(global.value));
   if(ret!=1) return SCM_BOOL_F;
   return SCM_BOOL_T;
}
/** get current number */
static SCM _get () {
   return scm_from_int(global.value);
}

/** output current number */
static SCM _emit () {
   fprintf(stderr,"%d\n",global.value);
   return SCM_BOOL_T;
}

/** dispose memory associated */
static SCM _dispose () {
   return SCM_BOOL_T;
}


static void*
inner_main (void *data)
{
     struct Global* g= (struct Global*)data;
     scm_c_define_gsubr("_next", 0, 0, 0, _next);
     scm_c_define_gsubr("_get", 0, 0, 0, _get);
     scm_c_define_gsubr("_emit", 0, 0, 0, _emit);
     scm_c_define_gsubr("_dispose", 0, 0, 0, _dispose);
     scm_c_eval_string(g->buffer);
     return 0;
}

int main(int argc,char** argv) {
     if(argc!=2) return -1;
     global.value=1;
     global.in = stdin;
     sprintf(global.buffer,"(while (_next) (if %s  (_emit)   ) (_dispose) )  ",argv[1]);
     scm_with_guile(inner_main,(void*)&global);
     return 0;
     }

/***************** Makefile ************************************************/GUILE_VERSION=2.2
# Tell the C compiler where to find <libguile.h>
CFLAGS=`pkg-config --cflags guile-$(GUILE_VERSION)`

# Tell the linker what libraries to use and where to find them.
LIBS=`pkg-config --libs guile-$(GUILE_VERSION)`


test: a.out
     seq 1 100 | ./a.out '(= (modulo (_get) 7) 0)'
a.out: filter.c
     $(CC) $(CFLAGS) -o $@ $< $(LIBS)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.