]> git.lyx.org Git - lyx.git/blob - src/support/LRegex.C
noncopyable + read ChangeLog
[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
9 #ifdef HAVE_REGEX_H
10 #include <regex.h>
11 #else
12 #include "lyxregex.h"
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 first_match(string const & str) const
59         {
60                 regmatch_t tmp;
61                 regexec(preg, str.c_str(), 1, &tmp, 0);
62                 unsigned int first = tmp.rm_so != -1 ?
63                         static_cast<unsigned int>(tmp.rm_so) : string::npos;
64                 unsigned int 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 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 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 subs = (preg->re_nsub != 0 ? (preg->re_nsub + 1) : 1);
92                 regmatch_t * mat = new regmatch_t[subs];
93                 unsigned int first = 0;
94                 unsigned int second = 0;
95                 matches.erase(matches.begin(), matches.end());
96                 if (!regexec(preg, str.c_str(), subs, mat, 0)) { // some match
97                         matches.reserve(subs);
98                         for (size_t i = 0; i < subs; ++i) {
99                                 first = mat[i].rm_so != -1 ?
100                                         static_cast<unsigned int>
101                                         (mat[i].rm_so) : string::npos;
102                                 second = mat[i].rm_eo != -1 ?
103                                         static_cast<unsigned int>
104                                         (mat[i].rm_eo) : string::npos;
105                                 matches.push_back(make_pair(first,
106                                                             second - first));
107                         }
108                 }
109                 delete[] mat;
110                 return matches;
111         }
112 };
113
114
115 LRegex::LRegex(string const & regex)
116         : impl(new Impl(regex)) {}
117
118
119 LRegex::~LRegex()
120 {
121         delete impl;
122 }
123
124
125 LRegex::SubMatches const & LRegex::exec(string const & str) const
126 {
127         return impl->exec(str);
128 }
129
130
131 bool LRegex::exact_match(string const & str) const
132 {
133         return impl->exact_match(str);
134 }
135
136
137 LRegex::MatchPair LRegex::first_match(string const & str) const
138 {
139         return impl->first_match(str);
140 }
141
142
143 string LRegex::getError() const
144 {
145         return impl->getError();
146 }
147
148
149 int LRegex::getErrorCode() const
150 {
151         return impl->error_code;
152 }
153
154
155 bool LRegex::ok() const {
156         return impl->error_code == 0;
157 }
158
159
160 #if 0
161 // some built in regular expressions
162
163 // this is good
164 const LRegex LRXwhite("[ \n\t\r\v\f]+");
165 // this is good
166 const LRegex LRXint("-?[0-9]+");
167 // this is good
168 const LRegex LRXdouble("-?(([0-9]+.[0-9]*)|"
169                      "([0-9]+)|(.[0-9]+))"
170                      "([eE][---+]?[0-9]+)?");
171 // not usable
172 // const LRegex LRXalpha("[A-Za-z]+");
173 // not usable (only ascii)
174 // const LRegex LRXlowercase("[a-z]+");
175 // not usable (only ascii)
176 // const LRegex LRXuppercase("[A-Z]+");
177 // not usable (only ascii)
178 // const LRegex LRXalphanum("[0-9A-Za-z]+");
179 // this is good
180 const LRegex LRXidentifier("[A-Za-z_][A-Za-z0-9_]*");
181 #endif