//
// 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.ewe_pat;
import ewe.util.*;
/**
Shareware: package pat
<a href="copyright.html">Copyright 2001, Steven R. Brandt</a>
*/ /**
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 h) {
throw new Error("No such method as clone1 for "+getClass().getName());
}
Pattern clone(Hashtable h) {
Pattern p = (Pattern)h.get(this);
if(p != null) {
return p;
}
p=clone1(h);
if(p==null)throw new Error("Null from clone1!");
h.put(this,p);
h.put(p,p);
if(next != null) p.next = next.clone(h);
if(parent != null) p.parent = parent.clone(h);
return p;
}
public boolean equals(Object o) {
return o == this;
}
};