//
// Copyright (C) 1991 Texas Instruments Incorporated.
//
// Permission is granted to any individual or institution to use, copy, modify,
// and distribute this software, provided that this complete copyright and
// permission notice is maintained, intact, in all copies and supporting
// documentation.
//
// Texas Instruments Incorporated provides this software "as is" without
// express or implied warranty.
//
// Created: MNF 06/13/89 -- Initial Design and Implementation
// Updated: LGO 08/09/89 -- Inherit from Generic
// Updated: MBN 09/07/89 -- Added conditional exception handling
// Updated: MBN 12/15/89 -- Sprinkled "const" qualifiers all over the place!
//
// This  is the header file  for the regular  expression class.   An object of
// this class contains a regular expression,  in  a special "compiled" format.
// This  compiled format consists  of  several slots   all kept as the objects
// private data.  The  Regexp class  provides a convenient  way  to  represent
// regular  expressions.  It makes it easy   to search  for  the  same regular
// expression in many different strings without having to  compile a string to
// regular expression format more than necessary.
//
// A regular  expression allows a programmer to  specify complex patterns that
// can be searched for  and  matched against the  character string of a String
// object.  In  its  simplest case, a   regular expression  is a  sequence  of
// characters with which you can search for exact character matches.  However,
// many times you may not know the exact sequence you want to find, or you may
// only want to find a match at the beginning or end of  a String.  The Regexp
// object  allows specification of  such patterns by  utilizing the  following
// regular  expression  meta-characters   (note   that  more  one  of    these
// meta-characters  can  be used in a single  regular  expression in  order to
// create complex search patterns):
//
//         ^    Match at beginning of line
//         $    Match at end of line
//         .    Match any single character
//         [ ]  Match any one character inside the brackets
//         [^ ] Match any character NOT inside the brackets
//         -    Match any character in range on either side of dash
//         *    Match preceding pattern zero or more times
//         +    Match preceding pattern one or more times
//         ?    Match preceding pattern zero or once only
//         ()   Save a matched expression and use it in a further match.
//
// There are three constructors for Regexp.  One  just creates an empty Regexp
// object.  Another creates a Regexp object  and initializes it with a regular
// expression  that is given  in  the form of a   char*.   The  third  takes a
// reference  to  a Regexp  object    as an  argument    and creates an object
// initialized with the information from the given Regexp object.

// The  find  member function  finds   the  first  occurence   of  the regualr
// expression of that object in the string given to find as an argument.  Find
// returns a boolean, and  if true,  mutates  the private  data appropriately.
// Find sets pointers to the beginning and end of  the thing last  found, they
// are pointers into the actual string  that was searched.   The start and end
// member functions return indicies  into the searched string that  correspond
// to the beginning   and  end pointers  respectively.   The    compile member
// function takes a char* and puts the  compiled version of the char* argument
// into the object's private data fields.  The == and  != operators only check
// the  to see  if   the compiled  regular  expression   is the same, and  the
// deep_equal functions also checks  to see if the  start and end pointers are
// the same.  The is_valid  function returns FALSE if  program is set to NULL,
// (i.e. there is no valid compiled exression).  The set_invalid function sets
// the  program to NULL  (Warning: this deletes the compiled  expression). The
// following examples may help clarify regular expression usage:
//
//   *  The regular expression  "^hello" matches  a "hello"  only at  the
//      beginning of a  line.  It would match "hello  there" but not "hi,
//      hello there".
//
//   *  The regular expression "long$" matches a  "long"  only at the end
//      of a line. It would match "so long\0", but not "long ago".
//
//   *  The regular expression "t..t..g"  will match anything that  has a
//      "t" then any two characters, another "t", any  two characters and
//      then a "g".   It will match  "testing", or "test again" but would
//      not match "toasting"
//
//   *  The regular  expression "[1-9ab]" matches any  number one through
//      nine, and the characters  "a" and  "b".  It would match "hello 1"
//      or "begin", but would not match "no-match".
//
//   *  The  regular expression "[^1-9ab]"  matches any character that is
//      not a number one  through nine, or  an "a" or "b".   It would NOT
//      match "hello 1" or "begin", but would match "no-match".
//
//   *  The regular expression "br* " matches  something that begins with
//      a "b", is followed by zero or more "r"s, and ends in a space.  It
//      would match "brrrrr ", and "b ", but would not match "brrh ".
//
//   *  The regular expression "br+ " matches something  that begins with
//      a "b", is followed by one or more "r"s, and ends in  a space.  It
//      would match "brrrrr ",  and  "br ", but would not  match "b  " or
//      "brrh ".
//
//   *  The regular expression "br? " matches  something that begins with
//      a "b", is followed by zero or one "r"s, and ends in  a space.  It
//      would  match  "br ", and "b  ", but would not match  "brrrr "  or
//      "brrh ".
//
//   *  The regular expression "(..p)b" matches  something ending with pb
//      and beginning with whatever the two characters before the first p
//      encounterd in the line were.  It would find  "repb" in "rep drepa
//      qrepb".  The regular expression "(..p)a"  would find "repa qrepb"
//      in "rep drepa qrepb"
//
//   *  The regular expression "d(..p)" matches something ending  with p,
//      beginning with d, and having  two characters  in between that are
//      the same as the two characters before  the first p  encounterd in
//      the line.  It would match "drepa qrepb" in "rep drepa qrepb".
//

