|
From: <chr...@us...> - 2009-05-05 21:20:44
|
Revision: 5427
http://jnode.svn.sourceforge.net/jnode/?rev=5427&view=rev
Author: chrisboertien
Date: 2009-05-05 21:20:25 +0000 (Tue, 05 May 2009)
Log Message:
-----------
New Argument that represents a list of integers and number ranges.
Signed-off-by: chrisboertien <chr...@gm...>
Added Paths:
-----------
trunk/cli/descriptors/org.jnode.command.argument.xml
trunk/cli/src/commands/org/jnode/command/argument/
trunk/cli/src/commands/org/jnode/command/argument/NumberListArgument.java
trunk/cli/src/commands/org/jnode/command/util/NumberRange.java
Added: trunk/cli/descriptors/org.jnode.command.argument.xml
===================================================================
--- trunk/cli/descriptors/org.jnode.command.argument.xml (rev 0)
+++ trunk/cli/descriptors/org.jnode.command.argument.xml 2009-05-05 21:20:25 UTC (rev 5427)
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plugin SYSTEM "jnode.dtd">
+
+<plugin id="org.jnode.command.argument"
+ name="JNode command arguments"
+ version="@VERSION@"
+ provider-name="@PROVIDER@"
+ license-name="lgpl">
+
+ <requires>
+ <import plugin="org.jnode.shell.syntax"/>
+ <import plugin="org.jnode.command.util"/>
+ </requires>
+
+ <runtime>
+ <library name="jnode-cli.jar">
+ <export name="org.jnode.command.argument.*"/>
+ </library>
+ </runtime>
+</plugin>
Added: trunk/cli/src/commands/org/jnode/command/argument/NumberListArgument.java
===================================================================
--- trunk/cli/src/commands/org/jnode/command/argument/NumberListArgument.java (rev 0)
+++ trunk/cli/src/commands/org/jnode/command/argument/NumberListArgument.java 2009-05-05 21:20:25 UTC (rev 5427)
@@ -0,0 +1,193 @@
+/*
+ * $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.argument;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import org.jnode.command.util.NumberRange;
+import org.jnode.driver.console.CompletionInfo;
+import org.jnode.shell.CommandLine.Token;
+import org.jnode.shell.syntax.CommandSyntaxException;
+import org.jnode.shell.syntax.Argument;
+
+/**
+ * Captures a list of multiple number ranges.
+ *
+ * A number list is represented by a comma delimited list of integers
+ * and ranges. A range is represented by two integers separated by a hyphen.
+ * Either of the integers may be omitted (but not both), to represent a range
+ * that spans from a single point, to the minimum or maximum values of the range.
+ *
+ * In other words, this argument captures the following syntax:
+ * <code>
+ * list ::= range | list,range
+ * range ::= integer | -integer | integer- | integer-integer
+ * <code>
+ * Note that integer is any number in the range 0-Integer.MAX_VALUE, and may be limited
+ * to a smaller range via constructor arguments.
+ *
+ * When a number list has been captured, it may be altered from the form and order
+ * it was found in on the command line. The Command can be certain that the ranges
+ * returned by this argument will have the following properties.
+ *
+ * <ul>
+ * <li>Ranges will never span beyond min/max
+ * <li>Ranges will be in sorted order.
+ * <li>Individual ranges will not overlap, or be sequential. Such ranges will be concatenated
+ * to form a single range. This means that 3-5,4-7 and 3,4,5,6,7 will form the range 3-7.
+ * </ul>
+ *
+ * @author chris boertien
+ */
+public class NumberListArgument extends Argument<NumberRange> {
+
+ private final String listDelim;
+ private final String rangeDelim;
+ private final int min;
+ private final int max;
+
+ public NumberListArgument(String label, int flags, int min, int max, String desc) {
+ super(label, flags | Argument.MULTIPLE, new NumberRange[0], desc);
+ this.rangeDelim = "-";
+ this.listDelim = ",";
+ this.min = min;
+ this.max = max;
+ }
+
+ public NumberListArgument(String label, int flags, String desc) {
+ this(label, flags, Integer.MIN_VALUE + 1, Integer.MAX_VALUE - 1, desc);
+ }
+
+ @Override
+ protected NumberRange doAccept(Token token, int flags) throws CommandSyntaxException {
+ NumberRange[] ranges = parseList(token.text);
+ if (ranges.length == 1) {
+ return ranges[0];
+ }
+
+ Arrays.sort(ranges);
+
+ // concat
+ for (int i = 1; i < ranges.length;) {
+ if (ranges[i - 1].end() >= (ranges[i].start() - 1)) {
+ ranges = concat(ranges, i - 1, i);
+ } else {
+ i++;
+ }
+ }
+ for (int i = 0; i < (ranges.length - 1); i++ ) {
+ values.add(ranges[i]);
+ }
+ return ranges[ranges.length - 1];
+ }
+
+ private NumberRange[] concat(NumberRange[] ranges, int i, int j) {
+ NumberRange[] newRanges = new NumberRange[ranges.length - (j - i)];
+ System.arraycopy(ranges, 0, newRanges, 0, i);
+ if (j < (ranges.length - 1)) {
+ System.arraycopy(ranges, j + 1, newRanges, j, newRanges.length - j);
+ }
+ newRanges[i] = new NumberRange(ranges[i].start(), ranges[j].end(), min - 1, max + 1);
+ return newRanges;
+ }
+
+ private static final boolean debug = false;
+
+ private void error(String s) {
+ if (debug) System.err.println(s);
+ }
+
+ /**
+ * Parse a number list
+ *
+ * list ::= range | list,range
+ */
+ private NumberRange[] parseList(String text) throws CommandSyntaxException {
+ int delimPos = text.indexOf(listDelim);
+ if (delimPos == -1) {
+ return new NumberRange[] { parseRange(text) };
+ } else {
+ String[] rangesText = text.split(listDelim);
+ NumberRange[] ranges = new NumberRange[rangesText.length];
+ for (int i = 0; i < ranges.length; i++) {
+ ranges[i] = parseRange(rangesText[i]);
+ }
+ return ranges;
+ }
+ }
+
+ /**
+ * Parse a number range.
+ *
+ * range ::= integer | -integer | integer- | integer-integer
+ */
+ private NumberRange parseRange(String text) throws CommandSyntaxException {
+ int delimPos = text.indexOf(rangeDelim);
+ int start;
+ int end;
+ if (text.equals(rangeDelim)) {
+ throw new CommandSyntaxException("Invalid number range");
+ }
+ if (delimPos == -1) {
+ // this is ok, as we allow a single integer to represent the range n-n
+ start = end = parseInt(text);
+ } else if (delimPos == 0) {
+ start = min;
+ end = parseInt(text.substring(rangeDelim.length(), text.length()));
+ } else if (delimPos == (text.length() - rangeDelim.length())) {
+ start = parseInt(text.substring(0, delimPos));
+ end = max;
+ } else {
+ start = parseInt(text.substring(0, delimPos));
+ end = parseInt(text.substring(delimPos + rangeDelim.length(), text.length()));
+ }
+ try {
+ return new NumberRange(start, end, min - 1, max + 1);
+ } catch (IllegalArgumentException ex) {
+ throw new CommandSyntaxException("Invalid number range");
+ }
+ }
+
+ private int parseInt(String text) throws CommandSyntaxException {
+ int n;
+ try {
+ n = Integer.parseInt(text);
+ } catch (NumberFormatException ex) {
+ throw new CommandSyntaxException("Invalid number range");
+ }
+ if (n < min || n > max) {
+ throw new CommandSyntaxException("Number out of range");
+ }
+ return n;
+ }
+
+ @Override
+ protected String state() {
+ return "min=" + min + ",max=" + max;
+ }
+
+ @Override
+ protected String argumentKind() {
+ return "number-list";
+ }
+}
Added: trunk/cli/src/commands/org/jnode/command/util/NumberRange.java
===================================================================
--- trunk/cli/src/commands/org/jnode/command/util/NumberRange.java (rev 0)
+++ trunk/cli/src/commands/org/jnode/command/util/NumberRange.java 2009-05-05 21:20:25 UTC (rev 5427)
@@ -0,0 +1,204 @@
+/*
+ * $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.util;
+
+/**
+ * An immutable representation of a sequential number range.
+ *
+ * A number range uses two number of values to denote points of
+ * positive and negative infinity. By default, these values are
+ * Integer.MAX_VALUE and Integer.MIN_VALUE respectively. If start
+ * or end are equal to or beyond the infinity values, then the
+ * range is considered to be infinite in that direction.
+ *
+ * It is worth noting that the Comparable interface is sensitive
+ * to the points of positive and negative infinity. Two number ranges
+ * can have different start and end points and be considered equal if
+ * both ranges are also infinite in that direction.
+ *
+ * @author chris boertien
+ * @see {@link org.jnode.command.argument.NumberRangeArgument}
+ */
+public final class NumberRange implements Comparable<NumberRange> {
+
+ private final int start;
+ private final int end;
+ private final int negativeInfinity;
+ private final int positiveInfinity;
+
+ /**
+ * Creates a number range.
+ *
+ * This number range uses posInf and negInf to denote positive and negative
+ * infinity respectively.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @param posInf the point of positive infinity
+ * @param negInf the point of negative infinity
+ * @throws IllegalArgumentException if start > end or negInf >= posInf
+ */
+ public NumberRange(int start, int end, int negInf, int posInf) {
+ if (start > end) {
+ throw new IllegalArgumentException("start > end");
+ }
+ if (negInf >= posInf) {
+ throw new IllegalArgumentException("negInf >= posInf");
+ }
+ this.start = start;
+ this.end = end;
+ this.negativeInfinity = negInf;
+ this.positiveInfinity = posInf;
+ }
+
+ /**
+ * Creates a number range.
+ *
+ * This number range uses Integer.MAX_VALUE and Integer.MIN_VALUE to denote
+ * positive and negative infinity respectively.
+ *
+ * @param start the start of the range
+ * @param end the end of the range
+ * @throws IllegalArgumentException if start > end
+ */
+ public NumberRange(int start, int end) {
+ this(start, end, Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Compares this NumberRange to another NumberRange for order.
+ *
+ * NumberRanges are ordered first by their start position, and second
+ * by their end position.
+ *
+ * A NumberRange that is negatively infinite is considered less than one that
+ * is not negatively infinite. Also a NumberRange that is not positively infinite
+ * is considered less than one that is positively infinite.
+ *
+ * @param that the NumberRange to compare this one to
+ * @return -1 if this comes before that, 1 if that comes before this, 0 if they are equal
+ * @see {@link #equals}
+ */
+ public int compareTo(NumberRange that) {
+ if (equals(that)) {
+ return 0;
+ }
+
+ boolean a1 = isStartInfinite();
+ boolean a2 = isEndInfinite();
+ boolean b1 = that.isStartInfinite();
+ boolean b2 = that.isEndInfinite();
+
+ if (a1 ^ b1) {
+ return a1 ? -1 : 1;
+ }
+ if ((a1 && b1) || (start == that.start)) {
+ if (a2 ^ b2) {
+ return a2 ? -1 : 1;
+ }
+ return end - that.end;
+ }
+ return start - that.start;
+ }
+
+ /**
+ * Tests this NumberRange for equivalence to that NumberRange.
+ *
+ * Two NumberRanges are considered equal if:
+ * <ul>
+ * <li>if both are negatively infinite AND both are positively infinite
+ * <li>if both are negatively infinite AND neither are positively infinite AND both have the same end point.
+ * <li>if neither are negatively infinite AND both have the same start point AND both are positvely infinite
+ * <li>if neither are negatively infinite AND both have the same start point AND
+ * neither are positively infinite AND both have the same end point.
+ * </ul>
+ *
+ * @param that the NumberRage to compare with
+ * @return true if both NumberRanges are equal
+ */
+ public boolean equals(NumberRange that) {
+ boolean a1 = isStartInfinite();
+ boolean a2 = isEndInfinite();
+ boolean b1 = that.isStartInfinite();
+ boolean b2 = that.isEndInfinite();
+
+ return ((a1 && b1) || (!(a1 ^ b1) && (start == that.start)))
+ && ((a2 && b2) || (!(a2 ^ b2) && (end == that.end)));
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ if (this == that) {
+ return true;
+ }
+ if (!(that instanceof NumberRange)) {
+ return false;
+ }
+ return equals((NumberRange) that);
+ }
+
+ @Override
+ public String toString() {
+ return start + "-" + end;
+ }
+
+ /**
+ * The starting position of this number range.
+ *
+ * Even if the start value is beyond the negative infinity point
+ * this will still return the value of the start position.
+ *
+ * @return the start
+ */
+ public int start() {
+ return start;
+ }
+
+ /**
+ * The ending position of this number range.
+ *
+ * Even if the end value is beyond the positive infinity point
+ * this will still return the value of the start position.
+ *
+ * @return the end
+ */
+ public int end() {
+ return end;
+ }
+
+ /**
+ * Does this NumberRange represent a range that is positively infinite.
+ *
+ * @return true if the end position is >= positive infinity.
+ */
+ public boolean isEndInfinite() {
+ return end >= positiveInfinity;
+ }
+
+ /**
+ * Does this NumberRange represent a range that is negatively infinite.
+ *
+ * @return true if the start positition is <= negative infinity
+ */
+ public boolean isStartInfinite() {
+ return start <= negativeInfinity;
+ }
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|