|
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.
|