Version 10 of Extending chan

Updated 2007-05-06 14:52:24 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 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 access modes 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 get the mode from. */
     const char *channelId;      /* Name of channel to get the mode from. */
     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 ]