mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1391 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			1391 lines
		
	
	
		
			58 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //+------------------------------------------------------------------+
 | |
| //|                                               Regular Expression |
 | |
| //|                        Copyright 2016, MetaQuotes Software Corp. |
 | |
| //|                                             https://www.mql5.com |
 | |
| //+------------------------------------------------------------------+
 | |
| //| Regular Expression Library from .NET Framework 4.6.1 implemented |
 | |
| //| in MetaQuotes Language 5 (MQL5)                                  |
 | |
| //| Original sources at https://github.com/Microsoft/referencesource |
 | |
| //|                                                                  |
 | |
| //| The capabilities of the Regular Expression Library include:      |
 | |
| //| - Lazy quantifiers                                               |
 | |
| //| - Positive and negative lookbehind                               |
 | |
| //| - Conditional evaluation                                         |
 | |
| //| - Balancing group definitions                                    |
 | |
| //| - Nonbacktracking subexpressions                                 |
 | |
| //| - Right-to-left matching                                         |
 | |
| //|                                                                  |
 | |
| //| If you find any functional differences between Regular Expression|
 | |
| //| Library for MQL5 and the original .NET Framework 4.6.1 project,  |
 | |
| //| please contact developers of MQL5 on the Forum at www.mql5.com.  |
 | |
| //|                                                                  |
 | |
| //| You can report bugs found in the computational algorithms of the |
 | |
| //| Regular Expression Library from .Net Framework 4.6.1 by notifying|
 | |
| //| the project coordinators.                                        |
 | |
| //+------------------------------------------------------------------+
 | |
| //|                     The MIT License (MIT)                        |
 | |
| //|                                                                  |
 | |
| //| 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.                                  |
 | |
| //|                                                                  |
 | |
| //| A copy of the MIT License (MIT) is available at                  |
 | |
| //| https://opensource.org/licenses/MIT                              |
 | |
| //+------------------------------------------------------------------+
 | |
| class Match;
 | |
| class MatchCollection;
 | |
| class CachedCodeEntry;
 | |
| class ReplacementReference;
 | |
| class RunnerReference;
 | |
| class RegexRunner;
 | |
| //+------------------------------------------------------------------+
 | |
| //| Callback class.                                                  |
 | |
| //+------------------------------------------------------------------+
 | |
| typedef string(*MatchEvaluator)(Match*);
 | |
| #include <Internal\TimeSpan\TimeSpan.mqh>
 | |
| #include <Internal\Generic\LinkedList.mqh>
 | |
| #include <Internal\Generic\Dictionary.mqh>
 | |
| #include "RegexOptions.mqh"
 | |
| #include "RegexCode.mqh"
 | |
| #include "RegexTree.mqh"
 | |
| #include "RegexParser.mqh"
 | |
| #include "RegexReplacement.mqh"
 | |
| #include "RegexWriter.mqh"
 | |
| #include "RegexMatchCollection.mqh"
 | |
| #include "RegexRunner.mqh"
 | |
| #include "RegexInterpreter.mqh"
 | |
| //+------------------------------------------------------------------+
 | |
| //| Purpose: The Regex class represents a single compiled instance of| 
 | |
| //| a regular expression.                                            |
 | |
| //+------------------------------------------------------------------+
 | |
| //+------------------------------------------------------------------+
 | |
| //| Represents an immutable, compiled regular expression. Also       |
 | |
| //| contains static methods that allow use of regular expressions    |
 | |
| //| without instantiating a Regex explicitly.                        |
 | |
| //+------------------------------------------------------------------+
 | |
| class Regex
 | |
