summaryrefslogtreecommitdiff
path: root/Bus/Ivy/Regexp.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Bus/Ivy/Regexp.cxx')
-rw-r--r--Bus/Ivy/Regexp.cxx1758
1 files changed, 0 insertions, 1758 deletions
diff --git a/Bus/Ivy/Regexp.cxx b/Bus/Ivy/Regexp.cxx
deleted file mode 100644
index 4dc1823..0000000
--- a/Bus/Ivy/Regexp.cxx
+++ /dev/null
@@ -1,1758 +0,0 @@
-// Win32 porting notes.
-
-#if defined( _MBCS )
-#pragma message( __FILE__ "This code is broken under _MBCS, " \
- "see the comments at the top of this file." )
-#endif //_MBCS
-//
-//
-// In case this isn't obvious from the later comments this is an ALTERED
-// version of the software. If you like my changes then cool, but nearly
-// all of the functionality here is derived from Henry Spencer's original
-// work.
-//
-// This code should work correctly under both _SBCS and _UNICODE, I did
-// start working on making it work with _MBCS but gave up after a while
-// since I don't need this particular port and it's not going to be as
-// straight forward as the other two.
-//
-// The problem stems from the compiled program being stored as TCHARS,
-// the individual items need to be wide enough to hold whatever character
-// is thrown at them, but currently they are accessed as an array of
-// whatever size integral type is appropriate. _MBCS would cause this
-// to be char, but at times it would need to be larger. This would
-// require making the program be an array of short with the appropriate
-// conversions used everywhere. Certainly it's doable, but it's a pain.
-// What's worse is that the current code will compile and run under _MBCS,
-// only breaking when it gets wide characters thrown against it.
-//
-// I've marked at least one bit of code with #pragma messages, I may not
-// get all of them, but they should be a start
-//
-// Guy Gascoigne - Piggford (ggp@bigfoot.com) Friday, February 27, 1998
-
-
-// regcomp and regexec -- regsub and regerror are elsewhere
-// @(#)regexp.c 1.3 of 18 April 87
-//
-// Copyright (c) 1986 by University of Toronto.
-// Written by Henry Spencer. Not derived from licensed software.
-//
-// Permission is granted to anyone to use this software for any
-// purpose on any computer system, and to redistribute it freely,
-// subject to the following restrictions:
-//
-// 1. The author is not responsible for the consequences of use of
-// this software, no matter how awful, even if they arise
-// from defects in it.
-//
-// 2. The origin of this software must not be misrepresented, either
-// by explicit claim or by omission.
-//
-// 3. Altered versions must be plainly marked as such, and must not
-// be misrepresented as being the original software.
-// *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
-// *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
-// *** as in BSD grep and ex.
-// *** THIS IS AN ALTERED VERSION. It was altered by John Gilmore,
-// *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
-// *** THIS IS AN ALTERED VERSION. It was altered by James A. Woods,
-// *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
-// *** THIS IS AN ALTERED VERSION. It was altered by Geoffrey Noer,
-// *** THIS IS AN ALTERED VERSION. It was altered by Guy Gascoigne - Piggford
-// *** guy@wyrdrune.com, on 15 March 1998, porting it to C++ and converting
-// *** it to be the engine for the Regexp class
-//
-// Beware that some of this code is subtly aware of the way operator
-// precedence is structured in regular expressions. Serious changes in
-// regular-expression syntax might require a total rethink.
-
-#include "IvyStdAfx.h"
-#include "regexp.h"
-
-// The first byte of the regexp internal "program" is actually this magic
-// number; the start node begins in the second byte.
-
-const char MAGIC = '\234';
-
-#pragma warning( disable : 4711 ) // automatic inline selected
-
-// The "internal use only" fields in regexp.h are present to pass info from
-// compile to execute that permits the execute phase to run lots faster on
-// simple cases. They are:
-//
-// regstart char that must begin a match; '\0' if none obvious
-// reganch is the match anchored (at beginning-of-line only)?
-// regmust string (pointer into program) that match must include, or NULL
-// regmlen length of regmust string
-//
-// Regstart and reganch permit very fast decisions on suitable starting
-// points for a match, cutting down the work a lot. Regmust permits fast
-// rejection of lines that cannot possibly match. The regmust tests are
-// costly enough that regcomp() supplies a regmust only if the
-// r.e. contains something potentially expensive (at present, the only
-// such thing detected is * or + at the start of the r.e., which can
-// involve a lot of backup). Regmlen is supplied because the test in
-// regexec() needs it and regcomp() is computing it anyway.
-
-// Structure for regexp "program". This is essentially a linear encoding
-// of a nondeterministic finite-state machine (aka syntax charts or
-// "railroad normal form" in parsing technology). Each node is an opcode
-// plus a "next" pointer, possibly plus an operand. "Next" pointers of
-// all nodes except BRANCH implement concatenation; a "next" pointer with
-// a BRANCH on both ends of it is connecting two alternatives. (Here we
-// have one of the subtle syntax dependencies: an individual BRANCH (as
-// opposed to a collection of them) is never concatenated with anything
-// because of operator precedence.) The operand of some types of node is
-// a literal string; for others, it is a node leading into a sub-FSM. In
-// particular, the operand of a BRANCH node is the first node of the
-// branch. (NB this is *not* a tree structure: the tail of the branch
-// connects to the thing following the set of BRANCHes.) The opcodes
-// are:
-
-enum {
-// definition number opnd? meaning
- END = 0, // no End of program.
- BOL = 1, // no Match beginning of line.
- EOL = 2, // no Match end of line.
- ANY = 3, // no Match any character.
- ANYOF = 4, // str Match any of these.
- ANYBUT = 5, // str Match any but one of these.
- BRANCH = 6, // node Match this, or the next..\&.
- BACK = 7, // no "next" ptr points backward.
- EXACTLY = 8, // str Match this string.
- NOTHING = 9, // no Match empty string.
- STAR = 10, // node Match this 0 or more times.
- PLUS = 11, // node Match this 1 or more times.
- WORDA = 12, // no Match "" at wordchar, where prev is nonword
- WORDZ = 13, // no Match "" at nonwordchar, where prev is word
- OPEN = 20, // no Sub-RE starts here.
- // OPEN+1 is number 1, etc.
- CLOSE = 40 // no Analogous to OPEN.
-};
-
-// Opcode notes:
-//
-// BRANCH The set of branches constituting a single choice are hooked
-// together with their "next" pointers, since precedence prevents
-// anything being concatenated to any individual branch. The
-// "next" pointer of the last BRANCH in a choice points to the
-// thing following the whole choice. This is also where the
-// final "next" pointer of each individual branch points; each
-// branch starts with the operand node of a BRANCH node.
-//
-// BACK Normal "next" pointers all implicitly point forward; BACK
-// exists to make loop structures possible.
-//
-// STAR,PLUS '?', and complex '*' and '+', are implemented as circular
-// BRANCH structures using BACK. Simple cases (one character
-// per match) are implemented with STAR and PLUS for speed
-// and to minimize recursive plunges.
-//
-// OPEN,CLOSE ...are numbered at compile time.
-
-// A node is one char of opcode followed by two chars of "next" pointer.
-// "Next" pointers are stored as two 8-bit pieces, high order first. The
-// value is a positive offset from the opcode of the node containing it.
-// An operand, if any, simply follows the node. (Note that much of the
-// code generation knows about this implicit relationship.)
-//
-// Using two bytes for the "next" pointer is vast overkill for most things,
-// but allows patterns to get big without disasters.
-
-
-enum
-{
- REGERR_SENTINEL_VALUE = 0,
- REGERR_NULLARG = 1, REGERR_CORRUPTED, REGERR_CORRUPTION, REGERR_CORRUPTED_POINTERS,
- REGERR_BAD_REGREPEAT, REGERR_CORRUPTED_OPCODE, REGERR_NULL_TO_REGSUB,
- REGERR_DAMAGED_REGEXP_REGSUB, REGERR_DAMAGED_MATCH_STRING, REGERR_NULL_TO_REGCOMP,
- REGERR_TO_BIG, REGERR_TO_MANY_PAREN, REGERR_UNTERMINATED_PAREN, REGERR_UNMATCHED_PAREN,
- REGERR_INTERNAL_ERROR_JUNK, REGERR_OP_COULD_BE_EMPTY, REGERR_NESTED_OP, REGERR_INVALID_RANGE,
- REGERR_UNMATCHED_BRACE, REGERR_INTERNAL_UNEXPECTED_CHAR, REGERR_OP_FOLLOWS_NOTHING,
- REGERR_TRAILING_ESC, REGERR_INTERNAL_STRSCSPN, REGERR_NO_REGEXP
-};
-
-struct regErr
-{
- int m_id;
- const char * m_err;
-} errors[] = {
- { REGERR_NULLARG, "NULL argument to regexec" },
- { REGERR_CORRUPTED, "corrupted regexp" },
- { REGERR_CORRUPTION, "regexp corruption" },
- { REGERR_CORRUPTED_POINTERS, "corrupted pointers" },
- { REGERR_BAD_REGREPEAT, "internal error: bad call of regrepeat" },
- { REGERR_CORRUPTED_OPCODE, "corrupted opcode" },
- { REGERR_NULL_TO_REGSUB, "NULL parm to regsub" },
- { REGERR_DAMAGED_REGEXP_REGSUB, "damaged regexp fed to regsub" },
- { REGERR_DAMAGED_MATCH_STRING, "damaged match string" },
- { REGERR_NULL_TO_REGCOMP, "NULL argument to regcomp" },
- { REGERR_TO_BIG, "regexp too big" },
- { REGERR_TO_MANY_PAREN, "too many ()" },
- { REGERR_UNTERMINATED_PAREN, "unterminated ()" },
- { REGERR_UNMATCHED_PAREN, "unmatched ()" },
- { REGERR_INTERNAL_ERROR_JUNK, "internal error: junk on end" },
- { REGERR_OP_COULD_BE_EMPTY, "*+ operand could be empty" },
- { REGERR_NESTED_OP, "nested *?+" },
- { REGERR_INVALID_RANGE, "invalid [] range" },
- { REGERR_UNMATCHED_BRACE, "unmatched []" },
- { REGERR_INTERNAL_UNEXPECTED_CHAR, "internal error: \\0|) unexpected" },
- { REGERR_OP_FOLLOWS_NOTHING, "?+* follows nothing" },
- { REGERR_TRAILING_ESC, "trailing \\" },
- { REGERR_INTERNAL_STRSCSPN, "internal error: strcspn 0" },
- { REGERR_NO_REGEXP, "NULL regexp" },
- { REGERR_SENTINEL_VALUE, "Unknown error" } // must be last value
-};
-
-// Flags to be passed up and down.
-
-enum {
- HASWIDTH = 01, // Known never to match null string.
- SIMPLE = 02, // Simple enough to be STAR/PLUS operand.
- SPSTART = 04, // Starts with * or +.
- WORST = 0 // Worst case.
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class CRegErrorHandler
-{
- friend Regexp;
- mutable ivy::string m_szError;
- static const char * FindErr( int id );
-protected:
- void ClearErrorString() const;
- void regerror( const char * s ) const;
- void regerror( int id ) const;
-public:
- CRegErrorHandler() { }
- CRegErrorHandler( const CRegErrorHandler & reh ) : m_szError( reh.m_szError ) {}
-
- const ivy::string & GetErrorString() const;
-};
-
-void CRegErrorHandler::regerror( const char * s ) const
-{
- TRACE( "regerror: %s\n", s );
- m_szError = s;
-}
-
-void CRegErrorHandler::regerror( int id ) const
-{
- regerror( FindErr( id ) );
-}
-
-const ivy::string & CRegErrorHandler::GetErrorString() const
-{
- return m_szError;
-}
-
-void CRegErrorHandler::ClearErrorString() const
-{
- m_szError.erase() ;
-}
-
-const char * CRegErrorHandler::FindErr( int id )
-{
- struct regErr * perr;
- for ( perr = errors; perr->m_id != REGERR_SENTINEL_VALUE; perr++ )
- if ( perr->m_id == id )
- return perr->m_err;
-
- return perr->m_err; // since we've fallen off the array, perr->m_id == 0
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-// All of the functions required to directly access the 'program'
-class CRegProgramAccessor : public CRegErrorHandler
-{
-public:
- static inline char OP( char * p )
- {
- return (*(p));
- }
- static inline char * OPERAND( char * p )
- {
- return p + 3;
- }
- static inline char * regnext( char * p )
- {
- const short offset = *((short*)(p+1));
-
- if (offset == 0)
- return(NULL);
-
- return((OP(p) == BACK) ? p-offset : p+offset);
- }
-#ifdef _RE_DEBUG
- char * CRegProgramAccessor::regprop( char * op );
-#endif
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-// The internal interface to the regexp, wrapping the compilation as well as the
-// execution of the regexp (matching)
-
-class regexp : public CRegProgramAccessor
-{
- friend class CRegExecutor;
- friend class Regexp;
-
- int m_programSize;
- char * startp[Regexp::NSUBEXP];
- char * endp[Regexp::NSUBEXP];
- char regstart; // Internal use only.
- char reganch; // Internal use only.
- char * regmust; // Internal use only.
- int regmlen; // Internal use only.
- char * program;
-
- bool status;
- int count; // used by Regexp to manage the reference counting of regexps
- int numSubs;
-public:
-
- regexp( const char * exp, bool iCase );
- regexp( const regexp & r );
- ~regexp();
-
- void ignoreCase( const char * in, char * out );
-
- bool regcomp( const char * exp );
- bool regexec( const char * string );
- bool Status() const { return status; }
-
- ivy::string GetReplaceString( const char* sReplaceExp ) const;
-
- regexp * getCopy();
-
-#ifdef _RE_DEBUG
- void regdump();
-#endif
-
-#ifdef _DEBUG
- ivy::string m_originalPattern;
- ivy::string m_modifiedPattern;
-#endif
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Compile / Validate the regular expression - ADT
-
-class CRegCompilerBase : public CRegProgramAccessor
-{
-public:
- CRegCompilerBase( const char * parse );
-
- char * reg(int paren, int *flagp);
-protected:
- char * regparse; // Input-scan pointer.
- int regnpar; // () count.
-
- char * regbranch(int *flagp);
- char * regpiece(int *flagp);
- char * regatom(int *flagp);
- inline bool ISREPN( char c ) { return ((c) == '*' || (c) == '+' || (c) == '?'); }
-
- virtual void regc(int c) = 0;
- virtual char * regnode(int op) = 0;
- virtual void reginsert(char op, char * opnd) = 0;
- virtual void regtail(char * p, char * val) = 0;
- virtual void regoptail(char * p, char * val) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// First pass over the expression, testing for validity and returning the
-// program size
-
-class CRegValidator : public CRegCompilerBase
-{
-public:
- CRegValidator( const char * parse );
-
- inline long Size() const { return regsize; }
-private:
- long regsize; // Code size.
- char regdummy[3]; // NOTHING, 0 next ptr
-protected:
- char * regnode(int) { regsize += 3; return regdummy; }
- void regc(int) { regsize++; }
- void reginsert(char, char *) { regsize += 3; }
- void regtail(char *, char *) { return; }
- void regoptail(char *, char *) { return; }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Second pass, actually generating the program
-
-class CRegCompiler : public CRegCompilerBase
-{
-public:
- CRegCompiler( const char * parse, char * prog );
-private:
- char * regcode;
-protected:
- // regc - emit (if appropriate) a byte of code
- void regc(int b)
- {
- *regcode++ = (char)b;
- }
- char * regnode(int op);
- void reginsert(char op, char * opnd);
- void regtail(char * p, char * val);
- void regoptail(char * p, char * val);
-};
-
-// regnode - emit a node
-char * CRegCompiler::regnode(int op)
-{
- char * const ret = regcode;
-
- char * ptr = ret;
- *ptr++ = (char)op;
- *ptr++ = '\0'; // Null next pointer.
- *ptr++ = '\0';
- regcode = ptr;
-
- return(ret);
-}
-
-// reginsert - insert an operator in front of already-emitted operand
-//
-// Means relocating the operand.
-void CRegCompiler::reginsert(char op, char * opnd)
-{
- char * place;
-
- (void) memmove(opnd+3, opnd, (size_t)((regcode - opnd)*sizeof(char)));
- regcode += 3;
-
- place = opnd; // Op node, where operand used to be.
- *place++ = op;
- *place++ = '\0';
- *place++ = '\0';
-}
-
-// regtail - set the next-pointer at the end of a node chain
-void CRegCompiler::regtail(char * p, char * val)
-{
- char * scan;
- char * temp;
-
- // Find last node.
- for (scan = p; (temp = regnext(scan)) != NULL; scan = temp)
- continue;
-
- *((short *)(scan+1)) = (short)((OP(scan) == BACK) ? scan - val : val - scan);
-}
-
-// regoptail - regtail on operand of first argument; nop if operandless
-void CRegCompiler::regoptail(char * p, char * val)
-{
- // "Operandless" and "op != BRANCH" are synonymous in practice.
- if (OP(p) == BRANCH)
- regtail(OPERAND(p), val);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-CRegCompilerBase::CRegCompilerBase( const char * parse )
- : regparse( (char *)parse ),
- regnpar(1)
-{
-}
-
-CRegValidator::CRegValidator( const char * parse )
- : CRegCompilerBase( parse ),
- regsize(0)
-{
- regc(MAGIC);
- regdummy[0] = NOTHING;
- regdummy[1] = regdummy[2] = 0;
-}
-
-CRegCompiler::CRegCompiler( const char * parse, char * prog )
- : CRegCompilerBase( parse ),
- regcode(prog)
-{
- regc(MAGIC);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-regexp::regexp( const char * exp, bool iCase )
- : regstart(0),
- reganch(0),
- regmust(0),
- regmlen(0),
- program(0),
- m_programSize(0)
-{
-#if _DEBUG
- m_originalPattern = exp; // keep a version of the pattern for debugging
-#endif
-
- if ( iCase )
- {
- char * out = new char[(strlen( exp ) * 4) + 1];
- ignoreCase( exp, out );
-
-#if _DEBUG
- m_modifiedPattern = out; // and the modified version if there is one
-#endif
- status = regcomp( out );
- delete [] out;
- }
- else
- status = regcomp( exp );
-
- count = numSubs = 0;
-}
-
-regexp::regexp( const regexp & orig )
- : regstart(orig.regstart),
- reganch(orig.reganch),
- regmlen(orig.regmlen),
- m_programSize(orig.m_programSize),
- numSubs(orig.numSubs),
- regmust(0)
-{
-#if _DEBUG
- m_originalPattern = orig.m_originalPattern;
- m_modifiedPattern = orig.m_modifiedPattern;
-#endif
- status = orig.status;
- count = 0;
- program = new char[m_programSize];
- memcpy( program, orig.program, m_programSize * sizeof( char ) );
- if ( orig.regmust )
- regmust = program + ( orig.regmust - orig.program );
-
- for ( int i = Regexp::NSUBEXP - 1; i >= 0; i--)
- {
- startp[i] = orig.startp[i];
- endp[i] = orig.endp[i];
- }
-}
-
-regexp::~regexp()
-{
- delete [] program;
-}
-
-
-// regcomp - compile a regular expression into internal code
-//
-// We can't allocate space until we know how big the compiled form will
-// be, but we can't compile it (and thus know how big it is) until we've
-// got a place to put the code. So we cheat: we compile it twice, once
-// with code generation turned off and size counting turned on, and once
-// "for real". This also means that we don't allocate space until we are
-// sure that the thing really will compile successfully, and we never
-// have to move the code and thus invalidate pointers into it. (Note
-// that it has to be in one piece because free() must be able to free it
-// all.)
-//
-// Beware that the optimization-preparation code in here knows about some
-// of the structure of the compiled regexp.
-
-bool regexp::regcomp(const char * exp)
-{
- char * scan;
- int flags;
-
- if (exp == NULL)
- {
- regerror( REGERR_NULL_TO_REGCOMP );
- return NULL;
- }
-
- // First pass: determine size, legality.
- CRegValidator tester( exp );
-
- if (tester.reg(0, &flags) == NULL)
- return false;
-
- // Small enough for pointer-storage convention?
- if (tester.Size() >= 0x7fffL) // Probably could be 0xffffL.
- {
- regerror(REGERR_TO_BIG);
- return NULL;
- }
-
- m_programSize = tester.Size();
- // Allocate space.
- program = new char[m_programSize];
-
- CRegCompiler comp( exp, program );
- // Second pass: emit code.
- if (comp.reg(0, &flags) == NULL)
- return false;
-
- scan = program + 1; // First BRANCH.
- if (OP(regnext(scan)) == END)
- { // Only one top-level choice.
- scan = OPERAND(scan);
-
- // Starting-point info.
- if (OP(scan) == EXACTLY)
- regstart = *OPERAND(scan);
- else if (OP(scan) == BOL)
- reganch = 1;
-
- // If there's something expensive in the r.e., find the
- // longest literal string that must appear and make it the
- // regmust. Resolve ties in favor of later strings, since
- // the regstart check works with the beginning of the r.e.
- // and avoiding duplication strengthens checking. Not a
- // strong reason, but sufficient in the absence of others.
-
- if (flags&SPSTART)
- {
- char * longest = NULL;
- size_t len = 0;
-
- for (; scan != NULL; scan = regnext(scan))
- if (OP(scan) == EXACTLY && strlen(OPERAND(scan)) >= len)
- {
- longest = OPERAND(scan);
- len = strlen(OPERAND(scan));
- }
- regmust = longest;
- regmlen = (int)len;
- }
- }
-
- return true;
-}
-
-regexp * regexp::getCopy()
-{
- return new regexp( *this );
-}
-
-// reg - regular expression, i.e. main body or parenthesized thing
-//
-// Caller must absorb opening parenthesis.
-//
-// Combining parenthesis handling with the base level of regular expression
-// is a trifle forced, but the need to tie the tails of the branches to what
-// follows makes it hard to avoid.
-
-char * CRegCompilerBase::reg( int paren, int *flagp )
-{
- char * ret = NULL;
- char * br;
- char * ender;
- int parno = 0;
- int flags;
-
- *flagp = HASWIDTH; // Tentatively.
-
- if (paren)
- {
- // Make an OPEN node.
- if (regnpar >= Regexp::NSUBEXP)
- {
- regerror(REGERR_TO_MANY_PAREN);
- return NULL;
- }
- parno = regnpar;
- regnpar++;
- ret = regnode(OPEN+parno);
- }
-
- // Pick up the branches, linking them together.
- br = regbranch(&flags);
- if (br == NULL)
- return(NULL);
- if (paren)
- regtail(ret, br); // OPEN -> first.
- else
- ret = br;
- *flagp &= ~(~flags&HASWIDTH); // Clear bit if bit 0.
- *flagp |= flags&SPSTART;
- while (*regparse == '|')
- {
- regparse++;
- br = regbranch(&flags);
- if (br == NULL)
- return(NULL);
- regtail(ret, br); // BRANCH -> BRANCH.
- *flagp &= ~(~flags&HASWIDTH);
- *flagp |= flags&SPSTART;
- }
-
- // Make a closing node, and hook it on the end.
- ender = regnode((paren) ? CLOSE+parno : END);
- regtail(ret, ender);
-
- // Hook the tails of the branches to the closing node.
- for (br = ret; br != NULL; br = regnext(br))
- regoptail(br, ender);
-
- // Check for proper termination.
- if (paren && *regparse++ != ')')
- {
- regerror( REGERR_UNTERMINATED_PAREN );
- return NULL;
- }
- else if (!paren && *regparse != '\0')
- {
- if (*regparse == ')')
- {
- regerror( REGERR_UNMATCHED_PAREN );
- return NULL;
- }
- else
- {
- regerror( REGERR_INTERNAL_ERROR_JUNK );
- return NULL;
- }
- // NOTREACHED
- }
-
- return(ret);
-}
-
-// regbranch - one alternative of an | operator
-//
-// Implements the concatenation operator.
-
-char * CRegCompilerBase::regbranch(int *flagp)
-{
- char * ret;
- char * chain;
- char * latest;
- int flags;
- int c;
-
- *flagp = WORST; // Tentatively.
-
- ret = regnode(BRANCH);
- chain = NULL;
- while ((c = *regparse) != '\0' && c != '|' && c != ')')
- {
- latest = regpiece(&flags);
- if (latest == NULL)
- return(NULL);
- *flagp |= flags&HASWIDTH;
- if (chain == NULL) // First piece.
- *flagp |= flags&SPSTART;
- else
- regtail(chain, latest);
- chain = latest;
- }
- if (chain == NULL) // Loop ran zero times.
- (void) regnode(NOTHING);
-
- return(ret);
-}
-
-// regpiece - something followed by possible [*+?]
-//
-// Note that the branching code sequences used for ? and the general cases
-// of * and + are somewhat optimized: they use the same NOTHING node as
-// both the endmarker for their branch list and the body of the last branch.
-// It might seem that this node could be dispensed with entirely, but the
-// endmarker role is not redundant.
-
-char * CRegCompilerBase::regpiece(int *flagp)
-{
- char * ret;
- char op;
- char * next;
- int flags;
-
- ret = regatom(&flags);
- if (ret == NULL)
- return(NULL);
-
- op = *regparse;
- if (!ISREPN(op))
- {
- *flagp = flags;
- return(ret);
- }
-
- if (!(flags&HASWIDTH) && op != '?' )
- {
- regerror( REGERR_OP_COULD_BE_EMPTY );
- return NULL;
- }
- switch (op)
- {
- case '*' : *flagp = WORST|SPSTART; break;
- case '+' : *flagp = WORST|SPSTART|HASWIDTH; break;
- case '?' : *flagp = WORST; break;
- }
-
- if (op == '*' && (flags&SIMPLE))
- reginsert(STAR, ret);
- else if (op == '*' )
- {
- // Emit x* as (x&|), where & means "self".
- reginsert(BRANCH, ret); // Either x
- regoptail(ret, regnode(BACK)); // and loop
- regoptail(ret, ret); // back
- regtail(ret, regnode(BRANCH)); // or
- regtail(ret, regnode(NOTHING)); // null.
- }
- else if (op == '+' && (flags&SIMPLE))
- reginsert(PLUS, ret);
- else if (op == '+' )
- {
- // Emit x+ as x(&|), where & means "self".
- next = regnode(BRANCH); // Either
- regtail(ret, next);
- regtail(regnode(BACK), ret); // loop back
- regtail(next, regnode(BRANCH)); // or
- regtail(ret, regnode(NOTHING)); // null.
- }
- else if (op == '?' )
- {
- // Emit x? as (x|)
- reginsert(BRANCH, ret); // Either x
- regtail(ret, regnode(BRANCH)); // or
- next = regnode(NOTHING); // null.
- regtail(ret, next);
- regoptail(ret, next);
- }
- regparse++;
- if (ISREPN(*regparse))
- {
- regerror( REGERR_NESTED_OP );
- return NULL;
- }
-
- return(ret);
-}
-
-// regatom - the lowest level
-//
-// Optimization: gobbles an entire sequence of ordinary characters so that
-// it can turn them into a single node, which is smaller to store and
-// faster to run. Backslashed characters are exceptions, each becoming a
-// separate node; the code is simpler that way and it's not worth fixing.
-
-char * CRegCompilerBase::regatom(int * flagp)
-{
- char * ret;
- int flags;
-
- *flagp = WORST; // Tentatively.
-
- switch ( *regparse++ )
- {
- // FIXME: these chars only have meaning at beg/end of pat?
- case '^':
- ret = regnode(BOL);
- break;
- case '$':
- ret = regnode(EOL);
- break;
- case '.':
- ret = regnode(ANY);
- *flagp |= HASWIDTH|SIMPLE;
- break;
- case '[':
- {
- int range;
- int rangeend;
- int c;
-
- if (*regparse == '^')
- { // Complement of range.
- ret = regnode(ANYBUT);
- regparse++;
- }
- else
- ret = regnode(ANYOF);
- if ((c = *regparse) == ']' || c == '-')
- {
- regc(c);
- regparse++;
- }
- while ((c = *regparse++ ) != '\0' && c != ']')
- {
- if (c != '-')
- regc(c);
- else if ((c = *regparse) == ']' || c == '\0')
- regc('-');
- else
- {
- range = (char)*(regparse-2);
- rangeend = (char)c;
- if (range > rangeend)
- {
- regerror( REGERR_INVALID_RANGE );
- return NULL;
- }
- for (range++; range <= rangeend; range++)
- regc(range);
- regparse++;
- }
- }
- regc('\0');
- if (c != ']')
- {
- regerror( REGERR_UNMATCHED_BRACE );
- return NULL;
- }
- *flagp |= HASWIDTH|SIMPLE;
- break;
- }
- case '(':
- ret = reg(1, &flags);
- if (ret == NULL)
- return(NULL);
- *flagp |= flags&(HASWIDTH|SPSTART);
- break;
- case '\0':
- case '|':
- case ')':
- // supposed to be caught earlier
- regerror( REGERR_INTERNAL_UNEXPECTED_CHAR );
- return NULL;
- case '?':
- case '+':
- case '*':
- {
- regerror( REGERR_OP_FOLLOWS_NOTHING );
- return NULL;
- }
- case '\\':
- switch (*regparse++)
- {
- case '\0':
- {
- regerror( REGERR_TRAILING_ESC );
- return NULL;
- }
- case '<':
- ret = regnode(WORDA);
- break;
- case '>':
- ret = regnode(WORDZ);
- break;
- /* FIXME: Someday handle \1, \2, ... */
- default:
- /* Handle general quoted chars in exact-match routine */
- goto de_fault;
- }
- break;
- de_fault:
- default:
- // Encode a string of characters to be matched exactly.
- //
- // This is a bit tricky due to quoted chars and due to
- // '*', '+', and '?' taking the SINGLE char previous
- // as their operand.
- //
- // On entry, the char at regparse[-1] is going to go
- // into the string, no matter what it is. (It could be
- // following a \ if we are entered from the '\' case.)
- //
- // Basic idea is to pick up a good char in ch and
- // examine the next char. If it's *+? then we twiddle.
- // If it's \ then we frozzle. If it's other magic char
- // we push ch and terminate the string. If none of the
- // above, we push ch on the string and go around again.
- //
- // regprev is used to remember where "the current char"
- // starts in the string, if due to a *+? we need to back
- // up and put the current char in a separate, 1-char, string.
- // When regprev is NULL, ch is the only char in the
- // string; this is used in *+? handling, and in setting
- // flags |= SIMPLE at the end.
- {
- char *regprev;
- register char ch;
-
- regparse--; /* Look at cur char */
- ret = regnode(EXACTLY);
- for ( regprev = 0 ; ; ) {
- ch = *regparse++; /* Get current char */
- switch (*regparse) { /* look at next one */
-
- default:
- regc(ch); /* Add cur to string */
- break;
-
- case '.': case '[': case '(':
- case ')': case '|': case '\n':
- case '$': case '^':
- case '\0':
- /* FIXME, $ and ^ should not always be magic */
- magic:
- regc(ch); /* dump cur char */
- goto done; /* and we are done */
-
- case '?': case '+': case '*':
- if (!regprev) /* If just ch in str, */
- goto magic; /* use it */
- /* End mult-char string one early */
- regparse = regprev; /* Back up parse */
- goto done;
-
- case '\\':
- regc(ch); /* Cur char OK */
- switch (regparse[1]){ /* Look after \ */
- case '\0':
- case '<':
- case '>':
- /* FIXME: Someday handle \1, \2, ... */
- goto done; /* Not quoted */
- default:
- /* Backup point is \, scan * point is after it. */
- regprev = regparse;
- regparse++;
- continue; /* NOT break; */
- }
- }
- regprev = regparse; /* Set backup point */
- }
- done:
- regc('\0');
- *flagp |= HASWIDTH;
- if (!regprev) /* One char? */
- *flagp |= SIMPLE;
- }
- break;
- }
-
- return(ret);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// regexec and friends
-
-// Work-variable struct for regexec().
-
-class CRegExecutor : public CRegProgramAccessor
-{
- friend bool regexp::regexec( const char * str );
-
- char * reginput; // string-input pointer.
- char * regbol; // Beginning of input, for ^ check.
- char * * regstartp; // Pointer to startp array.
- char * * regendp; // Ditto for endp.
-
- regexp * prog;
-public:
- CRegExecutor( regexp * prog, char * string );
-protected:
- bool regtry( char * string );
- bool regmatch( char * prog );
- size_t regrepeat( char * node );
-};
-
-CRegExecutor::CRegExecutor( regexp * p, char * string )
- : regbol( string ),
- regstartp( p->startp ),
- regendp( p->endp ),
- prog(p)
-{
-}
-
-#ifdef _RE_DEBUG
-int regnarrate = 0;
-#endif
-
-// regexec - match a regexp against a string
-
-bool regexp::regexec( const char * str )
-{
- char * string = (char *)str; // avert const poisoning
-
- // Be paranoid.
- if ( string == NULL )
- {
- regerror( REGERR_NULLARG );
- return false;
- }
-
- // Check validity of program.
- if (*program != MAGIC)
- {
- regerror( REGERR_CORRUPTED );
- return false;
- }
-
- // If there is a "must appear" string, look for it.
- if ( regmust != NULL && strstr( string, regmust ) == NULL )
- return false;
-
- CRegExecutor executor( this, string );
-
- // Simplest case: anchored match need be tried only once.
- if ( reganch )
- return( executor.regtry( string ) );
-
- // Messy cases: unanchored match.
- if ( regstart != '\0' )
- {
- // We know what char it must start with.
- for ( char * s = string; s != NULL; s = strchr( s+1 , regstart ) )
- if ( executor.regtry( s) )
- return true;
- return false;
- }
- else
- {
- // We don't -- general case.
- for ( char * s = string; ! executor.regtry( s ); s++ )
- if (*s == '\0')
- return false;
- }
- return true;
-}
-
-// regtry - try match at specific point
-bool CRegExecutor::regtry( char * string )
-{
- int i;
- char * * stp;
- char * * enp;
-
- reginput = string;
-
- stp = prog->startp;
- enp = prog->endp;
- for (i = Regexp::NSUBEXP; i > 0; i--)
- {
- *stp++ = NULL;
- *enp++ = NULL;
- }
- if ( regmatch( prog->program + 1 ) )
- {
- prog->startp[0] = string;
- prog->endp[0] = reginput;
- return true;
- }
- else
- return false;
-}
-
-// regmatch - main matching routine
-//
-// Conceptually the strategy is simple: check to see whether the current
-// node matches, call self recursively to see whether the rest matches,
-// and then act accordingly. In practice we make some effort to avoid
-// recursion, in particular by going through "ordinary" nodes (that don't
-// need to know whether the rest of the match failed) by a loop instead of
-// by recursion.
-
-bool CRegExecutor::regmatch( char * prog )
-{
- char * scan; // Current node.
- char * next; // Next node.
-
-#ifdef _RE_DEBUG
- if (prog != NULL && regnarrate)
- fprintf(stderr, "%s(\n", regprop(prog));
-#endif
- for (scan = prog; scan != NULL; scan = next)
- {
-#ifdef _RE_DEBUG
- if (regnarrate)
- fprintf(stderr, "%s...\n", regprop(scan));
-#endif
- next = regnext(scan);
-
- switch (OP(scan))
- {
- case BOL:
- if (reginput != regbol)
- return false;
- break;
- case EOL:
- if (*reginput != '\0')
- return false;
- break;
- case WORDA:
- /* Must be looking at a letter, digit, or _ */
- if ((!isalnum(*reginput)) && *reginput != '_')
- return(0);
- /* Prev must be BOL or nonword */
- if (reginput > regbol &&
- (isalnum(reginput[-1]) || reginput[-1] == '_'))
- return(0);
- break;
- case WORDZ:
- /* Must be looking at non letter, digit, or _ */
- if (isalnum(*reginput) || *reginput == '_')
- return(0);
- /* We don't care what the previous char was */
- break;
- case ANY:
- if (*reginput == '\0')
- return false;
- reginput++;
- break;
- case EXACTLY:
- {
- size_t len;
- char * const opnd = OPERAND(scan);
-
- // Inline the first character, for speed.
- if (*opnd != *reginput)
- return false;
- len = strlen(opnd);
- if (len > 1 && strncmp(opnd, reginput, len) != 0)
- return false;
- reginput += len;
-
- break;
- }
- case ANYOF:
- if (*reginput == '\0' ||
- strchr(OPERAND(scan), *reginput) == NULL)
- return false;
- reginput++;
- break;
- case ANYBUT:
- if (*reginput == '\0' ||
- strchr(OPERAND(scan), *reginput) != NULL)
- return false;
- reginput++;
- break;
- case NOTHING:
- break;
- case BACK:
- break;
- case OPEN+1: case OPEN+2: case OPEN+3:
- case OPEN+4: case OPEN+5: case OPEN+6:
- case OPEN+7: case OPEN+8: case OPEN+9:
- case OPEN+10: case OPEN+11: case OPEN+12:
- case OPEN+13: case OPEN+14: case OPEN+15:
- case OPEN+16: case OPEN+17: case OPEN+18:
- case OPEN+19:
- {
- const int no = OP(scan) - OPEN;
- char * const input = reginput;
-
- if (regmatch(next))
- {
- // Don't set startp if some later
- // invocation of the same parentheses
- // already has.
-
- if (regstartp[no] == NULL)
- regstartp[no] = input;
- return true;
- }
- else
- return false;
- break;
- }
- case CLOSE+1: case CLOSE+2: case CLOSE+3:
- case CLOSE+4: case CLOSE+5: case CLOSE+6:
- case CLOSE+7: case CLOSE+8: case CLOSE+9:
- case CLOSE+10: case CLOSE+11: case CLOSE+12:
- case CLOSE+13: case CLOSE+14: case CLOSE+15:
- case CLOSE+16: case CLOSE+17: case CLOSE+18:
- case CLOSE+19:
- {
- const int no = OP(scan) - CLOSE;
- char * const input = reginput;
-
- if (regmatch(next))
- {
- // Don't set endp if some later
- // invocation of the same parentheses
- // already has.
-
- if (regendp[no] == NULL)
- regendp[no] = input;
- return true;
- }
- else
- return false;
- break;
- }
- case BRANCH:
- {
- char * const save = reginput;
-
- if (OP(next) != BRANCH) // No choice.
- next = OPERAND(scan); // Avoid recursion.
- else
- {
- while (OP(scan) == BRANCH)
- {
- if (regmatch(OPERAND(scan)))
- return true;
- reginput = save;
- scan = regnext(scan);
- }
- return false;
- // NOTREACHED
- }
- break;
- }
- case STAR: case PLUS:
- {
- const char nextch = (OP(next) == EXACTLY) ? *OPERAND(next) : '\0';
- size_t no;
- char * const save = reginput;
- const size_t min = (OP(scan) == STAR) ? 0 : 1;
-
- for (no = regrepeat(OPERAND(scan)) + 1; no > min; no--)
- {
- reginput = save + no - 1;
- // If it could work, try it.
- if (nextch == '\0' || *reginput == nextch)
- if (regmatch(next))
- return true;
- }
- return false;
- break;
- }
- case END:
- return true; // Success!
- break;
- default:
- regerror( REGERR_CORRUPTION );
- return false;
- break;
- }
- }
-
- // We get here only if there's trouble -- normally "case END" is
- // the terminating point.
-
- regerror( REGERR_CORRUPTED_POINTERS );
- return false;
-}
-
-// regrepeat - report how many times something simple would match
-
-size_t CRegExecutor::regrepeat( char * node )
-{
- size_t count;
- char * scan;
- char ch;
-
- switch (OP(node))
- {
- case ANY:
- return(strlen(reginput));
- break;
- case EXACTLY:
- ch = *OPERAND(node);
- count = 0;
- for (scan = reginput; *scan == ch; scan++)
- count++;
- return(count);
- break;
- case ANYOF:
- return(strspn(reginput, OPERAND(node)));
- break;
- case ANYBUT:
- return(strcspn(reginput, OPERAND(node)));
- break;
- default: // Oh dear. Called inappropriately.
- regerror( REGERR_BAD_REGREPEAT );
- return(0); // Best compromise.
- break;
- }
- // NOTREACHED
-}
-
-#ifdef _RE_DEBUG
-
-// regdump - dump a regexp onto stdout in vaguely comprehensible form
-
-void regexp::regdump()
-{
- char * s;
- char op = EXACTLY; // Arbitrary non-END op.
- char * next;
-
- s = program + 1;
- while (op != END)
- { // While that wasn't END last time...
- op = OP(s);
- printf("%2d%s", s-program, regprop(s)); // Where, what.
- next = regnext(s);
- if (next == NULL) // Next ptr.
- printf("(0)" );
- else
- printf("(%d)", (s-program)+(next-s));
- s += 3;
- if (op == ANYOF || op == ANYBUT || op == EXACTLY)
- {
- // Literal string, where present.
- while (*s != '\0')
- {
- putchar(*s);
- s++;
- }
- s++;
- }
- putchar('\n');
- }
-
- // Header fields of interest.
- if (regstart != '\0')
- printf("start `%c' ", regstart);
- if (reganch)
- printf("anchored ");
- if (regmust != NULL)
- printf("must have \"%s\"" , regmust);
- printf("\n");
-}
-
-// regprop - printable representation of opcode
-
-#define OUTPUT(s) case s: p = #s; break
-char * CRegProgramAccessor::regprop( char * op )
-{
- char * p = NULL;
- static char buf[50];
-
- (void) strcpy(buf, ":" );
-
- switch (OP(op))
- {
- OUTPUT( BOL );
- OUTPUT( EOL );
- OUTPUT( ANY );
- OUTPUT( ANYOF );
- OUTPUT( ANYBUT );
- OUTPUT( BRANCH );
- OUTPUT( EXACTLY );
- OUTPUT( NOTHING );
- OUTPUT( BACK );
- OUTPUT( END );
- OUTPUT( STAR );
- OUTPUT( PLUS );
- OUTPUT( WORDA );
- OUTPUT( WORDZ );
- case OPEN+1: case OPEN+2: case OPEN+3:
- case OPEN+4: case OPEN+5: case OPEN+6:
- case OPEN+7: case OPEN+8: case OPEN+9:
- case OPEN+10: case OPEN+11: case OPEN+12:
- case OPEN+13: case OPEN+14: case OPEN+15:
- case OPEN+16: case OPEN+17: case OPEN+18:
- case OPEN+19:
- sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN);
- p = NULL;
- break;
- case CLOSE+1: case CLOSE+2: case CLOSE+3:
- case CLOSE+4: case CLOSE+5: case CLOSE+6:
- case CLOSE+7: case CLOSE+8: case CLOSE+9:
- case CLOSE+10: case CLOSE+11: case CLOSE+12:
- case CLOSE+13: case CLOSE+14: case CLOSE+15:
- case CLOSE+16: case CLOSE+17: case CLOSE+18:
- case CLOSE+19:
- sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE);
- p = NULL;
- break;
- default:
- regerror( REGERR_CORRUPTED_OPCODE );
- break;
- }
- if (p != NULL)
- (void) strcat(buf, p);
- return(buf);
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-
-Regexp::Regexp()
- : rc(0),
- str(0)
-{
-}
-
-Regexp::Regexp( const char * exp, bool iCase )
- : rc( new regexp( exp, iCase ) ),
- str( 0 )
-{
-}
-
-Regexp::Regexp( const Regexp &r )
- : rc( r.rc ),
- m_szError(r.m_szError),
- str(r.str)
-{
- if ( rc )
- rc->count++;
-}
-
-const Regexp & Regexp::operator=( const Regexp & r )
-{
- if ( this != &r )
- {
- if ( rc && rc->count-- == 0 )
- delete rc;
-
- rc = r.rc;
- if ( rc )
- rc->count++;
-
- str = r.str;
- m_szError = r.m_szError;
- }
- return *this;
-}
-
-Regexp::~Regexp()
-{
- if ( rc && rc->count-- == 0 )
- delete rc;
-}
-
-bool Regexp::Match( const char * s )
-{
- ClearErrorString();
- str = s;
- bool ret = false;
- if ( rc )
- {
- // copy on write !
-
- if ( rc->count )
- {
- rc->count--;
- rc = rc->getCopy();
- }
-
- ret = rc->regexec( s );
- int i = 0;
- if ( ret )
- for ( i = 0; i < Regexp::NSUBEXP && rc->startp[i] ; i++ )
- ;
- rc->numSubs = i - 1;
- }
- else
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- return ret;
-}
-
-ivy::string Regexp::GetReplaceString( const char * source ) const
-{
- ClearErrorString();
- if ( rc )
- return rc->GetReplaceString( source );
- else
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- return "";
-}
-
-int Regexp::SubStrings() const
-{
- ClearErrorString();
- int ret = -1;
- if ( rc )
- ret = rc->numSubs;
- else
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- return ret;
-}
-
-size_t Regexp::SubStart( size_t i ) const
-{
- ClearErrorString();
- size_t ret = -1;
- if ( rc )
- ret = rc->startp[safeIndex(i)] - str;
- else
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- return ret;
-}
-
-size_t Regexp::SubLength( size_t i ) const
-{
- ClearErrorString();
- size_t ret = -1;
- if ( rc )
- {
- i = safeIndex(i);
- ret = rc->endp[i] - rc->startp[i];
- }
- else
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- return ret;
-}
-
-bool Regexp::CompiledOK() const
-{
- return rc ? rc->Status() : false;
-}
-
-#ifdef _RE_DEBUG
-void Regexp::Dump()
-{
- if ( rc )
- rc->regdump();
-#if defined( _DEBUG )
- else
- TRACE( "No regexp to dump out\n" );
-#endif
-}
-#endif
-
-size_t Regexp::safeIndex( size_t i ) const
-{
- return i < Regexp::NSUBEXP ? i : Regexp::NSUBEXP;
-}
-
-const ivy::string Regexp::operator[]( size_t i ) const
-{
- ivy::string value;
- ClearErrorString();
- ASSERT( rc );
- if ( rc )
- {
- size_t len = SubLength(i);
- //char * szbuf = buffer.GetBufferSetLength( len );
- //memcpy( szbuf, rc->startp[i], len * sizeof(char) );
- //buffer.ReleaseBuffer();
- value = ivy::string ( rc->startp[i], len );
- }
- else
- {
- m_szError = CRegErrorHandler::FindErr( REGERR_NO_REGEXP );
- }
- return value;
-}
-
-void regexp::ignoreCase( const char * in, char * out )
-{
- // copy in to out making every top level character a [Aa] set
- bool inRange = false;
- while( *in )
- {
- if ( *in == '[' )
- inRange = true;
- if ( *in == ']' )
- inRange = false;
- if ( ! inRange && isalpha( *in ) )
- {
- *out++ = '[';
- *out++ = (char)toupper( *in );
- *out++ = (char)tolower( *in );
- *out++ = ']';
- }
- else
- *out++ = *in;
- in++;
- }
- *out = 0;
-}
-
-// GetReplaceString - Converts a replace expression to a string
-// - perform substitutions after a regexp match
-// Returns - The resultant string
-ivy::string regexp::GetReplaceString( const char* sReplaceExp ) const
-{
- ivy::string szEmpty( "" );
-
- char *src = (char *)sReplaceExp;
- //char *buf;
- char c;
- int no;
- size_t len;
-
- if( sReplaceExp == NULL )
- {
- regerror( REGERR_NULL_TO_REGSUB );
- return szEmpty;
- }
- if ( *program != MAGIC)
- {
- regerror( REGERR_DAMAGED_REGEXP_REGSUB );
- return szEmpty;
- }
-
- // First compute the length of the string
- size_t replacelen = 0;
- while ((c = *src++) != '\0')
- {
- if (c == '&')
- no = 0;
- else if (c == '\\' && isdigit(*src))
- no = *src++ - '0';
- else
- no = -1;
-
- if (no < 0)
- {
- // Ordinary character.
- if (c == '\\' && (*src == '\\' || *src == '&'))
- c = *src++;
- replacelen++;
- }
- else if (startp[no] != NULL && endp[no] != NULL &&
- endp[no] > startp[no])
- {
- // Get tagged expression
- len = endp[no] - startp[no];
- replacelen += len;
- }
- }
-
- ivy::string szReplace;
-
- //buf = szReplace.GetBufferSetLength( replacelen );
-
- // Now we can create the string
- src = (char *)sReplaceExp;
- while ((c = *src++) != '\0')
- {
- if (c == '&')
- no = 0;
- else if (c == '\\' && isdigit(*src))
- no = *src++ - '0';
- else
- no = -1;
-
- if (no < 0)
- {
- // Ordinary character.
- if (c == '\\' && (*src == '\\' || *src == '&'))
- c = *src++;
- //*buf++ = c;
- szReplace += c ;
- }
- else if (startp[no] != NULL && endp[no] != NULL &&
- endp[no] > startp[no])
- {
- // Get tagged expression
- len = endp[no] - startp[no];
- //strncpy(buf, startp[no], len);
- //buf += len;
- szReplace.append( startp[no], len );
-// if (len != 0 && *(buf-1) == '\0' ))
-// { /* strncpy hit NUL. */
-// regerror( REGERR_DAMAGED_MATCH_STRING );
-// return szEmpty;
-// }
- }
- }
-
- //szReplace.ReleaseBuffer( replacelen );
- return szReplace;
-}
-
-ivy::string Regexp::GetErrorString() const
-{
- // make sure that if status == 0 that we have an error string
- //assert( ( ! CompiledOK() ) ? ( rc ? rc->GetErrorString() : m_szError).length() != 0 : 1 );
- return rc ? rc->GetErrorString() : m_szError ;
-}
-
-void Regexp::ClearErrorString() const
-{
- if ( rc )
- rc->ClearErrorString();
- m_szError.erase();
-}
-