You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by py...@apache.org on 2006/07/25 08:18:32 UTC

svn commit: r425299 - in /incubator/harmony/enhanced/classlib/trunk/modules/luni/src: main/java/java/util/Scanner.java test/java/tests/api/java/util/ScannerTest.java

Author: pyang
Date: Mon Jul 24 23:18:31 2006
New Revision: 425299

URL: http://svn.apache.org/viewvc?rev=425299&view=rev
Log:
Fix for HARMONY-967 ([classlib][luni] Implementation of java.util.Scanner.findInLine())

Modified:
    incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
    incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java?rev=425299&r1=425298&r2=425299&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/main/java/java/util/Scanner.java Mon Jul 24 23:18:31 2006
@@ -56,34 +56,54 @@
  */
 public final class Scanner implements Iterator<String> {
 
-    //  Default delimiting pattern
+    //  Default delimiting pattern.
     private static final Pattern DEFAULT_DELIMITER = Pattern
             .compile("\\p{javaWhitespace}+"); //$NON-NLS-1$
     
-    //The boolean's pattern
+    // The boolean's pattern.
     private static final Pattern BOOLEAN_PATTERN = Pattern.compile(
             "true|false", Pattern.CASE_INSENSITIVE); //$NON-NLS-1$
     
-    // Pattern used to recognize line terminator
-    private static final Pattern LINE_TERMINATOR = Pattern
-            .compile("\n|\r\n|\r|\u0085|\u2028|\u2029"); //$NON-NLS-1$
     
+    // Pattern used to recognize line terminator.
+    private static final Pattern LINE_TERMINATOR;
+    
+    // Pattern used to recognize multiple line terminators.
+    private static final Pattern MULTI_LINE_TERMINATOR;
+
     // Pattern used to recognize a line with a line terminator.
-    private static final Pattern LINE_PATTERN = Pattern
-            .compile(".*(" + LINE_TERMINATOR.pattern() + //$NON-NLS-1$
-                    ")|.+(" + LINE_TERMINATOR.pattern() + ")?"); //$NON-NLS-1$ //$NON-NLS-2$
+    private static final Pattern LINE_PATTERN;
+
+    static {
+        String terminator = "\n|\r\n|\r|\u0085|\u2028|\u2029";  //$NON-NLS-1$
+        
+        LINE_TERMINATOR = Pattern.compile(terminator);
+        
+        StringBuilder multiTerminator = new StringBuilder();
+        MULTI_LINE_TERMINATOR = Pattern
+            .compile(multiTerminator.append("(") //$NON-NLS-1$
+                    .append(terminator)
+                    .append(")+").toString()); //$NON-NLS-1$
+        StringBuilder line = new StringBuilder();
+        LINE_PATTERN = Pattern
+            .compile(line.append(".*(") //$NON-NLS-1$
+                    .append(terminator)
+                    .append(")|.+(") //$NON-NLS-1$
+                    .append(terminator)
+                    .append(")?").toString()); //$NON-NLS-1$
+    }
     
-    // The pattern matching anything
+    // The pattern matches anything.
     private static final Pattern ANY_PATTERN = Pattern.compile("(?s).*"); //$NON-NLS-1$
 
     private static final int DIPLOID = 2;
 
-    // Default radix
+    // Default radix.
     private static final int DEFAULT_RADIX = 10;
 
     private static final int DEFAULT_TRUNK_SIZE = 1024;
 
-    // The input source of scanner
+    // The input source of scanner.
     private Readable input;
 
     private CharBuffer buffer;
@@ -96,16 +116,17 @@
 
     private Locale locale = Locale.getDefault();
 
-    // The position where find begins
+    // The position where find begins.
     private int findStartIndex = 0;
 
-    // The last find start position
+    // The last find start position.
     private int preStartIndex = findStartIndex;
 
-    // The length of the buffer
+    // The length of the buffer.
     private int bufferLength = 0;
 
-    // Used by find and nextXXX operation
+    // Record the status of this scanner. True if the scanner 
+    // is closed.
     private boolean closed = false;
 
     private IOException lastIOException;
@@ -114,7 +135,7 @@
     
     private DecimalFormat decimalFormat;
     
-    // Records whether the underlying readable has more input
+    // Records whether the underlying readable has more input.
     private boolean inputExhausted = false;
     
     private enum DataType{
@@ -306,14 +327,98 @@
         return delimiter;
     }
 
-    //TODO: To implement this feature
+    /**
+     * Tries to find the pattern in input. Delimiters are ignored. If the
+     * pattern is found before line terminator, the matched string will be
+     * returned, and the scanner will advance to the end of the matched string.
+     * Otherwise, null will be returned and the scanner will not advance the
+     * input. When waiting for input, the scanner may be blocked.
+     * 
+     * All the input may be cached if no line terminator exists in the buffer.
+     * 
+     * @param pattern
+     *            the pattern used to match input
+     * @return the matched string
+     * @throws IllegalStateException
+     *             if the scanner is closed
+     */
     public String findInLine(Pattern pattern) {
-        throw new NotYetImplementedException();
+        checkClosed();
+        checkNull(pattern);
+        int horizonLineSeparator = 0;
+
+        matcher.usePattern(MULTI_LINE_TERMINATOR);
+        matcher.region(findStartIndex, bufferLength);
+
+        boolean findComplete = false;
+        int terminatorLength = 0;
+        while (!findComplete) {
+            if (matcher.find()) {
+                horizonLineSeparator = matcher.start();
+                terminatorLength = matcher.end() - matcher.start();
+                findComplete = true;
+            } else {
+                if (!inputExhausted) {
+                    readMore();
+                    resetMatcher();
+                } else {
+                    horizonLineSeparator = bufferLength;
+                    findComplete = true;
+                }
+            }
+        }
+
+        matcher.usePattern(pattern);
+
+        /*
+         * TODO The following 2 statements are used to deal with regex's
+         * bug. java.util.regex.Matcher.region(int start, int end)
+         * implementation does not have any effects when called. They will be
+         * removed once the bug is fixed.
+         */
+        int oldLimit = buffer.limit();
+        buffer.limit(horizonLineSeparator);
+        // ========== To deal with regex bug ====================
+
+        matcher.region(findStartIndex, horizonLineSeparator);
+        if (matcher.find()) {
+            // The scanner advances past the input that matched
+            findStartIndex = matcher.end();
+            // If the matched pattern is immediately followed by line terminator. 
+            if(horizonLineSeparator == matcher.end()) {
+                findStartIndex += terminatorLength;
+            }
+            matchSuccessful = true;
+
+            // ========== To deal with regex bug ====================
+            buffer.limit(oldLimit);
+            // ========== To deal with regex bug ====================
+
+            return matcher.group();
+        }
+
+        // ========== To deal with regex bug ====================
+        buffer.limit(oldLimit);
+        // ========== To deal with regex bug ====================
+
+        matchSuccessful = false;
+        return null;
     }
 
-    //TODO: To implement this feature
+    /**
+     * Tries to find the pattern compiled from the specified string. The
+     * delimiter will be ignored. It is the same as invoke
+     * findInLine(Pattern.compile(pattern))
+     * 
+     * @param pattern
+     *            a string used to construct a pattern which in turn used to
+     *            match input
+     * @return the matched string
+     * @throws IllegalStateException
+     *             if the scanner is closed
+     */
     public String findInLine(String pattern) {
-        throw new NotYetImplementedException();
+        return findInLine(Pattern.compile(pattern));
     }
 
     /**
@@ -970,8 +1075,6 @@
      * locale specific negative prefixes and suffixes were present. At last the
      * resulting String is passed to {@link BigDecimal#BigDecimal(String)}}.
      * 
-     * @param integerRadix
-     *            the radix used to translate the token into BigDecimal
      * @return the BigDecimal scanned from the input
      * @throws IllegalStateException
      *             if this scanner has been closed
@@ -1624,7 +1727,7 @@
      * The operation of remove is not supported by this implementation of
      * Iterator.
      * 
-     * @return UnsupportedOperationException 
+     * @throw UnsupportedOperationException 
      *            if this method is invoked
      */
     public void remove() {
@@ -2060,9 +2163,9 @@
      */
     private void readMore() {
         int oldPosition = buffer.position();
-        int oldLimit = buffer.limit();
+        int oldBufferLength = bufferLength;
         // Increase capacity if empty space is not enough
-        if (buffer.limit() >= buffer.capacity()) {
+        if (bufferLength >= buffer.capacity()) {
             expandBuffer();
         }
 
@@ -2070,7 +2173,7 @@
         int readCount = 0;
         try {
             buffer.limit(buffer.capacity());
-            buffer.position(oldLimit);
+            buffer.position(oldBufferLength);
             while ((readCount = input.read(buffer)) == 0) {
                 // nothing to do here
             }
@@ -2078,7 +2181,7 @@
             // Consider the scenario: readable puts 4 chars into
             // buffer and then an IOException is thrown out. In this case, buffer is
             // actually grown, but readable.read() will never return.
-            bufferLength += (buffer.position() - oldLimit);
+            bufferLength = buffer.position();
             /*
              * Uses -1 to record IOException occurring, and no more input can be
              * read.

Modified: incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java
URL: http://svn.apache.org/viewvc/incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java?rev=425299&r1=425298&r2=425299&view=diff
==============================================================================
--- incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java (original)
+++ incubator/harmony/enhanced/classlib/trunk/modules/luni/src/test/java/tests/api/java/util/ScannerTest.java Mon Jul 24 23:18:31 2006
@@ -699,10 +699,10 @@
         // Harmony uses 1024 as default buffer size,
         // What if a sentence can not be read in all in once.
         StringBuilder longSentence = new StringBuilder(1025);
-        for (int i = 0; i <= 10; i++) {
+        for (int i = 0; i < 11; i++) {
             longSentence.append(" ");
         }
-        for (int i = 11; i <= 1025; i++) {
+        for (int i = 11; i < 1026; i++) {
             longSentence.append("a");
         }
         s = new Scanner(longSentence.toString());
@@ -4814,6 +4814,159 @@
         s = new Scanner("aaaa");
         result = s.findWithinHorizon(Pattern.compile("a*"), 0);
         assertEquals("aaaa", result);
+    }
+    
+    /**
+     * @tests java.util.Scanner#findInLine(Pattern)
+     */
+    public void test_findInLine_LPattern() {
+
+        Scanner s = new Scanner("");
+        try {
+            s.findInLine((Pattern) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+        String result = s.findInLine(Pattern.compile("^"));
+        assertEquals("", result);
+        MatchResult matchResult = s.match();
+        assertEquals(0, matchResult.start());
+        assertEquals(0, matchResult.end());
+
+        result = s.findInLine(Pattern.compile("$"));
+        assertEquals("", result);
+        matchResult = s.match();
+        assertEquals(0, matchResult.start());
+        assertEquals(0, matchResult.end());
+
+        /*
+         * When we use the operation of findInLine(Pattern), the match region
+         * should not span the line separator.
+         */
+        s = new Scanner("aa\nb.b");
+        result = s.findInLine(Pattern.compile("a\nb*"));
+        assertNull(result);
+
+        s = new Scanner("aa\nbb.b");
+        result = s.findInLine(Pattern.compile("\\."));
+        assertNull(result);
+
+        s = new Scanner("abcd1234test\n");
+        result = s.findInLine(Pattern.compile("\\p{Lower}+"));
+        assertEquals("abcd", result);
+        matchResult = s.match();
+        assertEquals(0, matchResult.start());
+        assertEquals(4, matchResult.end());
+
+        result = s.findInLine(Pattern.compile("\\p{Digit}{5}"));
+        assertNull(result);
+        try {
+            matchResult = s.match();
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+        assertEquals(0, matchResult.start());
+        assertEquals(4, matchResult.end());
+
+        result = s.findInLine(Pattern.compile("\\p{Lower}+"));
+        assertEquals("test", result);
+        matchResult = s.match();
+        assertEquals(8, matchResult.start());
+        assertEquals(12, matchResult.end());
+
+        char[] chars = new char[2048];
+        Arrays.fill(chars, 'a');
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append(chars);
+        stringBuilder.append("1234");
+        s = new Scanner(stringBuilder.toString());
+        result = s.findInLine(Pattern.compile("\\p{Digit}+"));
+        assertEquals("1234", result);
+        matchResult = s.match();
+        assertEquals(2048, matchResult.start());
+        assertEquals(2052, matchResult.end());
+
+        s = new Scanner("test");
+        s.close();
+        try {
+            s.findInLine((Pattern) null);
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException e) {
+            // expected
+        }
+
+        s = new Scanner("test1234\n1234 test");
+        result = s.findInLine(Pattern.compile("test"));
+        assertEquals("test", result);
+        matchResult = s.match();
+        assertEquals(0, matchResult.start());
+        assertEquals(4, matchResult.end());
+
+        int number = s.nextInt();
+        assertEquals(1234, number);
+        matchResult = s.match();
+        assertEquals(4, matchResult.start());
+        assertEquals(8, matchResult.end());
+
+        result = s.next();
+        assertEquals("1234", result);
+        matchResult = s.match();
+        assertEquals(9, matchResult.start());
+        assertEquals(13, matchResult.end());
+
+        result = s.findInLine(Pattern.compile("test"));
+        assertEquals("test", result);
+        matchResult = s.match();
+        assertEquals(14, matchResult.start());
+        assertEquals(18, matchResult.end());
+        
+        s = new Scanner("test\u0085\ntest");
+        result = s.findInLine("est");
+        assertEquals("est", result);
+        result = s.findInLine("est");
+        assertEquals("est", result);
+        
+        s = new Scanner("test\ntest");
+        result = s.findInLine("est");
+        assertEquals("est", result);
+        result = s.findInLine("est");
+        assertEquals("est", result);
+
+        s = new Scanner("test\n123\ntest");
+        result = s.findInLine("est");
+        assertEquals("est", result);
+        result = s.findInLine("est");
+        // RI fails. It is a RI's bug.
+        assertNull(result);
+    }
+
+    /**
+     * @tests java.util.Scanner#findInLine(String)
+     */
+    public void test_findInLine_LString() {
+        s = new Scanner("test");
+        try {
+            s.findInLine((String) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+
+        s.close();
+        try {
+            s.findInLine((String) null);
+            fail("Should throw NullPointerException");
+        } catch (NullPointerException e) {
+            // expected
+        }
+        try {
+            s.findInLine("test");
+            fail("Should throw IllegalStateException");
+        } catch (IllegalStateException e) {
+            // exptected
+        }
     }
     
     /**