##******************************************************** ## Name: stdout ## ## Description: ## ## Switch stdout handling by puts command from the usual ## behaviour to a state where stdout is redefined to be ## another file. ## ## Native puts command error handling is unimpaired and ## a dangling filehandle is never generated. ## ## ## Calling convention: ## ## stdout off - redirects stdout to nowhere ## ## stdout off /tmp/foo - redirects stdout to /tmp/foo ## ## stdout on - restores normal behaviour ## ## ## by: Phil Ehrens for the LIGO Lab at Caltech 09/02 ## valuable contributions by: Bruce Hartweg ##******************************************************** proc stdout { switch { file "" } } { if { ! [ llength [ info command __puts ] ] && \ [ string equal off $switch ] } { rename puts __puts if { [ string length $file ] } { eval [ subst -nocommands {proc puts { args } { set fid [ open $file a+ ] if { [ llength \$args ] > 1 && \ [ lsearch \$args stdout ] == 0 } { set args [ lreplace \$args 0 0 \$fid ] } elseif { [ llength \$args ] == 1 } { set args [ list \$fid \$args ] } if { [ catch { eval __puts \$args } err ] } { close \$fid return -code error \$err } close \$fid }} ] } else { eval [ subst -nocommands {proc puts { args } { if { [ llength \$args ] > 1 && \ [ lsearch \$args stdout ] == 0 || \ [ llength \$args ] == 1 } { # no-op } else { eval __puts \$args } }} ] } } elseif { [ llength [ info command __puts ] ] && \ [ string equal on $switch ] } { rename puts {} rename __puts puts } } ---- [BBH] To make it platform agnostic without a big switch, instead of redirecting to /dev/null, just make a puts to stdout be a complete no-op when it is turned off. ---- Well, the idea is that people will specify a file to redirect to, but you're right, it should just do nothing if no file is specified, so now it does ''';^)''' --- On a related note we use the following command to redirect any command producing stdout output to a tcl variable. It works by redirecting to a temporary file, although to do this it uses several UNIX specific calls though. (Actually we used to use this, but now we have no real need for it so it hasn't been tested it a while.) #include #include #include #include #include #include "os.h" #include "capture.h" #include "misc.h" int tcl_capture(ClientData clientData, Tcl_Interp *interp, int argc, char **argv) { int old_stdout; static int fd = 0; char *buf; struct stat statbuf; char *tmpfile; int result; if (argc != 2 && argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " command ?varName?\"", NULL); return TCL_ERROR; } /* File descriptor mangling */ if (!fd) { tmpfile = tmpnam(NULL); fd = open(tmpfile, O_RDWR|O_CREAT|O_TRUNC, 0666); } else { lseek(fd, 0, SEEK_SET); } old_stdout = dup(1); close(1); dup2(fd, 1); /* Run the command */ result = Tcl_Eval(interp, argv[1]); /* Reset file descriptors */ dup2(old_stdout, 1); close(old_stdout); /* Reload the output */ fstat(fd, &statbuf); if (NULL == (buf = (char *)xmalloc(statbuf.st_size+1))) return TCL_ERROR; lseek(fd, 0, SEEK_SET); read(fd, buf, statbuf.st_size); buf[statbuf.st_size]=0; /* Return it to Tcl */ if (argc == 3) { Tcl_ResetResult(interp); sprintf(interp->result, "%d", result); return Tcl_SetVar(interp, argv[2], buf, 0) ? TCL_OK : TCL_ERROR; } else { Tcl_SetResult(interp, buf, TCL_DYNAMIC); } return TCL_OK; } [James Bonfield]