Provided by: critcl_3.1.17+dfsg-1_all bug

NAME

       critcl-cproc-types - Critcl - cproc Type Reference

SYNOPSIS

       package require Tcl  8.4

       package require critcl  ?3.1.17?

       ::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

       Welcome  to the C Runtime In Tcl, CriTcl for short, a system to build C extension packages
       for Tcl on the fly, from C code embedded within Tcl scripts, for  all  who  wish  to  make
       their code go faster.

       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

       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.

       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;
                  char*    s;
                  int      len;
              } critcl_pstring;

       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** v;
                  int       c;
              } critcl_list;

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

       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.

       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;
                  char*    s;
                  int      len;
              } critcl_list;

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

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

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

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

       boolean

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

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

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

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

       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

       Tcl_Obj*

       object The  function returns a value of type Tcl_Obj*.  This value becomes the interpreter
              result, if not 0. The Tcl status is TCL_ERROR when a  0  is  returned,  and  TCL_OK
              otherwise.

              Note  how it is the responsibility of the function to set the interpreter result to
              an appropriate error message when returning 0.

              Attention: The conversion assumes that the value belonged to the function, with  an
              associated reference count, and decrements the reference count to indicate the loss
              of ownership by the function. This means that it is an  error  to  return  a  value
              whose reference count is zero. The system will crash at some point after the return
              due to reuse of the freed memory.

       Tcl_Obj*0

       object0
              The function returns a value of type Tcl_Obj*.  This value becomes the  interpreter
              result,  if  not  0.  The  Tcl status is TCL_ERROR when a 0 is returned, and TCL_OK
              otherwise.

              Note how it is the responsibility of the function to set the interpreter result  to
              an appropriate error message when returning 0.

              Attention:  Contrary  to  Tcl_Obj*  above this conversion assumes that the returned
              value has a reference count of 0 and performs no decrement. Returning a value whose
              reference count is greater than zero will likely cause a memory leak.

       char*

       vstring
              The  function  returns  a  value of type char*.  This value becomes the interpreter
              result, wrapped in a String.  It is assumed that the string  is  volatile  in  some
              way,  with  the  wrapping  in  a String duplicating it before making it the result,
              ensuring that we will not access a dangling pointer in the future.  The Tcl  status
              is always TCL_OK.

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

       string

       dstring
              The  function returns a value of type char*.  Contrary to the previous string types
              here it is assumed that the value is dynamically allocated,  via  Tcl_Alloc.   This
              value  becomes the interpreter result, as usual, but is not copied.  The Tcl status
              is always TCL_OK.

       double The function returns a value of type double.  This value  becomes  the  interpreter
              result, properly wrapped as a Double.  The Tcl status is always TCL_OK.

       float  The  function  returns  a  value of type float.  This value becomes the interpreter
              result, properly wrapped as a Double.  The Tcl status is always TCL_OK.

       boolean

       bool   The function returns a value of type  int,  interpreted  as  boolean.   This  value
              becomes  the  interpreter  result,  properly  wrapped  as a Int.  The Tcl status is
              always TCL_OK.

       int    The function returns a value of type  int.   This  value  becomes  the  interpreter
              result, properly wrapped as a Int.  The Tcl status is always TCL_OK.

       long   The  function returns a value of type long int.  This value becomes the interpreter
              result, properly wrapped as a Long.  The Tcl status is always TCL_OK.

       wideint
              The function  returns  a  value  of  type  Tcl_WideInt.   This  value  becomes  the
              interpreter  result,  properly  wrapped  as  a  WideInt.   The Tcl status is always
              TCL_OK.

       ok     The function returns a value of type int.  It is  interpreted  as  the  Tcl  status
              code.   The  interpreter result is left untouched (empty).  For a different outcome
              the function has to set the interpreter result by itself.

       void   The function does not return a value.  The interpreter  result  is  left  untouched
              (empty).  For a different outcome the function has to set the interpreter result by
              itself.  The Tcl status is always TCL_OK.

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  declared  already  an  error will be 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 The C type of the variable  to  hold  the
              conversion  result  is  ctype  and  the  type  of  the  function argument itself is
              ctypefun.  Both types default to name if they  are  not  specified  (or  the  empty
              string).

              If name is declared already an error will be thrown.

              The body's responsibility is the conversion of a command's Tcl_Obj* argument into a
              C value for the underlying function and its storage in a helper variable.

              The C code of body is guaranteed to be called inside of a  separate  C  code  block
              (thus  allowing  the  use  of  local  variables)  which has access to the following
              environment:

              interp A Tcl_Interp* typed C variable  referencing  the  interpreter  the  code  is
                     running in.

              @@     A  placeholder  for  the Tcl_Obj*-valued C expression providing the value of
                     the argument to convert.

              @A     A placeholder for the name of the C 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 will be 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  will  be 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;
                          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;
                          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 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-2015 Andreas Kupries