Provided by: critcl_3.1.18.1+dfsg-3_amd64 bug

NAME

       critcl-cproc-types - Critcl - cproc Type Reference

SYNOPSIS

       package require Tcl  8.4

       package require critcl  ?3.1.18?

       ::critcl::has-resulttype name

       ::critcl::resulttype name body ?ctype?

       ::critcl::resulttype name = origname

       ::critcl::has-argtype name

       ::critcl::argtype name body ?ctype? ?ctypefun?

       ::critcl::argtype name = origname

       ::critcl::argtypesupport name code ?guard?

       ::critcl::argtyperelease name code

_________________________________________________________________________________________________

DESCRIPTION

       C  Runtime In Tcl, or CriTcl , is a system for compiling C code embedded in Tcl on the fly
       and either loading the resulting objects into Tcl for immediate use or packaging them  for
       distribution.  Use CriTcl to improve performance by rewriting in C those routines that are
       performance bottlenecks.

       This document is a breakout of the descriptions for the predefined argument-  and  result-
       types  usable with the critcl::cproc command, as detailed in the reference manpage for the
       critcl package, plus the information on how to  extend  the  predefined  set  with  custom
       types.  The  breakout  was made to make this information easier to find (toplevel document
       vs. having to search the large main reference).

       Its intended audience are developers wishing to write Tcl packages with embedded C code.

