Thread: [tcljava-dev] PATCH: stdout flushing, mods for Swank
Brought to you by:
mdejong
From: Tom P. <tpo...@ny...> - 2002-07-01 05:00:26
|
Here's a patch that is similar in function to Shawn Boyce's recent patch, but works by only causing a flush on stdout when it is attached to a tty. Shawn's patch causes a flush for every puts on every file, which seems a little heavy handed. I modified 'jaclsh' to run the 'tty' program (on most Unix systems), which sets a property. The property is checked in the Interp() constructor. The StdChannel driver adds a flush if writing to stdout and the tty flag is set. Also, in Interp.eventuallyDispose(), all open file channels are flushed. My patch also includes the two minor fixes that are needed to run Swank in the stock Jacl interpreter, making TCL.OK and Interp.allowExceptions() public. And my jaclsh adds JACL_PROPS on the java command line to allow passing extra -Dxxxx=yyyy property values. -- Tom Poindexter tpo...@ny... http://www.nyx.net/~tpoindex/ diff -c -r tcljava.cvs/jaclsh.in tcljava.tp/jaclsh.in *** tcljava.cvs/jaclsh.in Sun Jun 30 22:24:16 2002 --- tcljava.tp/jaclsh.in Sun Jun 30 22:27:55 2002 *************** *** 30,35 **** --- 30,39 ---- # The arguments to the JAVA command JAVA_FLAGS="@JAVA_FLAGS@" + # Set jacl.tty property to 'tty' exit code, affects stdout flush behavior + tty -s >/dev/null 2>&1 + JACL_TTY="-Djacl.tty=$?" + # Run java with the args passed in from the calling environment # We must set the CLASSPATH env var instead of using the -classpath # argument because jacl might want to exec a program that also *************** *** 38,41 **** CLASSPATH=${JACL_CLASSPATH}:${CLASSPATH} export CLASSPATH ! exec ${JAVA} ${JAVA_FLAGS} tcl.lang.Shell ${1+"$@"} --- 42,45 ---- CLASSPATH=${JACL_CLASSPATH}:${CLASSPATH} export CLASSPATH ! exec ${JAVA} ${JAVA_FLAGS} ${JACL_TTY} ${JACL_PROPS} tcl.lang.Shell ${1+"$@"} diff -c -r tcljava.cvs/src/jacl/tcl/lang/Interp.java tcljava.tp/src/jacl/tcl/lang/Interp.java *** tcljava.cvs/src/jacl/tcl/lang/Interp.java Fri Apr 12 15:00:26 2002 --- tcljava.tp/src/jacl/tcl/lang/Interp.java Sun Jun 30 22:29:15 2002 *************** *** 162,167 **** --- 162,171 ---- boolean isSafe; + // Is the standard output a tty? Set via system property + + boolean isTty; + // Offset of character just after last one compiled or executed // by Parser.eval2(). *************** *** 327,332 **** --- 331,337 ---- scriptFile = null; flags = 0; isSafe = false; + isTty = false; assocData = null; *************** *** 404,409 **** --- 409,425 ---- TCL.GLOBAL_ONLY); } + // Check system property if running on a tty, so that we know to flush + // stdout output on each write. A "jacl.tty" property set to + // "0" means running stdin is a tty. + // This allows the exit code from the Unix 'tty' program to be used. + // Windows or MacOS < 10 will need to manually set the property. + String jaclTtyProp = Util.tryGetSystemProperty("jacl.tty", "1"); + if (jaclTtyProp.equals("0")) { + isTty = true; + } + + // Create the env array an populated it with proper // values. *************** *** 541,546 **** --- 557,573 ---- } } + // Flush all channels + for (Enumeration e = interpChanTable.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + Channel chan = (Channel) interpChanTable.get(key); + try { + chan.flush(this); + } catch (Exception ex) { + // Ignore flush error + } + } + // Finish deleting the global namespace. // FIXME : check impl of Tcl_DeleteNamespace *************** *** 3724,3730 **** *---------------------------------------------------------------------- */ ! void allowExceptions() { evalFlags |= Parser.TCL_ALLOW_EXCEPTIONS; --- 3751,3757 ---- *---------------------------------------------------------------------- */ ! public void allowExceptions() { evalFlags |= Parser.TCL_ALLOW_EXCEPTIONS; diff -c -r tcljava.cvs/src/jacl/tcl/lang/StdChannel.java tcljava.tp/src/jacl/tcl/lang/StdChannel.java *** tcljava.cvs/src/jacl/tcl/lang/StdChannel.java Wed Jan 23 02:53:49 2002 --- tcljava.tp/src/jacl/tcl/lang/StdChannel.java Sun Jun 30 22:29:22 2002 *************** *** 138,144 **** // The OutputStreamWriter class will buffer even if you don't // wrap it in a BufferedWriter. The stderr file object must // not require an explicit flush so we just hack a flush in. ! if (stdType == STDERR) flush(interp); } --- 138,145 ---- // The OutputStreamWriter class will buffer even if you don't // wrap it in a BufferedWriter. The stderr file object must // not require an explicit flush so we just hack a flush in. ! // Also flush if stdout and interp is connected to a tty ! if (stdType == STDERR || (stdType == STDOUT && interp.isTty)) flush(interp); } diff -c -r tcljava.cvs/src/tcljava/tcl/lang/TCL.java tcljava.tp/src/tcljava/tcl/lang/TCL.java *** tcljava.cvs/src/tcljava/tcl/lang/TCL.java Sun May 14 17:10:20 2000 --- tcljava.tp/src/tcljava/tcl/lang/TCL.java Sun Jun 30 22:30:02 2002 *************** *** 59,65 **** // the completion code TCL.OK. If the desired completion code is TCL.OK, no // exception should be thrown. ! static final int OK = 0; // The following value is used by the Interp::commandComplete(). It's used // to report that a script is not complete. --- 59,65 ---- // the completion code TCL.OK. If the desired completion code is TCL.OK, no // exception should be thrown. ! public static final int OK = 0; // The following value is used by the Interp::commandComplete(). It's used // to report that a script is not complete. |
From: Mo D. <md...@un...> - 2003-03-05 23:22:18
|
On Sun, 30 Jun 2002 23:00:21 -0600 Tom Poindexter <tpo...@ny...> wrote: > Here's a patch that is similar in function to Shawn Boyce's recent > patch, but works by only causing a flush on stdout when it is attached > to a tty. Shawn's patch causes a flush for every puts on every file, which > seems a little heavy handed. I ended up doing the following: 1. Flush stdout when in line buffering mode and a \n is the last char of the data. 2. Invoke close() for each channel when tearing down an interp. 3. Invoke flush() one last time from the close method for StdChannel 4. Remove the extra buffering for stderr and stdout The following two patches implement these changes. Index: ChangeLog =================================================================== RCS file: /cvsroot/tcljava/tcljava/ChangeLog,v retrieving revision 1.224 diff -u -r1.224 ChangeLog --- ChangeLog 14 Feb 2003 23:26:56 -0000 1.224 +++ ChangeLog 5 Mar 2003 22:54:32 -0000 @@ -1,3 +1,12 @@ +2003-03-05 Mo DeJong <md...@us...> + + * src/jacl/tcl/lang/StdChannel.java (open, write): + Avoid wrapping a buffered IO object around the + stdio and stderr streams since this was causing + problems where stdout was not being flushed. + Instead, explicitly handle flushing in the + write method. + 2003-02-14 Mo DeJong <md...@us...> * Makefile.in: Build a jar file named hello.jar Index: src/jacl/tcl/lang/StdChannel.java =================================================================== RCS file: /cvsroot/tcljava/tcljava/src/jacl/tcl/lang/StdChannel.java,v retrieving revision 1.16 diff -u -r1.16 StdChannel.java --- src/jacl/tcl/lang/StdChannel.java 23 Jan 2002 09:53:49 -0000 1.16 +++ src/jacl/tcl/lang/StdChannel.java 5 Mar 2003 22:54:32 -0000 @@ -97,19 +97,11 @@ mode = TclIO.WRONLY; setBuffering(TclIO.BUFF_LINE); setChanName("stdout"); - if (writer == null) { - writer = new BufferedWriter( - new OutputStreamWriter(System.out)); - } break; case STDERR: mode = TclIO.WRONLY; setBuffering(TclIO.BUFF_NONE); setChanName("stderr"); - if (writer == null) { - writer = new BufferedWriter( - new OutputStreamWriter(System.err)); - } break; default: throw new RuntimeException( @@ -133,13 +125,18 @@ void write(Interp interp, TclObject outData) throws IOException, TclException { - super.write(interp, outData); + checkWrite(interp); - // The OutputStreamWriter class will buffer even if you don't - // wrap it in a BufferedWriter. The stderr file object must - // not require an explicit flush so we just hack a flush in. - if (stdType == STDERR) - flush(interp); + if (stdType == STDERR) { + System.err.print(outData.toString()); + } else { + String s = outData.toString(); + System.out.print(s); + if (buffering == TclIO.BUFF_NONE || + (buffering == TclIO.BUFF_LINE && s.endsWith("\n"))) { + System.out.flush(); + } + } } String getChanType() { Index: ChangeLog =================================================================== RCS file: /cvsroot/tcljava/tcljava/ChangeLog,v retrieving revision 1.225 diff -u -r1.225 ChangeLog --- ChangeLog 5 Mar 2003 22:57:54 -0000 1.225 +++ ChangeLog 5 Mar 2003 23:18:21 -0000 @@ -1,3 +1,14 @@ +2003-03-05 Tom Poindexter <tpo...@ny...>, + Mo DeJong <md...@us...> + + * src/jacl/tcl/lang/Interp.java (eventuallyDispose): + * src/jacl/tcl/lang/StdChannel.java (close): Invoke + the close() method for any remaining channel + when the interp is being disposed of. The close + method in the StdChannel class will invoke flush + one final time for stdout in case there was output + that had not yet been flushed. + 2003-03-05 Mo DeJong <md...@us...> * src/jacl/tcl/lang/StdChannel.java (open, write): Index: src/jacl/tcl/lang/Interp.java =================================================================== RCS file: /cvsroot/tcljava/tcljava/src/jacl/tcl/lang/Interp.java,v retrieving revision 1.41 diff -u -r1.41 Interp.java --- src/jacl/tcl/lang/Interp.java 9 Jan 2003 02:15:39 -0000 1.41 +++ src/jacl/tcl/lang/Interp.java 5 Mar 2003 23:18:23 -0000 @@ -542,6 +542,18 @@ } } + // Close any remaining channels + + for (Enumeration e = interpChanTable.keys(); e.hasMoreElements();) { + Object key = e.nextElement(); + Channel chan = (Channel) interpChanTable.get(key); + try { + chan.close(); + } catch (IOException ex) { + // Ignore any IO errors + } + } + // Finish deleting the global namespace. // FIXME : check impl of Tcl_DeleteNamespace Index: src/jacl/tcl/lang/StdChannel.java =================================================================== RCS file: /cvsroot/tcljava/tcljava/src/jacl/tcl/lang/StdChannel.java,v retrieving revision 1.17 diff -u -r1.17 StdChannel.java --- src/jacl/tcl/lang/StdChannel.java 5 Mar 2003 22:57:59 -0000 1.17 +++ src/jacl/tcl/lang/StdChannel.java 5 Mar 2003 23:18:23 -0000 @@ -139,6 +139,18 @@ } } + /** + * Check for any output that might still need to be flushed + * when the channel is closed. + */ + + void close() throws IOException { + super.close(); + + if (stdType == STDOUT) + System.out.flush(); + } + String getChanType() { return "tty"; } cheers Mo DeJong |