Revision: 5642 http://jnode.svn.sourceforge.net/jnode/?rev=5642&view=rev Author: fduminy Date: 2009-08-15 09:24:53 +0000 (Sat, 15 Aug 2009)
Log Message: ----------- committed patch from zephyr (http://www.jnode.org/user/9083) for the 'tee' command (http://www.jnode.org/node/3061) Modified Paths: -------------- trunk/cli/descriptors/org.jnode.command.file.xml trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml Added Paths: ----------- trunk/cli/src/commands/org/jnode/command/file/TeeCommand.java trunk/cli/src/test/org/jnode/test/command/file/tee-command-tests.xml Modified: trunk/cli/descriptors/org.jnode.command.file.xml =================================================================== --- trunk/cli/descriptors/org.jnode.command.file.xml 2009-08-14 16:59:45 UTC (rev 5641) +++ trunk/cli/descriptors/org.jnode.command.file.xml 2009-08-15 09:24:53 UTC (rev 5642) @@ -44,6 +44,7 @@ <alias name="rm" class="org.jnode.command.file.DeleteCommand"/> <alias name="sort" class="org.jnode.command.file.SortCommand"/> <alias name="tail" class="org.jnode.command.file.TailCommand"/> + <alias name="tee" class="org.jnode.command.file.TeeCommand"/> <alias name="touch" class="org.jnode.command.file.TouchCommand"/> <alias name="wc" class="org.jnode.command.file.WcCommand"/> </extension> @@ -351,6 +352,16 @@ </repeat> </sequence> </syntax> + <syntax alias="tee"> + <sequence> + <optionSet label="globals"> + <option argLabel="append" shortName="a" longName="append"/> + </optionSet> + <repeat> + <argument argLabel="files"/> + </repeat> + </sequence> + </syntax> <syntax alias="touch"> <argument argLabel="file" description="touch the given file"/> </syntax> Added: trunk/cli/src/commands/org/jnode/command/file/TeeCommand.java =================================================================== --- trunk/cli/src/commands/org/jnode/command/file/TeeCommand.java (rev 0) +++ trunk/cli/src/commands/org/jnode/command/file/TeeCommand.java 2009-08-15 09:24:53 UTC (rev 5642) @@ -0,0 +1,170 @@ +/* + * $Id$ + * + * Copyright (C) 2003-2009 JNode.org + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +package org.jnode.command.file; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.jnode.command.util.IOUtils; +import org.jnode.shell.AbstractCommand; +import org.jnode.shell.syntax.Argument; +import org.jnode.shell.syntax.FileArgument; +import org.jnode.shell.syntax.FlagArgument; + +/** + * Copy standard input to standard output, making a copy in zero or more files.<br> + * Implementation based on: + * http://www.opengroup.org/onlinepubs/9699919799/utilities/tee.html. + */ +public class TeeCommand extends AbstractCommand { + + /** Help text for the parameter. */ + private static final String HELP_FILE = "One or more files that will receive the \"tee-d\" output"; + + /** Help text for the append switch. */ + private static final String HELP_APPEND = "Append to the given FILEs, do not overwrite"; + + /** Help text for the command. */ + private static final String HELP_SUPER = "Copy standard input to each FILE, and also to standard outputd"; + + /** The file argument. */ + private final FileArgument argFile; + + /** The append switch. */ + private final FlagArgument argAppend; + + /** The standard input. */ + private InputStream stdin; + + /** The standard output. */ + private OutputStream stdout; + + /** The files that will receive the output. */ + private File[] files; + + /** The return code of the command. */ + private int returnCode = 0; + + /** Flag to indicate if the files should be appended. */ + private boolean appendFiles; + + /** + * In the documentation it is stated that a minimum of 13 files must be + * supported. Limit the command to only accept a maximum of 13 files to + * limit resource usage. + */ + private static final int MAX_NUMBER_OF_FILES = 13; + + /** Buffer used in stream copies. */ + private static final int BUFFER_SIZE = 8192; + + /** + * Default constructor. + */ + public TeeCommand() { + super(HELP_SUPER); + int fileFlags = Argument.MULTIPLE; + argFile = new FileArgument("files", fileFlags, HELP_FILE); + argAppend = new FlagArgument("append", 0, HELP_APPEND); + registerArguments(argFile, argAppend); + } + + /** + * Used to run this command independently. + * + * @param args the arguments passed to the command + * @throws Exception if an error occurs + */ + public static void main(String[] args) throws Exception { + new TeeCommand().execute(args); + } + + @Override + public void execute() throws IOException { + OutputStream out = null; + byte[] buffer = new byte[BUFFER_SIZE]; + + stdin = getInput().getInputStream(); + stdout = getOutput().getOutputStream(); + + // Parse the command arguments + files = argFile.getValues(); + + if (files == null || files.length == 0) { + // The command is simply ignored if there are no files + // Just copy the input to the output and return + IOUtils.copyStream(stdin, stdout, buffer); + exit(returnCode); + } + + if (argAppend.isSet()) { + appendFiles = true; + } + + // A maximum of MAX_NUMBER_OF_FILES will be used + int numberOfFiles = files.length > MAX_NUMBER_OF_FILES ? MAX_NUMBER_OF_FILES : files.length; + + int successfullOpenFiles = 0; + + // Create an array to hold all output files + OutputStream[] outFiles = new OutputStream[numberOfFiles]; + + try { + // Open all output files + for (int i = 0; i < numberOfFiles; i++) { + if ((out = IOUtils.openOutputstream(files[i], appendFiles)) != null) { + outFiles[successfullOpenFiles++] = out; + } + } + + int count = 0; + do { + count = stdin.read(buffer); + for (int i = 0; i < successfullOpenFiles; i++) { + try { + outFiles[i].write(buffer, 0, count); + } catch (IOException e) { + // Only the return code is updated + returnCode++; + } + + } + stdout.write(buffer, 0, count); + } while (!(count < BUFFER_SIZE)); + + } finally { + // Close all open output files + for (int i = 0; i < successfullOpenFiles; i++) { + try { + outFiles[i].close(); + } catch (IOException e) { + // Nothing to do in this case + // Just continue closing the files + } + } + } + + // Returns the code + exit(returnCode); + } +} Modified: trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml =================================================================== --- trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml 2009-08-14 16:59:45 UTC (rev 5641) +++ trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml 2009-08-15 09:24:53 UTC (rev 5642) @@ -6,5 +6,6 @@ <include setName="paste-command-tests.xml"/> <include setName="sort-command-tests.xml"/> <include setName="tail-command-tests.xml"/> + <include setName="tee-command-tests.xml"/> <include setName="wc-command-tests.xml"/> </testSet> Added: trunk/cli/src/test/org/jnode/test/command/file/tee-command-tests.xml =================================================================== --- trunk/cli/src/test/org/jnode/test/command/file/tee-command-tests.xml (rev 0) +++ trunk/cli/src/test/org/jnode/test/command/file/tee-command-tests.xml 2009-08-15 09:24:53 UTC (rev 5642) @@ -0,0 +1,255 @@ +<testSet title="tee command tests"> + <plugin id="org.jnode.command.file"/> + <plugin id="org.jnode.shell.bjorne" class="org.jnode.test.shell.bjorne.BjornePseudoPlugin"/> + <testSpec title="no file" command="tee" runMode="AS_ALIAS" rc="0"> + <input>1234 +</input> + <output>1234 +</output> + </testSpec> + <testSpec title="single-file" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee @TEMP_DIR@/out + </script> + <file name="out" input="false">1234 +</file> + <output>1234 +</output> + </testSpec> + <testSpec title="max-files" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee @TEMP_DIR@/out @TEMP_DIR@/out_1 @TEMP_DIR@/out_2 @TEMP_DIR@/out_3 @TEMP_DIR@/out_4 @TEMP_DIR@/out_5 @TEMP_DIR@/out_6 @TEMP_DIR@/out_7 @TEMP_DIR@/out_8 @TEMP_DIR@/out_9 @TEMP_DIR@/out_10 @TEMP_DIR@/out_11 @TEMP_DIR@/out_12 + </script> + <file name="out" input="false">1234 +</file> + <file name="out_1" input="false">1234 +</file> + <file name="out_2" input="false">1234 +</file> + <file name="out_3" input="false">1234 +</file> + <file name="out_4" input="false">1234 +</file> + <file name="out_5" input="false">1234 +</file> + <file name="out_6" input="false">1234 +</file> + <file name="out_7" input="false">1234 +</file> + <file name="out_8" input="false">1234 +</file> + <file name="out_9" input="false">1234 +</file> + <file name="out_10" input="false">1234 +</file> + <file name="out_11" input="false">1234 +</file> + <file name="out_12" input="false">1234 +</file> + <output>1234 +</output> + </testSpec> + <testSpec title="more-then-max-files" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee @TEMP_DIR@/out @TEMP_DIR@/out_1 @TEMP_DIR@/out_2 @TEMP_DIR@/out_3 @TEMP_DIR@/out_4 @TEMP_DIR@/out_5 @TEMP_DIR@/out_6 @TEMP_DIR@/out_7 @TEMP_DIR@/out_8 @TEMP_DIR@/out_9 @TEMP_DIR@/out_10 @TEMP_DIR@/out_11 @TEMP_DIR@/out_12 @TEMP_DIR@/out_13 + </script> + <file name="out" input="false">1234 +</file> + <file name="out_1" input="false">1234 +</file> + <file name="out_2" input="false">1234 +</file> + <file name="out_3" input="false">1234 +</file> + <file name="out_4" input="false">1234 +</file> + <file name="out_5" input="false">1234 +</file> + <file name="out_6" input="false">1234 +</file> + <file name="out_7" input="false">1234 +</file> + <file name="out_8" input="false">1234 +</file> + <file name="out_9" input="false">1234 +</file> + <file name="out_10" input="false">1234 +</file> + <file name="out_11" input="false">1234 +</file> + <file name="out_12" input="false">1234 +</file> + <output>1234 +</output> + </testSpec> + + + <testSpec title="append-single-file" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee -a @TEMP_DIR@/out + </script> + <file name="out" input="true">Already in File out +</file> + <file name="out" input="false">Already in File out +1234 +</file> + <output>1234 +</output> + </testSpec> + <testSpec title="append-max-files" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee -a @TEMP_DIR@/out @TEMP_DIR@/out_1 @TEMP_DIR@/out_2 @TEMP_DIR@/out_3 @TEMP_DIR@/out_4 @TEMP_DIR@/out_5 @TEMP_DIR@/out_6 @TEMP_DIR@/out_7 @TEMP_DIR@/out_8 @TEMP_DIR@/out_9 @TEMP_DIR@/out_10 @TEMP_DIR@/out_11 @TEMP_DIR@/out_12 + </script> + + <!-- Exiting files --> + <file name="out" input="true">Already in File out +</file> + <file name="out_1" input="true">Already in File out_1 +</file> + <file name="out_2" input="true">Already in File out_2 +</file> + <file name="out_3" input="true">Already in File out_3 +</file> + <file name="out_4" input="true">Already in File out_4 +</file> + <file name="out_5" input="true">Already in File out_5 +</file> + <file name="out_6" input="true">Already in File out_6 +</file> + <file name="out_7" input="true">Already in File out_7 +</file> + <file name="out_8" input="true">Already in File out_8 +</file> + <file name="out_9" input="true">Already in File out_9 +</file> + <file name="out_10" input="true">Already in File out_10 +</file> + <file name="out_11" input="true">Already in File out_11 +</file> + <file name="out_12" input="true">Already in File out_12 +</file> + + <!-- Output files --> + <file name="out" input="false">Already in File out +1234 +</file> + <file name="out_1" input="false">Already in File out_1 +1234 +</file> + <file name="out_2" input="false">Already in File out_2 +1234 +</file> + <file name="out_3" input="false">Already in File out_3 +1234 +</file> + <file name="out_4" input="false">Already in File out_4 +1234 +</file> + <file name="out_5" input="false">Already in File out_5 +1234 +</file> + <file name="out_6" input="false">Already in File out_6 +1234 +</file> + <file name="out_7" input="false">Already in File out_7 +1234 +</file> + <file name="out_8" input="false">Already in File out_8 +1234 +</file> + <file name="out_9" input="false">Already in File out_9 +1234 +</file> + <file name="out_10" input="false">Already in File out_10 +1234 +</file> + <file name="out_11" input="false">Already in File out_11 +1234 +</file> + <file name="out_12" input="false">Already in File out_12 +1234 +</file> + <output>1234 +</output> + </testSpec> + <testSpec title="append-more-than-max-files" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + echo 1234 | tee -a @TEMP_DIR@/out @TEMP_DIR@/out_1 @TEMP_DIR@/out_2 @TEMP_DIR@/out_3 @TEMP_DIR@/out_4 @TEMP_DIR@/out_5 @TEMP_DIR@/out_6 @TEMP_DIR@/out_7 @TEMP_DIR@/out_8 @TEMP_DIR@/out_9 @TEMP_DIR@/out_10 @TEMP_DIR@/out_11 @TEMP_DIR@/out_12 @TEMP_DIR@/out_13 + </script> + + <!-- Exiting files --> + <file name="out" input="true">Already in File out +</file> + <file name="out_1" input="true">Already in File out_1 +</file> + <file name="out_2" input="true">Already in File out_2 +</file> + <file name="out_3" input="true">Already in File out_3 +</file> + <file name="out_4" input="true">Already in File out_4 +</file> + <file name="out_5" input="true">Already in File out_5 +</file> + <file name="out_6" input="true">Already in File out_6 +</file> + <file name="out_7" input="true">Already in File out_7 +</file> + <file name="out_8" input="true">Already in File out_8 +</file> + <file name="out_9" input="true">Already in File out_9 +</file> + <file name="out_10" input="true">Already in File out_10 +</file> + <file name="out_11" input="true">Already in File out_11 +</file> + <file name="out_12" input="true">Already in File out_12 +</file> + <file name="out_13" input="true">Already in File out_13 +</file> + + <!-- Output files --> + <file name="out" input="false">Already in File out +1234 +</file> + <file name="out_1" input="false">Already in File out_1 +1234 +</file> + <file name="out_2" input="false">Already in File out_2 +1234 +</file> + <file name="out_3" input="false">Already in File out_3 +1234 +</file> + <file name="out_4" input="false">Already in File out_4 +1234 +</file> + <file name="out_5" input="false">Already in File out_5 +1234 +</file> + <file name="out_6" input="false">Already in File out_6 +1234 +</file> + <file name="out_7" input="false">Already in File out_7 +1234 +</file> + <file name="out_8" input="false">Already in File out_8 +1234 +</file> + <file name="out_9" input="false">Already in File out_9 +1234 +</file> + <file name="out_10" input="false">Already in File out_10 +1234 +</file> + <file name="out_11" input="false">Already in File out_11 +1234 +</file> + <file name="out_12" input="false">Already in File out_12 +1234 +</file> + <file name="out_13" input="false">Already in File out_13 +</file> + <output>1234 +</output> + </testSpec> +</testSet> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ Let Crystal Reports handle the reporting - Free Crystal Reports 2008 30-Day trial. Simplify your report design, integration and deployment - and focus on what you do best, core application coding. Discover what's new with Crystal Reports now. http://p.sf.net/sfu/bobj-july _______________________________________________ Jnode-svn-commits mailing list Jnode-svn-commits@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/jnode-svn-commits