  SLIRP Reference Manual, Version 1.7.7
  Michael S. Noble, mnoble@space.mit.edu
  Jan 6, 2006
  ____________________________________________________________

  Table of Contents



   Preface
   Introduction

  1. Brief History
  2. The libtriv Module
  3. Expectations
  3. Code Generation
  4. Generated Type Mappings
     4.1 Generated Enumeration Values
     4.2 Other Generated Constants and Variables

  5. Basic Mapping Functions
  6. References
     6.1 Using S-Lang References Properly

  7. Guaranteed-Size Mappings
  8. Mappings For Aggregate Types
     8.1 Pointers
        8.1.1 Pointer Type Hierarchy
        8.1.2 To Code or Not To Code?
     8.2 Structures
     8.3 File Handles

  9. Opaque Types
     9.1 Initializers and Finalizers
     9.2 Default Mappings

  10. Defining New Type Mapping Functions
  11. C++
  12. FORTRAN
  13. Compilation: Generated Makefiles
  14. Template Modules
  15. Debugging: slirp_debug_pause()
  16. Usage Statements
  17. Vectorization
  17. Interface Files
  18. Loading Interface Files
  19. Nesting Interface Files
  20. Ignoring Symbols
     20.1 Functions
     20.2 Macros
     20.3 Variables

  21. Macro Substitutions
  22. NULL and Omitted Arguments
  22. Introduction To Annotations
  23. A Sample Annotation
  24. Dissecting an #argmap
     24.1 Custom File Loader
     24.2 Matching Rules

  25. Parameter Substitutions
     25.1 Metadata

  26. Variable Substitutions

  26. #argmap Annotations
  27. Wrapper Structure
  28. in Method
     28.1 Built-in in Maps
        28.1.1 File Descriptors
        28.1.2 Generic Pointers
        28.1.3 C++ string Objects
        28.1.4 FORTRAN Strings

  29. out Method
     29.1 Built-in out Maps

  30. final Method
  31. ignore Method
  31. Other Annotations
  32. #clear
  33. #copy
  34. #ignore
  35. #inline_c
  36. #prototype
  37. #retmap
     37.1 Built-in #retmap Annotations

  38. #typedef
     38.1 Built-in Type Definitions
     38.1 Annotation Grammar
     38.1 Command Line Reference


  ______________________________________________________________________



  [1m1.  Preface[0m



         SLIRP is the (Sl)ang (I)nte(r)face (P)ackage.

         Copyright (C) 2003-2005  Massachusetts Institute of Technology
         Copyright (C) 2002  Michael S. Noble <mnoble@space.mit.edu>

         This software was partially developed at the MIT Center for Space
         Research, under contract SV1-61010 from the Smithsonian Institution.

         Permission to use, copy, modify, distribute, and sell this software
         and its documentation for any purpose is hereby granted without fee,
         provided that the above copyright notice appear in all copies and
         that both that copyright notice and this permission notice appear in
         the supporting documentation, and that the name of the Massachusetts
         Institute of Technology not be used in advertising or publicity
         pertaining to distribution of the software without specific, written
         prior permission.  The Massachusetts Institute of Technology makes
         no representations about the suitability of this software for any
         purpose.  It is provided "as is" without express or implied warranty.

         THE MASSACHUSETTS INSTITUTE OF TECHNOLOGY DISCLAIMS ALL WARRANTIES
         WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
         MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL THE MASSACHUSETTS
         INSTITUTE OF TECHNOLOGY BE LIABLE FOR ANY SPECIAL, INDIRECT OR
         CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
         OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
         NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
         WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.



  [1m2.  Introduction[0m

  SLIRP, the (SL)ang (I)nte(R)face (P)ackage, is a code generator aimed
  primarily at simplifying the process of creating [4mmodules[24m for the S-
  Lang scripting language.  It can dramatically reduce the time and
  effort required to make C, C++, or FORTRAN code callable directly from
  the S-Lang interpreter, and will even generate Makefiles to automate
  the build process.

  SLIRP may also be used to generate pure C bindings for C++ code, or
  empty (stub) implementations for the interface(s) specified by its
  input.  These features are more general in nature, so as a result the
  emitted code has no dependencies upon S-Lang whatsoever.


  [1m2.1.  Brief History[0m


  SLIRP grew out of an effort by the author to develop SLgtk, the S-Lang
  bindings to the Gimp Toolkit (more popularly known as Gtk).  To it's
  credit the Gtk development community has paid close attention to the
  problem of binding Gtk to other languages, and mechanisms which
  considerably aid that process are readily available.  Oddly enough,
  many Gtk language bindings do not use SWIG, but instead rely upon so-
  called .defs files, which are descriptions -- in the Scheme language
  -- of the apis of the underlying libraries, apparently generated from
  the header files and then supplemented with additional semantics.

  In typical hacker fashion the SLgtk bindings project began by building
  upon the work of someone else, which in this case amounted to
  borrowing the .defs files from PyGtk and Gtk itself.  While this
  proved a useful starting point, over time enough
  undocumentedness/inconsistencies/omissions were encountered to
  undermine my confidence, so I opted to utilize the .defs files when
  they provided information not readily available in header files (e.g.,
  to identify functions which accept NULL for one or more arguments),
  and wrote a minimal generator to fabricate the bulk of the bindings
  directly from the Gtk headers.  After all, even though the source may
  not tell the complete story it certainly doesn't forget and never
  lies.  Relying too heavily upon .defs files could also limit the
  potential scope of the generator, making it too specialized to be used
  on other libraries which do not describe their apis in such fashion.

  Given that SWIG currently does not support S-Lang a logical question
  to ask is why I did not write a S-Lang extension for SWIG and use it
  to generate SLgtk?  Well, part of the answer lies above, namely that
  if Gtk were "more SWIG-able" then presumably more developers would be
  using SWIG for Gtk bindings generation.  Minimizing external
  dependencies was another significant motivation;  SLIRP is 99% pure S-
  Lang code, and about 1% C, so if you've got S-Lang and a C compiler
  installed (e.g., as millions of Linux users do by default) you can use
  SLIRP immediately, without installing any additional packages.  Other
  factors included having greater control over the generated code, as
  well as supporting FORTRAN and (eventually) S-Lang's powerful
  vectorized math capabilities.


  [1m2.2.  The libtriv  Module[0m

  As our first example, consider a library named libtriv whose public
  interface triv.h contains



      typedef struct { char *name; double value; } TrivDatum;


      typedef enum { TRIV_GOOD=0, TRIV_BAD, TRIV_UGLY, TRIV_HORRIFIC } TrivErrorCode;


      extern      long            triv_sum                (long augend, long addend);
      extern      double          triv_mult               (double op1, double op2);


      extern      TrivDatum       *triv_datum_new         (char *name, double value);

      extern      void            triv_datum_destroy      (TrivDatum *datum);

      extern      void            triv_set_ref_i          (int *i);

      extern      void            triv_print_array_f      (long nelems, float array [  ]);
      extern      char**          triv_make_array_s       (void);
      extern      void            triv_print_array_s      (long   nelems, char **array);

      extern      char**          triv_make_array_nts     (void);
      extern      void            triv_print_array_nts    (char **array);

      extern      TrivDatum**     triv_make_array_datum   (void);
      extern      void            triv_print_array_datum  (long nelems, TrivDatum **array);
      extern      void            triv_print_error        (TrivErrorCode err);


      extern      void            triv_swap_double        (double *i, double *j);
      extern      void            triv_close              (int fd);
      extern      FILE*           triv_fopen              (char *name, char *mode,
                                                  unsigned long  *size,
                                                  unsigned short *nlinks);



  Further suppose that one day that you misplaced your wits and decided
  it was absolutely necessary that you be able to call this library from
  a S-Lang script.  How would you go about such?  This is the problem
  SLIRP helps solve.  Let's begin by issuing the command


               unix% slirp triv.h



  which will generate, amongst others, the wrapper



          static void sl_triv_mult (void)
          {
             double result;
             double arg1;
             double arg2;

             if (SLang_Num_Function_Args != 2 ||
                  SLang_pop_double(&arg2) == -1 ||
                  SLang_pop_double(&arg1) == -1 )
                  {Slirp_usage_err("double = triv_mult(double,double)"); return;}

             result = triv_mult(arg1, arg2);
             (void) SLang_push_double ( result);
          }



  SLIRP provides a number of ways of tailoring its operation and output,
  but in this instance the code is emitted to a file named [4mtriv_glue.c[0m
  in the current working directory.  Next we need to make the S-Lang
  interpreter aware of this wrapper by installing it as a so-called
  [4mintrinsic[24m function.  There's more than one way to do this, but the
  best practice is to create an entry for each wrapper within an [4mintrin-[0m
  [4msic[24m [4mfunction[24m [4mtable[24m, and register all of them at once with a single
  call to either SLadd_intrin_fun_table() or its namespace variant
  SLns_add_intrin_fun_table().  To assist the language binder with this
  SLIRP also generates an intrinsic function table entry for each each
  wrapper function that it generates.  In our example this entry looks
  like


               MAKE_INTRINSIC_0("triv_mult",sl_triv_mult,V),



  and is also emitted to triv_glue.c.  Now all that remains is to pro-
  vide a means of binding the generated code to the S-Lang interpreter
  at runtime.  For this we need another code fragment to initialize the
  module, something along the lines of



          #include "slang.h"
          #include "triv.h"

          static SLang_Intrin_Fun_Type triv_Intrin_Funcs[] =
          {
            MAKE_INTRINSIC_0("triv_mult",sl_triv_mult,V),
            ...
            SLANG_END_INTRIN_FUN_TABLE
          };

          SLANG_MODULE(triv);
          int init_triv_module_ns(char *ns_name)
          {
             SLang_NameSpace_Type *ns = NULL;

             if (ns_name != NULL) {
                  ns = SLns_create_namespace (ns_name);
                  if (ns == NULL)
                     return -1;
             }

             if (-1 == SLns_add_intrin_fun_table (ns, triv_Funcs, "__triv__"))
                  return -1;

             return 0;
          }



  Typically the file generated by SLIRP will be compiled via Makefile
  rules, to build an [4mimportable[24m [4mmodule[24m which may be accessed at runtime
  via the S-Lang import() function.  In our case this would instruct the
  S-Lang runtime to dynamically load a shared object library named triv-
  module.so, invoke its init_triv_module_ns() initializer, and register
  the wrapper functions, constants, and variables defined within.

  Here's how our triv_mult wrapper might be used within a S-Lang script:


               import("triv");

               define do_mult(op1, op2)
               {
                  print("triv_mult(%S, %S) = %S", op1, op2, triv_mult(op1,op2));
               }

               do_mult(333, 3);
               do_mult(PI/2, 2);



  For more details consult the code for this example, which is located
  in the examples/triv directory of the SLIRP distribution and can be
  built and invoked by typing make followed by make demo at the command
  line.   The example also utilizes an interface file to define an
  opaque mapping for the TrivDatum type, as well as several function
  annotations.  The modules directory within the S-Lang source distribu-
  tion also contains a number of useful modules, as does the MIT modules
  page at  <http://space.mit.edu/cxc/software/slang/modules/>.



  [1m2.3.  Expectations[0m


  It is important to realize that SLIRP is [4mno[24m [4msilver[24m [4mbullet[24m.  In the
  abstract code generators are not meant to free the programmer from the
  responsibility of thinking [4mat[24m [4mall[24m, but rather aim at freeing them to
  think about [4monly[24m that which [4mrequires[24m substantive thought, leaving the
  rest of the presumably mundane details to be mechanically churned out
  by a machine.

  For a variety of reasons the developer may prefer to wrap portions of
  a library manually, instead of relying upon wrappers emitted by a
  generator.  As such most bindings projects will likely include both
  generated and hand-crafted code, so it is pragmatic to view a code
  generator as but one element in the toolbox of the language binder.

  It should also be noted that SLIRP is neither a preprocessor of nor a
  compiler for the C language.  By choosing a S-Lang-based
  implementation (instead of one, say, in C, generated from a grammar
  specified in Lex/Yacc) we exchange completeness for size, simplicity
  of design and distribution, ease of use, and portability.

  However, as discussed in section ``Pointers'', even if SLIRP contained
  a full C preprocessor or compiler it would still be impossible for it
  to mechanically map every possible construct from the universe of
  syntactically valid C libraries to an equivalent construction in S-
  Lang.  For reasons such as these code generators provide mechanisms to
  customize their behavior and layer additional semantics on top of the
  underlying api (such as the .defs mechanisms described earlier, or the
  interface files respectively employed by SWIG and SLIRP).

  Future versions of SLIRP may include a parser built from a complete C
  grammar, but until then SLIRP will be more heuristic than
  deterministic in its operation.  This has proven more than sufficient
  for processing Gtk and its constituent libraries, whose headers --
  while highly complex -- are generally well-structured and [4mbinding-[0m
  [4mfriendly[24m.  SLIRP is also known to generate useful bindings for many
  other FORTRAN, C++, and C codes, including OpenGL, MySQL, PVM,
  libGlade, glibc (gettext), HDF5, NetCDF, cgilib, and ASURV.



  [1m3.  Code Generation[0m


  One of the most important things to understand about code generation
  is that in order for a generator to emit useful wrappers it needs to
  know how to map the types it encounters, while parsing function
  signatures, to the target language.  The chief means through which
  SLIRP does this for S-Lang is by consulting a [4mtype[24m [4mmapping[24m [4mtable[24m.  One
  element of this table, for example, indicates how a S-Lang variable of
  Integer_Type should be passed to a C function expecting an int
  argument.

  By default this table contains entries for all of the basic C types
  (in the parlance of Kernighan and Ritchie, 1988), as well as arrays of
  and pointers (and C++ references) to them.  It may also be arbitrarily
  extended to support a wide range of types that may be defined by the
  libraries being wrapped, in one of several ways:

  o  Automatically, for the selected types described in the next
     section.

  o  Explicitly, via the slirp_map_* family of functions.

  o  Implicitly within a function prototype or annotation, when
     autotyping is enabled (the default) and their parameter lists refer
     to a type for which no mapping already exists (see the -noautotype
     option for more information).


  [1m3.1.  Generated Type Mappings[0m


  SLIRP will automatically fabricate a type mapping for enumerations
  that have been assigned a type name via the [4mtypedef[24m keyword, as well
  as for all "simple" type definitions of the form



               typedef         <existing_type_name>    <new_type>;



  With the help of the these rules SLIRP is able to automatically wrap


               extern  void    triv_print_array_i      (TrivIntP array);



  from our libtriv module, because when it earlier encountered


               typedef         int*            TrivIntP;



  a mapping was generated which established TrivIntP as a reference type
  of int*.  SLIRP is likewise able to automatically wrap


               extern          void            triv_print_error(TrivErrorCode err);


  because the error code enumeration is given a unique type name within
  triv.h.  Without these generation rules the triv interface file would
  need additional content, such as


               slirp_map_int("TrivErrorCode");



  in order to wrap the entire triv library.


  [1m3.1.1.  Generated Enumeration Values[0m


  While processing enumerations SLIRP emits additional code to reflect
  each [4menumeration[24m [4mvalue[24m within a table of [4mintrinsic[24m [4mconstants[24m.  This
  allows S-Lang scripts to utilize the enumeration mnemonics in the same
  manner as would C code, and in many instances a S-Lang call utilizing
  an enumeration mnemonic will be indistinguishable from its C
  counterpart.  For example, the following S-Lang snippet


                       variable value = TRIV_BAD;
                       triv_print_error(value);



  is equivalent to the C code


                       int value = TRIV_BAD;
                       triv_print_error(value);



  and in fact both could be reduced to the single line


                       triv_print_error(TRIV_BAD);



  and used interchangeably.


  [1m3.1.2.  Other Generated Constants and Variables[0m



  SLIRP can also emit intrinsic constant tables to mirror in S-Lang
  scope the value of each [4mintegral-valued[24m and [4mreal-valued[24m #define macro
  encountered, respectively as values of Integer_Type and Double_Type.
  Likewise, each [4mstring-valued[24m #define macro will be mirrored within an
  S-Lang string variable.  SLIRP adopts a conservative stance when
  performing these mappings, in that only "simple" C macros of the form


               #define         <macro_name>            <macro_value>



  will be reflected in S-Lang scope.  To avoid having a particular macro
  reflected as a S-Lang constant or variable see section ``Ignoring''.


  [1m3.2.  Basic Mapping Functions[0m


  The functions given in this section can be used to establish mappings
  to types defined as equivalent to the built-in types provided by C.
  For example, a C type definition of


               typedef  long   glong;



  would be mapped as follows:


               slirp_map_long("glong");



  As noted in the preceding section SLIRP will automatically establish
  type mappings for such typedefs, so in practice the basic type mapping
  functions should be rarely used.  It does no harm for you to include
  such within your interface file, however, and doing so can actually be
  a convenient way to override the default mapping (especially for types
  which specifically require a fixed number of bytes).

  All of the mapping functions have a void return type, and in each the
  the ctype parameter is a string denoting the name of the type
  definition to map.  Note that in the following list the first two
  functions map to a single-character type, while the last maps to char*
  strings.


               slirp_map_char(ctype)

               slirp_map_uchar(ctype)

               slirp_map_short(ctype)

               slirp_map_ushort(ctype)

               slirp_map_int(ctype)

               slirp_map_uint(ctype)

               slirp_map_long(ctype)

               slirp_map_ulong(ctype)

               slirp_map_float(ctype)

               slirp_map_double(ctype)

               slirp_map_long_long(ctype)

               slirp_map_ulong_long(ctype)

               slirp_map_string(ctype)


  [1m3.3.  References[0m

  C passes all arguments by value, so if you want a function call to
  change the value of a given variable you must pass it the value of a
  pointer, or [4mreference[24m, to that variable.  Reference typemaps can be
  added with


               slirp_map_ref(ctype)



  Note that SLIRP implicitly creates a reference mapping, such as


               slirp_map_ref("int*");



  for all basic C types, as well as types mapped to basic C types.  This
  allows the libtriv function


               void triv_set_ref_i (int *i) { *i = -9191; }



  to be automatically wrapped for use in S-Lang as


               variable i = 111;
               triv_set_ref_i(&i);
               vmessage("After triv_set_ref the new value of i is: %d",i);



  [1m3.3.1.  Using S-Lang References Properly[0m

  It is important to understand that the S-Lang C api only allows
  references to pass information in one direction, [4mfrom[24m a function
  wrapper [4mto[24m a S-Lang variable.  A S-Lang reference cannot be used to
  pass the value of a S-Lang variable [4minto[24m a C function.  For example,
  the default SLIRP wrapper for the libtriv function


               void triv_swap_double(double *i, double *j)
               {
                  double tmp;
                  if (i == NULL || j == NULL) return;
                  tmp = *i;
                  *i = *j;
                  *j = tmp;
               }



  is effectively unusable, since S-Lang calls such as



          variable i = 3, j = 4;
          triv_swap_double(&i, &j);



  will yield undefined results.  Using the -refscalars switch at genera-
  tion time would permit usages such as


               triv_swap_double(i, &j);



  (after which both i and j equal 3), but this addresses only part of
  the problem since calls such as


               triv_swap_double(i, j);



  would result in neither value being swapped.  Therefore it is prefer-
  able in these situations to either use annotations or craft the wrap-
  per entirely by hand.


  [1m3.4.  Guaranteed-Size Mappings[0m

  Variants of these which enforce 16-, 32-, or 64-, or 96-bit size
  guarantees are as follows:


               slirp_map_int16(ctype)

               slirp_map_uint16(ctype)

               slirp_map_int32(ctype)

               slirp_map_uint32(ctype)

               slirp_map_int64(ctype)

               slirp_map_uint64(ctype)

               slirp_map_float32(ctype)

               slirp_map_float64(ctype)

               slirp_map_float96(ctype)



  [1m3.5.  Mappings For Aggregate Types[0m



  [1m3.5.1.  Pointers[0m


  In this section we expand upon a comment made in section
  ``Expectations'', regarding the inability of any code generator, [4mby[0m
  [4mdefault[24m, to properly map [4mall[24m constructs from C to their "most natural"
  form in some target scripting language.  To see why, consider a
  function with signature


                       char** account_get_users(Account *a);



  Here Account is an opaque structure, whose layout and content are
  implementation details hidden from the programmer.  With help of the
  typemap


                       slirp_define_opaque("Account");



  SLIRP will have no trouble emitting code to create Account* instances
  in S-Lang scope and pass them back to C routines.

  However, the char** return value is another matter.  The idiom is
  understood to convey that account_get_users() returns an array of
  strings, but of what size?  The number of elements pointed to by the
  return value is unspecified in the declaration, which renders SLIRP
  unable to map the return value to a proper S-Lang array of
  String_Type, since to create an array in S-Lang one must indicate its
  size.  Moreover, in principle the return value might not denote an
  array at all, but rather a pointer to a char* whose value the C caller
  is free to modify.  Again, the absence of disambiguating clues in the
  prototype prevents SLIRP from adopting a definitive interpretation.
  The same would hold true for return values of type int*, float*, and
  so forth.

  Left to its own devices the best SLIRP can do when it encounters a
  return value denoting an array of indeterminate size is pass it to S-
  Lang scope as a [4mpointer[24m, in this case of string_ptr type.  This
  enables the C char** to exist as a S-Lang variable and be passed back
  to other C routines which expect an char**, but --- since pointers are
  opaque --- not directly manipulated in S-Lang scope.  For example,
  attempting to dereference the pointer with the @ operator or determine
  the value of the [4mi[24mth element using [[4mi[24m] would both signal an error.


  [1m3.5.1.1.  Pointer Type Hierarchy[0m

  The complete hierarchy of pointer types provided by SLIRP is as
  follows:



          void_ptr
             |
             +-string_ptr
             |
             +-uchar_ptr
             |
             +-short_ptr
             |
             +-ushort_ptr
             |
             +-int_ptr
             |
             +-uint_ptr
             |
             +-float_ptr
             |
             +-long_ptr
             |
             +-ulong_ptr
             |
             +-double_ptr
             |
             +-file_ptr
             |
             +-opaque_ptr



  The base void_ptr type corresponds to generic pointers, such as void*.
  The next 11 wrap pointers to the familiar C types, while the last
  marks pointers to user-defined opaque types (see next section).  The
  derived pointer types may be cast to and from the void_ptr type, but
  not each other.


  [1m3.5.1.2.  To Code or Not To Code?[0m


  Another option for the developer would be to forego the pointer types
  automatically generated by SLIRP in favor of manually coding a
  wrapper.  For example, suppose the documentation for
  account_get_users() noted that its return value is, in fact, an array
  of strings, and that its final element is guaranteed to be NULL A
  hand-crafted wrapper would then be able to loop over the array until
  the NULL is encountered, use the final loop index value to fabricate
  an appropriately sized String_Type array, and pass the result back to
  S-Lang scope.


  [1m3.5.2.  Structures[0m


  SLIRP can be instructed to map structures from C scope directly to
  proper S-Lang structures.  This is done for the GdkColor and
  GdkRectangle types within the SLgtk package, for example, by using


                               slirp_map_struct("GdkColor*");
                               slirp_map_struct("GdkRectangle*");



  Structure mappings provide an advantage over opaque mappings (see next
  section) in that they allow structure internals to be inspected or
  modified at runtime, but there are presently two tradeoffs with this
  approach:


  1. In the present implementation additional manual coding is required
     to define the structure layout used by the SLang_push_cstruct() and
     SLang_pop_cstruct() routines.

  2. It is more suitable for flatter structures, i.e. those which do not
     deeply nest other structures as fields.


  [1m3.5.3.  File Handles[0m

  S-Lang provides two kinds of handles through which the user may
  manipulate files: the FD_Type returned by the open intrinsic, and the
  File_Type returned by the fopen and popen intrinsics.  These types are
  wrappers around the integer file descriptor defined by POSIX and the
  FILE* pointer defined by the C stdio library, respectively.

  SLIRP can generate code which permits FD_Type variables to be passed
  to wrapped functions in place of integer file descriptors.  As
  described in section ``Builtin_Input_Mappings'', however, these
  transformations are not implicit, but rather require that you add an
  extra line or two to your interface file.

  In contrast, SLIRP will always permit a File_Type variable to be
  passed to a wrapped function in place of a FILE* pointer.  Keep in
  mind, though, that files opened by the S-Lang fopen() or popen()
  intrinsic functions should only be closed by the corresponding S-Lang
  fclose() or pclose() intrinsics.  This stems from the fact that S-Lang
  maintains additional state within a File_Type variable, and this state
  will not properly reflect that a file has been closed when non-
  intrinsic wrapper functions are used.  S-Lang may then attempt to
  manipulate the file again (e.g. to close it when the File_Type
  variable goes out of scope), resulting in undefined behavior.

  Finally, as noted above SLIRP also provides an opaque file_ptr,
  instances of which will be created when wrapped functions return a
  FILE*.  The resulting file_ptr variable may then be passed to any
  other wrapped function in place of FILE*, but may not be passed to S-
  Lang intrinsic functions in place of File_Type.


  [1m3.6.  Opaque Types[0m


  SLIRP provides one additional mechanism for using C aggregate types in
  S-Lang, namely through the [4mopaque[24m mapping functions:


               slirp_define_opaque(slang_type_name [, parent [, finalizer [, initializer]]])
               slirp_map_opaque(ctype [,slang_type_name])



  Opaque types are so named because, while one can create, pass around,
  and even destroy variables instantiated from such a type, one cannot
  modify, or even inspect, their internals.  In fact the only informa-
  tion which may be gleaned at runtime from an opaque variable instance
  is type metadata (e.g. the type name and class id).  The expert S-Lang
  programmer will instantly recognize the equivalence between the notion
  of SLIRP opaque types and the SLang_MMT_Type defined by the S-Lang C
  interface.  The new terminology is used within SLIRP only because it
  is felt that [4mopaque[24m is a more familiar term than [4mmmt[24m, and so will
  convey more information more quickly to more users.

  Opaque variables in S-Lang scope are usually just wrappers around
  structures defined and instantiated in C scope.  As above, the
  relationship between the S-Lang and C types is achieved using an
  interface file to define the opaque type and map it to one or more C
  types present in the header files that will be processed.  For
  example, consider the following sequence of calls taken from the SLgtk
  interface file:


               slirp_define_opaque("GtkOpaque");
               slirp_map_opaque("gpointer");
               slirp_map_opaque("gconstpointer");



  The first line causes SLIRP to fabricate a definition for a unique S-
  Lang type named GtkOpaque, and emit code to install that type when the
  SLgtk module is imported.   The second and third parameters are omit-
  ted in the call, which means that the type will have no parent, no
  initializer, and no finalizer.

  The second and third lines then map the C types gpointer and
  gconstpointer to the new GtkOpaque S-Lang type.  With this typemap
  SLIRP will be able to automatically generate wrappers, when later
  processing Gtk header files, for functions whose signatures contain
  either C type.  Without such a typemap SLIRP would otherwise ignore
  such functions.  Now consider


           slirp_define_opaque("GtkTreePath","GtkOpaque","gtk_tree_path_free");



  As above, this call fabricates a new opaque S-Lang type, GtkTreePath,
  and ensures that code will be emitted to install the type when the
  module is imported.  Unlike above, however, SLIRP will consider this
  new type a descendant of an existing type, namely GtkOpaque.  More-
  over, when instances of the type go out of S-Lang scope the opaque
  destructor will call gtk_tree_path_free to finalize the underlying C
  instance.


  [1m3.6.1.  Initializers and Finalizers[0m


  The initializers and finalizers mentioned above are optional helper
  functions which the programmer can direct SLIRP to call when opaque
  variables come into S-Lang scope (are created) or go out of S-Lang
  scope (are destroyed), loosely analogous to [4mconstructors[24m and
  [4mdestructors[24m within object-oriented languages such as [4mC++[24m and [4mJava[24m.
  Both are pointer types declared as


               void    (*INITIALIZER)          (void*);
               void    (*FINALIZER)            (void*);



  and usually refer to functions within either the api of the library
  being wrapped or the hand-crafted portion of the glue layer.  Typi-
  cally a finalizer is called to free resources allocated to the C
  variable which the opaque wraps;  this can be useful, for example, to
  [4mfree[24m fields within a wrapped C structure that were [4mmalloc[24m-ed when it
  was instantiated, thus avoiding memory leaks.


  [1m3.6.2.  Default Mappings[0m


  Note that each call to slirp_define_opaque() also creates a typemap
  between the new S-Lang type and a C type whose name is the
  concatenation of the S-Lang type name with an asterisk.  For example,
  an invocation such as


           slirp_define_opaque("GtkObject","GObject","slgtk_object_destroyer");



  would implicitly issue the call


           slirp_map_opaque("GtkObject*","GtkObject");



  This simplifies SLIRP interface files by eliminating the redundancy of
  having each opaque type definition followed immediately by the obvious
  C type mapping.

  Finally, note that each opaque type defined becomes the [4mdefault[24m S-Lang
  type for subsequent opaque mappings.  SLIRP uses this default to
  assign a S-Lang type when one is omitted in an opaque mapping, which
  simplifies the SLIRP interface file by allowing the programmer to
  specify a type only when it is explicitly necessary.  This tactic also
  increases the performance of the code generator, since the S-Lang
  interpreter needs to parse fewer tokens.  The default remains in
  effect until the next call to either slirp_define_opaque() or
  slirp_set_opaque_default()


  [1m3.7.  Defining New Type Mapping Functions[0m

  For completeness we note that the lowest-level function called by all
  mapping functions is:


               slirp_map (ctype,gluetype,mnemonic,typeid,typeclass [,freer])



  In principle this could be used to write custom type mapping func-
  tions, but in practice there should be little need for your interface
  file to call it explicitly.


  [1m3.8.  C++[0m


  When wrapping a C++ library SLIRP will attempt to wrap all functions,
  class methods,  constants, enumerated types, and simple #define macros
  specified in its public interface.  Get/set methods are automatically
  generated to wrap simple public fields of a class.  Overloaded
  functions and methods will be wrapped, and class inheritance
  relationships will be honored.  Default values are also supported,
  although you should be mindful that the only sensible default value
  which may be assigned to pointer arguments is NULL.

  While this enables the module developer to wrap a good fraction of
  bread-and-butter C++ code, by no means should this be considered a
  full treatment of the language.  For example, get/set wrappers for
  public class fields are generated only when those fields are of
  basic/primitive type (in the parlance of Kernighan and Ritchie, 1988),
  and a number of more semantically deep features of C++ (such as
  templates, operators, and friend classes) are completely unsupported.

  The -cfront option may be specified on the commandline to generate
  standalone C wrappers for a C++ library.  The code generated in this
  case will make no reference to the S-Lang C api, and is thus suitable
  for calling the C++ library directly from C or FORTRAN rather than
  from the S-Lang interpreter.  Examples of both usages are given in the
  examples/cpp directory.


  [1m3.9.  FORTRAN[0m


  If a FORTRAN compiler is detected on the system during configuration
  SLIRP will also be able to generate bindings for many FORTRAN codes,
  including complex-valued functions and subroutines with complex
  arguments.  Simply specify the FORTRAN source file(s) (which are
  assumed to end with either a .f or .F suffix) to SLIRP in the same
  manner one would normally specify C headers.  SLIRP also allows both
  FORTRAN files and C headers to be processed during the same
  invocation, which can simplify the creation of mixed-language modules.
  A sample FORTRAN module is given in the examples/fortran directory.

  Recall that FORTRAN call semantics differ from C, in that FORTRAN
  passes [4mall[24m variables [4mby[24m [4mreference[24m (i.e., as pointers), even scalars,
  while C passes only by value.  The implications of this are that to
  pass a scalar variable from C to FORTRAN one normally needs to use the
  address operator, as in:


               int c_variable = 5;
               some_fortran_function( ..., &c_variable, ...);



  As a convenience SLIRP hides this detail from the S-Lang programmer,
  enabling FORTRAN entry points to be invoked from S-Lang with the same
  syntax used to invoke C functions.  This benefit accrues not only to
  you as a module developer, but also to users of your module, who need
  not be burdened with knowing the implementation language of the under-
  lying library merely to use your bindings properly.

  Another convenience afforded by SLIRP is that FORTRAN functions and
  subroutines are invoked from S-Lang scope using exactly the same name
  as would be employed in FORTRAN scope.  That is, the S-Lang programmer
  needs no knowledge of how the FORTRAN compiler mangles entry point
  names (e.g. upper case, or underscore suffix, etc) in order to call a
  function or subroutine from S-Lang scope.

  In order to maximize portability SLIRP wraps all FORTRAN function
  calls within a subroutine whose first argument corresponds to the
  return value of the function.  In general this tactic will not be
  visible at the S-Lang layer, although the generated wrappers will
  themselves need to be reflected as a build dependency within the
  module Makefile.  For example, the SLIRP Makefile generation facility
  would automatically add sfwrap_foo.f as a dependency for a module
  generated from foo.f.

  At present multidimensional arrays are not automatically remapped from
  row-major format (employed by C and S-Lang) to column-major format
  (employed by FORTRAN); as a workaround the transpose function can in
  principle be used to perform this task in S-Lang scope, before and
  after the relevant FORTRAN calls.  Finally, routines and functions
  whose signatures contain function pointer arguments (actual arguments
  which are names, e.g., of external procedures) will not be
  automatically wrapped, nor will any subroutines or functions which
  rely upon the nefarious FORTRAN feature of implicit typing.


  [1m3.10.  Compilation: Generated Makefiles[0m


  As an additional convenience SLIRP can also generate "starter" make
  files to automate compilation and linking of your module.   For
  example, given a header file cos.h containing


               double cos(double x);



  one might generate the module, compile it, and invocation-test the
  result in just two simple steps:


               unix% slirp -lm cos.h
               Starter make file generated to 'Makefile'

               unix% make test

               cc  -fPIC -I. -c cos_glue.c
               gcc -shared -o cos-module.so cos_glue.o  -lm -lslang -ldl -lm

               slsh cos-test.sl
               Success!



  (see the examples/makef directory for a demonstration).  This process
  can be initiated or tuned by the -make, -ldflags, -I, -L, and -l
  flags, which are described in section ``Command_Line_Options'' and
  should be reasonably familiar to anyone conversant with compilation.


  [1m3.11.  Template Modules[0m

  SLIRP can be used to generate empty (template) modules, by either
  specifiying an empty header file, such as


               unix%  touch foo.h
               unix%  slirp foo.h
               unix%  ls -l foo_glue.c
               -rw-rw-r--  1 mnoble asc 3393 Nov 10 17:39 foo_glue.c



  or by specifying /dev/null as input:
               unix%  slirp -m template_example /dev/null
               unix%  ls -l template_example_glue.c
               -rw-rw-r--  1 mnoble asc  3470 Nov 10 17:41 template_example_glue.c



  [1m3.12.  Debugging: slirp_debug_pause()[0m

  Debugging modules can be difficult, e.g. because breakpoints cannot be
  set within a module until after it's been loaded.  Further, knowing
  exactly where (in the source code) and when (during process execution)
  this occurs requires in-depth knowledge of S-Lang library internals,
  and is virtually impossible to isolate when the S-Lang library has not
  been compiled for debugging.  To address these issues SLIRP embeds
  within all modules the [1mslirp_debug_pause() [22mstub.

  To activate the stub set the SLIRP_DEBUG_PAUSE environment variable
  before importing your module.  This will cause the parent process to
  wait before exiting module initialization, during which time you may
  set breakpoints within the codebase of the module (since its symbol
  table will have been loaded at that point) or its dependencies.  This
  removes the need for module developers to learn the internals of
  dynamic loading in S-Lang, and permits the module to be debugged even
  when the S-Lang library itself has not been compiled for such.

  The debugging stub will do nothing if SLIRP_DEBUG_PAUSE is unset in
  the environment.   When the variable is set, however, if the result of
  atoi(getenv(SLIRP_DEBUG_PAUSE)) evaluates to a negative integer [4mN[0m
  slirp_debug_pause() will sleep for abs(N) seconds, otherwise the stub
  will pause indefinitely, awaiting a keypress in the terminal from
  which the parent process was launched.



  [1m3.13.  Usage Statements[0m


  By default SLIRP will generate code to emit [1mUsage: [22mstatements within
  wrapper functions that have been invoked with the incorrect number of
  arguments.  These serve as useful reminders of the purpose of the
  function, for both new and veteran users of a library, and can often
  save a trip to the documentation.  See the -nopop runtime switch for
  more details.


  [1m3.14.  Vectorization[0m


  One of the most powerful features of S-Lang is the transparent manner
  in which scalars and arrays may be used in the same context.  For
  example,


               y = sin(x)



  produces a scalar result when x is a scalar, or a vector when x is a
  1D array, and so on.  This feature is referred to as [4mvectorization[24m,
  since for many operations it obviates the need to explicitly loop over
  array indices.  This gives S-Lang scripts powerful multidimensional
  mathematical capability, with performance on par with compiled C code
  and commercial analysis packages. The fact that this feature is native
  to S-Lang distinguishes it from other popular scripting languages like
  [1mPerl[22m, [1mPython[22m, or [1mTcl[22m, which natively lack high-performance multidimen-
  sional numerical capability.

  Given its origins as a tool for Gtk bindings, SLIRP does not presently
  generate vectorizing glue code.  In principle, however, this should
  not be difficult to achieve, and so it may be added in a future
  release.



  [1m4.  Interface Files[0m


  Using an interface file is a powerful means of customizing and
  extending SLIRP.  Interface files are S-Lang scripts, and so may
  contain any legal collection of S-Lang statements.  They are also
  optional, in the sense that SLIRP does not require one for nominal
  execution, but most bindings projects would likely benefit from their
  use.

  The SLgtk package, for instance, contains an interface file which, due
  to the nature of Gtk, adds scores of opaque, structured, and basic
  type mappings.  At the other end of the scale, the libtriv module
  could be generated from an interface file containing only


               slirp_define_opaque("TrivDatum",NULL,"triv_datum_destroy");



  While most SLIRP interface files won't be this brief, generating one
  for a first cut module for the typical library will usually take only
  a few minutes.  Additional interface files are bundled in the examples
  subdirectory of the SLIRP distribution, and include samples for gener-
  ating bindings to OpenGL and MySQL.


  [1m4.1.  Loading Interface Files[0m


  The interface file will be sought at runtime in the following order:


               $PWD/slirprc            Look in current working directory
               $SLIRPRC                Check environment variable



  As noted in section ``Command_Line_Options'', specifying the -rc
  switch during SLIRP invocation will override the above scheme, pro-
  vided the file is found and readable.


  [1m4.2.  Nesting Interface Files[0m


  An interface file may reference other interface files by calling


                   slirp_include_rc(filename)



  This permits modules with obvious dependencies to share common type
  definitions and variables, in fashion similar to that of the ANSI C
  #include mechanism.  Note that this will likely introduce a link time
  dependency between the modules, which will have to be reflected in
  your distribution (e.g. within a Makefile or project file).

  The function has a void return type, and will signal an error if
  problems occur while loading the external file.  To avoid redundancy
  and save space, code will not be generated for types loaded through
  external interfaces files.
  [1m4.3.  Ignoring Symbols[0m


  Sometimes it is desirable to have SLIRP avoid wrapping one or more
  functions, macros, or variables.  Typically this is done by adding
  each of their names to an [4mignore[24m [4marray[24m, either explicitly as described
  in this section (the traditional method), or by using an #ignore
  annotation as described in section ``IgnoreDirective'' (the preferred
  approach).  Note that both forms support the use of accompanying S-
  Lang comments, and that because C symbol names are case-sensitive the
  contents of ignore lists are as well.

  Groups of functions may also be tagged en masse for ignoring, by
  matching their argument signatures to an #argmap(ignore) annotation as
  described in section ``IgnoreMap''.


  [1m4.3.1.  Functions[0m


  There are three conditions under which SLIRP will not wrap a given
  function.  The first two occur when the -noautotype switch has been
  specified on the command line and there is no


  o  typemap entry matching the function return type

  o  matching typemap entry for one or more parameters within the
     function parameter list

  SLIRP will also ignore a function


  o  when it has been explicitly instructed to do so

  The latter is useful when you would prefer to code a function wrapper
  manually rather than accept what SLIRP would generate, and
  traditionally was achieved by explicitly adding the function name to
  the list of [4mignored[24m [4mfunctions[24m within your interface file.  This list
  is declared by SLIRP as a global array of String_Type


               variable ignored_functions = String_Type[0];



  that is empty by default.  The idiom for extending the list in this
  manner is


               ignored_functions = [
               "name_of_first_function_to_ignore",
               "name_of_second_function_to_ignore",
               ...
               "name_of_nth_function_to_ignore",
               ignored_functions ];



  [1m4.3.2.  Macros[0m



  Similarly, if you would like to force SLIRP to ignore a particular
  #define macro, say to avoid generating an S-Lang constant for it as
  described in section ``GeneratedConstants'', simply have your
  interface file add its name to the [4mignored_macros[24m list.  This is
  another  String_Type array, initially declared as


               variable ignored_macros = String_Type[0];



  [1m4.3.3.  Variables[0m

  Finally, the list


               variable ignored_variables = String_Type[0];



  can be used in like fashion to instruct SLIRP that it should not make
  selected global variables visible in S-Lang scope.


  [1m4.4.  Macro Substitutions[0m

  As noted above, SLIRP does not contain a C preprocessor.  In this
  section we discuss two consequences of this that are of interest to
  the language binder.  The first is that headers are not #include-ed at
  runtime.  For many libraries, especially those whose api is defined
  within a single header, this will not be an issue.  Libraries which
  define their public interface within multiple header files, such as
  Gtk, may also be wrapped by SLIRP, simply by specifying each public
  header on the command line at SLIRP invocation time.  A second
  consequence is that SLIRP performs only limited #define macro
  substitution at runtime.

  However, SLIRP does provide mechanisms which aid in the transformation
  of macros.  The first is


               slirp_substitute_macro(macro_name [, substitution ]);



  which can be used to augment (or enforce) macro substitutions.  Both
  parameters to this function are simple strings, with the latter
  defaulting to the empty string when omitted.  The second is


               slirp_map_macro(macro_name , "return_type ( argument_list )");



  which can be used to wrap the named macro as though it were a function
  prototyped as


               <return_type> <strlow(macro_name)> (<argument_list>) ;


  [1m4.5.  NULL  and Omitted Arguments[0m


  Unlike in other languages, where null is viewed as a value that may be
  assigned to pointers of any type, a null in S-Lang is both a value
  (NULL) and a type (Null_Type).  The Null_Type is useful, but can
  require additional care on the part of language binders.  To see why,
  consider the prototype


               void SomeFunc(char *name, double value);



  All C compilers should permit this function to be invoked as follows:


               SomeFunc(NULL, 5);



  (whether the function behaves well in such cases is a different ques-
  tion).  A straightforward mapping of this function to S-Lang would be
  registered with a function table entry like


               MAKE_INTRINSIC_2("SomeFunc", SomeFunc, SLANG_VOID_TYPE,
                                               SLANG_STRING_TYPE, SLANG_DOUBLE_TYPE)



  But this would prohibit the function being called from S-Lang scope as


               SomeFunc(NULL, 5);



  because the interpreter would complain that the Null_Type of the first
  argument cannot be cast to a String_Type.  Fortunately there is a way
  around this, namely to register the wrapper as though it accepts zero
  arguments


               MAKE_INTRINSIC_0("SomeFunc", SomeFunc, SLANG_VOID_TYPE)



  and then pop the char* and double values explicitly within the body of
  the wrapper, at which point their types may be checked and the NULL
  values handled accordingly.

  While this technique works, it would seem to require additional -- and
  more important, manual -- coding on the part of the language binder.
  To automate the generation of such code SLIRP provides the the
  [4massociative[24m [4marray[24m variable


               variable accepts_null_args = Assoc_Type[Any_Type,NULL];


  The elements of this array are themselves 1D arrays, whose elements
  represent those arguments in the function signature for which NULL is
  a valid value.   In our case a statement like


               accepts_null_args["SomeFunc"] = [1];



  would indicate to SLIRP that when it is asked to generate a wrapper
  for [4mSomeFunc[24m it should consider NULL a legal value for the first argu-
  ment, whatever its type may be.

  This feature also allows functions to be called with arguments
  omitted, since the two statements


               SomeFunc( , 5);
               SomeFunc(NULL, 5);



  are equivalent in S-Lang.



  [1m5.  Introduction To Annotations[0m


  Thus far we have focused mainly on the use of type maps to extend
  SLIRP and tailor its behavior.  Type mappings are simple to express
  and comprehend, and in many cases will be all the developer needs to
  create reasonably capable wrappers for a given library, especially in
  the initial phases of a bindings project.

  We now turn to a series of features, collectively referred to as
  [4mannotations[24m, which are arguably the most powerful SLIRP has to offer.
  In exchange for learning a bit of new and initially strange syntax,
  annotations provide a degree of control over the code generation
  process that goes well beyond what can be achieved with type mappings
  alone.  For instance, consider the problem of morphing a C function of
  M inputs and N outputs into a S-Lang function of M' inputs and N'
  outputs.  Such might arise when wrapping a function prototyped as


               int print_array_f(float *arr, int len);



  where the second argument indicates the number of elements in the
  first.  The default wrapper generated for this function would yield S-
  Lang usages such as


               variable arr = [1.1, 2.2, 3.3, 4.4, 5.5];
               print_array_f(arr, length(arr));



  However, since S-Lang arrays "know their size" the second parameter in
  the function call is superfluous and can be dropped, yielding the more
  natural usage


               print_array_f(arr);



  In our nomenclature the C version of this function has M=2 inputs and
  N=1 outputs, while the S-Lang version has M'=1 input and N'=N outputs.
  To achieve this transformation a module writer might hand-craft a
  wrapper along the lines of


               static int wrap_print_array_f(void)
               {
                  SLang_Array_Type *arr;
                  int status;

                  if ((-1 == SLang_pop_array_of_type (&arr, SLANG_FLOAT_TYPE))
                       return -1;

                  status = print_array_f(arr->data, arr->num_elements);
                  SLang_free_array(arr);
                  return status;
               }



  This approach works, but is laborious and requires in-depth knowledge
  of the S-Lang C api (e.g. to correctly use the SLang_Array_Type).
  Furthermore, since the pattern captured is a common one it would be
  better if such transformative wrappers could be generated in a more
  automated fashion.

  SLIRP annotations serve exactly this purpose, by enabling developers
  to tag function prototypes with semantic hints and source code
  fragments; with these additional semantics SLIRP is able to make more
  informed judgements about what prototypes mean; the additional code
  fosters the creation of custom wrappers, without resorting to writing
  them entirely by hand.

  Some users may recognize a resemblance --- in both spirit and syntax
  --- between SLIRP annotations and SWIG %typemaps.  This is not
  accidental, and it is only appropriate that we acknowledge the
  numerous insights that have been gleaned from SWIG through study of
  its %typemap capability.


  [1m5.1.  A Sample Annotation[0m


  By adding to the interface file an annotation such as


               #argmap(in, which=1) (float *arr, int)
                  $2 = ($2_type) $1_dim0;      /* float* argmap */
               #end



  SLIRP would generate a wrapper for print_array_f resembling


               static void sl_print_array_f (void)
               {
                  int result;
                  float* arg1;
                  Slirp_Ref arg1_ref = Slirp_ref_init(SLANG_FLOAT_TYPE, sizeof(float), arg1);
                  int arg2;

                  if (SLang_Num_Function_Args != 1 ||
                       pop_array_or_ref( &arg1_ref) == -1 )
                       {Slirp_usage_err("int = print_array_f(float_ptr)"); return;}

                  arg2 = (int) Slirp_ref_get_size(&arg1_ref,0);     /* float* argmap */
                  result = print_array_f(arg1, arg2);
                  (void) Slirp_ref_finalize(&arg1_ref);
                  (void) SLang_push_int ( result);
               }



  The desired effect has been achieved: the generated code expects only
  an array argument to be passed in from S-Lang scope.  Fewer lines of
  hand-written code (3 lines in an interface file, versus 10+ lines in
  C) were needed to wrap the function, while bookkeeping work --- such
  as registering wrappers within an intrinsic function table, merging
  manually-crafted code fragments with automatically-generated code, and
  writing usage statements --- is virtually eliminated.  The fact that
  the annotation does not reference the print_array_f function by name
  allows it to be used on any function with a matching prototype, and
  can sharply reduce the amount of coding required to create custom
  wrappers.

  Annotations may be used for other purposes as well, such as omitting
  return values, making values returned through a function parameter
  list in C appear as if they were returned on the stack in S-Lang, or
  injecting user-defined fragments of C code into the generated
  wrappers.  These and other ideas are explored in the context of
  numerous examples, many of which can be found in interface files
  bundled within the examples directory tree of the SLIRP distribution.


  [1m5.2.  Dissecting an #argmap[0m

  The syntax of an #argmap may seem peculiar to the uninitiated, and you
  would be justified in wondering at this point [4mHow[24m [4mdoes[24m [4mit[24m [4mactually[0m
  [4mwork?[24m  This question actually has two parts: the first concerns how
  annotations are read by the S-Lang interpreter, and is relevant
  because their semantics are expressed in a syntax not defined within
  the S-Lang grammar; the second concerns how SLIRP selects which
  annotations to apply while generating wrappers.


  [1m5.2.1.  Custom File Loader[0m

  The first part of the question is by far the easier to answer:  SLIRP
  contains a custom file loader, installed via a [4mload[24m [4mfile[24m [4mhook[24m, which
  S-Lang will call when evaluating scripts.  This loader scans the input
  interface file for directives (which happen to look like preprocessor
  tokens) marking an annotation block.  Each annotation directive
  utilizes a unique callback function which

  o  validates the syntax of the directive (at block open)

  o  accumulates each line within the body of the block into a text
     buffer

  o  processes the resulting buffer (at block close)


  [1m5.2.2.  Matching Rules[0m

  The second key to using annotations is understanding the pattern
  matching rules employed by SLIRP to decide whether a given annotation
  should be applied to some function.  For example, given


               #argmap(in, which=2) (long nelems, char **array)
                  $1 = ($1_type) $2_dim0;              /* char** argmap #1 */
               #end

               #argmap (in) char **
                  /* char** argmap #2 : just a single comment */
               #end



  and a function prototyped as


               extern  void print_array_s      (long   nelems, char **array);



  only the first mapping would be applied, since it is a stronger match.
  Now if the mapping


               #argmap(in, which=2) (long, char **)
                  $1 = ($1_type) $2_dim0;              /* char** argmap #3 */
               #end



  were also present which would SLIRP select?  Still the first, since
  not only does it match the prototype in the [4mquantity[24m and [4mtype[24m of its
  parameters, but also in their [4mnames[24m.  However, if the prototype
  instead looked like


               extern  void print_array_s      (long, char **);



  then the first #argmap would be rejected (because parameters named
  within an annotation do not match unnamed parameters within a proto-
  type) and the third would be used (since it provides a longer match
  than the second).  Finally, if the first and third mappings were
  removed then the second would be applied and yield broken runtime
  behavior, since the array size parameter would remain uninitialized in
  the wrapper (the argmap body contains only a comment).  The rules gov-
  erning the matching of annotations with function prototypes may thus
  be summarized as:

  o  function names are not relevant

  o  each parameter within a function prototype will match at most one
     annotation

  o  longer parameter sequences within parameter lists have higher
     precedence than shorter ones

  o  named annotation parameters never match unnamed prototype
     parameters

  o  unnamed annotation parameters will match [4meither[24m unnamed prototype
     parameters [4mor[24m, provided all named annotation parameters have
     already matched

  o  multiple annotations may be applied to the wrapper generated for a
     given function

     Matching can also be tuned with the #prototype and #copy
     directives, as discussed later.


  [1m5.3.  Parameter Substitutions[0m

  At this point it should be clear that parameters specified within the
  parameter list of an annotation are referenced elsewhere within the
  annotation by prefixing them with a dollar sign.  That is, the first
  parameter is referred to as $1, the second as $2, et cetera.  This
  allows the module writer to craft code fragments which explicitly
  refer to function arguments, irrespective of the names SLIRP later
  generates for their corresponding local variables.

  When the body of the annotation is injected into the wrapper SLIRP
  substitutes each $-delimited reference with the name of the respective
  local variable.  While at first glance this may seem trivial, you
  should recall that because multiple annotations can be applied to a
  function it is by no means clear what names SLIRP will assign to each
  variable declared within its wrapper.


  [1m5.3.1.  Metadata[0m

  SLIRP also provides lightweight introspective capabilities, loosely
  analogous to reflection in Java, which enable annotations to discern
  metadata about a parameter, such as its type, size, or argument
  number.  These substitutions are:

  o  $argnum

     Yields the ordinal position that the [4mfirst[24m argmap parameter
     occupies within the argument list of the function prototype to
     which it has been applied.  For example, the annotation


               #argmap(in) LongInt (tmp)
                  ...
                  tmp = $argnum;
                  ...
               #endif



  would be applied twice to a function prototyped as


               void diff(LongInt x1,  LongInt x2);



  causing the lines


                  tmp1 = 1;
                  ...
                  tmp2 = 2;



  to appear within its generated wrapper.

  o  $funcname

     Yields the name of the function to which the annotation has been
     applied.

  o  $[4mn[24m_dim[4mI[0m

     Yields the size of the [4mI[24m-th dimension (numbered from 1) of argument
     [4mn[24m when it is an array, otherwise 1.  When [4mI[24m is greater than the
     number of the dimensions in the array the size returned will be 0.
     When [4mI[24m is 0 the size returned will be the number of elements in the
     entire array.

  o  $[4mn[24m_length

     Equivalent to $[4mn[24m_dim[4m0[24m.


  o  $[4mn[24m_ndims

     Yields the number of dimensions of argument [4mn[24m when it is an array,
     otherwise 1.

  o  $[4mn[24m_nullify

     Yields code which will set argument [4mn[24m to NULL.  For non-opaque
     arguments this is trivial (and can be done through other means),
     but for opaquely typed arguments the wrapped object will be set to
     NULL.  This might be used in conjunction with the final method
     (described below) to avoid manual coding in cases where one wants
     to prevent an opaquely typed variable from pointing to freed
     memory.


  o  $[4mn[24m_type

     Yields the C type of the local variable corresponding to argument
     [4mn[24m.  In the above example this substitution is used to cast the
     value yielded by $[4mn[24m_dim0, so as to avoid potential compile
     warnings.



  [1m5.4.  Variable Substitutions[0m

  Another form of substitution is performed when an annotation includes
  variable declarations, as in


               #argmap (in) char ** (int size)
                  {
                       char **copy = $1;
                       size = 0;
                       while (*copy++)
                          size++;
                  }
                  printf("\nNull terminated string array size: %d elements\n",size);
               #end



  This annotation declares an integer size variable, and if applied to a
  function prototyped as


               extern void print_array_nts (char **array);



  (where the final element of array is expected to be NULL) would yield
  a wrapper resembling



          static void sl_print_array_nts (void)
          {
             int size1;
             char** arg1;

             ...

             {
                  char **copy = arg1;
                  size1 = 0;
                  while (*copy++)
                     size1++;
             }
             printf("\nNull terminated string array size: %d elements\n",size1);

             ...
          }



  Here the size declaration maps to the size1 automatic variable.  A
  numeric suffix is used to uniquely identify the instance of the
  declared variable since, as noted above, a single annotation might
  match multiple parameters within a prototype, causing its code frag-
  ment to be injected into the generated wrapper multiple times.  Notice
  that locally-scoped variables, such as copy, may also be declared and
  used within inner blocks.  Unlike wrapper-global variables, however,
  these do not require disambiguation.



  [1m6.  #argmap  Annotations[0m


  Formally, an #argmap specifies how a sequence of N >= 1 function
  arguments in C map to a sequence of M <= N arguments specified to a S-
  Lang function call.  In the common case N = M = 1, resulting in a one-
  to-one correspondence between C functions and their S-Lang wrappers.
  The case where N > 1 is referred to as a [4mmulti-argument[24m map and, as
  shown in the examples, is commonly used to collapse a sequence of C
  arguments into a shorter sequence of of S-Lang arguments.  The argmap
  grammar is given by

               #argmap ( [4mmethod[24m [4m[[24m,[4mqualifier_list][24m ) [4mparameter_list[24m [4m[[24m(
  [4mvariable_declaration_list[24m )[4m][0m

                   [4mcode_fragment[0m

               #end


  More details are given in the grammar reference, but in the context of
  the first argmap from the previous chapter


               #argmap(in, which=1) (float *arr, int)
                  $2 = ($2_type) $1_dim0;      /* float* argmap */
               #end



  o  The method is in, meaning that the arguments specified within its
     parameter list should be interpreted as inputs to the function.

  o  One qualifier has been specified, which=1, indicating that only the
     first parameter within the parameter list should be passed when the
     function is called from S-Lang scope and, consequently, that the
     second argument should be omitted.  That is, N = 2 and M = 1.

  o  The parameter list is (float *arr, int).

  o  There are no local variables declared.

  o  The single line $2 = ($2_type) $1_dim0; represents the body of the
     annotation, and initializes the second parameter to the
     (appropriately casted) number of elements in the first.

  Preprocessor tokens may not appear within the body of an annotation,
  which should be viewed as a fragment of C code subject to the
  substitution rules described earlier.  After substitution these
  fragments are injected directly into the wrapper during code
  generation.  No further validation is performed upon the generated
  code, making it entirely possible to write annotations which yield
  wrappers that will not compile.



  [1m6.1.  Wrapper Structure[0m

  A variety of argmaps are provided, each characterized by its
  respective [4mmethod[24m keyword.  This keyword also governs where argmap
  code fragments are placed within generated wrappers, all of which have
  the form


                  Function_Declaration
                  {
                     Variable_Declaration_Block
                     Marshal_Block
                     Function_Call_Block
                     Return_Block
                  }



  For instance, the body of an in argmap would appear within the Mar-
  shal_Block of a wrapper, while the code from a final argmap would be
  injected into its Return_Block.



  [1m6.2.  in  Method[0m


  The #argmap(in) form allows you to customize the code generated for
  passing inputs from S-Lang to wrapped functions.  By default all
  arguments expected by a wrapped function must be supplied to its
  wrapper at call time.  The optional which=[4mselection[24m qualifier may be
  used to change that, by identifying which parameters of a multi-
  argument map must be specified in the S-Lang call sequence (and, by
  implication, which should be omitted).  The [4mselection[24m value is a S-
  Lang array index expression, and gives rise to several forms for the
  qualifier:

  o  which=i   selects only the i-th argmap parameter

  o  which=i:j   selects the i-th through j-th parameters

  o  which=i:j:k   selects the i-th through j-th parameters, in
     increments of k

  o  which=[i [4m[,j,k,...][24m]   selects the parameters i (and optionally j,
     k, ...)

  Since function parameters are numbered from 1 the i, j, k, ... here
  may only take on positive integral values.  A compact way of omitting
  all parameters from the S-Lang call sequence is to use an omit
  qualifier.  For example, imagine you would like to ensure that a
  function prototyped as


                       arg_dropper(unsigned long int ul);



  be called from S-Lang only with the value 112233.  This could be
  achieved by forcing the function to be called from S-Lang with zero
  arguments, via


               #argmap(in, omit) unsigned long int ul
                  $1 = 112233;
               #end



  and letting the wrapper pass on the desired value.

  [1m6.2.1.  Built-in in  Maps[0m


  As a convenience SLIRP provides a number of input maps.  As discussed
  here, some of these will be applied automatically by SLIRP, while
  others will need to be specified manually within your interface file.


  [1m6.2.1.1.  File Descriptors[0m



               #argmap(in, proxy=SLFile_FD_Type) int FD_PROXY
                  if (-1 == SLfile_get_fd (proxy, &$1)) {
                       SLang_verror(SLEI, "could not assign file descriptor proxy");
                       return;
                  }
               #end



  The FD_PROXY annotation allows S-Lang FD_Type file handles, which are
  opaque, to be passed directly to compiled routines expecting an inte-
  ger file descriptor.  This permits natural usages such as


               variable fd = open("/some/dir/some_file",O_RDONLY);
               triv_close(fd);



  where the corresponding libtriv function is prototyped as


               extern  void  triv_close (int fd);



  The int parameter in this annotation is explicitly named FD_PROXY so
  that it will not be applied to just any int argument within any func-
  tion signature.  That is, because integers are a common type and we
  cannot reliably expect all libraries to employ the "int fd" idiom,
  your interface file must explicitly assert when it should be applied.
  For the triv_close function above this is achieved with


               #copy int FD_PROXY { int fd }



  [1m6.2.1.2.  Generic Pointers[0m



               #argmap(in, proxy=SLang_Array_Type) void* ARRAY_2_VOIDP
                  $1 = proxy->data;
               #end

               #argmap(in, proxy=SLang_Any_Type) void* ANY_2_VOIDP
                  $1 = proxy;
               #end

  The ARRAY_2_VOIDP and ANY_2_VOIDP annotations facilitate the passing
  of arrays or arbitrary objects, respectively, from S-Lang to compiled
  routines expecting a void* pointer.  As with the file descriptor map-
  ping above, these mappings are explicitly named as a precautionary
  measure, so as to prevent them from being applied to just any function
  with a void * argument.  As an example consider the HDF5 function


               herr_t H5LTmake_dataset( hid_t loc_id, const char *dset_name,
                                int rank, const hsize_t *dims, hid_t type_id,
                                const void *buffer );



  In C this function can be called with an arbitrarily-typed array as
  the last parameter (e.g. float*, double*, etc).  By default, however,
  SLIRP will wrap this function as if the last argument were an opaque
  pointer instance (absent any hints what else can it do?)  One way to
  use the builtin argmap to change the generated wrapper would be to
  copy it with


               #copy void* ARRAY_2_VOIDP { const void* }



  so that any function in the HDF5 api which expects a const void* argu-
  ment would automatically support the C idiom of passing in arbitrar-
  ily-typed arrays.

  [1m6.2.1.3.  C++ string  Objects[0m


  These annotations allow the use of S-Lang strings in place of C++
  string objects.  They support both scalars and arrays, and will be
  applied transparently.


               #argmap(in, proxy="char*") string
                  $1 = proxy;
               #end

               #argmap(in, proxy=SLang_Array_Type) string*
                  {
                  int i, l;
                  char **arr;
                  if (proxy->data_type != SLANG_STRING_TYPE) {
                       SLang_verror(SL_USAGE_ERROR, (char*)"String array is required here");
                       return;
                  }
                  arr = (char**)proxy->data;
                  l = proxy->num_elements;
                  $1 = new string[l];
                  for (i=0; i<l; i++)
                       $1[i] = string(arr[i]);
                  }
               #end



  If the C++ interface you're wrapping contains many functions or meth-
  ods with string array arguments, then to avoid duplicative bloat you
  may wish to move the content of the string* annotation into a function
  (defined, e.g., within an #inline_c directive) and override the built-
  in version in your interface file with an annotation whose body simply
  calls that function.  A similar strategy is employed by the built-in
  #retmap for NT_STR_ARRAY.

  [1m6.2.1.4.  FORTRAN Strings[0m



               #argmap(in, which=1) (char *, FTN_STR_LEN)
                  $2 = strlen($1);
               #end



  Finally, the FTN_STR_LEN annotation allows S-Lang calls to FORTRAN
  functions or subroutines to avoid having to pass a length parameter,
  too, when passing in a string.  It, too, is applied automatically
  SLIRP.

  [1m6.3.  out  Method[0m


  The #argmap(out) form allows you to customize the code generated for
  transferring output from wrapped functions back to S-Lang scope.  The
  method supports neither variable substitution nor multiple-argument
  parameter lists, and is commonly used to omit passing an argument
  (typically a reference) as input to a function, in favor of having its
  value returned on the stack instead.  In such cases calls to the
  resulting S-Lang wrappers would pass in 1 less argument and expect 1
  additional return value.  The usage=C_string_literal qualifier may be
  used to override the default Usage: message generated by SLIRP for the
  mapped argument.

  By way of example consider the prototype


               void triv_mult2 (double op1, double op2, double *result);



  which yields a default wrapper of


               static void sl_triv_mult2 (void)
               {
                  double arg1;
                  double arg2;
                  double* arg3;
                  Slirp_Ref arg3_ref = Slirp_ref_init(SLANG_DOUBLE_TYPE, sizeof(double), arg3);

                  if (SLang_Num_Function_Args != 3 ||
                       pop_array_or_ref( &arg3_ref) == -1 ||
                       SLang_pop_double(&arg2) == -1 ||
                       SLang_pop_double(&arg1) == -1 )
                       {Slirp_usage_err("triv_mult2(double,double,double_ptr)"); return;}

                  triv_mult2(arg1, arg2, arg3);
                  (void) Slirp_ref_finalize(&arg3_ref);
               }



  that requires the use of references to store the result value in S-
  Lang scope, such as


               variable result;
               triv_mult2(333, 3, &result);



  This is cumbersome, especially for ad-hoc use within applications that
  embed S-Lang for interactive use (such as ISIS at
  <http://space.mit.edu/cxc/isis/>, which presents a Matlab(tm)-style
  command line prompt for scientific analysis).  By employing an annota-
  tion such as


               #argmap(out) double *result
                  SLang_push_double($1);
               #end



  or the simpler one given in section ``copy_example'', the generated
  wrapper will instead look like


               static void sl_triv_mult2 (void)
               {
                  double arg1;
                  double arg2;
                  double arg3;

                  if (SLang_Num_Function_Args != 2 ||
                       SLang_pop_double(&arg2) == -1 ||
                       SLang_pop_double(&arg1) == -1 )
                       {Slirp_usage_err("double = triv_mult2(double,double)"); return;}

                  triv_mult2(arg1, arg2, &arg3);
                  SLang_push_double(arg3);
               }



  This effectively transforms triv_mult2 into a duplicate of triv_mult
  given in the opening example, changing its S-Lang usage to the more
  natural


               result = triv_mult2(333, 3);



  This transformation also lets the wrapper be called as an argument to
  other functions, such as


               printf("The result is %d\n", triv_mult2(333, 3));



  which is simply not possible in its original form.
  [1m6.3.1.  Built-in out  Maps[0m


  As a convenience SLIRP provides the following output maps:


               #argmap(out) short *OUTPUT
                  SLang_push_short($1);
               #end

               #argmap(out) unsigned short *OUTPUT
                  SLang_push_ushort($1);
               #end

               #argmap(out) int *OUTPUT
                  SLang_push_integer($1);
               #end

               #argmap(out) unsigned int *OUTPUT
                  SLang_push_uinteger($1);
               #end

               #argmap(out) unsigned *OUTPUT
                  SLang_push_uinteger($1);
               #end

               #argmap(out) long *OUTPUT
                  SLang_push_long($1);
               #end

               #argmap(out) unsigned long *OUTPUT
                  SLang_push_ulong($1);
               #end

               #argmap(out) float *OUTPUT
                  SLang_push_float($1);
               #end

               #argmap(out) double *OUTPUT
                  SLang_push_double($1);
               #end

               #argmap(out) size_t *OUTPUT
                  SLang_push_size_t($1);
               #end

               #argmap(out) ptrdiff_t *OUTPUT
                  SLang_push_ptrdiff_t($1);
               #end

               #argmap(out) complex *OUTPUT
                  SLang_push_complex($1.r, $1.i);
               #end

               #argmap(out) doublecomplex *OUTPUT
                  SLang_push_complex($1.r, $1.i);
               #end



  As shown in the next chapter, these may be combined with the #proto-
  type and #copy annotations to simplify or tune the matching of annota-
  tions to functions.  Note that the complex and doublecomplex mappings
  refer to the corresponding FORTRAN types.

  [1m6.4.  final  Method[0m


  The #argmap(final) form provides a means of explicitly specifying how
  arguments should be finalized by a wrapper just prior to its return.
  This can be useful for bookkeeping work, such as freeing memory
  allocated within the wrapper or ensuring that an object is properly
  destroyed.  As an example of the latter, suppose a C table I/O library
  contained the routines


                       extern Table*   table_open(char *name);
                       extern int      table_close(Table *t);
                       extern void*    table_get_column(Table *t, int column);



  that were wrapped by SLIRP by mapping Table* to an opaque type


                       slirp_define_opaque("Table", NULL, "table_close");



  and then called from S-Lang in the usual way


                       variable table = table_open("table.dat");
                       variable col1 = table_get_column(table, 1);
                       variable col2 = table_get_column(table, 2);



  If the C table_close routine frees its input Table* pointer (good pol-
  icy) then after a call


                       table_close(table);



  in S-Lang scope the opaque table variable would encapsulate freed mem-
  ory. Subsequent attempts to use it, such as


                       table_close(table);



  would yield undefined behavior (e.g. SEGV).  This can be prevented by
  executing


                       table = NULL;



  explicitly after the table_close call or, more elegantly, by having
  the table_close wrapper transparently achieve a similar effect by nul-
  lifying the Table* instance wrapped by the opaque S-Lang table
  variable.  Since it is, again, advantageous to avoid writing such a
  wrapper entirely by hand one might instead craft annotations such as


               #argmap(final) Table* NULLIFY
                  $1_nullify;
               #end

               #prototype
                  int   table_close(Table* NULLIFY);
               #end



  The first annotation performs the required nullification, and uses a
  uniquely named parameter list so as to limit its application only to
  the table_close function.  The second annotation redeclares the proto-
  type for this function, allowing it to match the #argmap(final).


  [1m6.5.  ignore  Method[0m


  The #argmap(ignore) form provides an alternative to the #ignore
  directive.  Rather than ignoring a function based upon its name, this
  annotation supports ignoring functions by matching on their argument
  signatures.  It provides a potentially powerful means of ignoring
  entire groups of functions with a single, simple annotation.  For
  example, when generating pure C bindings for C++ code (-cfront mode)
  SLIRP provides the builtin annotation


          #argmap(ignore) string*
               ...
          #end



  which ensures that functions containing string array arguments will
  not be reflected in the bindings.



  [1m7.  Other Annotations[0m



  [1m7.1.  #clear[0m



     [1mGrammar[0m
        #clear [4mparameter_list[0m


     [1mDescription[0m
        This directive deletes all annotations which match the given
        [4mparameter_list[24m.


      [1mExample[0m
        The directive


                  #clear double *result



     would delete the annotation applied above to triv_mult2, causing
     the generated wrapper to assume the default form (expecting 3 input
     arguments, and returning nothing on the stack).  The directive
     sequence


                  #clear double *result
                  #copy double *OUTPUT {double *result}



     also eliminates the annotation, but then replaces it with a copy of
     the default double* outmap.



  [1m7.2.  #copy[0m



     [1mGrammar[0m
        #copy [4mparameter_list[24m { [4mparameter_list[24m [4m[[24m,   [4m...][24m }


     [1mDescription[0m
        This directive provides a convenient way of targeting the
        application of existing #argmap annotations to specific
        functions, without redeclaring their prototypes.  For each
        destination [4mparameter_list[24m pattern a copy is created of every
        #argmap which matches the source [4mparameter_list[24m.  The
        [4mparameter_list[24m of each duplicate annotation is then changed to
        the corresponding destination [4mparameter_list[24m.  Note that any
        usage qualifier specified in the original annotation will not be
        propagated, since such content is usually tailored specifically
        to the original type.


      [1mExample[0m

        The triv_mult2 transformation given in the previous chapter
        could have been accomplished more easily by copying the double
        *OUTPUT mapping introduced in section ``Builtin_Out_Maps'':


                  #copy double *OUTPUT { double *result }



     An error will be thrown if any destination [4mparameter_list[24m is not
     isomorphic with the source [4mparameter_list[24m.  That is, a single-argu-
     ment copy cannot be made from a multi-argument annotation, and
     vice-versa.



  [1m7.3.  #ignore[0m



     [1mGrammar[0m
        #ignore

            [4msymbol_name_list[0m

        #end


     [1mDescription[0m
        This directive provides an alternative mechanism for instructing
        SLIRP to bypass the generation of wrapper code for one or more
        functions, macros, variables, or type definitions.  For example,
        rather explicitly adding symbol names to the ignored_functions,
        ignored_macros, or ignored_variables arrays, you would instead
        place the symbol names within an #ignore block.

        This approach yields shorter and cleaner interface files, since
        the names of all ignored symbols may be grouped within a single
        semantic block (although this is not required, as multiple
        #ignore blocks are permitted), symbol names remain unquoted, and
        comma delimters may be avoided.


      [1mExample[0m
        Several libtriv symbols can be omitted from its corresponding
        module via:


                  #ignore
                  triv_mult       % some functions ...
                  triv_print_array_f, triv_datum_new
                  TRIV_IGNORABLE_INT      % a variable
                  triv_datum_destroy      % another function
                  #end



  [1m7.4.  #inline_c[0m



     [1mGrammar[0m
        #inline_c [4m[[24m(init)[4m][0m

            C_translation_unit

        #end


     [1mDescription[0m
        This directive supports the inclusion of essentially arbitrary C
        source code within your interface file.   Unlike with #argmap or
        #retmap fragments, however, inlined source is injected verbatim
        into the generated code; that is, no parameter or variable
        substitutions are performed.

        Normally inlined code blocks are inserted into the generated
        source before any wrapper functions are defined, which permits
        #argmap and #retmap annotations to reference their content.  The
        init qualifier may be used to specify that the code should
        instead be injected into the module initialization function.


      [1mExample[0m
        Suppose you were wrapping a C++ library which includes a
        ProcessGlobal class that is intended to be instantiated only
        once per application.  Ordinarily, methods of this (or any)
        class would be called from S-Lang scope by passing in an
        instance of the class as its first argument.  For example, a
        report() method with a zero-argument C++ signature would be
        invoked from S-Lang scope as


                  variable pg = ProcessGlobal_new();
                  ProcessGlobal_report(pg);



     This is exactly how C++ invokes object methods, the only difference
     being that in C++ the first argument, [4mthis[24m, is generated by the
     compiler and usually hidden from the programmer.  You could achieve
     a similar effect by instantiating a hidden ProcessGlobal object
     within in your wrappers


                  #inline_c
                  ProcessGlobal *pg = new ProcessGlobal();
                  #end



     and then omitting the ProcessGlobal* argument from each method


                  #argmap(in, omit) ProcessGlobal*
                     $1 = pg;
                  #end



     to yield a wrapper (see examples/cpp for more details) such as



             static void sl_ProcessGlobal_report (void)
             {
                ProcessGlobal* arg0;

                if (SLang_Num_Function_Args != 0)
                     {Slirp_usage_err(13, 13); return;}

                arg0 = pg;
                arg0->report ();
             }



     As another example, consider that an annotation resembling


                  #inline_c(init)
                     if (H5open () != 0) return -1;
                  #end



     is used to generate the HDF5 module, which ensures that the HDF5
     library is itself initialized when the S-Lang interpreter initial-
     izes the module.


  [1m7.5.  #prototype[0m



     [1mGrammar[0m
        #prototype [4m[[24m(fortran)[4m][0m

            [4mfunction_prototype_list[0m

        #end


     [1mDescription[0m
        This directive supports the declaration of one or more function
        prototypes directly within a SLIRP interface file.  These
        supersede prototypes declared within header files, and are used
        to steer the pattern matching and code generation processes by
        relabeling parameters to match annotations.  The optional
        fortran qualifier may be used to specify that code generation
        semantics described in section ``FORTRAN'' should be in effect
        when the prototyped functions are wrapped. Omitting this
        qualifier does not prevent corresponding FORTRAN functions from
        being wrapped, but may reduce the "convenience" of their use
        from S-Lang scope. For example, function names given within a
        fortran-qualified #prototype block need not contain a trailing
        suffix, as one will be transparently added to ensure that the
        names of the prototyped functions match the entry point names
        generated by the FORTRAN compiler.


      [1mExample[0m
        A third way to achieve the triv_mult2 transformation given in
        the previous chapter would be to redeclare it as



             #prototype
                void triv_mult2 (double op1, double op2, double *OUTPUT);
             #end



     This allows SLIRP to match it against the built-in double *OUTPUT
     argmap, and would yield the same wrapper code as before.  Note
     that, as in C, each function declaration must be terminated with a
     semicolon.


  [1m7.6.  #retmap[0m



     [1mGrammar[0m
        #retmap [4m[[24m(omit)[4m][24m C_type_expression

            [4mcode_fragment[0m

        #end


     [1mDescription[0m
        By default SLIRP generates code to pass the return value from a
        wrapped function back to S-Lang scope, typically by having the
        last statement within the wrapper push an object of the
        appropriate type onto the stack.  The #retmap directive can be
        used to alter this scheme, allowing a wrapper to return an
        object of different type, more than 1 object, or even --- if the
        omit qualifier is specified --- no objects at all.


      [1mExample[0m
        Suppose you were wrapping a library in which some functions were
        prototyped to return an integer status code, such as


                  typedef enum {
                          STATUS_NULL_POINTER_REF=-2,
                          STATUS_OUT_OF_MEMORY=-1,
                          STATUS_GOOD=0
                          ...
                  } StatusCode;

                  int do_something(int i, int j);
                  int do_something_else(int i, int j);



     To ensure robustness the values returned from these functions must
     be checked, regardless of how unlikely the functions are to fail.
     This yields S-Lang code such as



             variable i = 100, j = 1, k = 200;

             if (do_something(i, j) != STATUS_GOOD)
                error("Could not do_something");

             if (do_something_else(i, j) != STATUS_GOOD)
                error("Could not do_something_else");

             if (do_something_else(k, j) != STATUS_GOOD)
                error("Could not do_something_else");

             ...



     If failure is a relatively rare event then this (necessary) strat-
     egy results in code that is not only longer and slower, but is also
     harder to read.  However, by using the omit qualifier to generate a
     wrapper which swallows the return status code, such as


                  #retmap(omit) int
                     if (result != STATUS_GOOD)
                          SLang_verror(SL_INTRINSIC_ERROR,"Wrapper error: %d",result);
                  #end



     we retain the same level of robustness (an error will still be sig-
     naled whenever a library function returns something other than STA-
     TUS_GOOD) while eliminating boilerplate safety code in S-Lang
     scope:


                  variable i = 100, j = 1, k = 200;

                  do_something(i, j);
                  do_something_else(i, j);
                  do_something_else(k, j);

                  ...



     [1m7.6.1.  Built-in #retmap  Annotations[0m

     [1mAs a convenience SLIRP provides the following return maps:[0m


                  #retmap  NT_STR_ARRAY
                          push_null_term_str_array($1, $funcname, 0);
                  #end

                  #retmap  NT_STR_ARRAY_FREE
                          push_null_term_str_array($1, $funcname, 1);
                  #end



     which can be used to automate the generation of wrappers for func-
     tions which return string arrays of known length.  To see how these
     might be used let's return to the Account* example given earlier in
     section ``Pointers''


                          char** account_get_users(Account *a);



     only now suppose that the documentation for this hypothetical func-
     tion states that the final element of its return value is NULL.
     With this knowledge we can determine the length of the array by
     traversal, and thereby return a more useful S-Lang array of
     String_Type, rather than merely an opaque string pointer.  To apply
     the appropriate return map simply redeclare the function within
     your interface file, such as


                  #prototype
                          NT_STR_ARRAY account_get_users(Account *a);
                  #end



     or, if you'd like the wrapper to free the C array and all of its
     elements prior to returning,


                  #prototype
                          NT_STR_ARRAY_FREE account_get_users(Account *a);
                  #end



     These annotations work because, as described below, NT_STR_ARRAY
     and NT_STR_ARRAY_FREE are built-in SLIRP type definitions.


  [1m7.7.  #typedef[0m



     [1mGrammar[0m
        #typedef C_identifier C_identifier [4m[[24m;[4m][0m


     [1mDescription[0m
        This directive supports the definition of simple types, as
        described in section ``TypeDefinitions'', directly within a
        SLIRP interface file.


      [1mExample[0m
        Consider applying the finalizer


                  #argmap(final) TrivInt (int copy)
                     copy = $argnum;
                     printf("Finalizing arg %d of %s (with local copy)\n",copy,$funcname);
                  #end



     to the libtriv module.  Because input header files (in this case
     triv.h) are not read until [4mafter[24m SLIRP processes the interface file
     no type map entry (associating TrivInt with int) will be defined
     when this annotation is read.  In such cases (in fact, whenever an
     unmapped type is encountered) SLIRP will either fabricate a mapping
     (e.g. to void_ptr) for it and proceed on its merry way (the
     default), or signal an "unmapped type" error (when the -noautotype
     switch has been specified).  A #typedef annotation such as


                  #typedef int TrivInt;



     can be used to steer the mapping if neither of these results are
     desired.  Types defined in this manner are only hints to SLIRP, and
     so are not replicated within the generated code.


     [1m7.7.1.  Built-in Type Definitions[0m

     [1mSLIRP provides the following built-in type definitions[0m


                  #typedef char** NT_STR_ARRAY
                  #typedef char** NT_STR_ARRAY_FREE



     which, as described above, are used to return NULL terminated
     arrays of C strings as S-Lang arrays of String_Type.



  [1m8.  Annotation Grammar[0m


  The style used in this chapter generally follows Kernighan and
  Ritchie, 1988.  Non-terminal productions are given in [4mitalics[24m, while
  terminals and literals are given in typewriter style.  Productions
  prefixed with C_ should be understood as referring to corresponding
  elements of the C grammar.  Ellipses connote comma-delimited sequences
  of one or more elements.  Empty lines and whitespace between whole
  syntactic elements are ignored.  Content within [4m[italicized[24m [4mbrackets][0m
  is optional, while [typewriter-style brackets] denote regular
  expressions.  For brevity all [4mqualifier[24m and [4mmethod[24m literals are lumped
  into single production rules, even though each is not supported by
  every annotation.  Only annotations whose grammars explicitly
  enumerate methods or qualifiers support such.


                [4mannotation[24m:

                     [4margmap_annotation[0m

                     [4mclear_annotation[0m

                     [4mcopy_annotation[0m

                     [4mignore_annotation[0m

                     [4minlinec_annotation[0m

                     [4mprototype_annotation[0m

                     [4mretmap_annotation[0m

                     [4mtypedef_annotation[0m



                [4margmap_annotation:[0m

                     #argmap ( [4mmethod[24m [4m[[24m,[4mqualifier_list][24m ) [4mparameter_list[0m
        [4m[[24m( [4mvariable_declaration_list[24m )[4m][0m

                         [4mcode_fragment[0m

                     #end



                [4mclear_annotation:[0m

                     #clear [4mparameter_list[0m



                [4mcopy_annotation:[0m

                     #copy [4mparameter_list[24m { [4mparameter_list[24m [4m[[24m,   [4m...][24m }



                [4mignore_annotation:[0m

                     #ignore

                         [4msymbol_name_list[0m

                     #end



                [4minlinec_annotation:[0m

                     #inline_c [4m[[24m(init)[4m][0m

                         C_translation_unit

                     #end



                [4mprototype_annotation:[0m

                     #prototype [4m[[24m(fortran)[4m][0m

                         [4mfunction_prototype_list[0m

                     #end



                [4mretmap_annotation:[0m

                     #retmap [4m[[24m(omit)[4m][0m

                         [4mcode_fragment[0m

                     #end



                [4mtypedef_annotation:[0m

                     #typedef C_identifier C_identifier [4m[[24m;[4m][0m



                [4mcode_fragment:[0m

                     [4mstatement_list[0m

                     { [4mstatement_list[24m }

                     { [4mcode_fragment[24m }



                [4mstatement_list[24m:

                     [4mstatement[0m

                     [4mstatement_list[24m [4mstatement[0m



                [4mstatement[24m:

                     C_statement

                     C_statement_with_SLIRP_substitutions


                [4mparameter_list:[0m

                     [4mparameter_expression[0m

                     ( [4mparameter_expression[24m ,   [4m...[24m )



                [4mqualifier_list:[0m

                     [4mqualifier_expression[0m

                     [4mqualifier_list[24m ,   [4m...[0m



                [4mqualifier_expression[24m:

                     [4mqualifier[0m

                     [4mqualifier[24m = [4mqualifier_value[0m



                [4mvariable_declaration_list:[0m

                     C_type_expression C_identifier

                     [4mvariable_declaration_list[24m ,   [4m...[0m



                [4mparameter_expression:[0m

                     C_type_expression

                     C_type_expression C_identifier



                [4mfunction_prototype_list:[0m

                     [4mfunction_prototype[0m

                     [4mfunction_prototype[24m SLang_comment

                     [4mfunction_prototype[24m [4mfunction_prototype_list[0m



                [4mfunction_prototype:[0m

                     C_identifier ( [4mparameter_expression[24m [4m[[24m,   [4m...][24m ) ;



                [4msymbol_name_list:[0m

                     C_identifier

                     C_identifier SLang_comment

                     C_identifier , [4msymbol_name_list[0m

                     C_identifier [4msymbol_name_list[0m

                [4mmethod[24m: one of

                     in out final



                [4mqualifier_value[24m: one of

                     [1-9]+

                     SLang_array_index_expression

                     C_string_literal



                [4mqualifier[24m: one of

                     which omit usage fortran



  [1m9.  Command Line Reference[0m



  -c++

       Mandate that input headers be interepreted as C++, which can
       be helpful to coerce the interpretation of files that either
       lack a .hh suffix or do not contain class definitions or
       other explicit C++ syntax.


  -cfront

       Generate standalone C wrappers (.cc and .h files) from the
       headers of a C++ library, enabling it to be called from C
       scope but not S-Lang proper.


  -const_strings

       Directs SLIRP to interpret functions with 'char*' return
       values as though they were actually 'const char*' instead.
       Without the aid of hints like 'const' SLIRP has no way of
       ascertaining if the function being wrapped returns a string
       which must be freed by the caller to avoid a memory leak.
       Since newer libraries that are carefully written tend to
       make judicious use of the 'const' qualifier, SLIRP takes the
       position that if 'const' is missing then a call to free() is
       required after pushing char* instances onto the stack.  The
       -const_strings switch turns that behavior off, but may
       result in memory leaks within your module.


  -fprefix [4mfunction_prefix[0m

       Directs SLIRP to generate wrapper functions [4monly[24m for those
       functions with names that begin with an exact match of [4mfunc-[0m
       [4mtion_prefix[24m.  This can be useful in situations when SLIRP
       either generates too many functions or two few, perhaps
       because it cannot distinguish between private and public
       functions in the api being wrapped.  By default SLIRP
       attempts to generate code for any function whose name
       matches the regular expression "^[a-zA-Z]+".


  -g

       Directs SLIRP to print debugging information during code
       generation.


  -I [4mdirectory[0m

       Specify directory to search for headers during code genera-
       tion.  Each -I opton is automatically propagated to make
       files generated by -make, as is any path prefix included in
       the specification of any input header file.


  -L [4mdirectory[0m

       Specify directory to search, within emitted make file, at
       link time.  Use of this option implicitly turns on -make.

  -l [4mlib[0m

       Specify the short-form name (consult your linker documenta-
       tion) of a library to pull in, within emitted make file,  at
       link time.  Use of this option implicitly turns on -make.


  -ldflags [4mflags[0m

       Specify additional flags to pass to the linker within emit-
       ted make file.  May also be used as an alternative to -L or
       -l.  To specify multiple linker flags with a single -ldflags
       option, separate them with whitespace and enclose within
       single- or double-quotes.  Use of this option implicitly
       turns on -make.


  -m [4mmodule_name[0m

       Emit generated code to files whose names begin with [4mmod-[0m
       [4mule_name[24m, instead of the default (which uses the stem of the
       first input file that is processed).


  -make

       Emit a make file that can be used to automate compilation of
       the module.  The content of the generated file can be tuned
       by use of the -I, -L, -l, and -ldflags options.



  -mapnames [4mregular_expression[24m [4mreplacement[0m

       Deprecated synonym for -rename


  -noautotype

       By default SLIRP will automatically map unknown types (i.e.
       types which have no entry in the SLIRP typemap table) to
       void_ptr.  This tactic permits larger portions of libraries
       to be wrapped automatically, and with less interface file
       writing.  This switch should be employed when this behavior
       is not desired, with the effect that SLIRP will not emit
       wrapper code for any function whose signature contains
       unknown types.


  -noinit

       Do not generate a module initialization fragment.


  -nopop

       Whenever possible, do not generate code to explicitly pop
       arguments from the S-Lang stack into local variables within
       the wrapper.  For instance, using -nopop during the genera-
       tion of the triv module above would yield a triv_mult wrap-
       per which looks like



          static void sl_triv_mult (double* arg1, double* arg2)
          {
             double result;
             result = triv_mult(*arg1, *arg2);
             (void) SLang_push_double ( result);
          }



  Using this option will thus shrink the size of generated
  code and may boost runtime performance slightly, but at the
  expense of other features like the automatic generation of
  [1mUsage: [22mstatements when an incorrect number of arguments are
  passed to the function.  Note even when -nopop is specified
  there may be instances when SLIRP has no choice but to
  explicitly pop arguments from the stack;  these conditions
  are enumerated within the internal source code documenta-
  tion.


  -otree

       Emit a hierarchical list of all opaque types defined by the
       current invocation, then exit.  The former name of this
       option was -l.


  -print

       Print the interface for code which would be generated, but
       don't actually generate it.



  -rc [4mfile[0m


       Load SLIRP customizations from [4mfile[24m, rather than from the
       first instance found within $PWD/slirprc or the $SLIRPRC
       environment variable.


  -refscalars


       Permit S-Lang scalars to be passed to C functions expecting
       arrays, or FORTRAN functions (which passes all arguments by
       reference), by popping them off the stack as 1-element
       arrays.  By default this behavior is on for bindings to FOR-
       TRAN codes, and off for bindings to C codes.  Note that this
       does not provide a way of modifying scalar variable values
       absent the use of the S-Lang reference operator (&), as the
       original scalar is effectively read-only in the glue layer.


  -rename [4mregular_expression[24m [4mreplacement[0m

       Directs SLIRP to map C function names matching the given
       [4mregular_expression[24m to S-Lang function names beginning with
       [4mreplacement[24m.  Suppose, for example, that


               slirp -mapnames triv_ yada_ triv.h


  were specified during the generation of the triv module in
  the opening chapter.  Then the do_mult() sample function
  would need to reflect such


               define do_mult(op1, op2)
               {
                  () = printf("triv_mult(%S,%S) = %S\n",
                                       op1, op2, yada_mult(op1, op2));
               }



  This option may be specified multiple times at invocation,
  using any regular expression suitable for the S-Lang
  string_match() function.  Consult the [4mRegular[24m [4mExpressions[0m
  chapter within the S-Lang language guide for more details.


  -stdout

       Cause generated code to be emitted to stdout instead of a
       named file.


  -stubs

       Generate source code for the interface specified as input to
       SLIRP, as a set of empty (stub) functions.  This supports
       exercising the module interface without the need to link in
       the underlying library or any of its (potentially numerous)
       dependencies.


  -tmapout [4mfile[0m

       Save a copy of the type mappings table (generated during the
       first pass SLIRP makes over its input header files) to the
       given file, as a series of SLIRP commands that can executed
       by the S-Lang interpreter to recreate the typemap table.


  -tmapin [4mfile[0m

       Load, using evalfile(), additional typemaps from the given
       file, which was presumably created by a -tmapout switch from
       a previous invocation of SLIRP.}


  --version

       Output the SLIRP version.


  -v

       Show verbose messages when loading S-Lang scripts



                            [1mTable of Contents[0m


  1. Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . .   4
  2. Introduction  . . . . . . . . . . . . . . . . . . . . . . . . .   5
  2.1. Brief History . . . . . . . . . . . . . . . . . . . . . . . .   5
  2.2. The libtriv  Module . . . . . . . . . . . . . . . . . . . . .   5
  2.3. Expectations  . . . . . . . . . . . . . . . . . . . . . . . .   9
  3. Code Generation . . . . . . . . . . . . . . . . . . . . . . . .  10
  3.1. Generated Type Mappings . . . . . . . . . . . . . . . . . . .  10
  3.1.1. Generated Enumeration Values  . . . . . . . . . . . . . . .  11
  3.1.2. Other Generated Constants and Variables . . . . . . . . . .  11
  3.2. Basic Mapping Functions . . . . . . . . . . . . . . . . . . .  12
  3.3. References  . . . . . . . . . . . . . . . . . . . . . . . . .  13
  3.3.1. Using S-Lang References Properly  . . . . . . . . . . . . .  13
  3.4. Guaranteed-Size Mappings  . . . . . . . . . . . . . . . . . .  14
  3.5. Mappings For Aggregate Types  . . . . . . . . . . . . . . . .  14
  3.5.1. Pointers  . . . . . . . . . . . . . . . . . . . . . . . . .  14
  3.5.1.1. Pointer Type Hierarchy  . . . . . . . . . . . . . . . . .  15
  3.5.1.2. To Code or Not To Code?   . . . . . . . . . . . . . . . .  16
  3.5.2. Structures  . . . . . . . . . . . . . . . . . . . . . . . .  16
  3.5.3. File Handles  . . . . . . . . . . . . . . . . . . . . . . .  17
  3.6. Opaque Types  . . . . . . . . . . . . . . . . . . . . . . . .  17
  3.6.1. Initializers and Finalizers . . . . . . . . . . . . . . . .  18
  3.6.2. Default Mappings  . . . . . . . . . . . . . . . . . . . . .  19
  3.7. Defining New Type Mapping Functions . . . . . . . . . . . . .  19
  3.8. C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . .  19
  3.9. FORTRAN . . . . . . . . . . . . . . . . . . . . . . . . . . .  20
  3.10. Compilation: Generated Makefiles . . . . . . . . . . . . . .  21
  3.11. Template Modules . . . . . . . . . . . . . . . . . . . . . .  21
  3.12. Debugging: slirp_debug_pause() . . . . . . . . . . . . . . .  22
  3.13. Usage Statements . . . . . . . . . . . . . . . . . . . . . .  22
  3.14. Vectorization  . . . . . . . . . . . . . . . . . . . . . . .  22
  4. Interface Files . . . . . . . . . . . . . . . . . . . . . . . .  24
  4.1. Loading Interface Files . . . . . . . . . . . . . . . . . . .  24
  4.2. Nesting Interface Files . . . . . . . . . . . . . . . . . . .  24
  4.3. Ignoring Symbols  . . . . . . . . . . . . . . . . . . . . . .  25
  4.3.1. Functions . . . . . . . . . . . . . . . . . . . . . . . . .  25
  4.3.2. Macros  . . . . . . . . . . . . . . . . . . . . . . . . . .  25
  4.3.3. Variables . . . . . . . . . . . . . . . . . . . . . . . . .  26
  4.4. Macro Substitutions . . . . . . . . . . . . . . . . . . . . .  26
  4.5. NULL  and Omitted Arguments . . . . . . . . . . . . . . . . .  27
  5. Introduction To Annotations . . . . . . . . . . . . . . . . . .  29
  5.1. A Sample Annotation . . . . . . . . . . . . . . . . . . . . .  30
  5.2. Dissecting an #argmap . . . . . . . . . . . . . . . . . . . .  31
  5.2.1. Custom File Loader  . . . . . . . . . . . . . . . . . . . .  31
  5.2.2. Matching Rules  . . . . . . . . . . . . . . . . . . . . . .  31
  5.3. Parameter Substitutions . . . . . . . . . . . . . . . . . . .  32
  5.3.1. Metadata  . . . . . . . . . . . . . . . . . . . . . . . . .  33
  5.4. Variable Substitutions  . . . . . . . . . . . . . . . . . . .  34
  6. #argmap  Annotations  . . . . . . . . . . . . . . . . . . . . .  36
  6.1. Wrapper Structure . . . . . . . . . . . . . . . . . . . . . .  36
  6.2. in  Method  . . . . . . . . . . . . . . . . . . . . . . . . .  37
  6.2.1. Built-in in  Maps . . . . . . . . . . . . . . . . . . . . .  38
  6.2.1.1. File Descriptors  . . . . . . . . . . . . . . . . . . . .  38
  6.2.1.2. Generic Pointers  . . . . . . . . . . . . . . . . . . . .  38
  6.2.1.3. C++ string  Objects . . . . . . . . . . . . . . . . . . .  39
  6.2.1.4. FORTRAN Strings . . . . . . . . . . . . . . . . . . . . .  40
  6.3. out  Method . . . . . . . . . . . . . . . . . . . . . . . . .  40
  6.3.1. Built-in out  Maps  . . . . . . . . . . . . . . . . . . . .  42
  6.4. final  Method . . . . . . . . . . . . . . . . . . . . . . . .  43
  6.5. ignore  Method  . . . . . . . . . . . . . . . . . . . . . . .  44
  7. Other Annotations . . . . . . . . . . . . . . . . . . . . . . .  45
  7.1. #clear  . . . . . . . . . . . . . . . . . . . . . . . . . . .  45
  7.2. #copy . . . . . . . . . . . . . . . . . . . . . . . . . . . .  45
  7.3. #ignore . . . . . . . . . . . . . . . . . . . . . . . . . . .  46
  7.4. #inline_c . . . . . . . . . . . . . . . . . . . . . . . . . .  46
  7.5. #prototype  . . . . . . . . . . . . . . . . . . . . . . . . .  48
  7.6. #retmap . . . . . . . . . . . . . . . . . . . . . . . . . . .  49
  7.6.1. Built-in #retmap  Annotations . . . . . . . . . . . . . . .  50
  7.7. #typedef  . . . . . . . . . . . . . . . . . . . . . . . . . .  51
  7.7.1. Built-in Type Definitions . . . . . . . . . . . . . . . . .  52
  8. Annotation Grammar  . . . . . . . . . . . . . . . . . . . . . .  53
  9. Command Line Reference  . . . . . . . . . . . . . . . . . . . .  57



