//
// 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 com.stevesoft.pat.MessageManager;
import java.util.*;
/**
Shareware: package pat
Copyright 2001, Steven R. Brandt
*/
/**
* Class Pattern is the base class on which all the other pattern elements are
* built.
*/
public abstract class Pattern
{
/**
* The ESC character, the user can provide his own value for the escape
* character through regex.esc
*/
public final static char ESC = '\\';
final static String PROTECT_THESE = "[]{}(),$,-\"^.";
/**
* The interal match function, it must be provided by any class which wishes
* to extend Pattern.
*/
public abstract int matchInternal(int i, Pthings p);
public abstract String toString();
// Class Pattern is a singly linked list
// chained together by member next. The member
// parent is used so that sub patterns can access
// the chain they are branching from.
Pattern next = null, parent = null;
/**
* This gets the next element of a Pattern that we wish to match. If we are at
* the end of a subchain of patterns, it will return us to the parent chain.
*/
public Pattern getNext()
{
return next != null ? next : (parent == null ? null : parent.getNext());
}
/**
* Call this method if you have a pattern element that takes a sub pattern
* (such as Or), and after you have added a sub pattern to the current pattern
* element.
*/
public void setParent(Pattern p)
{
if (next != null)
{
next.setParent(p);
}
else
{
parent = p;
}
}
/**
* This determines if the remainder of a Pattern matches. Type "return
* nextMatch" from within matchInternal if the current Pattern matches.
* Otherwise, return a -1.
*/
public int nextMatch(int i, Pthings pt)
{
Pattern p = getNext();
/*
* if(p == null) return i; return p.matchInternal(i,pt);
*/
return p == null ? i : p.matchInternal(i, pt);
}
/**
* This is a toString() for the remainder of the Pattern elements after this
* one. use this when overriding toString(). Called from within toString().
*/
public String nextString()
{
if (next == null)
{
return "";
}
return next.toString();
}
/** a method to detect whether char c is in String s */
final static boolean inString(char c, String s)
{
int i;
for (i = 0; i < s.length(); i++)
{
if (s.charAt(i) == c)
{
return true;
}
}
return false;
}
/**
* A method to create a string that protects the characters listed in
* PROTECT_THESE by prepending the esc character. The esc character itself is
* automatically protected.
*/
final static String protect(String s, String PROTECT_THESE, char esc)
{
int i;
StringBuffer sb = new StringBuffer();
String p = PROTECT_THESE + esc;
for (i = 0; i < s.length(); i++)
{
char c = s.charAt(i);
if (inString(c, p))
{
sb.append(esc);
}
sb.append(c);
}
return sb.toString();
}
/**
* This can be used to perform a match test from within class Pattern.
*/
public int match(StringLike s, Pthings pt)
{
return matchAt(s, 0, pt);
}
/**
* This can be used to perform a match test from within class Pattern.
*/
public int matchAt(StringLike s, int i, Pthings pt)
{
pt.src = s;
int r = matchInternal(i, pt);
if (r < 0)
{
return -1;
}
mfrom = r < i ? r + 1 : i;
return r < i ? i - r - 1 : r - i;
}
int mfrom = 0;
// Detect masked characters
final boolean Masked(int i, Pthings pt)
{
return pt.cbits == null ? false : pt.cbits.get(i);
}
/** add a Pattern to the singly-linked Pattern chain. */
public Pattern add(Pattern p)
{
if (next == null)
{
if (p == null)
{
return this;
}
next = p;
p.parent = parent;
parent = null;
}
else
{
next.add(p);
}
return this;
}
/**
* The minimum number of characters which this pattern element can match.
*/
public patInt minChars()
{
return new patInt(0);
}
/**
* The maximum number of characters which this pattern element can match.
*/
public patInt maxChars()
{
return new patInf();
}
/** return minimum number of characters in pattern */
public final patInt countMinChars()
{
Pattern p = this;
patInt sum = new patInt(0);
while (p != null)
{
sum.pluseq(p.minChars());
p = p.next;
}
return sum;
}
/** return maximum number of characters in pattern */
public final patInt countMaxChars()
{
Pattern p = this;
patInt sum = new patInt(0);
while (p != null)
{
sum.pluseq(p.maxChars());
p = p.next;
}
return sum;
}
// This method is only needed by Multi_stage2 so far...
// the reason is that it may try something else after a
// match succeeds. OrMark will only record the last thing
// tried in marks, so we need to backup the result of the
// last successful match and restore it if the next one
// does not succeed.
final int testMatch(Pattern p, int pos, Pthings pt)
{
int[] tab = null;
if (pt.marks != null)
{
try
{
tab = new int[pt.marks.length];
for (int i = 0; i < tab.length; i++)
{
tab[i] = pt.marks[i];
}
} catch (Throwable t)
{
}
}
int ret = p.matchInternal(pos, pt);
if (ret < 0)
{
pt.marks = tab;
}
return ret;
}
/**
* Clones this pattern elements without cloning others in the linked list.
*/
Pattern clone1(Hashtable