/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbRegExp.h
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/
#define _xbSD(name)		name ## A
#define _xbSTR			xbString
#define _xbCHAR			char
#define _xbUCHAR		uchar

//http://en.wikipedia.org/wiki/Regular_expression#POSIX_Basic_Regular_Expressions

/*
Norme retenue: POSIX ERE.
+ Extension pour les buffers:
$X ou $XX, 
Example:
sub *toto *\($1,$2,$3\) *\{$4\}
-> rpl par:
sub tutu($3,$2,$1) {}

Basic concepts
A regular expression, often called a pattern, is an expression that describes a set of strings. They are usually used to give a concise description of a set, without having to list all elements. For example, the set containing the three strings "Handel", "Händel", and "Haendel" can be described by the pattern H(ä|ae?)ndel (or alternatively, it is said that the pattern matches each of the three strings). In most formalisms, if there is any regex that matches a particular set then there is an infinite number of such expressions. Most formalisms provide the following operations to construct regular expressions.

Boolean "or" 
A vertical bar separates alternatives. For example, gray|grey can match "gray" or "grey". 
Grouping 
Parentheses are used to define the scope and precedence of the operators (among other uses). 
For example, gray|grey and gr(a|e)y are equivalent patterns which both describe the set of "gray" and "grey". 
Quantification 
A quantifier after a token (such as a character) or group specifies how often that preceding element is allowed 
to occur. The most common quantifiers are the question mark ?, the asterisk * (derived from the Kleene star),
and the plus sign +. 
? The question mark indicates there is zero or one of the preceding element. 
	For example, colou?r matches both "color" and "colour". 
* The asterisk indicates there are zero or more of the preceding element. 
	For example, ab*c matches "ac", "abc", "abbc", "abbbc", and so on. 
+ The plus sign indicates that there is one or more of the preceding element. 
	For example, ab+c matches "abc", "abbc", "abbbc", and so on, but not "ac". 

These constructions can be combined to form arbitrarily complex expressions, much like one can construct 
arithmetical expressions from numbers and the operations +, -, ×, and ÷. For example, H(ae?|a)ndel 
and H(a|ae|a)ndel are both valid patterns which match the same strings as the earlier example, H(a|ae?)ndel.

The precise syntax for regular expressions varies among tools and with context; more detail is given 
in the Syntax section

Metacharacter Description 
. Matches any single character (many applications exclude newlines, and exactly which characters 
are considered newlines is flavor, character encoding, and platform specific, but it is safe 
to assume that the line feed character is included). 
Within POSIX bracket expressions, the dot character matches a literal dot. 
For example, a.c matches "abc", etc., but [a.c] matches only "a", ".", or "c". 
[ ] A bracket expression. Matches a single character that is contained within the brackets. 
For example, [abc] matches "a", "b", or "c". [a-z] specifies a range which matches any 
lowercase letter from "a" to "z". These forms can be mixed: 
[abcx-z] matches "a", "b", "c", "x", "y", or "z", as does [a-cx-z]. 
The - character is treated as a literal character if it is the last or the first character 
within the brackets, or if it is escaped with a backslash: [abc-], [-abc], or [a\-bc].
 
[^ ] Matches a single character that is not contained within the brackets. 
For example, [^abc] matches any character other than "a", "b", or "c". [^a-z] matches any 
single character that is not a lowercase letter from "a" to "z". As above, literal characters 
and ranges can be mixed. 
^ Matches the starting position within the string. In line-based tools, it matches the starting position of any line. 
$ Matches the ending position of the string or the position just before a string-ending newline. In line-based tools, it matches the ending position of any line. 
BRE: \( \)
ERE: ( ) Defines a marked subexpression. The string matched within the parentheses can be recalled 
later (see the next entry, \n). A marked subexpression is also called a block or capturing group. 
\n Matches what the nth marked subexpression matched, where n is a digit from 1 to 9. This construct 
is theoretically irregular and was not adopted in the POSIX ERE syntax. Some tools allow referencing 
more than nine capturing groups. 
* Matches the preceding element zero or more times. For example, ab*c matches "ac", "abc", "abbbc", 
etc. [xyz]* matches "", "x", "y", "z", "zx", "zyx", "xyzzy", and so on. 
\(ab\)* matches "", "ab", "abab", "ababab", and so on. 
BRE: \{m,n\}
ERE: {m,n} Matches the preceding element at least m and not more than n times. For example, a\{3,5\} matches only "aaa", "aaaa", and "aaaaa". This is not found in a few, older instances of regular expressions. 

Examples:

.at matches any three-character string ending with "at", including "hat", "cat", and "bat". 
[hc]at matches "hat" and "cat". 
[^b]at matches all strings matched by .at except "bat". 
^[hc]at matches "hat" and "cat", but only at the beginning of the string or line. 
[hc]at$ matches "hat" and "cat", but only at the end of the string or line. 

[edit] POSIX Extended Regular Expressions
The meaning of metacharacters escaped with a backslash is reversed for some characters 
in the POSIX Extended Regular Expression (ERE) syntax. With this syntax, a backslash causes 
the metacharacter to be treated as a literal character. 
So, for example, \( \) is now ( ) and \{ \} is now { }. 
Additionally, support is removed for \n backreferences and the following metacharacters are added:

Metacharacter Description 
? Matches the preceding element zero or one time. For example, ba? matches "b" or "ba". 
+ Matches the preceding element one or more times. For example, ba+ matches "ba", "baa", "baaa", 
and so on. 
| The choice (aka alternation or set union) operator matches either the expression before 
or the expression after the operator. For example, abc|def matches "abc" or "def". 

Examples:

[hc]+at matches "hat", "cat", "hhat", "chat", "hcat", "ccchat", and so on, but not "at". 
[hc]?at matches "hat", "cat", and "at". 
cat|dog matches "cat" or "dog". 
*/