#ifndef REGEXPH					// If no regular expression
#define REGEXPH

#ifndef CHARH
#include <cool/char.h>
#endif

#ifndef GENERIC_H				// If no definition for class
#include <cool/Generic.h>				// include definition file
#endif

#define MAGIC 0234
#define NSUBEXP 10

class Regexp : public Generic {
private: 
  char           *startp[NSUBEXP];
  char           *endp[NSUBEXP];
  char            regstart;			// Internal use only
  char            reganch;			// Internal use only
  char           *regmust;			// Internal use only
  int             regmlen;			// Internal use only
  char           *program;   
  int             progsize;
  char           *searchstring;
   
public:
  inline Regexp ();				// Regexp with program=NULL
  inline Regexp (char*);			// Regexp with compiled char*
  Regexp (const Regexp&);			// Regexp duplicated from ref.
  ~Regexp();					// Destructor for Regexp class.

  void compile (char*);				// Compiles char* --> regexp
  Boolean find (char*);				// TRUE if regexp in char* arg
  inline long start() CONST;			// Index to start of first find
  inline long end() CONST;			// Index to end of first find

  Boolean operator== (const Regexp&) CONST;	// Equality operator
  inline Boolean operator!= (const Regexp&) CONST; // Inequality operator
  Boolean deep_equal (const Regexp&) CONST;	   // Same regexp and state?
  
  inline Boolean is_valid() CONST;		// TRUE if compiled regexp
  inline void set_invalid();			// Invalidates regexp
}; 

// Regexp -- Simple constructor
// Input:    None
// Output:   None

inline Regexp::Regexp () { 
  this->program = NULL;
}


// Regexp -- Constructor that accepts a string argument and compiles as a
//           regular expression
// Input:    Character string form of regular expression
// Output:   None

inline Regexp::Regexp (char* s) {  
  compile(s);
}


// Start -- Returns index into the searched string that corresponds to the
//          beginning pointer
// Input:   None
// Output:  Long index into searched string

inline long Regexp::start() CONST {
  return(this->startp[0] - searchstring);
}


// End -- Returns index into the searched string that corresponds to the
//        end pointer
// Input: None
// Output: Long index into searched string

inline long Regexp::end() CONST {
  return(this->endp[0] - searchstring);
}


// operator!= -- Overload inequality operator for Regexp class
// Input:        Constance Regexp reference
// Output:       Boolean TRUE/FALSE

inline Boolean Regexp::operator!= (const Regexp& r) CONST {
  return(!(*this == r));
}


// is_valid -- Indicates validity of regular expression, ie. is there a
//             compiled regular expression
// Input:      None
// Output:     Boolean TRUE/FALSE

inline Boolean Regexp::is_valid() CONST {
  return (this->program != NULL);
}


// set_invalid -- Invalidates regular expression
// Input:         None
// Output:        None

inline void Regexp::set_invalid() {
  this->program = NULL;
}

#endif



