--- doc/chan.n.orig 2006-10-28 22:37:48.000000000 -0600 +++ doc/chan.n 2006-10-28 22:51:33.000000000 -0600 @@ -24,6 +24,14 @@ \fIOption\fR indicates what to do with the channel; any unique abbreviation for \fIoption\fR is acceptable. Valid options are: .TP +\fBchan available \fIchannelId\fR +. +This returns the number of bytes of input currently buffered +internally for \fIchannelId\fr (especially useful in a readable event +callback to impose application-specific limits on line lengths to avoid +a potential denial-of-service attack where a hostile user crafts +an extremely long line that exceeds the available memory to buffer it). +.TP \fBchan blocked \fIchannelId\fR . This tests whether the last input operation on the channel called --- generic/tclBasic.c.orig 2006-10-28 21:55:59.000000000 -0600 +++ generic/tclBasic.c 2006-10-28 21:57:08.000000000 -0600 @@ -485,6 +485,10 @@ Tcl_CreateObjCommand(interp, "::tcl::chan::rPostevent", TclChanPostEventObjCmd, (ClientData) NULL, NULL); + /* TIP #287 */ + Tcl_CreateObjCommand(interp, "::tcl::chan::Available", + TclChanAvailableObjCmd, (ClientData) NULL, NULL); + /* * Register the built-in functions. This is empty now that they are * implemented as commands in the ::tcl::mathfunc namespace. --- generic/tclInt.h.orig 2006-10-28 22:08:38.000000000 -0600 +++ generic/tclInt.h 2006-10-28 22:09:52.000000000 -0600 @@ -2286,6 +2286,9 @@ MODULE_SCOPE int Tcl_CdObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); +MODULE_SCOPE int TclChanAvailableObjCmd( + ClientData clientData, Tcl_Interp *interp, + int objc, Tcl_Obj *CONST objv[]); MODULE_SCOPE int TclChanTruncateObjCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]); --- generic/tclIOCmd.c.orig 2006-10-28 21:58:27.000000000 -0600 +++ generic/tclIOCmd.c 2006-10-28 22:08:03.000000000 -0600 @@ -1619,6 +1619,56 @@ } /* + *--------------------------------------------------------------------------- + * + * TclChanAvailableObjCmd -- + * + * This function is invoked to process the Tcl "chan available" + * command. See the user documentation for details on what it does. + * + * Results: + * A standard Tcl result. + * + * Side effects: + * Sets interp's result to the number of bytes of input in the + * channels input buffer. + * + *--------------------------------------------------------------------------- + */ + + /* ARGSUSED */ +int +TclChanAvailableObjCmd( + ClientData unused, /* Not used. */ + Tcl_Interp *interp, /* Current interpreter. */ + int objc, /* Number of arguments. */ + Tcl_Obj *CONST objv[]) /* Argument objects. */ +{ + Tcl_Channel chan; + int mode; + char *arg; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 1, objv, "channelId"); + return TCL_ERROR; + } + + arg = Tcl_GetString(objv[1]); + chan = Tcl_GetChannel(interp, arg, &mode); + if (chan == NULL) { + return TCL_ERROR; + } + if ((mode & TCL_READABLE) == 0) { + Tcl_AppendResult(interp, "channel \"", arg, + "\" wasn't opened for reading", NULL); + return TCL_ERROR; + } + + Tcl_SetObjResult(interp, Tcl_NewIntObj(Tcl_InputBuffered(chan))); + return TCL_OK; +} + +/* *---------------------------------------------------------------------- * * Tcl_ChanTruncateObjCmd -- --- library/init.tcl.orig 2006-09-22 12:13:29.000000000 -0600 +++ library/init.tcl 2006-10-28 21:55:41.000000000 -0600 @@ -78,7 +78,9 @@ # Set up the 'chan' ensemble (TIP #208). namespace eval chan { # TIP #219. Added methods: create, postevent. + # TIP #287. Added method: available. namespace ensemble create -command ::chan -map { + available ::tcl::chan::Available blocked ::fblocked close ::close configure ::fconfigure --- tests/chan.test.orig 2006-10-29 13:59:35.000000000 -0700 +++ tests/chan.test 2006-10-29 14:22:51.000000000 -0700 @@ -24,7 +24,7 @@ } -returnCodes error -result "wrong # args: should be \"chan subcommand ?argument ...?\"" test chan-1.2 {chan command general syntax} -body { chan FOOBAR -} -returnCodes error -result "unknown or ambiguous subcommand \"FOOBAR\": must be blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate" +} -returnCodes error -result "unknown or ambiguous subcommand \"FOOBAR\": must be available, blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate" test chan-2.1 {chan command: blocked subcommand} -body { chan blocked foo bar @@ -96,6 +96,35 @@ catch {removeFile $file} } +# TIP 287: chan available +test chan-16.1 {chan command: available subcommand} -body { + chan available foo bar +} -returnCodes error -result "wrong # args: should be \"chan available channelId\"" +test chan-16.2 {chan command: available subcommand} -body { + chan available stdout +} -returnCodes error -result "channel \"stdout\" wasn't opened for reading" +test chan-16.3 {chan command: available subcommand} -body { + chan available stdin +} -result 0 +test chan-16.4 {chan command: available subcommand} -body { + chan available FOOBAR +} -returnCodes error -result "can not find channel named \"FOOBAR\"" +test chan-16.5 {chan command: available subcommand} -setup { + set file [makeFile {} testAvailable] + set f [open $file w+] + chan configure $f -translation lf -buffering line +} -body { + chan puts $f foo + chan puts $f bar + chan puts $f baz + chan seek $f 0 + chan gets $f + chan available $f +} -result 8 -cleanup { + catch {chan close $f} + catch {removeFile $file} +} + cleanupTests return --- tests/ioCmd.test.orig 2006-10-28 23:06:44.000000000 -0600 +++ tests/ioCmd.test 2006-10-28 23:09:10.000000000 -0600 @@ -628,7 +628,7 @@ test iocmd-20.1 {chan, unknown method} { catch {chan foo} msg set msg -} {unknown or ambiguous subcommand "foo": must be blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate} +} {unknown or ambiguous subcommand "foo": must be available, blocked, close, configure, copy, create, eof, event, flush, gets, names, postevent, puts, read, seek, tell, or truncate} # --- --- --- --------- --------- --------- # chan create, and method "initalize"