'\" '\" Generated from file 'critcl_cproc\&.man' by tcllib/doctools with format 'nroff' '\" Copyright (c) Jean-Claude Wippler '\" Copyright (c) Steve Landers '\" Copyright (c) 2011-2024 Andreas Kupries '\" .TH "critcl_cproc_types" n 3\&.3\&.1 doc "C Runtime In Tcl (CriTcl)" .\" The -*- nroff -*- definitions below are for supplemental macros used .\" in Tcl/Tk manual entries. .\" .\" .AP type name in/out ?indent? .\" Start paragraph describing an argument to a library procedure. .\" type is type of argument (int, etc.), in/out is either "in", "out", .\" or "in/out" to describe whether procedure reads or modifies arg, .\" and indent is equivalent to second arg of .IP (shouldn't ever be .\" needed; use .AS below instead) .\" .\" .AS ?type? ?name? .\" Give maximum sizes of arguments for setting tab stops. Type and .\" name are examples of largest possible arguments that will be passed .\" to .AP later. If args are omitted, default tab stops are used. .\" .\" .BS .\" Start box enclosure. From here until next .BE, everything will be .\" enclosed in one large box. .\" .\" .BE .\" End of box enclosure. .\" .\" .CS .\" Begin code excerpt. .\" .\" .CE .\" End code excerpt. .\" .\" .VS ?version? ?br? .\" Begin vertical sidebar, for use in marking newly-changed parts .\" of man pages. The first argument is ignored and used for recording .\" the version when the .VS was added, so that the sidebars can be .\" found and removed when they reach a certain age. If another argument .\" is present, then a line break is forced before starting the sidebar. .\" .\" .VE .\" End of vertical sidebar. .\" .\" .DS .\" Begin an indented unfilled display. .\" .\" .DE .\" End of indented unfilled display. .\" .\" .SO ?manpage? .\" Start of list of standard options for a Tk widget. The manpage .\" argument defines where to look up the standard options; if .\" omitted, defaults to "options". The options follow on successive .\" lines, in three columns separated by tabs. .\" .\" .SE .\" End of list of standard options for a Tk widget. .\" .\" .OP cmdName dbName dbClass .\" Start of description of a specific option. cmdName gives the .\" option's name as specified in the class command, dbName gives .\" the option's name in the option database, and dbClass gives .\" the option's class in the option database. .\" .\" .UL arg1 arg2 .\" Print arg1 underlined, then print arg2 normally. .\" .\" .QW arg1 ?arg2? .\" Print arg1 in quotes, then arg2 normally (for trailing punctuation). .\" .\" .PQ arg1 ?arg2? .\" Print an open parenthesis, arg1 in quotes, then arg2 normally .\" (for trailing punctuation) and then a closing parenthesis. .\" .\" # Set up traps and other miscellaneous stuff for Tcl/Tk man pages. .if t .wh -1.3i ^B .nr ^l \n(.l .ad b .\" # Start an argument description .de AP .ie !"\\$4"" .TP \\$4 .el \{\ . ie !"\\$2"" .TP \\n()Cu . el .TP 15 .\} .ta \\n()Au \\n()Bu .ie !"\\$3"" \{\ \&\\$1 \\fI\\$2\\fP (\\$3) .\".b .\} .el \{\ .br .ie !"\\$2"" \{\ \&\\$1 \\fI\\$2\\fP .\} .el \{\ \&\\fI\\$1\\fP .\} .\} .. .\" # define tabbing values for .AP .de AS .nr )A 10n .if !"\\$1"" .nr )A \\w'\\$1'u+3n .nr )B \\n()Au+15n .\" .if !"\\$2"" .nr )B \\w'\\$2'u+\\n()Au+3n .nr )C \\n()Bu+\\w'(in/out)'u+2n .. .AS Tcl_Interp Tcl_CreateInterp in/out .\" # BS - start boxed text .\" # ^y = starting y location .\" # ^b = 1 .de BS .br .mk ^y .nr ^b 1u .if n .nf .if n .ti 0 .if n \l'\\n(.lu\(ul' .if n .fi .. .\" # BE - end boxed text (draw box now) .de BE .nf .ti 0 .mk ^t .ie n \l'\\n(^lu\(ul' .el \{\ .\" Draw four-sided box normally, but don't draw top of .\" box if the box started on an earlier page. .ie !\\n(^b-1 \{\ \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .el \}\ \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\l'|0u-1.5n\(ul' .\} .\} .fi .br .nr ^b 0 .. .\" # VS - start vertical sidebar .\" # ^Y = starting y location .\" # ^v = 1 (for troff; for nroff this doesn't matter) .de VS .if !"\\$2"" .br .mk ^Y .ie n 'mc \s12\(br\s0 .el .nr ^v 1u .. .\" # VE - end of vertical sidebar .de VE .ie n 'mc .el \{\ .ev 2 .nf .ti 0 .mk ^t \h'|\\n(^lu+3n'\L'|\\n(^Yu-1v\(bv'\v'\\n(^tu+1v-\\n(^Yu'\h'-|\\n(^lu+3n' .sp -1 .fi .ev .\} .nr ^v 0 .. .\" # Special macro to handle page bottom: finish off current .\" # box/sidebar if in box/sidebar mode, then invoked standard .\" # page bottom macro. .de ^B .ev 2 'ti 0 'nf .mk ^t .if \\n(^b \{\ .\" Draw three-sided box if this is the box's first page, .\" draw two sides but no top otherwise. .ie !\\n(^b-1 \h'-1.5n'\L'|\\n(^yu-1v'\l'\\n(^lu+3n\(ul'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .el \h'-1.5n'\L'|\\n(^yu-1v'\h'\\n(^lu+3n'\L'\\n(^tu+1v-\\n(^yu'\h'|0u'\c .\} .if \\n(^v \{\ .nr ^x \\n(^tu+1v-\\n(^Yu \kx\h'-\\nxu'\h'|\\n(^lu+3n'\ky\L'-\\n(^xu'\v'\\n(^xu'\h'|0u'\c .\} .bp 'fi .ev .if \\n(^b \{\ .mk ^y .nr ^b 2 .\} .if \\n(^v \{\ .mk ^Y .\} .. .\" # DS - begin display .de DS .RS .nf .sp .. .\" # DE - end display .de DE .fi .RE .sp .. .\" # SO - start of list of standard options .de SO 'ie '\\$1'' .ds So \\fBoptions\\fR 'el .ds So \\fB\\$1\\fR .SH "STANDARD OPTIONS" .LP .nf .ta 5.5c 11c .ft B .. .\" # SE - end of list of standard options .de SE .fi .ft R .LP See the \\*(So manual entry for details on the standard options. .. .\" # OP - start of full description for a single option .de OP .LP .nf .ta 4c Command-Line Name: \\fB\\$1\\fR Database Name: \\fB\\$2\\fR Database Class: \\fB\\$3\\fR .fi .IP .. .\" # CS - begin code excerpt .de CS .RS .nf .ta .25i .5i .75i 1i .. .\" # CE - end code excerpt .de CE .fi .RE .. .\" # UL - underline word .de UL \\$1\l'|0\(ul'\\$2 .. .\" # QW - apply quotation marks to word .de QW .ie '\\*(lq'"' ``\\$1''\\$2 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\$2 .. .\" # PQ - apply parens and quotation marks to word .de PQ .ie '\\*(lq'"' (``\\$1''\\$2)\\$3 .\"" fix emacs highlighting .el (\\*(lq\\$1\\*(rq\\$2)\\$3 .. .\" # QR - quoted range .de QR .ie '\\*(lq'"' ``\\$1''\\-``\\$2''\\$3 .\"" fix emacs highlighting .el \\*(lq\\$1\\*(rq\\-\\*(lq\\$2\\*(rq\\$3 .. .\" # MT - "empty" string .de MT .QW "" .. .BS .SH NAME critcl_cproc_types \- CriTcl cproc Type Reference .SH SYNOPSIS package require \fBTcl 8\&.6\fR .sp package require \fBcritcl ?3\&.3\&.1?\fR .sp \fB::critcl::has-resulttype\fR \fIname\fR .sp \fB::critcl::resulttype\fR \fIname\fR \fIbody\fR ?\fIctype\fR? .sp \fB::critcl::resulttype\fR \fIname\fR \fB=\fR \fIorigname\fR .sp \fB::critcl::has-argtype\fR \fIname\fR .sp \fB::critcl::argtype\fR \fIname\fR \fIbody\fR ?\fIctype\fR? ?\fIctypefun\fR? .sp \fB::critcl::argtype\fR \fIname\fR \fB=\fR \fIorigname\fR .sp \fB::critcl::argtypesupport\fR \fIname\fR \fIcode\fR ?\fIguard\fR? .sp \fB::critcl::argtyperelease\fR \fIname\fR \fIcode\fR .sp .BE .SH DESCRIPTION .PP Be welcome to the \fIC Runtime In Tcl\fR (short: \fICriTcl\fR), a system for embedding and using C code from within \fITcl\fR [http://core\&.tcl-lang\&.org/tcl] scripts\&. .PP This document is a breakout of the descriptions for the predefined argument- and result-types usable with the \fBcritcl::cproc\fR command, as detailed in the reference manpage for the \fBcritcl\fR 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)\&. .PP Its intended audience are developers wishing to write Tcl packages with embedded C code\&. .SH "STANDARD ARGUMENT TYPES" Before going into the details first a quick overview: .CS CriTcl type | C type | Tcl type | Notes ---------------- | -------------- | --------- | ------------------------------ Tcl_Interp* | Tcl_Interp* | n/a | \fISpecial\fR, only first ---------------- | -------------- | --------- | ------------------------------ Tcl_Obj* | Tcl_Obj* | Any | \fIRead-only\fR object | | | Alias of \fBTcl_Obj*\fR above list | critcl_list | List | \fIRead-only\fR [], [*] | | | Alias of \fBlist\fR above ---------------- | -------------- | --------- | ------------------------------ [N] | | | Restricted \fBlist\fR-types\&. type[], type[N] | | | Length-limited ([\&.\&.]), expected []type, [N]type | | | element type, or both\&. | | | | | | Element types can be all known argument | | | types, except for any kind of list\&. | | | IOW multi-dimensional lists are not | | | supported\&. ---------------- | -------------- | --------- | ------------------------------ char* | const char* | Any | \fIRead-only\fR, \fIstring rep\fR pstring | critcl_pstring | Any | \fIRead-only\fR bytes | critcl_bytes | ByteArray | \fIRead-only\fR ---------------- | -------------- | --------- | ------------------------------ int | int | Int | long | long | Long | wideint | Tcl_WideInt | WideInt | double | double | Double | float | float | Double | ---------------- | -------------- | --------- | ------------------------------ X > N | | | For X in \fBint\fR \&.\&.\&. \fBfloat\fR above\&. X >= N | | | The C types are as per the base type X\&. X < N | | | N, A, B are expected to be constant integer X <= N | | | numbers for types \fBint\fR, \fBlong\fR, X > A < B | | | and \fBwideint\fR\&. For types \fBdouble\fR etc\&. | | | and \fBfloat\fR the N, A, and B can be floating | | | point numbers\&. Multiple restrictions are | | | fused as much as possible to yield at most | | | both upper and lower limits\&. ---------------- | -------------- | --------- | ------------------------------ boolean | int | Boolean | bool | | | Alias of \fBboolean\fR above ---------------- | -------------- | --------- | ------------------------------ channel | Tcl_Channel | String | Assumed to be registered unshared-channel | Tcl_Channel | String | As above, limited to current interpreter take-channel | Tcl_Channel | String | As above, C code takes ownership .CE And now the details: .TP Tcl_Interp* \fIAttention\fR: This is a \fIspecial\fR argument type\&. It can \fIonly\fR be used by the \fIfirst\fR argument of a function\&. Any other argument using it will cause critcl to throw an error\&. .sp When used, the argument will contain a reference to the current interpreter that the function body may use\&. Furthermore the argument will \fInot\fR be an argument of the Tcl command for the function\&. .sp 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\&. .TP Tcl_Obj* .TP object The function takes an argument of type \fBTcl_Obj*\fR\&. No argument checking is done\&. The Tcl level word is passed to the argument as-is\&. Note that this value must be treated as \fIread-only\fR (except for hidden changes to its intrep, i\&.e\&. \fIshimmering\fR)\&. .TP pstring The function takes an argument of type \fBcritcl_pstring\fR containing the original \fBTcl_Obj*\fR reference of the Tcl argument, plus the length of the string and a pointer to the character array\&. .CS typedef struct critcl_pstring { Tcl_Obj* o; const char* s; int len; } critcl_pstring; .CE .IP Note the \fIconst\fR\&. The string is \fIread-only\fR\&. 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\&. .TP list .TP [] .TP [*] The function takes an argument of type \fBcritcl_list\fR containing the original \fBTcl_Obj*\fR reference of the Tcl argument, plus the length of the Tcl list and a pointer to the array of the list elements\&. .CS typedef struct critcl_list { Tcl_Obj* o; Tcl_Obj* const* v; int c; } critcl_list; .CE .IP The Tcl argument must be convertible to \fBList\fR, an error is thrown otherwise\&. .sp Note the \fIconst\fR\&. The list is \fIread-only\fR\&. 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\&. .sp Further note that the system understands a number of more complex syntactical forms which all translate into forms of lists under the hood, as described by the following points\&. .TP [N] A \fIlist\fR type with additional checks limiting the length to \fBN\fR, an integer number greater than zero\&. .TP []type .TP type[] A \fIlist\fR type whose elements all have to be convertible for \fItype\fR\&. All known types, including user-defined, are allowed, except for \fBlist\fR and derivates\&. In other words, multi-dimensional lists are not supported\&. .sp The function will take a structure argument of the general form .CS typedef struct critcl_list_\&.\&.\&. { Tcl_Obj* o; int c; (Ctype)* v; } critcl_list_\&.\&.\&.; .CE .IP where \fB(Ctype)\fR represents the C type for values of type \fBtype\fR\&. .TP [N]type .TP type[N] These are \fBlist\fR types combining the elements of .CS [N] .CE .IP and .CS []type .CE .IP\&. .sp As an example, the specification of .CS int[3] a .CE .IP describes argument \fIa\fR as a list of exactly 3 elements, all of which have to be of type \fBint\fR\&. .sp Note that this example can also be written in the more C-like form of .CS int a[3] .CE .IP\&. The system will translate this internally to the first shown form\&. .TP bytes This is the \fInew\fR and usable \fBByteArray\fR type\&. .sp The function takes an argument of type \fBcritcl_bytes\fR containing the original \fBTcl_Obj*\fR reference of the Tcl argument, plus the length of the byte array and a pointer to the byte data\&. .CS typedef struct critcl_bytes { Tcl_Obj* o; const unsigned char* s; int len; } critcl_list; .CE .IP The Tcl argument must be convertible to \fBByteArray\fR, an error is thrown otherwise\&. .sp Note the \fIconst\fR\&. The bytes are \fIread-only\fR\&. 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\&. .TP char* The function takes an argument of type \fBconst char*\fR\&. The string representation of the Tcl argument is passed in\&. .sp Note the \fIconst\fR\&. The string is \fIread-only\fR\&. 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\&. .TP double The function takes an argument of type \fBdouble\fR\&. The Tcl argument must be convertible to \fBDouble\fR, an error is thrown otherwise\&. .TP double > N .TP double >= N .TP double < N .TP double <= N These are variants of \fIdouble\fR above, restricting the argument value to the shown relation\&. An error is thrown for Tcl arguments outside of the specified range\&. .sp The limiter \fIN\fR has to be a constant floating point value\&. .sp It is possible to use multiple limiters\&. For example \fIdouble > A > B <= C\fR\&. The system will fuse them to a single upper/lower limit (or both)\&. .sp The system will reject limits describing an empty range of values, or a range containing only a single value\&. .TP float The function takes an argument of type \fBfloat\fR\&. The Tcl argument must be convertible to \fBDouble\fR, an error is thrown otherwise\&. .TP float > N .TP float >= N .TP float < N .TP float <= N These are variants of \fIfloat\fR above, restricting the argument value to the shown relation\&. An error is thrown for Tcl arguments outside of the specified range\&. .sp The limiter \fIN\fR has to be a constant floating point value\&. .sp It is possible to use multiple limiters\&. For example \fIfloat > A > B <= C\fR\&. The system will fuse them to a single upper/lower limit (or both)\&. .sp The system will reject limits describing an empty range of values, or a range containing only a single value\&. .TP boolean .TP bool The function takes an argument of type \fBint\fR\&. The Tcl argument must be convertible to \fBBoolean\fR, an error is thrown otherwise\&. .TP channel The function takes an argument of type \fBTcl_Channel\fR\&. The Tcl argument must be convertible to type \fBChannel\fR, an error is thrown otherwise\&. The channel is further assumed to be \fIalready registered\fR with the interpreter\&. .TP unshared-channel This type is an extension of \fBchannel\fR above\&. All of the information above applies\&. .sp Beyond that the channel must not be shared by multiple interpreters, an error is thrown otherwise\&. .TP take-channel This type is an extension of \fBunshared-channel\fR above\&. All of the information above applies\&. .sp Beyond that the code removes the channel from the current interpreter without closing it, and disables all pre-existing event handling for it\&. .sp 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\&. .sp 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 \fBreturn-channel\fR\&. This will undo the registration changes made by this argument type\&. \fINote\fR however that the removal of pre-existing event handling done here cannot be undone\&. .sp \fIAttention\fR 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\&. .sp 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\&. .TP int The function takes an argument of type \fBint\fR\&. The Tcl argument must be convertible to \fBInt\fR, an error is thrown otherwise\&. .TP int > N .TP int >= N .TP int < N .TP int <= N These are variants of \fIint\fR above, restricting the argument value to the shown relation\&. An error is thrown for Tcl arguments outside of the specified range\&. .sp The limiter \fIN\fR has to be a constant integer value\&. .sp It is possible to use multiple limiters\&. For example \fIint > A > B <= C\fR\&. The system will fuse them to a single upper/lower limit (or both)\&. .sp The system will reject limits describing an empty range of values, or a range containing only a single value\&. .TP long The function takes an argument of type \fBlong int\fR\&. The Tcl argument must be convertible to \fBLong\fR, an error is thrown otherwise\&. .TP long > N .TP long >= N .TP long < N .TP long <= N These are variants of \fIlong\fR above, restricting the argument value to the shown relation\&. An error is thrown for Tcl arguments outside of the specified range\&. .sp The limiter \fIN\fR has to be a constant integer value\&. .sp It is possible to use multiple limiters\&. For example \fIlong > A > B <= C\fR\&. The system will fuse them to a single upper/lower limit (or both)\&. .sp The system will reject limits describing an empty range of values, or a range containing only a single value\&. .TP wideint The function takes an argument of type \fBTcl_WideInt\fR\&. The Tcl argument must be convertible to \fBWideInt\fR, an error is thrown otherwise\&. .TP wideint > N .TP wideint >= N .TP wideint < N .TP wideint <= N These are variants of \fIwideint\fR above, restricting the argument value to the shown relation\&. An error is thrown for Tcl arguments outside of the specified range\&. .sp The limiter \fIN\fR has to be a constant integer value\&. .sp It is possible to use multiple limiters\&. For example \fIwideint > A > B <= C\fR\&. The system will fuse them to a single upper/lower limit (or both)\&. .sp The system will reject limits describing an empty range of values, or a range containing only a single value\&. .TP void* .PP .SH "STANDARD RESULT TYPES" Before going into the details first a quick overview: .CS 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 \fBint\fR above bool | | | Alias of \fBint\fR above long | long | Long | wideint | Tcl_WideInt | WideInt | double | double | Double | float | float | Double | -------------- | -------------- | --------- | ------------------------------ char* | char* | String | \fIMakes a copy\fR vstring | | | Alias of \fBchar*\fR above const char* | const char* | | Behavior of \fBchar*\fR above -------------- | -------------- | --------- | ------------------------------ string | | String | Freeable string set directly | | | \fINo copy is made\fR dstring | | | Alias of \fBstring\fR above -------------- | -------------- | --------- | ------------------------------ | | | For all below: Null is ERROR | | | Body has to set any message Tcl_Obj* | Tcl_Obj* | Any | \fIrefcount --\fR object | | | Alias of \fBTcl_Obj*\fR above Tcl_Obj*0 | | Any | \fIrefcount unchanged\fR object0 | | | Alias of \fBTcl_Obj*0\fR above -------------- | -------------- | --------- | ------------------------------ known-channel | Tcl_Channel | String | Assumes to already be registered new-channel | Tcl_Channel | String | New channel, will be registered return-channel | Tcl_Channel | String | Inversion of take-channel .CE And now the details: .TP Tcl_Obj* .TP object If the returned \fBTcl_Obj*\fR is \fBNULL\fR, the Tcl return code is \fBTCL_ERROR\fR and the function should \fIset an error mesage\fR [https://www\&.tcl-lang\&.org/man/tcl/TclLib/SetResult\&.htm] as the interpreter result\&. Otherwise, the returned \fBTcl_Obj*\fR is set as the interpreter result\&. .sp 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 \fBTcl_Interp*\fR for the details on how to make that happen\&. .sp Note further that the returned \fBTcl_Obj*\fR should have a reference count greater than \fB0\fR\&. 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 \fBTcl_Obj*\fR\&. If a \fBTcl_Obj*\fR with a reference count of \fB0\fR were returned, the reference count would become \fB1\fR when set as the interpreter result, and immediately thereafter be decremented to \fB0\fR 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\&. .TP Tcl_Obj*0 .TP object0 Like \fBTcl_Obj*\fR except that this conversion assumes that the returned value has a reference count of \fB0\fR and \fIdoes not\fR decrement it\&. Returning a value whose reference count is greater than \fB0\fR is therefore likely to cause a memory leak\&. .sp 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 \fBTcl_Interp*\fR for the details on how to make that happen\&. .TP new-channel A \fBString\fR Tcl_Obj holding the name of the returned \fBTcl_Channel\fR is set as the interpreter result\&. The channel is further assumed to be \fInew\fR, and therefore registered with the interpreter to make it known\&. .TP known-channel A \fBString\fR Tcl_Obj holding the name of the returned \fBTcl_Channel\fR is set as the interpreter result\&. The channel is further assumed to be \fIalready registered\fR with the interpreter\&. .TP return-channel This type is a variant of \fBnew-channel\fR above\&. It varies slightly from it in the registration sequence to be properly complementary to the argument type \fBtake-channel\fR\&. A \fBString\fR Tcl_Obj holding the name of the returned \fBTcl_Channel\fR is set as the interpreter result\&. The channel is further assumed to be \fInew\fR, and therefore registered with the interpreter to make it known\&. .TP char* .TP vstring A \fBString\fR Tcl_Obj holding a \fIcopy\fR of the returned \fBchar*\fR 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\&. .TP const char* Like \fBchar*\fR above, except that the returned string is \fBconst\fR-qualified\&. .TP string .TP dstring The returned \fBchar*\fR is directly set as the interpreter result \fIwithout making a copy\fR\&. Therefore it must be dynamically allocated via \fBTcl_Alloc\fR\&. Release happens automatically when the Interpreter finds that the value is not required any longer\&. .TP double .TP float The returned \fBdouble\fR or \fBfloat\fR is converted to a \fBDouble\fR Tcl_Obj and set as the interpreter result\&. .TP boolean .TP bool The returned \fBint\fR value is converted to an \fBInt\fR Tcl_Obj and set as the interpreter result\&. .TP int The returned \fBint\fR value is converted to an \fBInt\fR Tcl_Obj and set as the interpreter result\&. .TP long The returned \fBlong int\fR value is converted to a \fBLong\fR Tcl_Obj and set as the interpreter result\&. .TP wideint The returned \fBTcl_WideInt\fR value is converted to a \fBWideInt\fR Tcl_Obj and set as the interpreter result\&. .TP ok The returned \fBint\fR 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 \fBTcl_Interp*\fR for the details on how to make that happen\&. .TP void The function does not return a value\&. The interpreter result is left untouched and can be set by the function if desired\&. .PP .SH "ADVANCED: ADDING TYPES" While the \fBcritcl::cproc\fR command understands the most common C types (as per the previous 2 sections), sometimes this is not enough\&. .PP To get around this limitation the commands in this section enable users of \fBcritcl\fR to extend the set of argument and result types understood by \fBcritcl::cproc\fR\&. In other words, they allow them to define their own, custom, types\&. .TP \fB::critcl::has-resulttype\fR \fIname\fR This command tests if the named result-type is known or not\&. It returns a boolean value, \fBtrue\fR if the type is known and \fBfalse\fR otherwise\&. .TP \fB::critcl::resulttype\fR \fIname\fR \fIbody\fR ?\fIctype\fR? This command defines the result type \fIname\fR, and associates it with the C code doing the conversion (\fIbody\fR) from C to Tcl\&. The C return type of the associated function, also the C type of the result variable, is \fIctype\fR\&. This type defaults to \fIname\fR if it is not specified\&. .sp If \fIname\fR is already declared an error is thrown\&. \fIAttention!\fR The standard result type \fBvoid\fR is special as it has no accompanying result variable\&. This cannot be expressed by this extension command\&. .sp The \fIbody\fR'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\&. .sp The C code of \fIbody\fR is guaranteed to be called last in the wrapper around the actual implementation of the \fBcproc\fR in question and has access to the following environment: .RS .TP \fBinterp\fR A Tcl_Interp* typed C variable referencing the interpreter the result has to be stored into\&. .TP \fBrv\fR The C variable holding the result to convert, of type \fIctype\fR\&. .RE .IP As examples here are the definitions of two standard result types: .CS resulttype int { Tcl_SetObjResult(interp, Tcl_NewIntObj(rv)); return TCL_OK; } resulttype ok { /* interp result must be set by cproc body */ return rv; } int .CE .TP \fB::critcl::resulttype\fR \fIname\fR \fB=\fR \fIorigname\fR This form of the \fBresulttype\fR command declares \fIname\fR as an alias of result type \fIorigname\fR, which has to be defined already\&. If this is not the case an error is thrown\&. .TP \fB::critcl::has-argtype\fR \fIname\fR This command tests if the named argument-type is known or not\&. It returns a boolean value, \fBtrue\fR if the type is known and \fBfalse\fR otherwise\&. .TP \fB::critcl::argtype\fR \fIname\fR \fIbody\fR ?\fIctype\fR? ?\fIctypefun\fR? This command defines the argument type \fIname\fR, and associates it with the C code doing the conversion (\fIbody\fR) from Tcl to C\&. \fIctype\fR is the C type of the variable to hold the conversion result and \fIctypefun\fR is the type of the function argument itself\&. Both types default to \fIname\fR if they are the empty string or are not provided\&. .sp If \fIname\fR is already declared an error is thrown\&. .sp \fIbody\fR 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\&. .sp \fIbody\fR is called inside its own code block to isolate local variables, and the following items are in scope: .RS .TP \fBinterp\fR A variable of type \fBTcl_Interp*\fR which is the interpreter the code is running in\&. .TP \fB@@\fR A placeholder for an expression that evaluates to the \fBTcl_Obj*\fR to convert\&. .TP \fB@A\fR A placeholder for the name of the variable to store the converted argument into\&. .RE .IP As examples, here are the definitions of two standard argument types: .CS 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; } .CE .TP \fB::critcl::argtype\fR \fIname\fR \fB=\fR \fIorigname\fR This form of the \fBargtype\fR command declares \fIname\fR as an alias of argument type \fIorigname\fR, which has to be defined already\&. If this is not the case an error is thrown\&. .TP \fB::critcl::argtypesupport\fR \fIname\fR \fIcode\fR ?\fIguard\fR? This command defines a C code fragment for the already defined argument type \fIname\fR 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 \fIname\fR, but can also be set explicitly, via \fIguard\fR\&. This latter allows different custom types to share a common support structure without having to perform their own guarding\&. .TP \fB::critcl::argtyperelease\fR \fIname\fR \fIcode\fR This command defines a C code fragment for the already defined argument type \fIname\fR which is inserted whenever the worker function of a \fBcritcl::cproc\fR returns to the shim\&. It is the responsibility of this fragment to unconditionally release any resources the \fBcritcl::argtype\fR conversion code allocated\&. An example of this are the \fIvariadic\fR types for the support of the special, variadic \fIargs\fR argument to \fBcritcl::cproc\fR'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\&. .PP .SH EXAMPLES The examples shown here have been drawn from the section "Embedding C" in the document about \fIUsing CriTcl\fR\&. Please see that document for many more examples\&. .SS "A SIMPLE PROCEDURE" Starting simple, let us assume that the Tcl code in question is something like .CS proc math {x y z} { return [expr {(sin($x)*rand())/$y**log($z)}] } .CE with the expression pretending to be something very complex and slow\&. Converting this to C we get: .CS critcl::cproc math {double x double y double z} double { double up = rand () * sin (x); double down = pow(y, log (z)); return up/down; } .CE Notable about this translation: .IP [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\&. .IP [2] We now also have to declare the type of the result, here "double", again\&. .IP [3] The reference manpage lists all the legal C types supported as arguments and results\&. .PP .PP While the above example was based on type \fBdouble\fR for both arguments and result we have a number of additional types in the same category, i\&.e\&. simple types\&. These are: .CS CriTcl type | C type | Tcl type | Notes ----------- | -------------- | --------- | ------------------------------ bool | | | Alias of \fBboolean\fR below boolean | int | Boolean | double | double | Double | float | float | Double | int | int | Int | long | long | Long | wideint | Tcl_WideInt | WideInt | .CE .PP A slightly advanced form of these simple types are a limited set of constraints on the argument value\&. Note that \fBbool\fR and alias do not support this\&. .CS critcl::cproc sqrt {{double >= 0} x} double { return sqrt(x); } .CE .PP In the example above CriTcl's argument handling will reject calling the command with a negative number, without ever invoking the C code\&. .PP These constraints are called \fIlimited\fR because only \fB0\fR and \fB1\fR can be used as the borders, although all the operators \fB<\fR, \fB<=\fR, \fB>\fR, and \fB>=\fR are possible\&. It is also not possible to combine restrictions\&. .SS "MORE BUILTIN TYPES: STRINGS" .PP Given that "Everything is a String" is a slogan of Tcl the ability of \fBcproc\fRs to receive strings as arguments, and return them as results is quite important\&. .PP We actually have a variety of builtin string types, all alike, yet different\&. .PP For arguments we have: .CS CriTcl type | C type | Tcl type | Notes ----------- | -------------- | --------- | ------------------------------ char* | const char* | Any | \fIRead-only\fR, \fIstring rep\fR pstring | critcl_pstring | Any | \fIRead-only\fR bytes | critcl_bytes | ByteArray | \fIRead-only\fR .CE In C .CS critcl::cproc takeStrings { char* cstring pstring pstring bytes barray } void { printf ("len %d = %s\\n", strlen(cstring), cstring); printf ("len %d = %s\\n", pstring\&.len, pstring\&.s); printf ("len %d = %s\\n", barray\&.len, barray\&.s); return; // void result, no result } .CE Notable about the above: .IP [1] The \fBcstring\fR is a plain \fBconst char*\fR\&. It \fIpoints directly\fR into the \fBTcl_Obj*\fR holding the argument in the script\&. .IP [2] The \fBpstring\fR is a slight extension to that\&. The value is actually a structure containing the string pointer like \fBcstring\fR (field \fB\&.s\fR), the length of the string (field \fB\&.len\fR), and a pointer to the \fBTcl_Obj*\fR these came from\&. .IP [3] The last, \fBbarray\fR is like \fBpstring\fR, however it has ensured that the \fBTcl_Obj*\fR is a Tcl ByteArray, i\&.e\&. binary data\&. .PP .PP Treat all of them as \fIRead Only\fR\&. Do not modify ever\&. .PP On the other side, string results, we have: .CS CriTcl type | C type | Tcl type | Notes ------------- | -------------- | --------- | ------------------------------ char* | char* | String | \fIMakes a copy\fR vstring | | | Alias of \fBchar*\fR above const char* | const char* | | Behavior of \fBchar*\fR above ------------- | -------------- | --------- | ------------------------------ string | char* | String | Freeable string set directly | | | \fINo copy is made\fR dstring | | | Alias of \fBstring\fR above .CE .CS critcl::cproc returnCString {} char* { return "a string"; } critcl::cproc returnString {} string { char* str = Tcl_Alloc (200); sprintf (str, "hello world"); return str; } .CE Notable about the above: .IP [1] The type \fBchar*\fR is best used for static strings, or strings in some kind fixed buffer\&. .sp CriTcl's translation layer makes a copy of it for the result of the command\&. While it is possible to return heap-allocated strings it is the C code who is responsible for freeing such at some point\&. If that is not done they will leak\&. .IP [2] The type \fBstring\fR on the other hand is exactly for returning strings allocated with \fBTcl_Alloc\fR and associates\&. .sp For these the translation layer makes no copy at all, and sets them directly as the result of the command\&. A \fIvery important effect\fR of this is that the ownership of the string pointer moves from the function to Tcl\&. .sp \fITcl\fR will release the allocated memory when it does not need it any longer\&. The C code has no say in that\&. .PP .SS "CUSTOM TYPES, INTRODUCTION" When writing bindings to external libraries \fBcritcl::cproc\fR 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\&. .PP The critcl commands \fBargtype\fR, \fBresulttype\fR and their adjuncts are provided to help here, by allowing a developer to extend critcl's type system with custom conversions\&. .PP This and the three following sections will demonstrate this, from trivial to complex\&. .PP 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\&. .PP Our example is pulled from an incomplete project of mine, a binding to \fIJeffrey Kegler\fR's \fIlibmarpa\fR library managing Earley parsers\&. Several custom types simply reflect the typedef's done by the library, to make the \fBcritcl::cproc\fRs as self-documenting as the underlying library functions themselves\&. .CS 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); } \&.\&.\&. .CE .SS "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\&. .PP The first example is taken from the \fBtclyaml\fR package, a binding to the \fBlibyaml\fR library\&. In a few places we have to map readable names for block styles, scalar styles, etc\&. to the internal enumeration\&. .CS 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: seq_start