]> git.lyx.org Git - lyx.git/blob - src/support/LRegex.C
in addition to the changes mentioned in ChangeLog, there is the usual batch of whites...
[lyx.git] / src / support / LRegex.C
1 #ifdef __GNUG__
2 #pragma implementation
3 #endif
4
5 #include <config.h>
6
7 #include <sys/types.h>
8 #include <regex.h>
9 #include "LRegex.h"
10
11 using std::make_pair;
12
13 ///
14 struct LRegex::Impl {
15         ///
16         regex_t * preg;
17         
18         ///
19         int error_code;
20         
21         ///
22         mutable LRegex::SubMatches matches;
23         
24         ///
25         Impl(string const & regex) 
26                 : preg(new regex_t), error_code(0)
27         {
28                 error_code = regcomp(preg, regex.c_str(), REG_EXTENDED);
29         }
30         
31         ///
32         ~Impl()
33         {
34                 regfree(preg);
35                 delete preg;
36         }
37         
38         ///
39         bool exact_match(string const & str) const
40         {
41                 regmatch_t tmp;
42                 if (!regexec(preg, str.c_str(), 1, &tmp, 0)) {
43                         if (tmp.rm_so == 0 && 
44                             tmp.rm_eo == static_cast<signed int>(str.length()))
45                                 return true;
46                 }
47                 // no match
48                 return false;
49         }
50         
51         ///
52         LRegex::MatchPair first_match(string const & str) const
53         {
54                 regmatch_t tmp;
55                 regexec(preg, str.c_str(), 1, &tmp, 0);
56                 unsigned int first = tmp.rm_so != -1 ?
57                         static_cast<unsigned int>(tmp.rm_so) : string::npos;
58                 unsigned int second = tmp.rm_eo != -1 ?
59                         static_cast<unsigned int>(tmp.rm_eo) : string::npos;
60                 return make_pair(first, second - first);
61         }
62         
63         ///
64         string getError() const
65         {
66                 size_t nr = regerror(error_code, preg, 0, 0);
67                 char * tmp = new char[nr];
68                 regerror(error_code, preg, tmp, nr);
69                 string ret(tmp);
70                 delete [] tmp;
71                 return ret;
72         }
73         
74         ///
75         LRegex::SubMatches const & exec(string const & str) const
76         {
77                 // Some room for improvement in this func. I realize
78                 // that it is double as expensive as needed, but that
79                 // is something I am willing to pay to get the nice
80                 // interface. One thing that can be done is to only put
81                 // valid submatches into matches. That will not make this
82                 // func much faster, but client code will be simpler,
83                 // because then it will only be needed to scan through
84                 // all the entries in matches.
85                 size_t subs = (preg->re_nsub != 0 ? (preg->re_nsub + 1) : 1);
86                 regmatch_t * mat = new regmatch_t[subs];
87                 unsigned int first = 0;
88                 unsigned int second = 0;
89                 matches.erase(matches.begin(), matches.end());
90                 if (!regexec(preg, str.c_str(), subs, mat, 0)) { // some match
91                         matches.reserve(subs);
92                         for (size_t i = 0; i < subs; ++i) {
93                                 first = mat[i].rm_so != -1 ?
94                                         static_cast<unsigned int>
95                                         (mat[i].rm_so) : string::npos;
96                                 second = mat[i].rm_eo != -1 ?
97                                         static_cast<unsigned int>
98                                         (mat[i].rm_eo) : string::npos;
99                                 matches.push_back(make_pair(first,
100                                                             second - first));
101                         }
102                 }
103                 delete[] mat;
104                 return matches;
105         }
106 };
107
108
109 LRegex::LRegex(string const & regex)
110         : impl(new Impl(regex)) {}
111
112
113 LRegex::~LRegex()
114 {
115         delete impl;
116 }
117
118
119 LRegex::SubMatches const & LRegex::exec(string const & str) const
120 {
121         return impl->exec(str);
122 }
123
124
125 bool LRegex::exact_match(string const & str) const
126 {
127         return impl->exact_match(str);
128 }
129
130
131 LRegex::MatchPair LRegex::first_match(string const & str) const
132 {
133         return impl->first_match(str);
134 }
135
136
137 string LRegex::getError() const
138 {
139         return impl->getError();
140 }
141
142
143 int LRegex::getErrorCode() const
144 {
145         return impl->error_code;
146 }
147
148
149 bool LRegex::ok() const {
150         return impl->error_code == 0;
151 }
152
153
154 #if 0
155 // some built in regular expressions
156
157 // this is good
158 const LRegex LRXwhite("[ \n\t\r\v\f]+");
159 // this is good
160 const LRegex LRXint("-?[0-9]+");
161 // this is good
162 const LRegex LRXdouble("-?(([0-9]+.[0-9]*)|"
163                      "([0-9]+)|(.[0-9]+))"
164                      "([eE][---+]?[0-9]+)?");
165 // not usable
166 // const LRegex LRXalpha("[A-Za-z]+");
167 // not usable (only ascii)
168 // const LRegex LRXlowercase("[a-z]+");
169 // not usable (only ascii)
170 // const LRegex LRXuppercase("[A-Z]+");
171 // not usable (only ascii)
172 // const LRegex LRXalphanum("[0-9A-Za-z]+");
173 // this is good
174 const LRegex LRXidentifier("[A-Za-z_][A-Za-z0-9_]*");
175 #endif