STANDARD ARGUMENT TYPES

       Before going into the details first a quick overview:

              Critcl type | C type         | Tcl type  | Notes
              ----------- | -------------- | --------- | ------------------------------
              Tcl_Interp* | Tcl_Interp*    | n/a       | Special, only first
              ----------- | -------------- | --------- | ------------------------------
              Tcl_Obj*    | Tcl_Obj*       | Any       | Read-only
              object      |                |           | Alias of Tcl_Obj* above
              list        | critcl_list    | List      | Read-only
              ----------- | -------------- | --------- | ------------------------------
              char*       | const char*    | Any       | Read-only, string rep
              pstring     | critcl_pstring | Any       | Read-only
              bytes       | critcl_bytes   | ByteArray | Read-only
              ----------- | -------------- | --------- | ------------------------------
              int         | int            | Int       |
              long        | long           | Long      |
              wideint     | Tcl_WideInt    | WideInt   |
              double      | double         | Double    |
              float       | float          | Double    |
              ----------- | -------------- | --------- | ------------------------------
              X > 0       |                |           | For X in int ... float above.
              X >= 0      |                |           | C types as per the base type X.
              X < 0       |                |           | Allowed argument values are
              X <= 0      |                |           | restricted as per the shown
              X > 1       |                |           | relation
              X >= 1      |                |           |
              X < 1       |                |           | This is not a general mechanism
              X <= 1      |                |           | open to other values. Only 0/1.
              ----------- | -------------- | --------- | ------------------------------
              boolean     | int            | Boolean   |
              bool        |                |           | Alias of boolean above
              ----------- | -------------- | --------- | ------------------------------
              bytearray   |                |           | DEPRECATED
              rawchar     |                |           | DEPRECATED
              rawchar*    |                |           | DEPRECATED
              double*     |                |           | DEPRECATED
              float*      |                |           | DEPRECATED
              int*        |                |           | DEPRECATED
              void*       |                |           | DEPRECATED

       And now the details:

       Tcl_Interp*
              Attention: This is a special argument type. It  can  only  be  used  by  the  first
              argument  of a function.  Any other argument using it will cause critcl to throw an
              error.

              When used, the argument will contain a reference to the  current  interpreter  that
              the  function body may use. Furthermore the argument will not be an argument of the
              Tcl command for the function.

              This is useful when the function has to do more  than  simply  returning  a  value.
              Examples would be setting up error messages on failure, or querying the interpreter
              for variables and other data.

       Tcl_Obj*

       object The function takes an argument of type Tcl_Obj*.  No  argument  checking  is  done.
              The  Tcl  level word is passed to the argument as-is.  Note that this value must be
              treated as read-only (except for hidden changes to its intrep, i.e. shimmering).

       pstring
              The function takes an argument  of  type  critcl_pstring  containing  the  original
              Tcl_Obj* reference of the Tcl argument, plus the length of the string and a pointer
              to the character array.

              typedef struct critcl_pstring {
                  Tcl_Obj*    o;
                  const char* s;
                  int         len;
              } critcl_pstring;

              Note the const. The string  is  read-only.  Any  modification  can  have  arbitrary
              effects,  from  pulling  out  the  rug under the script because of string value and
              internal representation not matching anymore, up to crashes anytime later.

       list   The function takes an argument of type critcl_list containing the original Tcl_Obj*
              reference of the Tcl argument, plus the length of the Tcl list and a pointer to the
              array of the list elements.

              typedef struct critcl_list {
                  Tcl_Obj*        o;
                  Tcl_Obj* const* v;
                  int             c;
              } critcl_list;

              The Tcl argument must be convertible to List, an error is thrown otherwise.

              Note the const. The  list  is  read-only.   Any  modification  can  have  arbitrary
              effects,  from  pulling  out  the  rug under the script because of string value and
              internal representation not matching anymore, up to crashes anytime later.

       bytearray

       rawchar*

       rawchar
              The function takes an argument of type char*.  The Tcl argument must be convertible
              to  ByteArray, an error is thrown otherwise.  Note that the length of the ByteArray
              is not passed to the function, making this type not very usable.

              Attention: These types are considered DEPRECATED.  It is planned  to  remove  their
              documentation  in  release  3.2,  and  their  implementation in release 3.3.  Their
              deprecation can be undone if good use cases are shown.

       bytes  This is the new and usable ByteArray type.

              The function takes  an  argument  of  type  critcl_bytes  containing  the  original
              Tcl_Obj*  reference  of  the  Tcl argument, plus the length of the byte array and a
              pointer to the byte data.

              typedef struct critcl_bytes {
                  Tcl_Obj*             o;
                  const unsigned char* s;
                  int                len;
              } critcl_list;

              The Tcl argument must be convertible to ByteArray, an error is thrown otherwise.

              Note the const. The bytes are  read-only.   Any  modification  can  have  arbitrary
              effects,  from  pulling  out  the  rug under the script because of string value and
              internal representation not matching anymore, up to crashes anytime later.

       char*  The function takes an argument of type const char*.  The string  representation  of
              the Tcl argument is passed in.

              Note  the  const.  The  string  is  read-only.  Any modification can have arbitrary
              effects, from pulling out the rug under the script  because  of  string  value  and
              internal representation not matching anymore, up to crashes anytime later.

       double The  function  takes  an  argument  of  type  double.   The  Tcl  argument  must be
              convertible to Double, an error is thrown otherwise.

       double > 0

       double >= 0

       double < 0

       double <= 0

       double > 1

       double >= 1

       double < 1

       double <= 1
              These are variants of double above, restricting the argument  value  to  the  shown
              relation.  An  error  is  thrown  for Tcl arguments outside of the specified range.
              Note: This is not a general range  specification  syntax.  Only  the  listed  types
              exist.

       float  The function takes an argument of type float.  The Tcl argument must be convertible
              to Double, an error is thrown otherwise.

       float > 0

       float >= 0

       float < 0

       float <= 0

       float > 1

       float >= 1

       float < 1

       float <= 1
              These are variants of float above, restricting the  argument  value  to  the  shown
              relation.  An  error  is  thrown  for Tcl arguments outside of the specified range.
              Note: This is not a general range  specification  syntax.  Only  the  listed  types
              exist.

       boolean

       bool   The  function  takes an argument of type int.  The Tcl argument must be convertible
              to Boolean, an error is thrown otherwise.

       channel
              The function takes an argument of type  Tcl_Channel.   The  Tcl  argument  must  be
              convertible  to type Channel, an error is thrown otherwise.  The channel is further
              assumed to be already registered with the interpreter.

       unshared-channel
              This type is an extension of channel above.  All of the information above applies.

              Beyond that the channel must not be shared by multiple interpreters,  an  error  is
              thrown otherwise.

       take-channel
              This  type is an extension of unshared-channel above.  All of the information above
              applies.

              Beyond that the code removes the  channel  from  the  current  interpreter  without
              closing it, and disables all pre-existing event handling for it.

              With  this  the function takes full ownership of the channel in question, taking it
              away from the interpreter invoking it. It is then responsible for the lifecycle  of
              the channel, up to and including closing it.

              Should  the  system the function is a part of wish to return control of the channel
              back to the interpeter it then has to use the result type return-channel. This will
              undo  the  registration  changes made by this argument type.  Note however that the
              removal of pre-existing event handling done here cannot be undone.

              Attention Removal from the interpreter without closing the channel is  effected  by
              incrementing the channel's reference count without providing an interpreter, before
              decrementing the  same  for  the  current  interpreter.  This  leaves  the  overall
              reference  count intact without causing Tcl to close it when it is removed from the
              interpreter structures. At this point the channel is effectively  a  globally-owned
              part of the system not associated with any interpreter.

              The  complementary  result  type  then  runs  this  sequence in reverse. And if the
              channel is never returned to Tcl either the function or the system it is a part  of
              have to unregister the global reference when they are done with it.

       int    The  function  takes an argument of type int.  The Tcl argument must be convertible
              to Int, an error is thrown otherwise.

       int > 0

       int >= 0

       int < 0

       int <= 0

       int > 1

       int >= 1

       int < 1

       int <= 1
              These are variants of int above,  restricting  the  argument  value  to  the  shown
              relation.  An  error  is  thrown  for Tcl arguments outside of the specified range.
              Note: This is not a general range  specification  syntax.  Only  the  listed  types
              exist.

       long   The  function  takes  an  argument  of  type  long  int.   The Tcl argument must be
              convertible to Long, an error is thrown otherwise.

       long > 0

       long >= 0

       long < 0

       long <= 0

       long > 1

       long >= 1

       long < 1

       long <= 1
              These are variants of long above, restricting  the  argument  value  to  the  shown
              relation.  An  error  is  thrown  for Tcl arguments outside of the specified range.
              Note: This is not a general range  specification  syntax.  Only  the  listed  types
              exist.

       wideint
              The  function  takes  an  argument  of  type Tcl_WideInt.  The Tcl argument must be
              convertible to WideInt, an error is thrown otherwise.

       wideint > 0

       wideint >= 0

       wideint < 0

       wideint <= 0

       wideint > 1

       wideint >= 1

       wideint < 1

       wideint <= 1
              These are variants of wideint above, restricting the argument value  to  the  shown
              relation.  An  error  is  thrown  for Tcl arguments outside of the specified range.
              Note: This is not a general range  specification  syntax.  Only  the  listed  types
              exist.

       void*

       double*

       float*

       int*   The  function takes an argument of the same-named C type.  The Tcl argument must be
              convertible to ByteArray, an error is thrown otherwise.  The bytes in the ByteArray
              are  then  re-interpreted  as  the  raw representation of a single C pointer of the
              given type which is then passed as argument to the function.  In other words,  this
              is for Tcl values somehow holding raw C pointers, i.e. memory addresses.

              Attention:  These  types  are considered DEPRECATED.  It is planned to remove their
              documentation in release 3.2, and  their  implementation  in  release  3.3.   Their
              deprecation can be undone if good use cases are shown.