/*
[edit] POSIX character classes
Since many ranges of characters depend on the chosen locale setting (i.e., in some settings 
letters are organized as abc...zABC...Z, while in some others as aAbBcC...zZ), 
the POSIX standard defines some classes or categories of characters as shown in the following table:

POSIX Perl ASCII Description 
[:alnum:]  [A-Za-z0-9] Alphanumeric characters 
[:word:] \w [A-Za-z0-9_] Alphanumeric characters plus "_" 
 \W [^\w] non-word character 
[:alpha:]  [A-Za-z] Alphabetic characters 
[:blank:]  [ \t] Space and tab 
[:cntrl:]  [\x00-\x1F\x7F] Control characters 
[:digit:] \d [0-9] Digits 
 \D [^\d] non-digit 
[:graph:]  [\x21-\x7E] Visible characters 
[:lower:]  [a-z] Lowercase letters 
[:print:]  [\x20-\x7E] Visible characters and spaces 
[:punct:]  [-!"#$%&'()*+,./:;<=>?@[\\\]_`{|}~] Punctuation characters 
[:space:] \s [ \t\r\n\v\f] Whitespace characters 
 \S [^\s] non-whitespace character 
[:upper:]  [A-Z] Uppercase letters 
[:xdigit:]  [A-Fa-f0-9] Hexadecimal digits 

POSIX character classes can only be used within bracket expressions. 
For example, [[:upper:]ab] matches the uppercase letters and lowercase "a" and "b".

In Perl regular expressions, [:print:] matches [:graph:] union [:space:]. 
An additional non-POSIX class understood by some tools is [:word:], 
which is usually defined as [:alnum:] plus underscore. 
This reflects the fact that in many programming languages these are the characters 
that may be used in identifiers. The editor Vim further distinguishes word and word-head 
classes (using the notation \w and \h) since in many programming languages the characters 
that can begin an identifier are not the same as those that can occur in other positions.

Note that what the POSIX regular expression standards call character classes are commonly referred 
to as POSIX character classes in other regular expression flavors which support them. 
With most other regular expression flavors, the term character class is used to describe 
what POSIX calls bracket expressions
*/
class xbEXPORT _xbSD(xbRegExp)
{
public:
	_xbSD(xbRegExp)()
		:m_mode(0),m_tabSz(0),m_cBuffer(-1)
	{
	}
	void SetCaseDep(bool bVal);
	bool GetCaseDep() const {return (m_mode & xbRegExp_CASEDEP)?true:false;}
	void SetWholeWord(bool bVal);
	bool GetWholeWord() const {return (m_mode & xbRegExp_WHOLEWORD)?true:false;}
	void SetLocale(bool bVal);
	bool GetLocale() const {return (m_mode & xbRegExp_LOCALE)?true:false;}
	void SetCsyntax(bool bVal);
	bool GetCsyntax() const {return (m_mode & xbRegExp_CSYNTAX)?true:false;}
	void SetXDsyntax(bool bVal);
	bool GetXDsyntax() const {return (m_mode & xbRegExp_XDSYNTAX)?true:false;}
	bool IsCsyntax() const {return (m_mode & (xbRegExp_CSYNTAX|xbRegExp_XDSYNTAX))?true:false;}
	void SetMode(ulong mode) {m_mode = mode;}
	void SetTabLength(ulong tabSz) {m_tabSz = tabSz;}
	ulong GetTabLength() {return m_tabSz;}

