wip II
[sdk] / extras / Regex.ec
1
2 #define __restrict
3 #ifndef __restrict_arr
4 #define __restrict_arr
5 #endif
6
7 #define uint _uint
8 #ifdef __WIN32__
9 #include <sys/types.h>
10 #endif
11 #include <regex.h>
12 #undef uint
13
14 #ifdef BUILDING_ECERE_COM
15 namespace sys;
16 import "instance"
17 #else
18 #ifdef ECERE_STATIC
19 public import static "ecere"
20 #else
21 public import "ecere"
22 #endif
23 #endif
24
25 public class Regex : struct
26 {
27 public:
28    property String regex
29    {
30       set
31       {
32          if((value || regex) && (value != regex || strcmp(value, regex)))
33          {
34             if(value)
35             {
36                delete regex;
37                regex = CopyString(value);
38                Compile();
39             }
40             else
41                Free();
42          }
43          
44       }
45       get { return regex; }
46    }
47
48    property bool caseInsensitive
49    {
50       set
51       {
52          if(value != (compileFlags & REG_ICASE))
53          {
54             compileFlags = value ? compileFlags | REG_ICASE : compileFlags & ~REG_ICASE;
55             if(regex)
56                Compile();
57          }
58       }
59       get { return (compileFlags & REG_ICASE) != 0; }
60    }
61
62    property bool newLineException
63    {
64       set
65       {
66          if(value != (compileFlags & REG_NEWLINE))
67             compileFlags = value ? compileFlags | REG_NEWLINE : compileFlags & ~REG_NEWLINE;
68          if(regex)
69             Compile();
70       }
71       get { return (compileFlags & REG_NEWLINE) != 0; }
72    }
73
74    property bool lineStartException
75    {
76       set
77       {
78          if(value != (executeFlags & REG_NOTBOL))
79             executeFlags = value ? executeFlags | REG_NOTBOL : executeFlags & ~REG_NOTBOL;
80       }
81       get { return (executeFlags & REG_NOTBOL) != 0; }
82    }
83
84    property bool lineEndException
85    {
86       set
87       {
88          if(value != (executeFlags & REG_NOTEOL))
89             executeFlags = value ? executeFlags | REG_NOTEOL : executeFlags & ~REG_NOTEOL;
90       }
91       get { return (executeFlags & REG_NOTEOL) != 0; }
92    }
93
94    property bool extendedSyntax
95    {
96       set
97       {
98          if(value != (compileFlags & REG_EXTENDED))
99          {
100             compileFlags = value ? compileFlags | REG_EXTENDED : compileFlags & ~REG_EXTENDED;
101             if(regex)
102                Compile();
103          }
104       }
105       get { return (compileFlags & REG_EXTENDED) != 0; }
106    }
107
108    property bool valid { get { return valid; } }
109
110    property int maxMatchCount
111    {
112       set
113       {
114          if(value != maxMatchCount)
115          {
116             maxMatchCount = value > 0 ? value : 1;
117             delete matches;
118             matches = new regmatch_t[maxMatchCount];
119          }
120       }
121       get { return maxMatchCount; }
122    }
123
124    property int matchCount { get { return matchCount; } }
125
126    char * Match(String string)
127    {
128       if(valid)
129       {
130          int c;
131          int result;
132          result = regexec(&compiledRegex, string, maxMatchCount, matches, executeFlags); 
133          if(result == 0) // != REG_NOMATCH
134          {
135             for(c = 0; c < maxMatchCount; c++)
136             {
137                if(matches[c].rm_so == -1)
138                {
139                   matchCount = c;
140                   break;
141                }
142             }
143             if(c == maxMatchCount)
144                matchCount = maxMatchCount;      
145             return string + matches[0].rm_so;
146          }
147          else
148             matchCount = 0;
149       }
150       return null;
151    }
152
153    int GetMatchStartOffset(int matchPos)
154    {
155       return matches[matchPos].rm_so;
156    }
157    
158    int GetMatchEndOffset(int matchPos)
159    {
160       return matches[matchPos].rm_eo;
161    }
162
163 private:
164    bool valid;
165    int compileFlags;
166    int executeFlags;
167    int matchCount;
168    int maxMatchCount;
169    regex_t compiledRegex;
170    regmatch_t * matches;
171
172    ~Regex()
173    {
174       Free();
175    }
176
177    void Free()
178    {
179       delete matches;
180       delete regex;
181       regfree(&compiledRegex);
182       valid = false;
183    }
184
185    void Compile()
186    {
187       int result;
188       regfree(&compiledRegex);
189       // compileFlags -- REG_NOSUB --  no substring addressing of matches -- nmatch and pmatch in regexec(...) are ignored if used
190       result = regcomp(&compiledRegex, regex, compileFlags/* | REG_NOSUB*/);
191       valid = result == 0;
192       if(valid && !maxMatchCount)
193          property::maxMatchCount = 1;
194       
195       // TODO: handle errors?
196       // size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); 
197       // REG_BADBR      Invalid use of back reference operator. 
198       // REG_BADPAT     Invalid use of pattern operators such as group or list. 
199       // REG_BADRPT     Invalid use of repetition operators such as using '*' as the first character. 
200       // REG_EBRACE     Un-matched brace interval operators. 
201       // REG_EBRACK     Un-matched bracket list operators. 
202       // REG_ECOLLATE   Invalid collating element. 
203       // REG_ECTYPE     Unknown character class name. 
204       // REG_EEND       Non specific error. This is not defined by POSIX.2. 
205       // REG_EESCAPE    Trailing backslash. 
206       // REG_EPAREN     Un-matched parenthesis group operators. 
207       // REG_ERANGE     Invalid use of the range operator, eg. the ending point of the range occurs prior to the starting point. 
208       // REG_ESIZE      Compiled regular expression requires a pattern buffer larger than 64Kb. This is not defined by POSIX.2. 
209       // REG_ESPACE     The regex routines ran out of memory. 
210       // REG_ESUBREG    Invalid back reference to a subexpression.
211    }
212
213    String regex;
214 }