JAL-1807 still testing
[jalviewjs.git] / unused / com / stevesoft / pat / RegOpt.java
index 97f05ba..c7ed628 100644 (file)
-//
-// This software is now distributed according to
-// the Lesser Gnu Public License.  Please see
-// http://www.gnu.org/copyleft/lesser.txt for
-// the details.
-//    -- Happy Computing!
-//
-package com.stevesoft.pat;
-
-import java.util.*;
-
-/** This class is just like oneChar, but doesn't worry about case. */
-class FastChar extends oneChar
-{
-  FastChar(char c)
-  {
-    super(c);
-  }
-
-  public int matchInternal(int p, Pthings pt)
-  {
-    return (p < pt.src.length() && pt.src.charAt(p) == c) ? nextMatch(
-            p + 1, pt) : -1;
-  }
-
-  Pattern clone1(Hashtable h)
-  {
-    return new FastChar(c);
-  }
-}
-
-/**
- * This class is a hashtable keyed by Character Objects. It is used to match
- * things of the form (?:a..|b..|c..|..) match with greater efficiency -- by
- * using a Hashtable that indexes into the group of patterns.
- */
-class Branch extends Pattern
-{
-  Hashtable h = new Hashtable();
-
-  // We need to keep track of the order
-  // of the keys -- if we don't then
-  // recompiling the output of toString
-  // may produce errors by re-ordering
-  // ()'s and changing the id number of
-  // the backreference associated with
-  // a subpattern.
-  Vector keys = new Vector();
-
-  Branch()
-  {
-  }
-
-  Pattern clone1(Hashtable x)
-  {
-    Branch b = new Branch();
-    b.keys = (Vector) keys.clone();
-    x.put(this, b);
-    x.put(b, b);
-
-    for (int i = 0; i < keys.size(); i++)
-    {
-      Pattern p = (Pattern) h.get(keys.elementAt(i));
-      b.h.put(keys.elementAt(i), p.clone(x));
-    }
-    return b;
-  }
-
-  // this function eliminates Branches with 0 or 1 elements.
-  final Pattern reduce(boolean ignoreCase, boolean dontMinQ)
-  {
-    if (h.size() == 1)
-    {
-      Enumeration e = h.keys();
-      Character c = (Character) e.nextElement();
-      Pattern oc;
-      if (ignoreCase || dontMinQ)
-      {
-        oc = new oneChar(c.charValue());
-      }
-      else
-      {
-        oc = new FastChar(c.charValue());
-      }
-      oc.next = (Pattern) h.get(c);
-      oc.add(next);
-      return oc;
-    }
-    else if (h.size() == 0)
-    {
-      return null;
-    }
-    return this;
-  }
-
-  public patInt maxChars()
-  {
-    Enumeration e = h.keys();
-    patInt count = new patInt(0);
-    while (e.hasMoreElements())
-    {
-      Object key = e.nextElement();
-      Pattern pa = (Pattern) h.get(key);
-      patInt pi = pa.maxChars();
-      pi.inc();
-      count.maxeq(pi);
-    }
-    return count;
-  }
-
-  public patInt minChars()
-  {
-    Enumeration e = h.keys();
-    patInt count = new patInt(0);
-    while (e.hasMoreElements())
-    {
-      Object key = e.nextElement();
-      Pattern pa = (Pattern) h.get(key);
-      patInt pi = pa.minChars();
-      pi.inc();
-      count.mineq(pi);
-    }
-    return count;
-  }
-
-  // adds a oneChar object to this Branch
-  void addc(oneChar o, boolean ignoreCase, boolean dontMinQ)
-  {
-    Pattern n = o.next;
-    if (n == null)
-    {
-      n = new NullPattern();
-    }
-    else
-    {
-      n = RegOpt.opt(n, ignoreCase, dontMinQ);
-    }
-    n.setParent(this);
-    set(new Character(o.c), n, ignoreCase, dontMinQ);
-    if (ignoreCase)
-    {
-      if (o.c != o.altc)
-      {
-        set(new Character(o.altc), n, ignoreCase, dontMinQ);
-      }
-      if (o.c != o.altc2 && o.altc != o.altc2)
-      {
-        set(new Character(o.altc2), n, ignoreCase, dontMinQ);
-      }
-    }
-  }
-
-  void set(Character c, Pattern n, boolean igc, boolean dontMinQ)
-  {
-    Pattern p = (Pattern) h.get(c);
-    next = null;
-    // This letter is not yet used in the Branch object.
-    // We need to add it.
-    if (p == null)
-    {
-      if (n instanceof Or)
-      {
-        // A NullPattern is prepended to an Or
-        // to prevent confusing this object.
-        // For example: (boo|bug) => (b(?:oo|ug))
-        // during this process. However, we
-        // want (b(?:oo|ell)|bug)
-        NullPattern np = new NullPattern();
-        np.add(n);
-        h.put(c, np);
-      }
-      else
-      {
-        h.put(c, n);
-      }
-      // Make sure we remember the order things were
-      // added into the Branch object so that we can
-      // properly convert it to a String.
-      keys.addElement(c);
-    }
-    else if (p instanceof Or)
-    {
-      ((Or) p).addOr(n);
-    }
-    else if (p instanceof oneChar && n instanceof oneChar
-            && ((oneChar) p).c != ((oneChar) n).c)
-    {
-      Branch b = new Branch();
-      b.addc((oneChar) p, igc, dontMinQ);
-      b.addc((oneChar) n, igc, dontMinQ);
-      h.put(c, b);
-      b.setParent(this);
-    }
-    else if (p instanceof Branch && n instanceof oneChar)
-    {
-      ((Branch) p).addc((oneChar) n, igc, dontMinQ);
-      n.setParent(p);
-    }
-    else
-    {
-      // Create an Or object to receive the variety
-      // of branches in the pattern if the current letter
-      // is matched. We do not attempt to make these
-      // sub-branches into a Branch object yet.
-      Or o = new Or();
-      o.setParent(this);
-
-      // Remove NullPattern from p -- it's no longer needed.
-      if (p instanceof NullPattern && p.parent == null && p.next != null)
-      {
-        o.addOr(p.next);
-      }
-      else
-      {
-        o.addOr(p);
-      }
-      o.addOr(n);
-
-      Pattern optpat = RegOpt.opt(o, igc, dontMinQ);
-      h.put(c, optpat);
-      optpat.setParent(this);
-    }
-  }
-
-  public String toString()
-  {
-    javajs.util.SB sb = new javajs.util.SB();
-    // should protect this...
-    sb.append("(?:(?#branch)"); // Hashtable)");
-    for (int i = 0; i < keys.size(); i++)
-    {
-      Character c = (Character) keys.elementAt(i);
-      sb.appendC(c);
-      sb.append((String) h.get(c));
-      if (i + 1 < keys.size())
-      {
-        sb.append("|");
-      }
-    }
-    sb.append(")");
-    sb.append(nextString());
-    return sb.toString();
-  }
-
-  public int matchInternal(int pos, Pthings pt)
-  {
-    if (pos >= pt.src.length())
-    {
-      return -1;
-    }
-    Pattern n = (Pattern) h.get(new Character(pt.src.charAt(pos)));
-    if (n == null)
-    {
-      return -1;
-    }
-    if (pt.cbits != null && pt.cbits.get(pos))
-    {
-      return -1;
-    }
-    return n.matchInternal(pos + 1, pt);
-  }
-}
-
-/**
- * This is just a place to put the optimizing function. It is never instantiated
- * as an Object. It just sorts through the RegOpt looking for things it can
- * change and make faster.
- */
-public class RegOpt
-{
-  static Pattern opt(Pattern p, boolean ignoreCase, boolean dontMinQ)
-  {
-    if (p == null)
-    {
-      return p;
-    }
-    if (p instanceof Bracket)
-    {
-      Bracket b = (Bracket) p;
-      // FastBracket is the only special
-      // optimized class to have its own
-      // source file.
-      p = FastBracket.process(b, ignoreCase);
-      // if(!(p instanceof FastBracket)
-      // p = Switch.process(b,ignoreCase);
-      p.next = b.next;
-      p.parent = b.parent;
-    }
-    else if (p instanceof oneChar && !ignoreCase && !dontMinQ)
-    {
-      oneChar o = (oneChar) p;
-      p = new FastChar(o.c);
-      p.next = o.next;
-      p.parent = o.parent;
-    }
-    else if (p instanceof Or && ((Or) p).leftForm().equals("(?:")
-            && ((Or) p).v.size() == 1)
-    { // Eliminate this Or Object.
-      Or o = (Or) p;
-      p = (Pattern) o.v.elementAt(0);
-      p.setParent(null);
-      p = RegOpt.opt(p, ignoreCase, dontMinQ);
-      p.add(o.next);
-    }
-    else if (p instanceof Or)
-    {
-      Or o = (Or) p;
-      o.pv = null;
-      Vector v = o.v;
-      o.v = new Vector();
-      Branch b = new Branch();
-      b.parent = o.parent;
-      for (int i = 0; i < v.size(); i++)
-      {
-        Pattern pp = (Pattern) v.elementAt(i);
-        // We want to have at least two oneChar's in
-        // the Or Object to consider making a Branch.
-        if (pp instanceof oneChar
-                && (b.h.size() >= 1 || (i + 1 < v.size() && v
-                        .elementAt(i + 1) instanceof oneChar)))
-        {
-          b.addc((oneChar) pp, ignoreCase, dontMinQ);
-        }
-        else
-        {
-          if (b.keys.size() > 0)
-          {
-            Pattern p2 = (Pattern) b.reduce(ignoreCase, dontMinQ);
-            if (p2 != null)
-            {
-              o.addOr(p2);
-              b = new Branch();
-              b.parent = o.parent;
-            }
-          }
-          o.addOr(opt(pp, ignoreCase, dontMinQ));
-        }
-      }
-      if (b.keys.size() > 0)
-      {
-        Pattern p2 = (Pattern) b.reduce(ignoreCase, dontMinQ);
-        if (p2 != null)
-        {
-          o.addOr(p2);
-        }
-      }
-      if (o.v.size() == 1 && o.leftForm().equals("(?:"))
-      { // Eliminate Or Object
-        p = (Pattern) o.v.elementAt(0);
-        p.setParent(null);
-        p = RegOpt.opt(p, ignoreCase, dontMinQ);
-        p.add(o.next);
-      }
-    }
-    else if (p instanceof FastMulti)
-    {
-      PatternSub ps = (PatternSub) p;
-      ps.sub = RegOpt.opt(ps.sub, ignoreCase, dontMinQ);
-    }
-    else if (p instanceof Multi && safe4fm(((PatternSub) p).sub))
-    {
-      Multi m = (Multi) p;
-      FastMulti fm = null;
-      try
-      {
-        fm = new FastMulti(m.a, m.b, opt(m.sub, ignoreCase, dontMinQ));
-      } catch (RegSyntax rs)
-      {
-      }
-      fm.parent = m.parent;
-      fm.matchFewest = m.matchFewest;
-      fm.next = m.next;
-      p = fm;
-    }
-    if (p.next != null)
-    {
-      p.next = opt(p.next, ignoreCase, dontMinQ);
-    }
-    return p;
-  }
-
-  final static boolean safe4fm(Pattern x)
-  {
-    while (x != null)
-    {
-      if (x instanceof Bracket)
-      {
-        ;
-      }
-      else if (x instanceof Range)
-      {
-        ;
-      }
-      else if (x instanceof oneChar)
-      {
-        ;
-      }
-      else if (x instanceof Any)
-      {
-        ;
-      }
-      else if (x instanceof Custom
-              && ((Custom) x).v instanceof UniValidator)
-      {
-        ;
-      }
-      else if (x instanceof Or)
-      {
-        Or o = (Or) x;
-        if (!o.leftForm().equals("(?:"))
-        {
-          return false;
-        }
-        patInt lo = o.countMinChars();
-        patInt hi = o.countMaxChars();
-        if (!lo.equals(hi))
-        {
-          return false;
-        }
-        for (int i = 0; i < o.v.size(); i++)
-        {
-          if (!safe4fm((Pattern) o.v.elementAt(i)))
-          {
-            return false;
-          }
-        }
-      }
-      else
-      {
-        return false;
-      }
-      x = x.next;
-    }
-    return true;
-  }
-  /*
-   * public static void setParents(Regex r) { setParents(r.thePattern,null); }
-   * static void setParents(Pattern p,Pattern x) { if(p instanceof PatternSub &&
-   * !(p instanceof FastMulti) && !(p instanceof DotMulti)) RegOpt.setParents(
-   * ((PatternSub)p).sub, p); else if(p instanceof Or && !(p instanceof
-   * Bracket)) { Or o = (Or)p; for(int i=0;i<o.v.size();i++)
-   * RegOpt.setParents((Pattern)o.v.elementAt(i),o); } else if(p instanceof
-   * Branch) { Branch b = (Branch)p; Enumeration e = b.h.keys();
-   * while(e.hasMoreElements()) { Object o = e.nextElement(); RegOpt.setParents(
-   * (Pattern)b.h.get(o), b); } } if(p.next == null) p.parent = x; else {
-   * p.parent = null; RegOpt.setParents(p.next,x); } }
-   */
-}
+//\r
+// This software is now distributed according to\r
+// the Lesser Gnu Public License.  Please see\r
+// http://www.gnu.org/copyleft/lesser.txt for\r
+// the details.\r
+//    -- Happy Computing!\r
+//\r
+package com.stevesoft.pat;\r
+\r
+import java.util.*;\r
+\r
+/** This class is just like oneChar, but doesn't worry about case. */\r
+class FastChar extends oneChar\r
+{\r
+  FastChar(char c)\r
+  {\r
+    super(c);\r
+  }\r
+\r
+  public int matchInternal(int p, Pthings pt)\r
+  {\r
+    return (p < pt.src.length() && pt.src.charAt(p) == c) ? nextMatch(\r
+            p + 1, pt) : -1;\r
+  }\r
+\r
+  Pattern clone1(Hashtable h)\r
+  {\r
+    return new FastChar(c);\r
+  }\r
+}\r
+\r
+/**\r
+ * This class is a hashtable keyed by Character Objects. It is used to match\r
+ * things of the form (?:a..|b..|c..|..) match with greater efficiency -- by\r
+ * using a Hashtable that indexes into the group of patterns.\r
+ */\r
+class Branch extends Pattern\r
+{\r
+  Hashtable h = new Hashtable();\r
+\r
+  // We need to keep track of the order\r
+  // of the keys -- if we don't then\r
+  // recompiling the output of toString\r
+  // may produce errors by re-ordering\r
+  // ()'s and changing the id number of\r
+  // the backreference associated with\r
+  // a subpattern.\r
+  Vector keys = new Vector();\r
+\r
+  Branch()\r
+  {\r
+  }\r
+\r
+  Pattern clone1(Hashtable x)\r
+  {\r
+    Branch b = new Branch();\r
+    b.keys = (Vector) keys.clone();\r
+    x.put(this, b);\r
+    x.put(b, b);\r
+\r
+    for (int i = 0; i < keys.size(); i++)\r
+    {\r
+      Pattern p = (Pattern) h.get(keys.elementAt(i));\r
+      b.h.put(keys.elementAt(i), p.clone(x));\r
+    }\r
+    return b;\r
+  }\r
+\r
+  // this function eliminates Branches with 0 or 1 elements.\r
+  final Pattern reduce(boolean ignoreCase, boolean dontMinQ)\r
+  {\r
+    if (h.size() == 1)\r
+    {\r
+      Enumeration e = h.keys();\r
+      Character c = (Character) e.nextElement();\r
+      Pattern oc;\r
+      if (ignoreCase || dontMinQ)\r
+      {\r
+        oc = new oneChar(c.charValue());\r
+      }\r
+      else\r
+      {\r
+        oc = new FastChar(c.charValue());\r
+      }\r
+      oc.next = (Pattern) h.get(c);\r
+      oc.add(next);\r
+      return oc;\r
+    }\r
+    else if (h.size() == 0)\r
+    {\r
+      return null;\r
+    }\r
+    return this;\r
+  }\r
+\r
+  public patInt maxChars()\r
+  {\r
+    Enumeration e = h.keys();\r
+    patInt count = new patInt(0);\r
+    while (e.hasMoreElements())\r
+    {\r
+      Object key = e.nextElement();\r
+      Pattern pa = (Pattern) h.get(key);\r
+      patInt pi = pa.maxChars();\r
+      pi.inc();\r
+      count.maxeq(pi);\r
+    }\r
+    return count;\r
+  }\r
+\r
+  public patInt minChars()\r
+  {\r
+    Enumeration e = h.keys();\r
+    patInt count = new patInt(0);\r
+    while (e.hasMoreElements())\r
+    {\r
+      Object key = e.nextElement();\r
+      Pattern pa = (Pattern) h.get(key);\r
+      patInt pi = pa.minChars();\r
+      pi.inc();\r
+      count.mineq(pi);\r
+    }\r
+    return count;\r
+  }\r
+\r
+  // adds a oneChar object to this Branch\r
+  void addc(oneChar o, boolean ignoreCase, boolean dontMinQ)\r
+  {\r
+    Pattern n = o.next;\r
+    if (n == null)\r
+    {\r
+      n = new NullPattern();\r
+    }\r
+    else\r
+    {\r
+      n = RegOpt.opt(n, ignoreCase, dontMinQ);\r
+    }\r
+    n.setParent(this);\r
+    set(new Character(o.c), n, ignoreCase, dontMinQ);\r
+    if (ignoreCase)\r
+    {\r
+      if (o.c != o.altc)\r
+      {\r
+        set(new Character(o.altc), n, ignoreCase, dontMinQ);\r
+      }\r
+      if (o.c != o.altc2 && o.altc != o.altc2)\r
+      {\r
+        set(new Character(o.altc2), n, ignoreCase, dontMinQ);\r
+      }\r
+    }\r
+  }\r
+\r
+  void set(Character c, Pattern n, boolean igc, boolean dontMinQ)\r
+  {\r
+    Pattern p = (Pattern) h.get(c);\r
+    next = null;\r
+    // This letter is not yet used in the Branch object.\r
+    // We need to add it.\r
+    if (p == null)\r
+    {\r
+      if (n instanceof Or)\r
+      {\r
+        // A NullPattern is prepended to an Or\r
+        // to prevent confusing this object.\r
+        // For example: (boo|bug) => (b(?:oo|ug))\r
+        // during this process. However, we\r
+        // want (b(?:oo|ell)|bug)\r
+        NullPattern np = new NullPattern();\r
+        np.add(n);\r
+        h.put(c, np);\r
+      }\r
+      else\r
+      {\r
+        h.put(c, n);\r
+      }\r
+      // Make sure we remember the order things were\r
+      // added into the Branch object so that we can\r
+      // properly convert it to a String.\r
+      keys.addElement(c);\r
+    }\r
+    else if (p instanceof Or)\r
+    {\r
+      ((Or) p).addOr(n);\r
+    }\r
+    else if (p instanceof oneChar && n instanceof oneChar\r
+            && ((oneChar) p).c != ((oneChar) n).c)\r
+    {\r
+      Branch b = new Branch();\r
+      b.addc((oneChar) p, igc, dontMinQ);\r
+      b.addc((oneChar) n, igc, dontMinQ);\r
+      h.put(c, b);\r
+      b.setParent(this);\r
+    }\r
+    else if (p instanceof Branch && n instanceof oneChar)\r
+    {\r
+      ((Branch) p).addc((oneChar) n, igc, dontMinQ);\r
+      n.setParent(p);\r
+    }\r
+    else\r
+    {\r
+      // Create an Or object to receive the variety\r
+      // of branches in the pattern if the current letter\r
+      // is matched. We do not attempt to make these\r
+      // sub-branches into a Branch object yet.\r
+      Or o = new Or();\r
+      o.setParent(this);\r
+\r
+      // Remove NullPattern from p -- it's no longer needed.\r
+      if (p instanceof NullPattern && p.parent == null && p.next != null)\r
+      {\r
+        o.addOr(p.next);\r
+      }\r
+      else\r
+      {\r
+        o.addOr(p);\r
+      }\r
+      o.addOr(n);\r
+\r
+      Pattern optpat = RegOpt.opt(o, igc, dontMinQ);\r
+      h.put(c, optpat);\r
+      optpat.setParent(this);\r
+    }\r
+  }\r
+\r
+  public String toString()\r
+  {\r
+    javajs.util.SB sb = new javajs.util.SB();\r
+    // should protect this...\r
+    sb.append("(?:(?#branch)"); // Hashtable)");\r
+    for (int i = 0; i < keys.size(); i++)\r
+    {\r
+      Character c = (Character) keys.elementAt(i);\r
+      sb.appendC(c);\r
+      sb.append((String) h.get(c));\r
+      if (i + 1 < keys.size())\r
+      {\r
+        sb.append("|");\r
+      }\r
+    }\r
+    sb.append(")");\r
+    sb.append(nextString());\r
+    return sb.toString();\r
+  }\r
+\r
+  public int matchInternal(int pos, Pthings pt)\r
+  {\r
+    if (pos >= pt.src.length())\r
+    {\r
+      return -1;\r
+    }\r
+    Pattern n = (Pattern) h.get(new Character(pt.src.charAt(pos)));\r
+    if (n == null)\r
+    {\r
+      return -1;\r
+    }\r
+    if (pt.cbits != null && pt.cbits.get(pos))\r
+    {\r
+      return -1;\r
+    }\r
+    return n.matchInternal(pos + 1, pt);\r
+  }\r
+}\r
+\r
+/**\r
+ * This is just a place to put the optimizing function. It is never instantiated\r
+ * as an Object. It just sorts through the RegOpt looking for things it can\r
+ * change and make faster.\r
+ */\r
+public class RegOpt\r
+{\r
+  static Pattern opt(Pattern p, boolean ignoreCase, boolean dontMinQ)\r
+  {\r
+    if (p == null)\r
+    {\r
+      return p;\r
+    }\r
+    if (p instanceof Bracket)\r
+    {\r
+      Bracket b = (Bracket) p;\r
+      // FastBracket is the only special\r
+      // optimized class to have its own\r
+      // source file.\r
+      p = FastBracket.process(b, ignoreCase);\r
+      // if(!(p instanceof FastBracket)\r
+      // p = Switch.process(b,ignoreCase);\r
+      p.next = b.next;\r
+      p.parent = b.parent;\r
+    }\r
+    else if (p instanceof oneChar && !ignoreCase && !dontMinQ)\r
+    {\r
+      oneChar o = (oneChar) p;\r
+      p = new FastChar(o.c);\r
+      p.next = o.next;\r
+      p.parent = o.parent;\r
+    }\r
+    else if (p instanceof Or && ((Or) p).leftForm().equals("(?:")\r
+            && ((Or) p).v.size() == 1)\r
+    { // Eliminate this Or Object.\r
+      Or o = (Or) p;\r
+      p = (Pattern) o.v.elementAt(0);\r
+      p.setParent(null);\r
+      p = RegOpt.opt(p, ignoreCase, dontMinQ);\r
+      p.add(o.next);\r
+    }\r
+    else if (p instanceof Or)\r
+    {\r
+      Or o = (Or) p;\r
+      o.pv = null;\r
+      Vector v = o.v;\r
+      o.v = new Vector();\r
+      Branch b = new Branch();\r
+      b.parent = o.parent;\r
+      for (int i = 0; i < v.size(); i++)\r
+      {\r
+        Pattern pp = (Pattern) v.elementAt(i);\r
+        // We want to have at least two oneChar's in\r
+        // the Or Object to consider making a Branch.\r
+        if (pp instanceof oneChar\r
+                && (b.h.size() >= 1 || (i + 1 < v.size() && v\r
+                        .elementAt(i + 1) instanceof oneChar)))\r
+        {\r
+          b.addc((oneChar) pp, ignoreCase, dontMinQ);\r
+        }\r
+        else\r
+        {\r
+          if (b.keys.size() > 0)\r
+          {\r
+            Pattern p2 = (Pattern) b.reduce(ignoreCase, dontMinQ);\r
+            if (p2 != null)\r
+            {\r
+              o.addOr(p2);\r
+              b = new Branch();\r
+              b.parent = o.parent;\r
+            }\r
+          }\r
+          o.addOr(opt(pp, ignoreCase, dontMinQ));\r
+        }\r
+      }\r
+      if (b.keys.size() > 0)\r
+      {\r
+        Pattern p2 = (Pattern) b.reduce(ignoreCase, dontMinQ);\r
+        if (p2 != null)\r
+        {\r
+          o.addOr(p2);\r
+        }\r
+      }\r
+      if (o.v.size() == 1 && o.leftForm().equals("(?:"))\r
+      { // Eliminate Or Object\r
+        p = (Pattern) o.v.elementAt(0);\r
+        p.setParent(null);\r
+        p = RegOpt.opt(p, ignoreCase, dontMinQ);\r
+        p.add(o.next);\r
+      }\r
+    }\r
+    else if (p instanceof FastMulti)\r
+    {\r
+      PatternSub ps = (PatternSub) p;\r
+      ps.sub = RegOpt.opt(ps.sub, ignoreCase, dontMinQ);\r
+    }\r
+    else if (p instanceof Multi && safe4fm(((PatternSub) p).sub))\r
+    {\r
+      Multi m = (Multi) p;\r
+      FastMulti fm = null;\r
+      try\r
+      {\r
+        fm = new FastMulti(m.a, m.b, opt(m.sub, ignoreCase, dontMinQ));\r
+      } catch (RegSyntax rs)\r
+      {\r
+      }\r
+      fm.parent = m.parent;\r
+      fm.matchFewest = m.matchFewest;\r
+      fm.next = m.next;\r
+      p = fm;\r
+    }\r
+    if (p.next != null)\r
+    {\r
+      p.next = opt(p.next, ignoreCase, dontMinQ);\r
+    }\r
+    return p;\r
+  }\r
+\r
+  final static boolean safe4fm(Pattern x)\r
+  {\r
+    while (x != null)\r
+    {\r
+      if (x instanceof Bracket)\r
+      {\r
+        ;\r
+      }\r
+      else if (x instanceof Range)\r
+      {\r
+        ;\r
+      }\r
+      else if (x instanceof oneChar)\r
+      {\r
+        ;\r
+      }\r
+      else if (x instanceof Any)\r
+      {\r
+        ;\r
+      }\r
+      else if (x instanceof Custom\r
+              && ((Custom) x).v instanceof UniValidator)\r
+      {\r
+        ;\r
+      }\r
+      else if (x instanceof Or)\r
+      {\r
+        Or o = (Or) x;\r
+        if (!o.leftForm().equals("(?:"))\r
+        {\r
+          return false;\r
+        }\r
+        patInt lo = o.countMinChars();\r
+        patInt hi = o.countMaxChars();\r
+        if (!lo.equals(hi))\r
+        {\r
+          return false;\r
+        }\r
+        for (int i = 0; i < o.v.size(); i++)\r
+        {\r
+          if (!safe4fm((Pattern) o.v.elementAt(i)))\r
+          {\r
+            return false;\r
+          }\r
+        }\r
+      }\r
+      else\r
+      {\r
+        return false;\r
+      }\r
+      x = x.next;\r
+    }\r
+    return true;\r
+  }\r
+  /*\r
+   * public static void setParents(Regex r) { setParents(r.thePattern,null); }\r
+   * static void setParents(Pattern p,Pattern x) { if(p instanceof PatternSub &&\r
+   * !(p instanceof FastMulti) && !(p instanceof DotMulti)) RegOpt.setParents(\r
+   * ((PatternSub)p).sub, p); else if(p instanceof Or && !(p instanceof\r
+   * Bracket)) { Or o = (Or)p; for(int i=0;i<o.v.size();i++)\r
+   * RegOpt.setParents((Pattern)o.v.elementAt(i),o); } else if(p instanceof\r
+   * Branch) { Branch b = (Branch)p; Enumeration e = b.h.keys();\r
+   * while(e.hasMoreElements()) { Object o = e.nextElement(); RegOpt.setParents(\r
+   * (Pattern)b.h.get(o), b); } } if(p.next == null) p.parent = x; else {\r
+   * p.parent = null; RegOpt.setParents(p.next,x); } }\r
+   */\r
+}\r