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