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.
% 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
package ifneeded chanmode 0.1 \ [list source [file join [file dirname [info script]] 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
#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; }