STANDARD RESULT TYPES

       Before going into the details first a quick overview:

              Critcl type   | C type         | Tcl type  | Notes
              ------------- | -------------- | --------- | ------------------------------
              void          | n/a            | n/a       | Always OK. Body sets result
              ok            | int            | n/a       | Result code. Body sets result
              ------------- | -------------- | --------- | ------------------------------
              int           | int            | Int       |
              boolean       |                |           | Alias of int above
              bool          |                |           | Alias of int above
              long          | long           | Long      |
              wideint       | Tcl_WideInt    | WideInt   |
              double        | double         | Double    |
              float         | float          | Double    |
              ------------- | -------------- | --------- | ------------------------------
              char*         | char*          | String    | Makes a copy
              vstring       |                |           | Alias of char* above
              const char*   | const char*    |           | Behavior of char* above
              ------------- | -------------- | --------- | ------------------------------
              string        |                | String    | Freeable string set directly
                            |                |           | No copy is made
              dstring       |                |           | Alias of string above
              ------------- | -------------- | --------- | ------------------------------
                            |                |           | For all below: Null is ERROR
                            |                |           | Body has to set any message
              Tcl_Obj*      | Tcl_Obj*       | Any       | refcount --
              object        |                |           | Alias of Tcl_Obj* above
              Tcl_Obj*0     |                | Any       | refcount unchanged
              object0       |                |           | Alias of Tcl_Obj*0 above
              ------------- | -------------- | --------- | ------------------------------
              known-channel | Tcl_Channel    | String    | Assumes to already be registered
              new-channel   | Tcl_Channel    | String    | New channel, will be registered

       And now the details:

       Tcl_Obj*

       object If the returned Tcl_Obj* is NULL, the Tcl return code is TCL_ERROR and the function
              should set an error mesage  [https://www.tcl-lang.org/man/tcl/TclLib/SetResult.htm]
              as  the  interpreter  result.   Otherwise,  the  returned  Tcl_Obj*  is  set as the
              interpreter result.

              Note that setting an error message requires the function body to have access to the
              interpreter  the  function is running in. See the argument type Tcl_Interp* for the
              details on how to make that happen.

              Note further that the returned Tcl_Obj* should have a reference count greater  than
              0.  This  is  because  the  converter  decrements  the  reference  count to release
              possession after setting the interpreter  result.  It  assumes  that  the  function
              incremented  the  reference  count  of the returned Tcl_Obj*.  If a Tcl_Obj* with a
              reference count of 0 were returned, the reference count would become 1 when set  as
              the  interpreter  result,  and  immediately  thereafter  be decremented to 0 again,
              causing the memory to be freed.  The system is then likely to crash at  some  point
              after the return due to reuse of the freed memory.

       Tcl_Obj*0

       object0
              Like  Tcl_Obj*  except  that  this conversion assumes that the returned value has a
              reference count of 0 and does not decrement it. Returning a value  whose  reference
              count is greater than 0 is therefore likely to cause a memory leak.

              Note that setting an error message requires the function body to have access to the
              interpreter the function is running in. See the argument type Tcl_Interp*  for  the
              details on how to make that happen.

       new-channel
              A  String  Tcl_Obj  holding  the  name  of  the  returned Tcl_Channel is set as the
              interpreter result.  The channel is  further  assumed  to  be  new,  and  therefore
              registered with the interpreter to make it known.

       known-channel
              A  String  Tcl_Obj  holding  the  name  of  the  returned Tcl_Channel is set as the
              interpreter result.  The channel is further assumed to be already  registered  with
              the interpreter.

       return-channel
              This  type  is  a  variant of new-channel above.  It varies slightly from it in the
              registration sequence to be properly  complementary  to  the  argument  type  take-
              channel.   A  String Tcl_Obj holding the name of the returned Tcl_Channel is set as
              the interpreter result.  The channel is further assumed to be  new,  and  therefore
              registered with the interpreter to make it known.

       char*

       vstring
              A  String  Tcl_Obj  holding  a copy of the returned char* is set as the interpreter
              result. If the value is allocated then the function itself and the extension it  is
              a  part of are responsible for releasing the memory when the data is not in use any
              longer.

       const char*
              Like char* above, except that the returned string is const-qualified.

       string

       dstring
              The returned char* is directly set as the interpreter result without making a copy.
              Therefore   it  must  be  dynamically  allocated  via  Tcl_Alloc.  Release  happens
              automatically when the Interpreter finds that the value is not required any longer.

       double

       float  The returned double or float is converted to  a  Double  Tcl_Obj  and  set  as  the
              interpreter result.

       boolean

       bool   The  returned  int  value is converted to an Int Tcl_Obj and set as the interpreter
              result.

       int    The returned int value is converted to an Int Tcl_Obj and set  as  the  interpreter
              result.

       long   The  returned  long  int  value  is  converted  to  a  Long  Tcl_Obj and set as the
              interpreter result.

       wideint
              The returned Tcl_WideInt value is converted to a WideInt Tcl_Obj  and  set  as  the
              interpreter result.

       ok     The returned int value becomes the Tcl return code.  The interpreter result is left
              untouched and can be set by the function if desired. Note that doing this  requires
              the function body to have access to the interpreter the function is running in. See
              the argument type Tcl_Interp* for the details on how to make that happen.

       void   The function does not return a value.  The interpreter result is left untouched and
              can be set by the function if desired.

ADVANCED: ADDING TYPES

       While the critcl::cproc command understands the most common C types (as per the previous 2
       sections), sometimes this is not enough.

       To get around this limitation the commands in this  section  enable  users  of  critcl  to
       extend  the  set of argument and result types understood by critcl::cproc. In other words,
       they allow them to define their own, custom, types.

       ::critcl::has-resulttype name
              This command tests if the named result-type is known or not.  It returns a  boolean
              value, true if the type is known and false otherwise.

       ::critcl::resulttype name body ?ctype?
              This  command defines the result type name, and associates it with the C code doing
              the conversion (body) from C to Tcl.  The C return type of the associated function,
              also  the C type of the result variable, is ctype. This type defaults to name if it
              is not specified.

              If name is already declared an error is thrown.   Attention!  The  standard  result
              type  void  is  special  as  it has no accompanying result variable. This cannot be
              expressed by this extension command.

              The body's responsibility is the conversion of the  functions  result  into  a  Tcl
              result  and  a  Tcl status. The first has to be set into the interpreter we are in,
              and the second has to be returned.

              The C code of body is guaranteed to be called last in the wrapper around the actual
              implementation   of  the  cproc  in  question  and  has  access  to  the  following
              environment:

              interp A Tcl_Interp* typed C variable referencing the interpreter the result has to
                     be stored into.

              rv     The C variable holding the result to convert, of type ctype.

              As examples here are the definitions of two standard result types:

                  resulttype int {
                Tcl_SetObjResult(interp, Tcl_NewIntObj(rv));
                return TCL_OK;
                  }

                  resulttype ok {
                /* interp result must be set by cproc body */
                return rv;
                  } int

       ::critcl::resulttype name = origname
              This  form  of  the  resulttype  command  declares  name as an alias of result type
              origname, which has to be defined already. If this is not  the  case  an  error  is
              thrown.

       ::critcl::has-argtype name
              This  command  tests  if  the  named  argument-type  is known or not.  It returns a
              boolean value, true if the type is known and false otherwise.

       ::critcl::argtype name body ?ctype? ?ctypefun?
              This command defines the argument type name, and associates  it  with  the  C  code
              doing  the conversion (body) from Tcl to C.  ctype is the C type of the variable to
              hold the conversion result and ctypefun  is  the  type  of  the  function  argument
              itself.   Both  types  default  to  name  if  they  are the empty string or are not
              provided.

              If name is already declared an error is thrown.

              body is a C code fragment that converts a Tcl_Obj* into a C value which  is  stored
              in a helper variable in the underlying function.

              body  is  called  inside  its  own  code  block to isolate local variables, and the
              following items are in scope:

              interp A variable of type Tcl_Interp* which is the interpreter the code is  running
                     in.

              @@     A placeholder for an expression that evaluates to the Tcl_Obj* to convert.

              @A     A  placeholder  for the name of the variable to store the converted argument
                     into.

              As examples, here are the definitions of two standard argument types:

                  argtype int {
                if (Tcl_GetIntFromObj(interp, @@, &@A) != TCL_OK) return TCL_ERROR;
                  }

                  argtype float {
                double t;
                if (Tcl_GetDoubleFromObj(interp, @@, &t) != TCL_OK) return TCL_ERROR;
                @A = (float) t;
                  }

       ::critcl::argtype name = origname
              This form of the argtype command  declares  name  as  an  alias  of  argument  type
              origname,  which  has  to  be  defined already. If this is not the case an error is
              thrown.

       ::critcl::argtypesupport name code ?guard?
              This command defines a C code fragment for the already defined argument  type  name
              which  is  inserted  before  all  functions  using  that  type.  Its purpose is the
              definition of any supporting C types needed by the argument type.  If the  type  is
              used  by  many  functions  the  system  ensures that only the first of the multiple
              insertions of the code fragment is active, and  the  others  disabled.   The  guard
              identifier  is  normally  derived  from  name,  but can also be set explicitly, via
              guard. This latter  allows  different  custom  types  to  share  a  common  support
              structure without having to perform their own guarding.

       ::critcl::argtyperelease name code
              This  command  defines a C code fragment for the already defined argument type name
              which is inserted whenever the worker function of a critcl::cproc  returns  to  the
              shim.  It  is  the  responsibility  of this fragment to unconditionally release any
              resources the critcl::argtype conversion code allocated.  An example  of  this  are
              the  variadic  types  for  the  support  of  the special, variadic args argument to
              critcl::cproc's.  They allocate a C array for the collected arguments which has  to
              be  released  when  the  worker  returns. This command defines the C code for doing
              that.

EXAMPLES

       The examples shown here have been drawn from section "Embedding C" in the  document  about
       Using CriTcl. Please see that document for many more examples.

   A SIMPLE PROCEDURE
       Starting simple, let us assume that the Tcl code in question is something like

                  proc math {x y z} {
                      return [expr {(sin($x)*rand())/$y**log($z)}]
                  }

       with the expression pretending to be something very complex and slow. Converting this to C
       we get:

                  critcl::cproc math {double x double y double z} double {
                      double up   = rand () * sin (x);
                      double down = pow(y, log (z));
                      return up/down;
                  }

       Notable about this translation:

       [1]    All the arguments got type information added to them, here "double".  Like in C the
              type  precedes  the  argument  name.  Other  than  that  it  is  pretty  much a Tcl
              dictionary, with keys and values swapped.

       [2]    We now also have to declare the type of the result, here "double", again.

       [3]    The reference manpage lists all the  legal  C  types  supported  as  arguments  and
              results.

   CUSTOM TYPES, INTRODUCTION
       When  writing  bindings to external libraries critcl::cproc is usually the most convenient
       way of writing the lower layers. This is however hampered by the fact that critcl  on  its
       own  only  supports  a few standard (arguably the most import) standard types, whereas the
       functions we wish to bind most certainly will use much more,  specific  to  the  library's
       function.

       The  critcl  commands argtype, resulttype and their adjuncts are provided to help here, by
       allowing a developer to extend critcl's type system with custom conversions.

       This and the three following sections will demonstrate this, from trivial to complex.

       The most trivial use is to create types which are aliases of existing types,  standard  or
       other.  As  an  alias  it  simply  copies and uses the conversion code from the referenced
       types.

       Our example is pulled from an incomplete project of mine, a binding  to  Jeffrey  Kegler's
       libmarpa  library  managing  Earley  parsers.  Several  custom  types  simply  reflect the
       typedef's done by the library, to make  the  critcl::cprocs  as  self-documenting  as  the
       underlying library functions themselves.

                  critcl::argtype Marpa_Symbol_ID     = int
                  critcl::argtype Marpa_Rule_ID       = int
                  critcl::argtype Marpa_Rule_Int      = int
                  critcl::argtype Marpa_Rank          = int
                  critcl::argtype Marpa_Earleme       = int
                  critcl::argtype Marpa_Earley_Set_ID = int

                  ...

                  method sym-rank: proc {
                      Marpa_Symbol_ID sym
                      Marpa_Rank      rank
                  } Marpa_Rank {
                      return marpa_g_symbol_rank_set (instance->grammar, sym, rank);
                  }

                  ...

   CUSTOM TYPES, SEMI-TRIVIAL
       A  more  involved  custom  argument type would be to map from Tcl strings to some internal
       representation, like an integer code.

       The first example is taken from the tclyaml package, a binding to the libyaml library.  In
       a  few  places  we have to map readable names for block styles, scalar styles, etc. to the
       internal enumeration.

                  critcl::argtype yaml_sequence_style_t {
                      if (!encode_sequence_style (interp, @@, &@A)) return TCL_ERROR;
                  }

                  ...

                  critcl::ccode {
                      static const char* ty_block_style_names [] = {
                          "any", "block", "flow", NULL
                      };

                      static int
                      encode_sequence_style (Tcl_Interp* interp, Tcl_Obj* style,
                                             yaml_sequence_style_t* estyle)
                      {
                          int value;
                          if (Tcl_GetIndexFromObj (interp, style, ty_block_style_names,
                                                   "sequence style", 0, &value) != TCL_OK) {
                              return 0;
                          }
                          *estyle = value;
                          return 1;
                      }
                  }

                  ...

                  method sequence_start proc {
                      pstring anchor
                      pstring tag
                      int implicit
                      yaml_sequence_style_t style
                  } ok {
                      /* Syntax: <instance> seq_start <anchor> <tag> <implicit> <style> */
                      ...
                  }

                  ...

       It should be noted that this code precedes the advent of the supporting generator  package
       critcl::emap. using the generator the definition of the mapping becomes much simpler:

                  critcl::emap::def yaml_sequence_style_t {
                      any   0
                      block 1
                      flow  2
                  }

       Note  that  the  generator  will  not  only  provide  the conversions, but also define the
       argument and result types needed for their use by critcl::cproc.  Another example of  such
       a  semi-trivial  argument  type  can  be  found  in  the  CRIMP  package,  which defines a
       Tcl_ObjType for image values. This not only provides a basic argument type for any  image,
       but  also  derived types which check that the image has a specific format. Here we see for
       the first time non-integer arguments, and  the  need  to  define  the  C  types  used  for
       variables  holding  the  C  level  value,  and  the  type of function parameters (Due to C
       promotion rules we may need different types).

                  critcl::argtype image {
                      if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
                          return TCL_ERROR;
                      }
                  } crimp_image* crimp_image*

                  ...

                      set map [list <<type>> $type]
                      critcl::argtype image_$type [string map $map {
                          if (crimp_get_image_from_obj (interp, @@, &@A) != TCL_OK) {
                              return TCL_ERROR;
                          }
                          if (@A->itype != crimp_imagetype_find ("crimp::image::<<type>>")) {
                              Tcl_SetObjResult (interp,
                                                Tcl_NewStringObj ("expected image type <<type>>",
                                                                  -1));
                              return TCL_ERROR;
                          }
                      }] crimp_image* crimp_image*

                  ...

   CUSTOM TYPES, SUPPORT STRUCTURES
       The adjunct command critcl::argtypesupport is for when  the  conversion  needs  additional
       definitions, for example a helper structure.

       An  example  of  this  can be found among the standard types of critcl itself, the pstring
       type. This type provides the C function with not only the string  pointer,  but  also  the
       string  length,  and  the  Tcl_Obj*  this  data  came  from.  As  critcl::cproc's  calling
       conventions allow us only one argument for the data of the parameter a structure is needed
       to convey these three pieces of information.

       Thus the argument type is defined as

                  critcl::argtype pstring {
                      @A.s = Tcl_GetStringFromObj(@@, &(@A.len));
                      @A.o = @@;
                  } critcl_pstring critcl_pstring

                  critcl::argtypesupport pstring {
                      typedef struct critcl_pstring {
                          Tcl_Obj*    o;
                          const char* s;
                          int         len;
                      } critcl_pstring;
                  }

       In the case of such a structure being large we may wish to allocate it on the heap instead
       of having it taking space on the stack. If we do that we  need  another  adjunct  command,
       critcl::argtyperelease.  This  command  specifies the code required to release dynamically
       allocated resources when the worker function returns,  before  the  shim  returns  to  the
       caller  in Tcl.  To keep things simple our example is synthetic, a modification of pstring
       above, to demonstrate the technique. An actual, but more complex example is  the  code  to
       support the variadic args argument of critcl::cproc.

                  critcl::argtype pstring {
                      @A = (critcl_pstring*) ckalloc(sizeof(critcl_pstring));
                      @A->s = Tcl_GetStringFromObj(@@, &(@A->len));
                      @A->o = @@;
                  } critcl_pstring* critcl_pstring*

                  critcl::argtypesupport pstring {
                      typedef struct critcl_pstring {
                          Tcl_Obj*    o;
                          const char* s;
                          int         len;
                      } critcl_pstring;
                  }

                  critcl::argtyperelease pstring {
                      ckfree ((char*)) @A);
                  }

       Note,  the  above example shows only the most simple case of an allocated argument, with a
       conversion that cannot fail (namely, string retrieval). If the conversion  can  fail  then
       either  the  allocation  has to be defered to happen only on successful conversion, or the
       conversion code has to release the allocated memory itself in the failure path, because it
       will never reach the code defined via critcl::argtyperelease in that case.

   CUSTOM TYPES, RESULTS
       All  of the previous sections dealt with argument conversions, i.e. going from Tcl into C.
       Custom result types are for the reverse direction, from C to Tcl.  This is usually easier,
       as  most  of  the time errors should not be possible. Supporting structures, or allocating
       them on the heap are not really required and therefore not supported.

       The example of a result type shown below was pulled from KineTcl. It is a variant  of  the
       builtin  result  type Tcl_Obj*, aka object. The builtin conversion assumes that the object
       returned by the function has a refcount of 1 (or higher), with the  function  having  held
       the reference, and releases that reference after placing the value into the interp result.
       The conversion below on the other hand assumes that the value has a refcount of 0 and thus
       that  decrementing  it  is  forbidden, lest it be released much to early, and crashing the
       system.

                  critcl::resulttype KTcl_Obj* {
                      if (rv == NULL) { return TCL_ERROR; }
                      Tcl_SetObjResult(interp, rv);
                      /* No refcount adjustment */
                      return TCL_OK;
                  } Tcl_Obj*

       This type of definition is also found  in  Marpa  and  recent  hacking  hacking  on  CRIMP
       introduced  it  there as well. Which is why this definition became a builtin type starting
       with version 3.1.16, under the names Tcl_Obj*0 and object0.

       Going back to errors and their handling, of course, if a function we are wrapping  signals
       them  in-band, then the conversion of such results has to deal with that. This happens for
       example in KineTcl, where we find

                  critcl::resulttype XnStatus {
                      if (rv != XN_STATUS_OK) {
                          Tcl_AppendResult (interp, xnGetStatusString (rv), NULL);
                          return TCL_ERROR;
                      }
                      return TCL_OK;
                  }

                  critcl::resulttype XnDepthPixel {
                      if (rv == ((XnDepthPixel) -1)) {
                          Tcl_AppendResult (interp,
                                            "Inheritance error: Not a depth generator",
                                            NULL);
                          return TCL_ERROR;
                      }
                      Tcl_SetObjResult (interp, Tcl_NewIntObj (rv));
                      return TCL_OK;
                  }

AUTHORS

       Jean Claude Wippler, Steve Landers, Andreas Kupries

BUGS, IDEAS, FEEDBACK

       This document, and the package it describes,  will  undoubtedly  contain  bugs  and  other
       problems.   Please report them at https://github.com/andreas-kupries/critcl/issues.  Ideas
       for enhancements you may have for either package, application,  and/or  the  documentation
       are   also   very   welcome   and   should   be  reported  at  https://github.com/andreas-
       kupries/critcl/issues as well.

KEYWORDS

       C code, Embedded C Code, code generator, compile & run, compiler, dynamic code generation,
       dynamic   compilation,   generate  package,  linker,  on  demand  compilation,  on-the-fly
       compilation

CATEGORY

       Glueing/Embedded C code

COPYRIGHT

       Copyright (c) Jean-Claude Wippler
       Copyright (c) Steve Landers
       Copyright (c) 2011-2018 Andreas Kupries