I'm writing a program/game where I use Guile for scripting on top of a C program.
For example I have a command struct type(which is also used for move_to) in C and corresponding
move_to wrapper function to to create move_to commands in Guile. In the UI an input line can be entered
and is then executed in Guile.
For move_to it look like this in C:
Some entity id is passed here as a SCM value, same for the new
the position and SCM value is passed for x and the same for y.
static SCM move_to(SCM scm_id, SCM x, SCM y) {
unsigned int id = scm_to_int(scm_id);
float new_x = scm_to_double(x);
float new_y = scm_to_double(y);
// Search for entity
int index = -1;
for (int i = 0; i < gs.entities.size(); i++) {
if (get_id(&(gs.entities[i])) == id) { index = i; break; }
}
command c = {new_x,new_y,MOVETO,0};
// Add move command to entity if one was found
if (index != -1) { printf("found index\n");add_command(&(gs.entities[index]), c); }
return SCM_UNSPECIFIED;
}
In this code the entity is searched in some entity list and if it exist, we
create a new move_to_command and add it to the command list of the entity.
In the UI then e.g. (move_to 0 100 100) can be entered and is then executed.
It's straightforward when creating a C function and wrapper when the function just returns an integer or nothing at all. But I'm not sure how to implement a function which returns a (C-/Guile-) struct value to Guile.
Let's say we have this struct type in C:
typedef struct {
unsigned int id;
event_type type;
unsigned int entity_id;
unsigned int by_entity;
} event;
How would I go to create a Guile struct value from this C struct which is returned when
when for example some Guile function - like 'get-next-event'(which I have to write) is called. It would now also
be OK if I had to copy the value from the C struct to a new Guile struct over.
Saw that there is the function scm_make_struct(SCM vtable, SCM tail_size, SCM init_list),
but I am not sure how to create a vtable value which to pass here as a first argument.
I think older guile versions there was scm_make_vtable_vtable.
Also I tried the C-function scm_struct_vtable from the current version.
ADDENDUM:
- found a function to create a vtable in the file struct.h, which is not documented:
SCM_API SCM scm_make_vtable (SCM fields, SCM printer);
Source Code Example:
#include "libguile.h"
static SCM give_me_100(void) {
return scm_from_int(100);
}
static SCM give_me_a_struct(void) {
SCM fields = scm_from_locale_string("pwpw");
SCM vtable = scm_make_vtable(fields,0);
SCM mystruct = scm_c_make_struct(vtable,0, 10, 20, SCM_UNDEFINED); //
return mystruct;
}
static void inner_main(void *closure, int argc, char **argv) {
/* preparation - make C functions callable from Guile */
scm_c_define_gsubr("give-me-100", 0, 0, 0, &give_me_100);
scm_c_define_gsubr("give-me-a-struct", 0, 0, 0, &give_me_a_struct);
scm_shell(argc, argv);
/* after exit */
}
int main(int argc, char **argv) {
scm_boot_guile(argc, argv, inner_main, 0);
return 0; /* never reached, see inner_main */
}
Which can be compiled with this line for example: gcc -o main -I/usr/include/guile/3.0 -lguile-3.0 main.c
Example output:
GNU Guile 3.0.8
Copyright (C) 1995-2021 Free Software Foundation, Inc.
Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.
Enter `,help' for help.
scheme@(guile-user)> (give-me-100)
$1 = 100
scheme@(guile-user)> (give-me-a-struct)
$2 = zsh: segmentation fault (core dumped) ./main
Thank you for any help and suggestions, Rael
To use and export C structs to Guile, one could do it like this - the example code is from here: https://github.com/agentlans/guile-foreign-example/blob/master/bessel.c