Version 23 of Extending chan

Updated 2007-05-06 13:22:22 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 you 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 following small extension.

pkgIndex.tcl

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

chanmode.tcl

 load [file dirname [info script]]/chanmode0.1.dll
 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;
 }