Version 30 of Extending chan

Updated 2007-05-06 13:32:18 by MJ

MJ - With the use of namespace ensembles to create newer Tcl core commands (e.g. chan) it's very straightforward to extend core commands with your own functionallity. One way is to change the Tcl core as described in chan mode.

A better way that allows to achieve this is to write an extension adding the functionallity. For instance we can extend the Tcl chan command to have a new subcommand chan mode that returns a list of the mode of a file handle (r for readable, w for writeable) with the small extension below.

To register the new subcommand in the namespace ensemble the ensemble map needs to be updated (as described by NEM at the chan mode page)

examples

 % package require chanmode
 0.1
 % chan mode stderr
 w
 % chan mode stdin
 r
 % set f [open c:/temp.txt w+]
 filee1f908
 % chan mode $f
 r w

pkgIndex.tcl

 package ifneeded chanmode 0.1 \
 [list source [file dirname [info script]]/chanmode.tcl]

chanmode.tcl

 load [file dirname [info script]]/chanmode0.1[info sharedlibextension]
 set map [namespace ensemble configure ::chan -map]
 dict set map mode ::chanmode::mode
 namespace ensemble configure ::chan -map $map

chanmode.c

 #include <tcl.h>
 #include <stdio.h>
  int
  Chanmode_ModeObjCmd(
     ClientData dummy,           /* Not used. */
     Tcl_Interp *interp,         /* Current interpreter. */
     int objc,                   /* Number of arguments. */
     Tcl_Obj *const objv[])      /* Argument objects. */
  {
     Tcl_Channel chan;           /* The channel to puts on. */
     const char *channelId; /* Name of channel for puts. */
     int mode;                   /* Mode in which channel is opened. */

     if (objc != 2) {
         Tcl_WrongNumArgs(interp, 1, objv, "channelId");
         return TCL_ERROR;
     }

     channelId = Tcl_GetString(objv[1]);

     chan = Tcl_GetChannel(interp, channelId, &mode);
     if (chan == (Tcl_Channel) NULL) {
         return TCL_ERROR;
     }

     if ((mode & TCL_READABLE) != 0) {
         Tcl_AppendElement(interp, "r");
     }

     if ((mode & TCL_WRITABLE) != 0) {
         Tcl_AppendElement(interp, "w");
     }

     return TCL_OK;

  }

 int DLLEXPORT
 Chanmode_Init(Tcl_Interp *interp)
 {
   if (Tcl_InitStubs(interp, "8.5", 0) == 0L) {
     return TCL_ERROR;
   }
   Tcl_CreateObjCommand(interp, "chanmode::mode", Chanmode_ModeObjCmd, NULL, NULL);
   Tcl_PkgProvide(interp, "chanmode", "0.1");
   return TCL_OK;
 }

[ Category Example|Category Channel ]