Subject: [clisp-list] modules: constants and encodings (was: another gdi question)

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Mon Apr 29 06:52:03 2002

Hi,

[I take the freedom to reply to the list, since I believe this may be of interest to other people.]

Dan Stanger wrote:

> Is it possible to generate constants in the c code?  In the 
> file gdi.lisp there are hundreds of
> constants from the cygwin headers, is it possible to create 
> these constants in c, and export them to lisp?

It is possible, but cumbersome. I believe it's not worth the effort. My idea of how modules are used is that there's a C part, and there's a LISP part (like you already have: gdi.c and gdi.lisp).

Things that are easily written in Lisp should be left there (e.g. defpackage, macros, Lisp DEFUNs etc.).
You have in gdi.lisp
(defconstant WGL_SWAP_UNDERLAY12 #x8000000)
What's wrong with that (except using #\_ instread of #\-)? :)

The problem I see with it may be:
 o if it's not automatically generated from C files, there may be deviations over time in the values. It is your responsibility as module provider to assess this risk.

 o if it is automatical, then it is your responsibility as the module provider to say: "this is really the same constant on all platforms where this module can work."

I.e. UNIX SIG_USR1 signal numbers is a counter-example: the actual signal number varies from UNIX to UNIX and is not easily accessible at the Lisp level (not in a file like gdi.lisp which you don't want your users to generate first). Therefore, you should take the effort and have C code generate that value, which the Lisp system then can use, and not write
(defconstant SIG-USR1 31) ; bad, broken, wrong

Despite all the recommendations for caution, "the thing is a constant and (DEFCONSTANT foo 128) is perfectly fine" applies in most cases.

Below is how to do this inside a module.

> Also, regarding encoding, I wanted to have package variable 
> for the current encoding, which
> would be set to the clisp encoding.  I have seen reference to
> internal-encoding, in the clisp
> code, so I assume that this would be the one to use as the default.

It's unclear to me why this should be a variable.

First, several encodings may be necessary, depending on the purpose.
Second, each of these could be constant, depending on the module or string properties. There might be no point in having a variable for any of them.

internal_encoding is what's used inside "literal strings" in the CLISP C source code. Remember that all CLISP files have been converted to UTF-8 (-16?) some years ago. So it may not suit your needs, if you fail to use this very same encoding in your C source file.

If the string is a pathname, then O(pathname_encoding) is the right choice (like I did in dynload.d for the foreign library name). Not a variable as far as your module is concerned (it's a variable from the CLISP user point of view).

If you interface to some particular MS-Windows functions, maybe UTF-16 is the encoding required by MS-Windows (e.g. FooBarW() functions). Not a variable either.

Etc.

Now here's how to define constants from within a module.

First, you need to define the symbols. Use the module__object_tab for this.
Then, you need to have the values as Lisp objects. Use either module__object_tab again (for Lisp data) or individual lines of code (best with numbers) for each variable as shown below.
Finally, your module__init_function1() will call define_constant(symbol,Lisp-value).

  define_constant(MymoduleO(sig_usr1),fixnum(SIG_USR1));
or
  sintB val = SIG_USR1;
  define_constant(MymoduleO(sig_usr1),fixnum(SIG_USR1));
  var object val = UL_to_I(0x8000000)
  define_constant(MymoduleO(foobar),val);
  define_constant(MymoduleO(barfoo),MyModuleO(my_encoding));
Beware, define_constant is not GC-safe.

Instead of having a thousand module_object_tab entries, you could have a single one: a huge list of the symbols, and then walk this list. Examples of C code walking a list are abundant in CLISP C source, e.g.
    while (consp(STACK_0)) {
      var object obj = STACK_0;
      STACK_0 = Cdr(obj); funcall(Car(obj),0);

As you automatically generate the module's C code, you have a different set of options (w.r.t. what's comfortable) than somebody writing one directly by hand.

Regards,
	Jorg Hohle.