From: <chr...@us...> - 2009-05-11 22:52:47
|
Revision: 5480 http://jnode.svn.sourceforge.net/jnode/?rev=5480&view=rev Author: chrisboertien Date: 2009-05-11 22:52:39 +0000 (Mon, 11 May 2009) Log Message: ----------- Unix 'paste' command + blackbox tests Signed-off-by: chrisboertien <chr...@gm...> Modified Paths: -------------- trunk/cli/descriptors/org.jnode.command.file.xml trunk/cli/src/commands/org/jnode/command/util/IOUtils.java trunk/cli/src/test/org/jnode/test/command/argument/all-argument-tests.xml trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml Added Paths: ----------- trunk/cli/src/commands/org/jnode/command/file/PasteCommand.java trunk/cli/src/test/org/jnode/test/command/file/paste-command-tests.xml Modified: trunk/cli/descriptors/org.jnode.command.file.xml =================================================================== --- trunk/cli/descriptors/org.jnode.command.file.xml 2009-05-11 20:26:47 UTC (rev 5479) +++ trunk/cli/descriptors/org.jnode.command.file.xml 2009-05-11 22:52:39 UTC (rev 5480) @@ -38,8 +38,8 @@ <alias name="hexdump" class="org.jnode.command.file.HexdumpCommand"/> <alias name="ls" class="org.jnode.command.file.DirCommand"/> <alias name="md5sum" class="org.jnode.command.file.Md5SumCommand"/> - <!-- NoSuchAlgorithmException: md5 Message Digest not available --> <alias name="mkdir" class="org.jnode.command.file.MkdirCommand"/> + <alias name="paste" class="org.jnode.command.file.PasteCommand"/> <alias name="pwd" class="org.jnode.command.file.PwdCommand"/> <alias name="rm" class="org.jnode.command.file.DeleteCommand"/> <alias name="tail" class="org.jnode.command.file.TailCommand"/> @@ -280,6 +280,18 @@ <syntax alias="mkdir"> <argument argLabel="directory" description="create a new directory"/> </syntax> + <syntax alias="paste"> + <empty /> + <sequence> + <optionSet> + <option argLabel="serial" shortName="s" longName="serial"/> + <option argLabel="delims" shortName="d" longName="delimiters"/> + </optionSet> + <repeat> + <argument argLabel="files"/> + </repeat> + </sequence> + </syntax> <syntax alias="pwd"> <empty description="show the pathname for the current directory"/> </syntax> Added: trunk/cli/src/commands/org/jnode/command/file/PasteCommand.java =================================================================== --- trunk/cli/src/commands/org/jnode/command/file/PasteCommand.java (rev 0) +++ trunk/cli/src/commands/org/jnode/command/file/PasteCommand.java 2009-05-11 22:52:39 UTC (rev 5480) @@ -0,0 +1,191 @@ +/* + * $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.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.jnode.command.argument.NumberListArgument; +import org.jnode.command.util.IOUtils; +import org.jnode.command.util.NumberRange; +import org.jnode.shell.AbstractCommand; +import org.jnode.shell.syntax.Argument; +import org.jnode.shell.syntax.FileArgument; +import org.jnode.shell.syntax.FlagArgument; +import org.jnode.shell.syntax.StringArgument; + +/** + * Unix 'paste' command + * + * @author chris boertien + */ +public class PasteCommand extends AbstractCommand { + + private static final String help_files = "list of files to be operated on"; + private static final String help_serial = "if set, paste files one at a time, instead of in parallel"; + private static final String help_delims = "use the supplied characters as delimiters instead of <TAB>"; + private static final String help_super = "merge lines of files"; + + private final FileArgument argFiles; + private final FlagArgument argSerial; + private final StringArgument argDelims; + private PrintWriter out; + + private List<File> files; + private char[] delims; + private int delimPos; + private int rc = 0; + private boolean serial; + + public PasteCommand() { + super(help_super); + int filesFlags = Argument.MULTIPLE | Argument.EXISTING | FileArgument.HYPHEN_IS_SPECIAL; + argFiles = new FileArgument("files", filesFlags, help_files); + argSerial = new FlagArgument("serial", 0, help_serial); + argDelims = new StringArgument("delims", 0, help_delims); + registerArguments(argFiles, argSerial, argDelims); + } + + public void execute() { + out = getOutput().getPrintWriter(); + parseOptions(); + try { + if (serial) { + pasteSerial(); + } else { + pasteParallel(); + } + } finally { + exit(rc); + } + } + + private void pasteParallel() { + List<BufferedReader> readers = new ArrayList<BufferedReader>(files.size()); + List<String> names = new ArrayList<String>(files.size()); + List<String> lines = new ArrayList<String>(files.size()); + try { + for (File file : files) { + String name = file.getName(); + int i = names.indexOf(name); + if (i != -1) { + readers.add(readers.get(i)); + } else { + if (name.equals("-")) { + readers.add(IOUtils.openBufferedReader(getInput().getReader())); + } else { + readers.add(IOUtils.openBufferedReader(file)); + } + } + names.add(name); + } + while (true) { + int num = readLines(lines, readers); + if (num == 0) break; + writeLines(lines, num); + lines.clear(); + } + } finally { + for (BufferedReader reader : readers) { + IOUtils.close(reader); + } + } + } + + private void pasteSerial() { + BufferedReader reader = null; + for (File file : files) { + try { + List<String> lines = null; + if (file.getName().equals("-")) { + reader = IOUtils.openBufferedReader(getInput().getReader()); + } else { + reader = IOUtils.openBufferedReader(file); + } + if (reader != null) { + lines = IOUtils.readLines(reader); + if (lines != null) { + writeLines(lines, lines.size()); + } + } + } finally { + IOUtils.close(reader); + } + } + } + + private int readLines(List<String> lines, List<BufferedReader> readers) { + int count = 0; + String line = null; + for (BufferedReader reader : readers) { + try { + line = reader.readLine(); + } catch (IOException e) { + rc = 1; + return 0; + } + if (line != null) { + lines.add(line); + count++; + } + } + return count; + } + + private void writeLines(List<String> lines, int max) { + boolean first = true; + for (int i = 0; i < max; i++) { + if (!first) { + out.write(nextDelim()); + } + first = false; + out.write(lines.get(i)); + } + out.println(); + delimPos = 0; + } + + private char nextDelim() { + char c = delims[delimPos++]; + if (delimPos == delims.length) delimPos = 0; + return c; + } + + private void parseOptions() { + if (argFiles.isSet()) { + files = Arrays.asList(argFiles.getValues()); + } else { + files = new ArrayList(1); + files.add(new File("-")); + } + + if (argDelims.isSet()) { + delims = argDelims.getValue().toCharArray(); + } else { + delims = new char[]{'\t'}; + } + serial = argSerial.isSet(); + } +} Modified: trunk/cli/src/commands/org/jnode/command/util/IOUtils.java =================================================================== --- trunk/cli/src/commands/org/jnode/command/util/IOUtils.java 2009-05-11 20:26:47 UTC (rev 5479) +++ trunk/cli/src/commands/org/jnode/command/util/IOUtils.java 2009-05-11 22:52:39 UTC (rev 5480) @@ -298,6 +298,30 @@ } /** + * Wraps a {@code Reader} with a {@code BufferedReader}. + * + * @param reader the reader to wrap + * @return a {@code BufferedReader} + * @throws NullPointerException if reader is null + */ + public static BufferedReader openBufferedReader(Reader reader) { + return openBufferedReader(reader, BUFFER_SIZE); + } + + /** + * Wraps a {@code Reader} with a {@code BufferedReader}. + * + * @param reader the reader to wrap + * @param bufferSize the size of buffer to use + * @return a {@code BufferedReader} + * @throws NullPointerException if reader is null + */ + public static BufferedReader openBufferedReader(Reader reader, int bufferSize) { + checkNull(reader); + return new BufferedReader(reader, bufferSize); + } + + /** * Opens a LineNumberReader on a file. * * This method will not throw a FileNotFoundException like the FileReader Modified: trunk/cli/src/test/org/jnode/test/command/argument/all-argument-tests.xml =================================================================== --- trunk/cli/src/test/org/jnode/test/command/argument/all-argument-tests.xml 2009-05-11 20:26:47 UTC (rev 5479) +++ trunk/cli/src/test/org/jnode/test/command/argument/all-argument-tests.xml 2009-05-11 22:52:39 UTC (rev 5480) @@ -56,8 +56,8 @@ <output>13579 </output> </testSpec> + <testSpec title="num-list sort 2" command="cut" runMode="AS_ALIAS" rc="0"> <arg>-b</arg> - <testSpec title="num-list sort 2" command="cut" runMode="AS_ALIAS" rc="0"> <arg>6-7,5,9-10,2,3,1</arg> <input>1234567890 </input> 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-05-11 20:26:47 UTC (rev 5479) +++ trunk/cli/src/test/org/jnode/test/command/file/all-file-tests.xml 2009-05-11 22:52:39 UTC (rev 5480) @@ -1,5 +1,6 @@ <testSet title="All file command tests"> + <include setName="cut-command-tests.xml"/> + <include setName="paste-command-tests.xml"/> <include setName="wc-command-tests.xml"/> - <include setName="cut-command-tests.xml"/> </testSet> Added: trunk/cli/src/test/org/jnode/test/command/file/paste-command-tests.xml =================================================================== --- trunk/cli/src/test/org/jnode/test/command/file/paste-command-tests.xml (rev 0) +++ trunk/cli/src/test/org/jnode/test/command/file/paste-command-tests.xml 2009-05-11 22:52:39 UTC (rev 5480) @@ -0,0 +1,131 @@ +<testSet title="POSIX paste command tests"> + <plugin id="org.jnode.command.file"/> + <plugin id="org.jnode.shell.bjorne" class="org.jnode.test.shell.bjorne.BjornePseudoPlugin"/> + <testSpec title="serial stdin default-delim" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-s</arg> + <input>1 +2 +3 +4 +</input> + <output>1 2 3 4 +</output> + </testSpec> + <testSpec title="title serial stdin single-delim" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-s</arg> + <arg>-d</arg> + <arg>;</arg> + <input>1 +2 +3 +4 +</input> + <output>1;2;3;4 +</output> + </testSpec> + <testSpec title="serial stdin multi-delim 1" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-s</arg> + <arg>-d</arg> + <arg>;:,</arg> + <input>1 +2 +3 +4 +</input> + <output>1;2:3,4 +</output> + </testSpec> + <testSpec title="serial stdin multi-delim 2" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-s</arg> + <arg>-d</arg> + <arg>;:</arg> + <input>1 +2 +3 +4 +</input> + <output>1;2:3;4 +</output> + </testSpec> + <testSpec title="parallel stdin default-delim" command="paste" runMode="AS_ALIAS" rc="0"> + <input>1 +2 +3 +4 +</input> + <output>1 +2 +3 +4 +</output> + </testSpec> + <testSpec title="parallel stdin-multi single-delim" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-d</arg> + <arg>;</arg> + <arg>-</arg> + <arg>-</arg> + <input>1 +2 +3 +4 +</input> + <output>1;2 +3;4 +</output> + </testSpec> + <testSpec title="parallel stdin-multi multi-delim" command="paste" runMode="AS_ALIAS" rc="0"> + <arg>-d</arg> + <arg>;:,</arg> + <arg>-</arg> + <arg>-</arg> + <arg>-</arg> + <arg>-</arg> + <input>1 +2 +3 +4 +</input> + <output>1;2:3,4 +</output> + </testSpec> + <testSpec title="parallel file-dup sync" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + paste -d ";" @TEMP_DIR@/a @TEMP_DIR@/a + </script> + <file name="a" input="true">1 +2 +3 +4 +</file> + <output>1;2 +3;4 +</output> + </testSpec> + <testSpec title="parallel file-dup async" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + paste -d ";" @TEMP_DIR@/a @TEMP_DIR@/a @TEMP_DIR@/a + </script> + <file name="a" input="true">1 +2 +3 +4 +</file> + <output>1;2;3 +4 +</output> + </testSpec> + <testSpec title="parallel file-dup async multi-delim" command="run" runMode="AS_SCRIPT" rc="0"> + <script>#!bjorne + paste -d ";:" @TEMP_DIR@/a @TEMP_DIR@/a @TEMP_DIR@/a + </script> + <file name="a" input="true">1 +2 +3 +4 +5 +</file> + <output>1;2:3 +4;5 +</output> + </testSpec> +</testSet> This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |