|
From: <chr...@us...> - 2009-05-05 21:22:26
|
Revision: 5428
http://jnode.svn.sourceforge.net/jnode/?rev=5428&view=rev
Author: chrisboertien
Date: 2009-05-05 21:22:20 +0000 (Tue, 05 May 2009)
Log Message:
-----------
Unix 'cut' command
Signed-off-by: chrisboertien <chr...@gm...>
Modified Paths:
--------------
trunk/all/conf/default-plugin-list.xml
trunk/cli/descriptors/org.jnode.command.file.xml
trunk/cli/src/commands/org/jnode/command/util/IOUtils.java
Added Paths:
-----------
trunk/cli/src/commands/org/jnode/command/file/CutCommand.java
Modified: trunk/all/conf/default-plugin-list.xml
===================================================================
--- trunk/all/conf/default-plugin-list.xml 2009-05-05 21:20:25 UTC (rev 5427)
+++ trunk/all/conf/default-plugin-list.xml 2009-05-05 21:22:20 UTC (rev 5428)
@@ -50,6 +50,7 @@
<plugin id="org.jnode.awt.swingpeers"/>
<plugin id="org.apache.tools.archive" />
+ <plugin id="org.jnode.command.argument"/>
<plugin id="org.jnode.command.archive"/>
<plugin id="org.jnode.command.common"/>
<plugin id="org.jnode.command.dev"/>
Modified: trunk/cli/descriptors/org.jnode.command.file.xml
===================================================================
--- trunk/cli/descriptors/org.jnode.command.file.xml 2009-05-05 21:20:25 UTC (rev 5427)
+++ trunk/cli/descriptors/org.jnode.command.file.xml 2009-05-05 21:22:20 UTC (rev 5428)
@@ -8,6 +8,7 @@
license-name="lgpl">
<requires>
+ <import plugin="org.jnode.command.argument"/>
<import plugin="org.jnode.command.util"/>
<import plugin="org.jnode.driver"/>
<import plugin="org.jnode.fs"/>
@@ -26,6 +27,7 @@
<alias name="cat" class="org.jnode.command.file.CatCommand"/>
<alias name="cd" class="org.jnode.command.file.CdCommand" internal="yes"/>
<alias name="cp" class="org.jnode.command.file.CpCommand"/>
+ <alias name="cut" class="org.jnode.command.file.CutCommand"/>
<alias name="del" class="org.jnode.command.file.DeleteCommand"/>
<alias name="df" class="org.jnode.command.file.DFCommand"/>
<alias name="dir" class="org.jnode.command.file.DirCommand"/>
@@ -85,6 +87,22 @@
<argument argLabel="target"/>
</sequence>
</syntax>
+ <syntax alias="cut">
+ <sequence description="select parts of lines">
+ <optionSet>
+ <option argLabel="byte-range" shortName="b" longName="bytes" />
+ <option argLabel="char-range" shortName="c" longName="characters"/>
+ <option argLabel="field-range" shortName="f" longName="fields"/>
+ <option argLabel="in-delim" shortName="d" longName="delimiter"/>
+ <option argLabel="suppress" shortName="s" longName="only-delimited"/>
+ <option argLabel="complement" longName="complement"/>
+ <option argLabel="out-delim" longName="output-delimiter"/>
+ </optionSet>
+ <repeat>
+ <argument argLabel="files"/>
+ </repeat>
+ </sequence>
+ </syntax>
<syntax alias="del">
<sequence description="delete files and directories">
<optionSet>
Added: trunk/cli/src/commands/org/jnode/command/file/CutCommand.java
===================================================================
--- trunk/cli/src/commands/org/jnode/command/file/CutCommand.java (rev 0)
+++ trunk/cli/src/commands/org/jnode/command/file/CutCommand.java 2009-05-05 21:22:20 UTC (rev 5428)
@@ -0,0 +1,248 @@
+/*
+ * $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.BufferedWriter;
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+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.FileArgument;
+import org.jnode.shell.syntax.FlagArgument;
+import org.jnode.shell.syntax.StringArgument;
+
+/**
+ * Unix `cut` command
+ *
+ * TODO add --complement to select byte/chars/fields that are *not* within the given ranges
+ * TODO make byte-ranges multi-byte character friendly
+ * @author chris boertien
+ */
+public class CutCommand extends AbstractCommand {
+
+ private static final String help_byte = "Select only the listed bytes";
+ private static final String help_char = "Select only the listed chars";
+ private static final String help_field = "Select only the listed fields";
+ private static final String help_in_delim = "Use this for the delimeter instead of TAB";
+ private static final String help_out_delim = "Replace the input delimeter with this in the output";
+ private static final String help_files = "The files to operate on, or stdin if none are given";
+ private static final String help_suppress = "Do not output lines that do not contain a delimeter character";
+ private static final String help_complement = "Complement the set of selected bytes, chars or fields";
+ private static final String help_super = "Remove ranges of bytes, chars, or fields from input lines";
+ private static final String err_delim = "An delimeter may only be present when operating on fields.";
+ private static final String err_multi_mode = "Only one type of list may be specified";
+ private static final String err_no_mode = "Must select either a byte, char or field range";
+ private static final String err_suppress = "Suppression only makes sense when using fields";
+ private static final String fmt_err = "cut: %s%n";
+
+ private static enum Mode {
+ BYTE, CHAR, FIELD;
+ }
+
+ private final NumberListArgument argByteRange;
+ private final NumberListArgument argCharRange;
+ private final NumberListArgument argFieldRange;
+ private final StringArgument argInDelim;
+ private final StringArgument argOutDelim;
+ private final FileArgument argFiles;
+ private final FlagArgument argSuppress;
+ private final FlagArgument argComplement;
+
+ private PrintWriter err;
+ private BufferedWriter out;
+ private File[] files;
+ private Mode mode;
+ private NumberRange[] list;
+ private String inDelim;
+ private String outDelim;
+ private boolean suppress;
+ private boolean complement;
+
+ public CutCommand() {
+ super(help_super);
+ argByteRange = new NumberListArgument("byte-range", 0, 1, Integer.MAX_VALUE - 1, help_byte);
+ argCharRange = new NumberListArgument("char-range", 0, 1, Integer.MAX_VALUE - 1, help_char);
+ argFieldRange = new NumberListArgument("field-range", 0, 1, Integer.MAX_VALUE - 1, help_field);
+ argInDelim = new StringArgument("in-delim", 0, help_in_delim);
+ argOutDelim = new StringArgument("out-delim", 0, help_out_delim);
+ argFiles = new FileArgument("files", 0, help_files);
+ argSuppress = new FlagArgument("suppress", 0, help_suppress);
+ argComplement = new FlagArgument("complement", 0, help_complement);
+ registerArguments(argByteRange, argCharRange, argFieldRange, argInDelim, argOutDelim, argFiles);
+ registerArguments(argSuppress, argComplement);
+ }
+
+ public void execute() {
+ err = getError().getPrintWriter();
+ out = new BufferedWriter(getOutput().getPrintWriter());
+ parseOptions();
+
+ BufferedReader reader;
+ List<String> lines;
+
+ for (File file : files) {
+ if (file.getName().equals("-")) {
+ reader = new BufferedReader(getInput().getReader());
+ } else {
+ reader = IOUtils.openBufferedReader(file);
+ }
+ try {
+ lines = IOUtils.readLines(reader);
+ } finally {
+ IOUtils.close(reader);
+ }
+ try {
+ if (mode == Mode.BYTE) {
+ cutBytes(lines);
+ } else if (mode == Mode.CHAR) {
+ cutChars(lines);
+ } else if (mode == Mode.FIELD) {
+ cutFields(lines);
+ }
+ } catch (IOException e) {
+
+ } finally {
+ IOUtils.flush(out);
+ }
+ }
+ }
+
+ private void cutBytes(List<String> lines) throws IOException {
+ // FIXME
+ // In the case of single-byte characters, this is the right
+ // path to take, but if characters are multi-byte, then there
+ // is supposed to be aligning done to make sure a byte-range
+ // does not fall in the middle of a character.
+ cutChars(lines);
+ }
+
+ private void cutChars(List<String> lines) throws IOException {
+ int limit, start, end;
+ for (String line : lines) {
+ limit = line.length();
+ for (NumberRange range : list) {
+ start = Math.min(limit, range.start());
+ end = Math.min(limit, range.end());
+ if (start == limit) break;
+ out.write(line.substring(start - 1, end));
+ }
+ out.newLine();
+ }
+ }
+
+ private void cutFields(List<String> lines) throws IOException {
+ boolean first;
+ int limit, start, end;
+ for (String line : lines) {
+ if (line.indexOf(inDelim) == -1) {
+ if (!suppress) {
+ out.write(line);
+ out.newLine();
+ }
+ continue;
+ }
+ String[] fields = line.split(inDelim);
+ if (fields == null || fields.length == 0) {
+ out.newLine();
+ continue;
+ }
+
+ first = true;
+ limit = fields.length;
+ for (NumberRange range : list) {
+ start = Math.min(limit, range.start());
+ end = Math.min(limit, range.end());
+ if (start == limit) break;
+ for (int i = start - 1; i < end; i++) {
+ if (!first) {
+ out.write(outDelim);
+ }
+ first = false;
+ out.write(fields[i]);
+ }
+ }
+ out.newLine();
+ }
+ }
+
+ private void parseOptions() {
+ if (argByteRange.isSet()) {
+ mode = Mode.BYTE;
+ list = argByteRange.getValues();
+ }
+ if (argCharRange.isSet()) {
+ if (mode != null) {
+ error(err_multi_mode);
+ }
+ mode = Mode.CHAR;
+ list = argCharRange.getValues();
+ }
+ if (argFieldRange.isSet()) {
+ if (mode != null) {
+ error(err_multi_mode);
+ }
+ mode = Mode.FIELD;
+ list = argFieldRange.getValues();
+ }
+ if (mode == null) {
+ error(err_no_mode);
+ }
+ if (argInDelim.isSet()) {
+ if (mode != Mode.FIELD) {
+ error(err_delim);
+ }
+ inDelim = argInDelim.getValue();
+ } else {
+ inDelim = "\t";
+ }
+ if (argOutDelim.isSet()) {
+ if (mode != Mode.FIELD) {
+ error(err_delim);
+ }
+ outDelim = argOutDelim.getValue();
+ } else {
+ outDelim = inDelim;
+ }
+ if (argSuppress.isSet()) {
+ if (mode != Mode.FIELD) {
+ error(err_suppress);
+ }
+ suppress = true;
+ }
+ complement = argComplement.isSet();
+ if (argFiles.isSet()) {
+ files = argFiles.getValues();
+ } else {
+ files = new File[] {new File("-")};
+ }
+ }
+
+ private void error(String s) {
+ err.format(fmt_err, s);
+ exit(1);
+ }
+}
Modified: trunk/cli/src/commands/org/jnode/command/util/IOUtils.java
===================================================================
--- trunk/cli/src/commands/org/jnode/command/util/IOUtils.java 2009-05-05 21:20:25 UTC (rev 5427)
+++ trunk/cli/src/commands/org/jnode/command/util/IOUtils.java 2009-05-05 21:22:20 UTC (rev 5428)
@@ -100,6 +100,27 @@
}
/**
+ * Call the flush method of a list of Flushable objects.
+ *
+ * This method will not throw a NullPointerException if any of the objects are null.
+ *
+ * This method will trap the IOException from flush.
+ *
+ * @param objs one or more Flushable objects
+ */
+ public static void flush(Flushable... objs) {
+ for (Flushable obj : objs) {
+ if (obj != null) {
+ try {
+ obj.flush();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ /**
* Copies data from an Inputstream to an OutputStream.
*
* This method allocates a 4096 byte buffer each time it is called.
@@ -245,6 +266,20 @@
/**
* Opens a BufferedReader on a file.
+ *
+ * This method will not throw a FileNotFoundException like the FileReader
+ * constructor would.
+ *
+ * @param file the file to open the reader on
+ * @return the reader, or null if the file could not be opened
+ * @throws NullPointerException if file is null
+ */
+ public static BufferedReader openBufferedReader(File file) {
+ return openBufferedReader(file, BUFFER_SIZE);
+ }
+
+ /**
+ * Opens a BufferedReader on a file.
*
* This method will not throw a FileNotFoundException like the FileReader
* constructor would.
@@ -505,6 +540,7 @@
* @throws NullPointerException if reader is null
*/
public static List<String> readLines(BufferedReader reader, int max) {
+ checkNull(reader);
List<String> ret = new LinkedList<String>();
String line;
int count = 0;
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|