1//--------This file shamelessly stolen from Jeremy Friesner's excellent MUSCLE---------
2/* This file is Copyright 2000 Level Control Systems.  See the included LICENSE.txt file for details. */
3
4#include <new>
5#include <stdio.h>
6
7#include "StringMatcher.h"
8
9#include <string.h>
10#include <String.h>
11
12StringMatcher::StringMatcher() : _regExpValid(false)
13{
14   // empty
15}
16
17StringMatcher :: StringMatcher(const char * str) : _regExpValid(false)
18{
19   SetPattern(str);
20}
21
22StringMatcher::~StringMatcher()
23{
24   if (_regExpValid) regfree(&_regExp);
25}
26
27bool StringMatcher::SetPattern(const char * str, bool isSimple)
28{
29   PortableString pattern;
30
31   if (isSimple)
32   {
33      pattern = "^\\(";
34
35      bool escapeMode = false;
36      for (const char * ptr = str; *ptr != '\0'; ptr++)
37      {
38         if (escapeMode)
39         {
40            escapeMode = false;
41            switch(*ptr)
42            {
43               case ',': case '|': case '(': case ')': case '?':
44                  pattern += *ptr;
45               break;
46
47               default:
48                  pattern += '\\';
49                  pattern += *ptr;
50               break;
51            }
52         }
53         else
54         {
55            switch(*ptr)
56            {
57               case ',': case '|':
58                  pattern += "\\|";
59               break;
60
61               case '.': case '(': case ')':
62                  pattern += '\\';
63                  pattern += *ptr;
64               break;
65
66               case '*':
67                  pattern += ".*";
68               break;
69
70               case '?':
71                  pattern += '.';
72               break;
73
74               case '\\':
75                  escapeMode = true;
76               break;
77
78               break;
79
80               default:
81                  pattern += *ptr;
82               break;
83            }
84         }
85      }
86      pattern += "\\)$";
87      //printf("OUTPUT: pattern became '%s'.\n", pattern.Cstr());
88   }
89
90   // Free the old regular expression, if any
91   if (_regExpValid)
92   {
93     regfree(&_regExp);
94     _regExpValid = false;
95   }
96
97   // And compile the new one
98   _regExpValid = (regcomp(&_regExp, (pattern.Length() > 0) ? pattern.String() : str, 0) == 0);
99   return _regExpValid;
100}
101
102
103bool
104StringMatcher::Match(const char *str) const
105{
106	if (_regExpValid == false)
107		return false;
108
109	int regExpStat = regexec(&_regExp, str, 0, NULL, 0);
110
111	return (regExpStat != REG_NOMATCH);
112}
113
114
115bool IsRegexToken(char c)
116{
117   switch(c)
118   {
119     case '[': case ']': case '*': case '?': case '\\': case ',': case '|': case '(': case ')':
120        return true;
121
122     default:
123        return false;
124   }
125}
126
127void EscapeRegexTokens(PortableString & s)
128{
129   const char * str = s.String();
130
131   PortableString ret;
132   while(*str)
133   {
134     if (IsRegexToken(*str)) ret += '\\';
135     ret += *str;
136     str++;
137   }
138   s = ret;
139}
140
141bool HasRegexTokens(const char * str)
142{
143   while(*str)
144   {
145     if (IsRegexToken(*str)) return true;
146                        else str++;
147   }
148   return false;
149}
150
151bool MakeRegexCaseInsensitive(PortableString & str)
152{
153   bool changed = false;
154   PortableString ret;
155   for (uint32 i=0; i<(unsigned)str.Length(); i++)
156   {
157     char next = str[i];
158     if ((next >= 'A')&&(next <= 'Z'))
159     {
160        char buf[5];
161        sprintf(buf, "[%c%c]", next, next+('a'-'A'));
162        ret += buf;
163        changed = true;
164     }
165     else if ((next >= 'a')&&(next <= 'z'))
166     {
167        char buf[5];
168        sprintf(buf, "[%c%c]", next, next+('A'-'a'));
169        ret += buf;
170        changed = true;
171     }
172     else ret += next;
173   }
174   if (changed) str = ret;
175   return changed;
176}
177