Executable Modules provide additional functionality to a Tcl interpreter by means of a command that, when called, communicates with an external program and then returns a result.
With executable modules, the Tcl C API is not used. The external program component of an executable module can be implemented in any language. Sometimes preexisting programs can be put to use in an executable model. All that is required is a procedure that manages the communication with that program. An executable module typically communicates via Tcl command channel created via open. To communicate binary data, use chan configure $comechan -translation binary. Alternatively, shared memory could be used.
Pro:
Con:
/* * By George Peter Staplin * This is version 2 of a simple executable-module written in C. * This is simply a demonstration. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <limits.h> #define SEPFMT " \t\n" void get_input (char *buf, size_t s) { if (NULL == fgets (buf, s, stdin)) { if (feof (stdin)) { exit (EXIT_SUCCESS); } exit (EXIT_FAILURE); } } int expect_int (void) { char *t = strtok (NULL, SEPFMT); char *end; long l; if (NULL == t) { fprintf (stderr, "premature end of token stream.\n"); exit (EXIT_FAILURE); } l = strtol (t, &end, 10); if ((LONG_MIN == l && ERANGE == errno) || (end < (t + (strlen (t) - 1)))) { fprintf (stderr, "invalid integer '%s'\n", t); exit (EXIT_FAILURE); } return (int) l; } int main (int argc, char *argv[]) { char buf[1024]; char *tok; again: get_input (buf, sizeof (buf)); tok = strtok (buf, SEPFMT); if (NULL == tok || 1 != strlen (tok)) { fprintf (stderr, "invalid operator: '%s'\n", tok); exit (EXIT_FAILURE); } switch (tok[0]) { case '+': printf ("%d\n", expect_int () + expect_int ()); break; case '-': { int a, b; a = expect_int (); b = expect_int (); printf ("%d\n", a - b); } break; default: fprintf (stderr, "unknown operator: '%c'\n", tok[0]); exit (EXIT_FAILURE); } goto again; return EXIT_FAILURE; }
To use the code above as a module we will use a two-way pipe. Tcl uses the | character in open to create channel between to the program. For two-way communication, use the w+ flag. gets is used to retrieve the result. read could also be used, but it would require a fixed-length format, non-blocking I/O, or a read of a single character until \n is reached.
#! /bin/env tclsh set ::mathModule [open {|./modmath} w+] proc modMath {args} { puts -nonewline "$args is " puts $::mathModule $args flush $::mathModule return [gets $::mathModule] } proc main {} { puts [modMath + 200 300] puts [modMath - 5600 1243] puts Done } main