chan mode

MJ: 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 writable) with the small extension below.

To register the new subcommand in the namespace ensemble the ensemble map needs to be updated.

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 join [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) {
       Tcl_AppendElement(interp, "r");
   }

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

   return TCL_OK;
}

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