Development quick access |
|
This page describes how to write lisp codes in C within Librep. It's far from complete.
Functions and data types are registered on modules load. The dealing with registered data types is handled by call-backs. Librep uses a mark and sweep garbage collector. For each data type registered, appropriate mark and sweep functions are registered.
Most of macros in this page are defined in librep/src/rep_lisp.h and sawfish/src/sawfish.h.
Value types[]
repv is the type which represents lisp value. Qt and Qnil are repv for lisp `t' and `nil'.
Comparison like v == Qnil is possible.
Return value rep_NULL is equal to Qnil.
Conversion from / to native[]
- integer
- rep_MAKE_INT(x) is native -> lisp, rep_INT(v) is lisp -> native.
- string
- rep_string_dup(char * str) / rep_string_dupn(char * str, int length) copies the native to repv, rep_STR(v) makes the char * from repv.
- window
- The C struct for windows is Lisp_Window. VWIN(v) from lisp to C, rep_VAL(w) for C struct to lisp.
Type check macros[]
These macros check the lisp type of a repv object. They can be used within if like if(rep_INTP(v)), and also in rep_DECLARE* described below.
rep_INTP, rep_NUMERICP (any number type), rep_CONSP, rep_STRINGP, rep_LISTP, rep_VECTORP and so on.
WINDOWP is in sawfish, too.
Car and cdr[]
If the value is a cons, then you can access the car and cdr with macros rep_CAR and rep_CDR. Changing car and cdr can be done with them, too, so
rep_CAR(v) = Qt;
works.
Registering new symbols[]
DEFSYM Macro[]
DEFSYM(add_window_hook, "add-window-hook");
This creates a C variable Qadd_window_hook with the lisp name "add-window-hook". This should go somewhat near the top of the file (and not in a function).
rep_INTERN[]
rep_INTERN(x)
Registers the symbol with the lisp environment. Usually placed inside the init code. For dynamical scope symbol, use rep_INTERN_SPECIAL.
Registering new functions[]
DEFUN Macro[]
#define DEFUN(name,fsym,ssym,args,type) Let's see an example:
DEFUN("call-window-hook", Fcall_window_hook, Scall_window_hook, (repv hook, repv win, repv args, repv type), rep_Subr4) /* ::doc:sawfish.wm.windows.subrs#call-window-hook:: call-window-hook HOOK WINDOW &optional ARGS HOOK-TYPE Call HOOK for WINDOW with extra arguments ARGS. See `call-hook' for a description of HOOK-TYPE. ::end:: */ { /* code goes here */ }
- name
- The string name of the function, this is how it will appear inside the rep environment.
- fsym
- The actual C function that gets created, it will have the signature of repv fsym args. It can be called by the C code directly.
- ssym
- The SUBR. This is passed to rep_ADD_SUBR to register the function.
- args
- The arguments to the function. (repv arg1) for one argument, (repv arg1,repv arg2) for 2, and so on up to 5 arguments. For N arguments (repv args).
- type
- The symbols rep_Subr0 -> rep_Subr5 and rep_SubrN corresponding to how many args defined in "args"
Then comes the doc-string. The return value is a repv. For functions that do not return a value (only there for side-effects) return Qt.
Don't forget to include the function in the header file, librep/src/rep_subrs.h or sawfish/src/sawfish_subrs.h.
rep_DECLARE*[]
In the above example, these two lines are there at the beginnig of the function body:
rep_DECLARE1(hook, rep_SYMBOLP); rep_DECLARE2(win, XWINDOWP);
This forces the type for each argument. If the type is wrong, an error is signaled.
Value `nil' is not allowed. To include `nil', use rep_DECLARE1_OPT(x,t) instead, for argument 1 for example.
rep_ADD_SUBR[]
The DEFUN macro only defines C function. To make it available in lisp, use this kind of expression:
repv tem; tem = rep_push_structure ("sawfish.wm.windows.subrs"); rep_ADD_SUBR(Scall_window_hook); rep_pop_structure (tem);
Accessing lisp values[]
Lisp variables values[]
In most cases, this suffices:
DEFSYM(global_keymap, "global_keymap"); ... repv v = Fsymbol_value(Qglobal_keymap, Qt); // never mind Qt ... rep_INTERN(global_keymap);
Sometimes you have to specify the module which defines the symbol:
repv tem = rep_push_structure_name ("foo.bar.baz"); value = Fsymbol_value (sym, Qt); rep_pop_structure (tem);
Calling lisp functions[]
First, read the previous section on variable.
If the function is defined with DEFUN macro, then you can simply call it like this:
repv win2 = Fwindow_get (win, Qplaced, Qt);
It's possible to access functions defined in lisp: (define (foo-func a b) ....)
DEFSYM(foo_func, "foo_func"); ... repv a = Qt, b = Qnil; repv v = rep_call_lisp2(Fsymbol_value(Qfoo_func, Qt), a, b); ... rep_INTERN(foo_func);
If the function takes only one argument, then use rep_call_lisp1 instead.
Registering new types[]
u_int rep_register_new_type(char *name, int (*compare)(repv, repv), void (*princ)(repv, repv), void (*print)(repv, repv), void (*sweep)(void), void (*mark)(repv), void (*mark_type)(void), int (*getc)(repv), int (*ungetc)(repv, int), int (*putc)(repv, int), int (*puts)(repv, void *, int, rep_bool), repv (*bind)(repv), void (*unbind)(repv))
"Required" arguments are "name","princ","print","sweep", and "mark." All others can be passed 0 (aka NULL?) if no implementation is given. "compare" is common (need to find out when it is used). "sweep" isn't used for "datum".... and neither "sweep" or "mark" is used for "weak-ref"...
compare[]
I have yet to find an example that doesn't compare one object to another by pointer:
static int x_window_cmp (repv w1, repv w2) { return w1 != w2; }
princ[]
how to print the object: not sure on difference between print and princ yet
static void x_window_prin (repv stream, repv obj) { char buf[256]; sprintf (buf, "#<x-drawable 0x%lx>", VX_DRAWABLE (obj)->id); rep_stream_puts (stream, buf, -1, FALSE); }
print[]
Like princ but formats output to be acceptable for reading in.
For example:
(print "hi") prints out "hi" (princ "hi") prints out hi (no quotes)
sweep[]
static void some_name (void)
Walk the list of objects (you should keep track of all self managed object you create) freeing those that are not marked (rep_GC_CELL_MARKEDP(rep_VAL(w))). Cleanup the object (if it holds and open connection, close it. malloced data, free it etc) then free the cell with rep_FREE_CELL(w). If it is marked (i.e. it does need to be collected) clear the GC bit with rep_GC_CLR_CELL(rep_VAL(w)).
To make it easier to manage, use the pattern:
Lisp_Struct *w = object_list; while (w != 0) { Lisp_Struct *next = w->next; if (!rep_GC_CELL_MARKEDP (rep_VAL (w))) { } else { rep_GC_CLR_CELL (rep_VAL (w)); w->next = object_list; object_list = w; } w = next; }
This is reversing the list of objects as it traverses it, omitting any objects that need to be Collected.
mark[]
static void some_name (repv obj)
This should call rep_MARKVAL on any repvs that are stored inside the struct. This allows the mark phase to find any other objects that are found through your object.
mark_type[]
static void mark_all (void)
Mark all the objects of this type? Not entirely sure when this is needed. unix_processes uses it to keep around any process that is still active (even if no reference is held, still want it to run....).
getc[]
putc[]
static int some_name (repv stream, int c)
The return value is the number of bytes actually written? int c is the char to send, cast/save to char?
puts[]
static int some_name (repv stream, void *data, int len, rep_bool is_lisp)
The return value is the number of bytes actually written? is_lisp signals that data is a rep_STR?
bind[]
unbind[]
load/unload[]
These functions are called on load and unload respectively.
rep_dl_init[]
This is where all initial registration and setup is done. Symbols, functions, datatypes and documentation registered.
rep_dl_kill[]
Any closing or registering that needs to be on dl unloading.