|   {
 | |
| protected:
 | |
|    string            m_pattern;
 | |
|    RegexOptions      m_roptions;
 | |
| private:
 | |
|    static const TimeSpan MaximumMatchTimeout;
 | |
| public:
 | |
|    static const TimeSpan InfiniteMatchTimeout;
 | |
| protected:
 | |
|    TimeSpan          m_internalMatchTimeout;// timeout for the execution of this regex
 | |
| private:
 | |
|    static const string DefaultMatchTimeout_ConfigKeyName;
 | |
| public:
 | |
|    static const TimeSpan FallbackDefaultMatchTimeout;
 | |
|    static const TimeSpan DefaultMatchTimeout;
 | |
| protected:
 | |
|    Dictionary<int,int>*m_caps;        // if captures are sparse, this is the hashtable capnum->index
 | |
|    Dictionary<string,int>*m_capnames; // if named captures are used, this maps names->index
 | |
|    string            m_capslist[];    // if captures are sparse or named captures are used, this is the sorted list of names
 | |
|    int               m_capsize;       // the size of the capture array
 | |
|    RegexTree        *m_tree;
 | |
|    RunnerReference *m_runnerref;      // cached runner
 | |
|    ReplacementReference*m_replref;    // cached parsed replacement pattern
 | |
|    RegexCode        *m_code;          // if interpreted, this is the code for RegexIntepreter
 | |
|    bool              m_refsInitialized;// Default is false
 | |
|    static            LinkedList<CachedCodeEntry*>m_livecode;// the cached of code that are currently loaded
 | |
|    static int        m_cacheSize;     // Default is 15
 | |
| public:
 | |
|    static const int  MaxOptionShift;
 | |
| public:
 | |
|    //--- Constructors:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Initializes a new instance of the Regex class.                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      Regex() : m_refsInitialized(false)
 | |
|      {
 | |
|       this.m_internalMatchTimeout=DefaultMatchTimeout;
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Creates and compiles a regular expression object for the         |
 | |
|    //| specified regular expression.                                    |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      Regex(const string pattern) : m_refsInitialized(0)
 | |
|      {
 | |
|       Initialize(pattern,None,DefaultMatchTimeout,false);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Creates and compiles a regular expression object for the         |
 | |
|    //| specified regular expression with options that modify the        |
 | |
|    //| pattern.                                                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      Regex(const string pattern,RegexOptions options) : m_refsInitialized(0)
 | |
|      {
 | |
|       Initialize(pattern,options,DefaultMatchTimeout,false);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Initializes a new instance of the Regex class for the specified  |
 | |
|    //| regular expression,with options that modify the pattern and a    |
 | |
|    //| value that specifies how long a pattern matching method should   |
 | |
|    //| attempt a match before it times out.                             |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      Regex(const string pattern,RegexOptions options,const TimeSpan &matchTimeout) : m_refsInitialized(0)
 | |
|      {
 | |
|       Initialize(pattern,options,matchTimeout,false);
 | |
|      }
 | |
|    //--- Destructors:     
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Destructor without parameters.                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|                     ~Regex()
 | |
|      {
 | |
|       if(CheckPointer(m_tree)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_tree;
 | |
|         }
 | |
|       if(CheckPointer(m_caps)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_caps;
 | |
|         }
 | |
|       bool deleteRun=true;
 | |
|       bool deleteRepl = true;
 | |
|       bool deleteCode = true;
 | |
|       for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | |
|         {
 | |
|          if(CheckPointer(current.Value())==POINTER_DYNAMIC)
 | |
|            {
 | |
|             if(current.Value().RunnerRef()==m_runnerref)
 | |
|               {
 | |
|                deleteRun=false;
 | |
|               }
 | |
|             if(current.Value().ReplRef()==m_replref)
 | |
|               {
 | |
|                deleteRepl=false;
 | |
|               }
 | |
|             if(current.Value().Code()==m_code)
 | |
|               {
 | |
|                deleteCode=false;
 | |
|               }
 | |
|            }
 | |
|         }
 | |
|       if(CheckPointer(m_replref)==POINTER_DYNAMIC && deleteRepl)
 | |
|         {
 | |
|          delete m_replref;
 | |
|         }
 | |
|       if(CheckPointer(m_runnerref)==POINTER_DYNAMIC && deleteRun)
 | |
|         {
 | |
|          delete m_runnerref;
 | |
|         }
 | |
|       if(CheckPointer(m_code)==POINTER_DYNAMIC && deleteCode)
 | |
|         {
 | |
|          delete m_code;
 | |
|         }
 | |
|      }
 | |
| private:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| General constructor with parameters.                             |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      Regex(const string pattern,RegexOptions options,const TimeSpan &matchTimeout,const bool useCache) : m_refsInitialized(0)
 | |
|      {
 | |
|       Initialize(pattern,options,matchTimeout,useCache);
 | |
|      }
 | |
|    //--- Methods:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Initialize.                                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void Initialize(const string pattern,RegexOptions options,const TimeSpan &matchTimeout,const bool useCache)
 | |
|      {
 | |
|       RegexTree *tree;
 | |
|       CachedCodeEntry *cached=NULL;
 | |
|       if(pattern==NULL)
 | |
|         {
 | |
|          Print("Argument 'pattern'= Null.");
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       if(options<None || (((int) options)>>MaxOptionShift)!=0)
 | |
|         {
 | |
|          Print("Argument 'options' out of range.");
 | |
|          //--- return 
 | |
|          return;
 | |
|         }
 | |
|       if((options    &ECMAScript)!=0
 | |
|          && (options  &~(ECMAScript|IgnoreCase|Multiline
 | |
|          #ifdef _DEBUG
 | |
|          |Debug
 | |
|          #endif
 | |
|          ))!=0)
 | |
|         {
 | |
|          Print("Argument 'options' out of range");
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       ValidateMatchTimeout(matchTimeout);
 | |
|       //--- Try to look up this regex in the cache.  We do this regardless of whether useCache is true since there's really no reason not to. 
 | |
|       string key=IntegerToString(options)+":"+pattern;
 | |
|       cached=LookupCachedAndUpdate(key);
 | |
|       this.m_pattern=pattern;
 | |
|       this.m_roptions=options;
 | |
|       this.m_internalMatchTimeout=matchTimeout;
 | |
|       if(cached==NULL)
 | |
|         {
 | |
|          //--- Parse the input
 | |
|          tree=RegexParser::Parse(pattern,(RegexOptions)m_roptions);
 | |
|          //--- Extract the relevant information
 | |
|          m_capnames=tree.CapNames();
 | |
|          tree.GetCapsList(m_capslist);
 | |
|          m_code       = RegexWriter::Write(tree);
 | |
|          m_caps       = m_code.Caps();
 | |
|          m_capsize    = m_code.CapSize();
 | |
|          InitializeReferences();
 | |
|          m_tree=tree;
 | |
|          if(useCache)
 | |
|            {
 | |
|             cached=CacheCode(key);
 | |
|            }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|          m_caps       = cached.Caps();
 | |
|          m_capnames   = cached.CapNames();
 | |
|          cached.GetCapList(m_capslist);
 | |
|          m_capsize    = cached.CapSize();
 | |
|          m_code       = cached.Code();
 | |
|          m_runnerref  = cached.RunnerRef();
 | |
|          m_replref    = cached.ReplRef();
 | |
|          m_refsInitialized=true;
 | |
|         }
 | |
|      }
 | |
| public:
 | |
|    //--- Methods:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Pattern.                                                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Pattern()
 | |
|      {
 | |
|       //--- return pattern
 | |
|       return (m_pattern);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Validates that the specified match timeout value is valid.       |
 | |
|    //| The valid range is:                                              | 
 | |
|    //| TimeSpan::Zero < matchTimeout <= Regex::MaximumMatchTimeout.     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void ValidateMatchTimeout(const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       if(InfiniteMatchTimeout==matchTimeout)
 | |
|         {
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       //--- Change this to make sure timeout is not longer then Environment.Ticks cycle length:
 | |
|       if(TimeSpan::Zero()<matchTimeout && matchTimeout<=MaximumMatchTimeout)
 | |
|         {
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       Print("Argument 'matchTimeout' out of range.");
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Specifies the default RegEx matching timeout value (i.e. the     |
 | |
|    //| timeout that will be used if no explicit timeout is specified).  |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static TimeSpan InitDefaultMatchTimeout()
 | |
|      {
 | |
|       //--- retrun result
 | |
|       return (FallbackDefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the runner reference.                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RunnerReference*RunnerReference()
 | |
|      {
 | |
|       //--- return runner reference
 | |
|       return (m_runnerref);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the weak reference.                                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|    ReplacementReference*ReplacementReference()
 | |
|      {
 | |
|       //--- return week reference
 | |
|       return (m_replref);
 | |
|      };
 | |
|    Dictionary<int,int>*Caps()
 | |
|      {
 | |
|       //---
 | |
|       return (m_caps);
 | |
|      }
 | |
|    Dictionary<string,int>*CapNames()
 | |
|      {
 | |
|       //--- return 
 | |
|       return (m_capnames);
 | |
|      }
 | |
|    int CapSize()
 | |
|      {
 | |
|       //--- 
 | |
|       return (m_capsize);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns the options passed into the constructor.                 |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RegexOptions Options()
 | |
|      {
 | |
|       //--- return
 | |
|       return (m_roptions);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Escape metacharacters within the string.                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Escape(const string str)
 | |
|      {
 | |
|       if(StringLen(str)==NULL)
 | |
|         {
 | |
|          Print("Argument 'str' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return RegexParser::Escape(str);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Unescape character codes within the string.                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Unescape(const string str)
 | |
|      {
 | |
|       if(StringLen(str)==NULL)
 | |
|         {
 | |
|          Print("Argument 'str' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return RegexParser::Unescape(str);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| CacheCount.                                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static int CacheCount()
 | |
|      {
 | |
|       //--- return count
 | |
|       return (m_livecode.Count());
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| CacheSize.                                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static int CacheSize()
 | |
|      {
 | |
|       //--- return size
 | |
|       return (m_cacheSize);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| CacheSize.                                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void CacheSize(const int value)
 | |
|      {
 | |
|       if(value<0)
 | |
|         {
 | |
|          Print("Argument 'value' out of range.");
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       m_cacheSize=value;
 | |
|       if(m_livecode.Count()>m_cacheSize)
 | |
|         {
 | |
|          while(m_livecode.Count()>m_cacheSize)
 | |
|            {
 | |
|             m_livecode.RemoveLast();
 | |
|            }
 | |
|         }
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| The match timeout used by this Regex instance.                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    TimeSpan MatchTimeout()
 | |
|      {
 | |
|       //--- return result
 | |
|       return (m_internalMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| True if the regex is leftward.                                   |
 | |
|    //|                                                                  |
 | |
|    //| Indicates whether the regular expression matches from right to   |
 | |
|    //| left.                                                            |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool RightToLeft()
 | |
|      {
 | |
|       //--- return result
 | |
|       return UseOptionR();
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns the regular expression pattern passed into the           |
 | |
|    //| constructor.                                                     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string ToString()
 | |
|      {
 | |
|       //--- return result
 | |
|       return (m_pattern);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns an array of the group names that are used to capture     |
 | |
|    //| groups in the regular expression. Only needed if the regex is not|
 | |
|    //| known until runtime, and one wants to extract captured groups.   |
 | |
|    //| (Probably unusual, but supplied for completeness.).              |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void GetGroupNames(string &result[])
 | |
|      {
 | |
|       if(ArraySize(m_capslist)==NULL)
 | |
|         {
 | |
|          int max=m_capsize;
 | |
|          ArrayResize(result,max);
 | |
|          for(int i=0; i<max; i++)
 | |
|            {
 | |
|             result[i]=IntegerToString(i);
 | |
|            }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|          ArrayCopy(result,m_capslist,0,0);
 | |
|         }
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns an array of the group names that are used to capture     |
 | |
|    //| groups in the regular expression. Only needed if the regex is not|
 | |
|    //| known until runtime, and one wants to extract captured groups.   |
 | |
|    //| (Probably unusual, but supplied for completeness.).              |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void GetGroupNumbers(int &result[])
 | |
|      {
 | |
|       if(m_caps==NULL)
 | |
|         {
 | |
|          int max=m_capsize;
 | |
|          ArrayResize(result,max);
 | |
|          for(int i=0; i<max; i++)
 | |
|            {
 | |
|             result[i]=i;
 | |
|            }
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|          ArrayResize(result,m_caps.Count());
 | |
|          DictionaryEnumerator<int,int>*de=m_caps.GetEnumerator();
 | |
|          while(de.MoveNext())
 | |
|            {
 | |
|             result[(int)de.Value()]=(int)de.Key();
 | |
|            }
 | |
|          delete de;
 | |
|         }
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Given a group number, maps it to a group name. Note that nubmered|
 | |
|    //| groups automatically get a group name that is the decimal string |
 | |
|    //| equivalent of its number.                                        |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string GroupNameFromNumber(const int index)
 | |
|      {
 | |
|       int i=index;
 | |
|       if(ArraySize(m_capslist)==NULL)
 | |
|         {
 | |
|          if(i>=0 && i<m_capsize)
 | |
|            {
 | |
|             //--- return result
 | |
|             return IntegerToString(i);
 | |
|            }
 | |
|          //--- return result
 | |
|          return ("");
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|          if(m_caps!=NULL)
 | |
|            {
 | |
|             if(!m_caps.ContainsKey(i))
 | |
|               {
 | |
|                //--- return result
 | |
|                return ("");
 | |
|               }
 | |
|             i=m_caps[i];
 | |
|            }
 | |
|          if(i>=0 && i<ArraySize(m_capslist))
 | |
|            {
 | |
|             //--- return result
 | |
|             return (m_capslist[i]);
 | |
|            }
 | |
|          //--- return result
 | |
|          return ("");
 | |
|         }
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Given a group name, maps it to a group number. Note that nubmered|
 | |
|    //| groups automatically get a group name that is the decimal string |   
 | |
|    //| equivalent of its number.                                        |
 | |
|    //|                                                                  |
 | |
|    //| Returns -1 if the name is not a recognized group name.           |
 | |
|    //+------------------------------------------------------------------+
 | |
|    int GroupNumberFromName(const string name)
 | |
|      {
 | |
|       int result=-1;
 | |
|       if(name==NULL)
 | |
|         {
 | |
|          Print("Argument 'name' = NNULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- look up name if we have a hashtable of names
 | |
|       if(m_capnames!=NULL)
 | |
|         {
 | |
|          if(!m_capnames.ContainsKey(name))
 | |
|            {
 | |
|             //--- return result
 | |
|             return (-1);
 | |
|            }
 | |
|          //--- return result
 | |
|          return (m_capnames[name]);
 | |
|         }
 | |
|       //--- convert to an int if it looks like a number
 | |
|       result=0;
 | |
|       for(int i=0; i<StringLen(name); i++)
 | |
|         {
 | |
|          ushort ch=StringGetCharacter(name,i);
 | |
|          if(ch>'9' || ch<'0')
 | |
|            {
 | |
|             //--- return result
 | |
|             return (-1);
 | |
|            }
 | |
|          result *= 10;
 | |
|          result += (ch - '0');
 | |
|         }
 | |
|       //--- return int if it's in range
 | |
|       if(result>=0 && result<m_capsize)
 | |
|         {
 | |
|          //--- return result
 | |
|          return (result);
 | |
|         }
 | |
|       //--- return result
 | |
|       return (-1);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the input string for one or more occurrences of the text|
 | |
|    //| supplied in the pattern parameter.                               |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static bool IsMatch(const string in,const string pattern)
 | |
|      {
 | |
|       //--- return result
 | |
|       return IsMatch(in, pattern, None, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more occurrences of the text   |
 | |
|    //| supplied in the pattern parameter.                               |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static bool IsMatch(const string in,const string pattern,const RegexOptions options)
 | |
|      {
 | |
|       //--- return result
 | |
|       return IsMatch(in, pattern, options, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more occurrences of the text   |
 | |
|    //| supplied in the pattern parameter.                               |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static bool IsMatch(const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex regex(pattern,options,matchTimeout,true);
 | |
|       //--- return result
 | |
|       return (regex.IsMatch(in));
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more matches using the         |
 | |
|    //| previous pattern, options, and starting position.                |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool IsMatch(const string in)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return IsMatch(in, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more matches using the         |
 | |
|    //| previous pattern and options, with a new starting position.      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool IsMatch(const string in,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       Match *run=Run(true,-1,in,0,StringLen(in),startat);
 | |
|       bool result=(NULL==run);
 | |
|       if(CheckPointer(run)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete run;
 | |
|         }
 | |
|       //--- return result
 | |
|       return (result);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more occurrences of the text|
 | |
|    //| supplied in the pattern parameter.                               |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static Match *Match(const string in,const string pattern)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Regex::Match(in, pattern, None, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more occurrences of the text|
 | |
|    //| supplied in the pattern parameter. Matching is modified with an  |
 | |
|    //| option string.                                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static Match *Match(const string in,const string pattern,const RegexOptions options)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Regex::Match(in, pattern, options, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Searches the in string for one or more occurrences of the text|
 | |
|    //| supplied in the pattern parameter. Matching is modified with an  |
 | |
|    //| option string.                                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static Match *Match(string in,string pattern,RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex *regex=new Regex(pattern,options,matchTimeout,true);
 | |
|       //--- return result
 | |
|       return (regex.Match(in));
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Matches a regular expression with a string and returns the       |
 | |
|    //| precise result as a RegexMatch object.                           |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Match *Match(const string in)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Regex::Match(in, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Matches a regular expression with a string and returns the       |
 | |
|    //| precise result as a RegexMatch object.                           |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Match *Match(const string in,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Run(false, -1, in, 0, StringLen(in), startat);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Matches a regular expression with a string and returns the       |
 | |
|    //| precise result as a RegexMatch object.                           |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Match *Match(const string in,const int beginning,const int length)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Run(false, -1, in, beginning, length, UseOptionR() ? beginning + length : beginning);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns all the successful matches as if Match was called        |
 | |
|    //| iteratively numerous times.                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static MatchCollection *Matches(const string in,const string pattern)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Regex::Matches(in, pattern, None, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns all the successful matches as if Match was called        |
 | |
|    //| iteratively numerous times.                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static MatchCollection *Matches(const string in,const string pattern,const RegexOptions options)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Regex::Matches(in, pattern, options, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns all the successful matches as if Match was called        |
 | |
|    //| iteratively numerous times.                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static MatchCollection *Matches(const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex *regex=new Regex(pattern,options,matchTimeout,true);
 | |
|       //--- return result
 | |
|       return (regex.Matches(in));
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns all the successful matches as if Match was called        |
 | |
|    //| iteratively numerous times.                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    MatchCollection *Matches(const string in)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Matches(in, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Returns all the successful matches as if Match was called        |
 | |
|    //| iteratively numerous times.                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    MatchCollection *Matches(const string in,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return new MatchCollection(GetPointer(this), in, 0, StringLen(in), startat);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the pattern with the "replacement"   |
 | |
|    //| pattern, starting at the first character in the in string.       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,const string replacement)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Replace(in, pattern, replacement, None, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the "replacement" |
 | |
|    //| pattern, starting at the first character in the in string.       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,const string replacement,const RegexOptions options)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Replace(in, pattern, replacement, options, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the "replacement" |
 | |
|    //| pattern, starting at the first character in the in string.       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,const string replacement,const RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex *regex = new Regex(pattern,options,matchTimeout,true);
 | |
|       string result=regex.Replace(in,replacement);
 | |
|       delete regex;
 | |
|       //--- return result
 | |
|       return (result);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern " with the "replacement"|
 | |
|    //| pattern, starting at the first character in the in string, using |
 | |
|    //| the previous patten.                                             |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,const string replacement)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Replace(in, replacement, -1, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the (previously defined) "pattern"   |
 | |
|    //| with the "replacement" pattern, starting at the first character  |
 | |
|    //| in the in string.                                                |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,const string replacement,const int count)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result
 | |
|       return Replace(in, replacement, count, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the recent        |
 | |
|    //| "replacement" pattern, starting at the character position        |
 | |
|    //| "startat.".                                                      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,const string replacement,const int count,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'replacement' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- A little code to grab a cached parsed replacement object
 | |
|       RegexReplacement *repl=m_replref.Get();
 | |
|       if(repl==NULL || !(repl.Pattern()==replacement))
 | |
|         {
 | |
|          repl=RegexParser::ParseReplacement(replacement,m_caps,m_capsize,m_capnames,this.m_roptions);
 | |
|          if(CheckPointer(m_replref.Get())==POINTER_DYNAMIC)
 | |
|            {
 | |
|             delete m_replref.Get();
 | |
|            }
 | |
|          m_replref.Set(repl);
 | |
|         }
 | |
|       //--- return result
 | |
|       return repl.Replace(GetPointer(this), in, count, startat);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the "replacement" |
 | |
|    //| pattern ".".                                                     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,MatchEvaluator evaluator)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Replace(in, pattern, evaluator, None, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern " with the recent       |
 | |
|    //| "replacement" pattern, starting at the first character ".".      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,MatchEvaluator evaluator,const RegexOptions options)
 | |
|      {
 | |
|       //--- return result
 | |
|       return Replace(in, pattern, evaluator, options, DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern " with the recent       |
 | |
|    //| "replacement" pattern, starting at the first character ".".      |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static string Replace(const string in,const string pattern,MatchEvaluator evaluator,const RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex regex(pattern,options,matchTimeout,true);
 | |
|       string result=regex.Replace(in,evaluator);
 | |
|       //--- return result
 | |
|       return (result);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the recent        |
 | |
|    //| "replacement" pattern, starting at the first character position  |
 | |
|    //| ".".                                                             |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,MatchEvaluator evaluator)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result  
 | |
|       return Replace(in, evaluator, -1, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the "pattern" with the recent        |
 | |
|    //| "replacement" pattern, starting at the first character position  |
 | |
|    //| ".".                                                             |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,MatchEvaluator evaluator,const int count)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result 
 | |
|       return Replace(in, evaluator, count, UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Replaces all occurrences of the (previouly defined) "pattern"    |
 | |
|    //| with the recent "replacement" pattern, starting at the character |
 | |
|    //| position "startat."                                              |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Replace(const string in,MatchEvaluator evaluator,const int count,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       //--- return result 
 | |
|       return RegexReplacement::Replace(evaluator, GetPointer(this), in, count, startat);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by "pattern".     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void Split(string &result[],const string in,const string pattern)
 | |
|      {
 | |
|       Split(result,in,pattern,None,DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by "pattern".     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void Split(string &result[],const string in,const string pattern,RegexOptions options)
 | |
|      {
 | |
|       Split(result,in,pattern,options,DefaultMatchTimeout);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by "pattern".     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void Split(string &result[],const string in,const string pattern,const RegexOptions options,const TimeSpan &matchTimeout)
 | |
|      {
 | |
|       Regex regex(pattern,options,matchTimeout,true);
 | |
|       regex.Split(result,in);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by a previous     |
 | |
|    //| "pattern".                                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void Split(string &result[],const string in)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return 
 | |
|          return;
 | |
|         }
 | |
|       Split(result,in,0,UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by a previous     |
 | |
|    //| "pattern".                                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void Split(string &result[],const string in,const int count)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return 
 | |
|          return;
 | |
|         }
 | |
|       RegexReplacement::Split(result,GetPointer(this),in,count,UseOptionR() ? StringLen(in) : 0);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Splits the "in" string at the position defined by a previous     |
 | |
|    //| "pattern".                                                       |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void Split(string &result[],const string in,const int count,const int startat)
 | |
|      {
 | |
|       if(in==NULL)
 | |
|         {
 | |
|          Print("Argument 'in' = NULL.");
 | |
|          //--- return 
 | |
|          return;
 | |
|         }
 | |
|       RegexReplacement::Split(result,GetPointer(this),in,count,startat);
 | |
|      }
 | |
| protected:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| InitializeReferences.                                            |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void InitializeReferences()
 | |
|      {
 | |
|       if(m_refsInitialized)
 | |
|         {
 | |
|          Print("Internal error! On file:'"+__FILE__+"'; in function:'"+__FUNCTION__+"'.");
 | |
|          //--- return
 | |
|          return;
 | |
|         }
 | |
|       m_refsInitialized=true;
 | |
|       m_runnerref  = new RunnerReference();
 | |
|       m_replref    = new ReplacementReference();
 | |
|      }
 | |
| public:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Internal worker called by all the  APIs.                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Match *Run(const bool quick,const int prevlen,const string in,const int beginning,const int length,const int startat)
 | |
|      {
 | |
|       Match *match;
 | |
|       RegexRunner *runner=NULL;
 | |
|       if(startat<0 || startat>StringLen(in))
 | |
|         {
 | |
|          Print("Argument 'start' out of range.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       if(length<0 || length>StringLen(in))
 | |
|         {
 | |
|          Print("Argument 'length' out of range.");
 | |
|          //--- return NULL
 | |
|          return (NULL);
 | |
|         }
 | |
|       bool fromCache=false;
 | |
|       //--- There may be a cached runner; grab ownership of it if we can.
 | |
|       if(m_runnerref!=NULL)
 | |
|         {
 | |
|          fromCache=true;
 | |
|          runner=m_runnerref.Get();
 | |
|         }
 | |
|       //--- Create a RegexRunner instance if we need to
 | |
|       if(runner==NULL)
 | |
|         {
 | |
|          fromCache=false;
 | |
|          //--- Use the compiled RegexRunner factory if the code was compiled to MSIL
 | |
|          runner=new RegexInterpreter(m_code);
 | |
|         }
 | |
|       //--- Do the scan starting at the requested position            
 | |
|       match=runner.Scan(GetPointer(this),in,beginning,beginning+length,startat,prevlen,quick,m_internalMatchTimeout);
 | |
|       if(m_runnerref!=NULL && !fromCache)
 | |
|         {
 | |
|          if(CheckPointer(m_runnerref.Get())==POINTER_DYNAMIC)
 | |
|            {
 | |
|             delete m_runnerref.Get();
 | |
|            }
 | |
|          //--- Release or fill the cache slot
 | |
|          m_runnerref.Set(runner);
 | |
|         }
 | |
|       else if(!fromCache)
 | |
|         {
 | |
|          delete runner;
 | |
|         }
 | |
| #ifdef _DEBUG
 | |
|       if(Debug() && match!=NULL)
 | |
|         {
 | |
|          match.Dump();
 | |
|         }
 | |
| #endif
 | |
|       //--- return result
 | |
|       return (match);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Find code cache based on options+pattern.                        |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static CachedCodeEntry *LookupCachedAndUpdate(const string key)
 | |
|      {
 | |
|       for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | |
|         {
 | |
|          if(current.Value().Key()==key)
 | |
|            {
 | |
|             //--- If we find an entry in the cache, move it to the head at the same time. 
 | |
|             m_livecode.Remove(current);
 | |
|             m_livecode.AddFirst(current);
 | |
|             //--- retrun result
 | |
|             return (current.Value());
 | |
|            }
 | |
|         }
 | |
|       //--- return result
 | |
|       return (NULL);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Add current code to the cache.                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    CachedCodeEntry *CacheCode(const string key)
 | |
|      {
 | |
|       CachedCodeEntry *newcached=NULL;
 | |
|       //--- first look for it in the cache and move it to the head
 | |
|       for(LinkedListNode<CachedCodeEntry*>*current=m_livecode.First(); current!=NULL; current=current.Next())
 | |
|         {
 | |
|          if(current.Value().Key()==key)
 | |
|            {
 | |
|             m_livecode.Remove(current);
 | |
|             m_livecode.AddFirst(current);
 | |
|             //--- return result
 | |
|             return (current.Value());
 | |
|            }
 | |
|         }
 | |
|       //--- it wasn't in the cache, so we'll add a new one.  Shortcut out for the case where cacheSize is zero.
 | |
|       if(m_cacheSize!=0)
 | |
|         {
 | |
|          newcached=new CachedCodeEntry(key,m_capnames,m_capslist,m_code,m_caps,m_capsize,m_runnerref,m_replref);
 | |
|          m_livecode.AddFirst(newcached);
 | |
|          if(m_livecode.Count()>m_cacheSize)
 | |
|            {
 | |
|             m_livecode.RemoveLast();
 | |
|            }
 | |
|         }
 | |
|       //--- return result
 | |
|       return (newcached);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Delete all objects in cache.                                     |
 | |
|    //+------------------------------------------------------------------+
 | |
|    static void ClearCache()
 | |
|      {
 | |
|       IEnumerator<CachedCodeEntry*>*en=m_livecode.GetEnumerator();
 | |
|       while(en.MoveNext())
 | |
|         {
 | |
|          if(CheckPointer(en.Current())==POINTER_DYNAMIC)
 | |
|            {
 | |
|             if(CheckPointer(en.Current().RunnerRef().Get().RunRegex())==POINTER_DYNAMIC)
 | |
|               {
 | |
|                delete en.Current().RunnerRef().Get().RunRegex();
 | |
|               }
 | |
|             delete en.Current();
 | |
|            }
 | |
|         }
 | |
|       delete en;
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| True if the O option was set.                                    |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool UseOptionC()
 | |
|      {
 | |
|       return(m_roptions) != 0;
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| True if the L option was set.                                    |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool UseOptionR()
 | |
|      {
 | |
|       return(m_roptions & RightToLeft) != 0;
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| UseOptionInvariant.                                              |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool UseOptionInvariant()
 | |
|      {
 | |
|       return(m_roptions) != 0;
 | |
|      }
 | |
| #ifdef _DEBUG
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| True if the regex has debugging enabled.                         |
 | |
|    //+------------------------------------------------------------------+
 | |
|    bool Debug()
 | |
|      {
 | |
|       //--- return result
 | |
|       return((m_roptions &Debug) != 0);
 | |
|      }
 | |
| #endif
 | |
|   };
 | |
| static const TimeSpan   Regex::MaximumMatchTimeout=TimeSpan::FromMilliseconds(Int32::MaxValue-1);
 | |
| static const TimeSpan   Regex::InfiniteMatchTimeout(0,0,0,0,-1);
 | |
| static const string Regex::DefaultMatchTimeout_ConfigKeyName="REGEX_DEFAULT_MATCH_TIMEOUT";
 | |
| static const TimeSpan   Regex::FallbackDefaultMatchTimeout=Regex::InfiniteMatchTimeout;
 | |
| static const TimeSpan   Regex::DefaultMatchTimeout=Regex::InitDefaultMatchTimeout();
 | |
| static LinkedList<CachedCodeEntry*>Regex::m_livecode();
 | |
| static int Regex::m_cacheSize=15;
 | |
| static const int Regex::MaxOptionShift=10;
 | |
| //+------------------------------------------------------------------+
 | |
| //| Purpose: Used to cache byte codes or compiled factories.         |
 | |
| //+------------------------------------------------------------------+
 | |
| class CachedCodeEntry : public IComparable
 | |
|   {
 | |
| private:
 | |
|    string            m_key;
 | |
|    RegexCode        *m_code;
 | |
|    Dictionary<int,int>*m_caps;
 | |
|    Dictionary<string,int>*m_capnames;
 | |
|    string            m_capslist[];
 | |
|    int               m_capsize;
 | |
|    RunnerReference *m_runnerref;
 | |
|    ReplacementReference *m_replref;
 | |
| public:
 | |
|    //--- Constructors:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Constructor with parameters.                                     |
 | |
|    //+------------------------------------------------------------------+
 | |
|                      CachedCodeEntry(const string key,Dictionary<string,int>*capnames,const string &capslist[],
 | |
|                                                        RegexCode *code,Dictionary<int,int>*caps,const int capsize,
 | |
|                                                        RunnerReference *runner,ReplacementReference *repl)
 | |
|      {
 | |
|       m_key=key;
 | |
|       m_capnames=capnames;
 | |
|       ArrayCopy(m_capslist,capslist);
 | |
|       m_code= code;
 | |
|       m_caps= caps;
 | |
|       m_capsize=capsize;
 | |
|       m_runnerref=runner;
 | |
|       m_replref=repl;
 | |
|      }
 | |
|    //--- Destructors:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| destructor without parameters.                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|                     ~CachedCodeEntry()
 | |
|      {
 | |
|       if(CheckPointer(m_code)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_code;
 | |
|         }
 | |
|       if(CheckPointer(m_caps)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_caps;
 | |
|         }
 | |
|       if(CheckPointer(m_capnames)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_capnames;
 | |
|         }
 | |
|       if(CheckPointer(m_replref)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_replref;
 | |
|         }
 | |
|       if(CheckPointer(m_runnerref)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_runnerref;
 | |
|         }
 | |
|      }
 | |
|    //--- Methods:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the runnerref.                                              |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RunnerReference *RunnerRef()
 | |
|      {
 | |
|       //--- reurn runnerref
 | |
|       return (m_runnerref);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the replref.                                                |
 | |
|    //+------------------------------------------------------------------+
 | |
|    ReplacementReference *ReplRef()
 | |
|      {
 | |
|       //--- return replref
 | |
|       return (m_replref);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the key.                                                    |
 | |
|    //+------------------------------------------------------------------+
 | |
|    string Key()
 | |
|      {
 | |
|       //--- return key
 | |
|       return (m_key);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the caps.                                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Dictionary<int,int>*Caps()
 | |
|      {
 | |
|       //--- return caps
 | |
|       return (m_caps);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the capnames.                                               |
 | |
|    //+------------------------------------------------------------------+
 | |
|    Dictionary<string,int>*CapNames()
 | |
|      {
 | |
|       //--- return capnames
 | |
|       return (m_capnames);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the capsize.                                                |
 | |
|    //+------------------------------------------------------------------+
 | |
|    int CapSize()
 | |
|      {
 | |
|       //--- retrun capsize
 | |
|       return (m_capsize);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the code.                                                   |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RegexCode *Code()
 | |
|      {
 | |
|       //--- return code
 | |
|       return (m_code);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Gets the caplist.                                                |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void GetCapList(string &array[])
 | |
|      {
 | |
|       ArrayCopy(array,m_capslist);
 | |
|      }
 | |
|   };
 | |
| //+------------------------------------------------------------------+
 | |
| //| Used to cache a weak reference in a threadsafe way.              |
 | |
| //+------------------------------------------------------------------+
 | |
| class ReplacementReference
 | |
|   {
 | |
| private:
 | |
|    RegexReplacement *m_obj;
 | |
| public:
 | |
|    //--- Destructors:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Destructor without parameters.                                   |
 | |
|    //+------------------------------------------------------------------+   
 | |
|                     ~ReplacementReference()
 | |
|      {
 | |
|       if(CheckPointer(m_obj)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_obj;
 | |
|         }
 | |
|      }
 | |
|    //--- Methods:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Get RegexReplacement.                                            |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RegexReplacement *Get()
 | |
|      {
 | |
|       //--- return pointer
 | |
|       return (m_obj);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Set RegexReplacement.                                            |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void      Set(RegexReplacement *obj)
 | |
|      {
 | |
|       m_obj=obj;
 | |
|      }
 | |
|   };
 | |
| //+------------------------------------------------------------------+
 | |
| //| Used to cache one exclusive runner reference.                    |
 | |
| //+------------------------------------------------------------------+
 | |
| class RunnerReference
 | |
|   {
 | |
| private:
 | |
|    RegexRunner      *m_obj;
 | |
| public:
 | |
|    //--- Destructors:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Destructor without parameters.                                   |
 | |
|    //+------------------------------------------------------------------+   
 | |
|                     ~RunnerReference()
 | |
|      {
 | |
|       if(CheckPointer(m_obj)==POINTER_DYNAMIC)
 | |
|         {
 | |
|          delete m_obj;
 | |
|         }
 | |
|      }
 | |
|    //--- Methods:
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Get RegexRunner.                                                 |
 | |
|    //+------------------------------------------------------------------+
 | |
|    RegexRunner *Get()
 | |
|      {
 | |
|       //--- return pointer
 | |
|       return (m_obj);
 | |
|      }
 | |
|    //+------------------------------------------------------------------+
 | |
|    //| Set RegexRunner.                                                 |
 | |
|    //+------------------------------------------------------------------+
 | |
|    void Set(RegexRunner *obj)
 | |
|      {
 | |
|       m_obj=obj;
 | |
|      }
 | |
|   };
 | |
| //+------------------------------------------------------------------+
 |