	bool FindExpr(const _xbSTR &expr, int *pInvalidPos = NULL, xbOpMode opm =xbOp_Required);
	bool FindString(const _xbSTR &str,bool bSpcTolerant = true);
	bool FindExprAdd(const _xbSTR &expr, int *pInvalidPos = NULL, xbOpMode opm =xbOp_Required);
	bool FindStringAdd(const _xbSTR &str,bool bSpcTolerant = true);
	void Reset();

	bool ParseLine(const _xbSTR &line);
	bool ParseText(const _xbSTR &txt);

	//Position occurence trouvée
	bool GetStartPos(ulong *pLine, ulong *pCol, ulong *pOffs) const;
	bool GetEndPos(ulong *pLine, ulong *pCol, ulong *pOffs) const;
	int GetExprFound() const;

	//Buffers remplis
	bool GetBuffers(xbArray<_xbSTR> *pArr) const;
	void SetBuffers(const xbArray<_xbSTR> &arr);
	void SetBuffersLength(int cBuffer);
	int GetBuffersLength() const const;
	bool ReplaceWithBuffers(const _xbSTR &strRpl, _xbSTR *pStrResult) const;
protected:
	ulong m_mode;	//cf xbRegExp_*
	ulong m_tabSz;	//0-> pas de calc tab
	int m_cBuffer;	//0-> pas de support sur buffers, -1 -> on s'en fout, X le nombre de buffers remplis doit etre de X buffers
};

class _xbSD(xbRegExpIt_Base):public xbBase
{
public:
	_xbSD(xbRegExpIt_Base)()
	{
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbDnSession);
		return xbBase::GetInterface(riid,ppInterf);
	}
};

class _xbSD(xbRegExpIt_BaseWithChild):public _xbSD(xbRegExpIt_Base)
{
public:
	_xbSD(xbRegExpIt_BaseWithChild)()
	{
	}

	xbPtrArray<_xbSD(xbRegExpIt_Base)> m_arrChild;
};

class _xbSD(xbRegExpIt_Word):public _xbSD(xbRegExpIt_Base)
{
public:
	xbRegExpIt_Word(const _xbSTR &word)
		:m_word(word)
	{
	}

	_xbSTR	m_word;
};

class _xbSD(xbRegExpIt_CharList):public _xbSD(xbRegExpIt_Base)
{
public:
	xbRegExpIt_CharList(const _xbSTR &chars)
		:m_chars(chars)
	{
	}

	_xbSTR	m_chars;
};

class _xbSD(xbRegExpIt_CharAlone):public _xbSD(xbRegExpIt_Base)
{
public:
	xbRegExpIt_CharRange(_xbUCHAR charAlone)
		:m_char(charAlone)
	{
	}

	_xbUCHAR	m_char;
};

class _xbSD(xbRegExpIt_CharRange):public _xbSD(xbRegExpIt_Base)
{
public:
	xbRegExpIt_CharRange(_xbUCHAR charStart,_xbUCHAR charEnd)
		:m_charStart(charStart),m_charEnd(charEnd)
	{
	}

	_xbUCHAR	m_charStart;
	_xbUCHAR	m_charEnd;
};

//[...]
class _xbSD(xbRegExpIt_CharMatch):public _xbSD(xbRegExpIt_BaseWithChild)
{
public:
	xbRegExpIt_CharMatch(bool bNot)
		:m_bNot(bNot)
	{
	}

	bool m_bNot;
};

//(...)
class _xbSD(xbRegExpIt_ExprBlock):public _xbSD(xbRegExpIt_BaseWithChild)
{
public:
	xbRegExpIt_CharMatch(bool bNot)
		:m_bNot(bNot)
	{
	}

	bool m_bNot;
};
