~ubuntu-branches/debian/sid/oprofile/sid

« back to all changes in this revision

Viewing changes to libregex/op_regex.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Al Stone
  • Date: 2008-02-10 11:51:49 UTC
  • mfrom: (4.1.1 gutsy)
  • Revision ID: james.westby@ubuntu.com-20080210115149-9itpgjhw62l74o89
Tags: 0.9.3-2
* Closes: bug#415827 -- manpage corrected upstream so that all options are
  now unique
* Update to latest Debian standards version.
* Closes: bug#420815 -- find separate debug files in archive properly (patch
  applied)
* Closes: bug#450607 -- oprof_start no longer links against libbfd.so (used
  patch from submitter)
* Closes: bug#446360 -- similar problem with libbfd; the patch for 450607
  was more inclusive, though, so it also fixes this problem; thanks for the
  NMU, nonetheless.
* Closes: bug#447797 -- remove bashisms from opcontrol (used patch from
  ubuntu)
* Closes: bug#420760 -- cannot reproduce this problem in 0.9.3 (was reported
  with 0.9.2)
* Closes: bug#422178 -- cannot reproduce this problem in 0.9.3 (was reported
  with 0.9.2)
* Closes: bug#428299 -- latest Linux kernel (2.6.23-1 on dual core Intel) no
  longer shows this problem.
* Closes: bug#424760 -- invalid arithmetic expression in opcontrol script
  replaced in newer versions
* Closes: bug#456069 -- patched C++ files to accommodate changes in the
  header files for g++ 4.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * @file op_regex.cpp
3
 
 * This file contains implementation for a lightweight wrapper around
4
 
 * libc regex, providing regular expression match and replace facility.
5
 
 *
6
 
 * @remark Copyright 2003 OProfile authors
7
 
 * @remark Read the file COPYING
8
 
 * @remark Idea comes from TextFilt project <http://textfilt.sourceforge.net>
9
 
 *
10
 
 * @author Philippe Elie
11
 
 */
12
 
 
13
 
#include <cerrno>
14
 
 
15
 
#include <iostream>
16
 
#include <fstream>
17
 
 
18
 
#include "string_manip.h"
19
 
 
20
 
#include "op_regex.h"
21
 
 
22
 
using namespace std;
23
 
 
24
 
namespace {
25
 
 
26
 
string op_regerror(int err, regex_t const & regexp)
27
 
{
28
 
        size_t needed_size = regerror(err, &regexp, 0, 0);
29
 
        char * buffer = new char[needed_size];
30
 
        regerror(err, &regexp, buffer, needed_size);
31
 
 
32
 
        return buffer;
33
 
}
34
 
 
35
 
 
36
 
void op_regcomp(regex_t & regexp, string const & pattern)
37
 
{
38
 
        int err = regcomp(&regexp, pattern.c_str(), REG_EXTENDED);
39
 
        if (err) {
40
 
                throw bad_regex("regcomp error: " + op_regerror(err, regexp)
41
 
                                + " for pattern : " + pattern);
42
 
        }
43
 
}
44
 
 
45
 
 
46
 
bool op_regexec(regex_t const & regex, string const & str, regmatch_t * match,
47
 
               size_t nmatch)
48
 
{
49
 
        return regexec(&regex, str.c_str(), nmatch, match, 0) != REG_NOMATCH;
50
 
}
51
 
 
52
 
 
53
 
void op_regfree(regex_t & regexp)
54
 
{
55
 
        regfree(&regexp);
56
 
}
57
 
 
58
 
 
59
 
// return the index number associated with a char seen in a "\x".
60
 
// Allowed range are for x is [0-9a-z] return size_t(-1) if x is not in
61
 
// these ranges.
62
 
size_t subexpr_index(char ch)
63
 
{
64
 
        if (isdigit(ch))
65
 
                return ch - '0';
66
 
        if (ch >= 'a' && ch <= 'z')
67
 
                return ch - 'a' + 10;
68
 
        return size_t(-1);
69
 
}
70
 
 
71
 
}  // anonymous namespace
72
 
 
73
 
 
74
 
bad_regex::bad_regex(string const & pattern)
75
 
        : op_exception(pattern)
76
 
{
77
 
}
78
 
 
79
 
 
80
 
regular_expression_replace::regular_expression_replace(size_t limit_,
81
 
                                                       size_t limit_defs)
82
 
        :
83
 
        limit(limit_),
84
 
        limit_defs_expansion(limit_defs)
85
 
{
86
 
}
87
 
 
88
 
 
89
 
regular_expression_replace::~regular_expression_replace()
90
 
{
91
 
        for (size_t i = 0 ; i < regex_replace.size() ; ++i)
92
 
                op_regfree(regex_replace[i].regexp);
93
 
}
94
 
 
95
 
 
96
 
void regular_expression_replace::add_definition(string const & name,
97
 
                                                string const & definition)
98
 
{
99
 
        defs[name] = expand_string(definition);
100
 
}
101
 
 
102
 
 
103
 
void regular_expression_replace::add_pattern(string const & pattern,
104
 
                                             string const & replace)
105
 
{
106
 
        string expanded_pattern = expand_string(pattern);
107
 
 
108
 
        regex_t regexp;
109
 
        op_regcomp(regexp, expanded_pattern);
110
 
        replace_t regex = { regexp, replace };
111
 
        regex_replace.push_back(regex);
112
 
}
113
 
 
114
 
 
115
 
string regular_expression_replace::expand_string(string const & input)
116
 
{
117
 
        string last, expanded(input);
118
 
        size_t i = 0;
119
 
        for (i = 0 ; i < limit_defs_expansion ; ++i) {
120
 
                last = expanded;
121
 
                expanded = substitute_definition(last);
122
 
                if (expanded == last)
123
 
                        break;
124
 
        }
125
 
 
126
 
        if (i == limit_defs_expansion)
127
 
                throw bad_regex("too many substitution for: + input");
128
 
 
129
 
        return last;
130
 
}
131
 
 
132
 
 
133
 
string regular_expression_replace::substitute_definition(string const & pattern)
134
 
{
135
 
        string result;
136
 
        bool previous_is_escape = false;
137
 
 
138
 
        for (size_t i = 0 ; i < pattern.length() ; ++i) {
139
 
                if (pattern[i] == '$' && !previous_is_escape) {
140
 
                        size_t pos = pattern.find('{', i);
141
 
                        if (pos != i + 1) {
142
 
                                throw bad_regex("invalid $ in pattern: " + pattern);
143
 
                        }
144
 
                        size_t end = pattern.find('}', i);
145
 
                        if (end == string::npos) {
146
 
                                throw bad_regex("no matching '}' in pattern: " + pattern);
147
 
                        }
148
 
                        string def_name = pattern.substr(pos+1, (end-pos) - 1);
149
 
                        if (defs.find(def_name) == defs.end()) {
150
 
                                throw bad_regex("definition not found and used in pattern: (" + def_name + ") " + pattern);
151
 
                        }
152
 
                        result += defs[def_name];
153
 
                        i = end;
154
 
                } else {
155
 
                        if (pattern[i] == '\\' && !previous_is_escape)
156
 
                                previous_is_escape = true;
157
 
                        else
158
 
                                previous_is_escape = false;
159
 
                        result += pattern[i];
160
 
                }
161
 
        }
162
 
 
163
 
        return result;
164
 
}
165
 
 
166
 
 
167
 
// FIXME limit output string size ? (cause we can have exponential growing
168
 
// of output string through a rule "a" = "aa")
169
 
bool regular_expression_replace::execute(string & str) const
170
 
{
171
 
        bool changed = true;
172
 
        for (size_t nr_iter = 0; changed && nr_iter < limit ; ++nr_iter) {
173
 
                changed = false;
174
 
                for (size_t i = 0 ; i < regex_replace.size() ; ++i) {
175
 
                        if (do_execute(str, regex_replace[i]))
176
 
                                changed = true;
177
 
                }
178
 
        }
179
 
 
180
 
        // this don't return if the input string has been changed but if
181
 
        // we reach the limit number of iteration.
182
 
        return changed == false;
183
 
}
184
 
 
185
 
 
186
 
bool regular_expression_replace::do_execute(string & str,
187
 
                                            replace_t const & regexp) const
188
 
{
189
 
        bool changed = false;
190
 
 
191
 
        regmatch_t match[max_match];
192
 
        for (size_t iter = 0;
193
 
             op_regexec(regexp.regexp, str, match, max_match) && iter < limit;
194
 
             iter++) {
195
 
                changed = true;
196
 
                do_replace(str, regexp.replace, match);
197
 
        }
198
 
 
199
 
        return changed;
200
 
}
201
 
 
202
 
 
203
 
regmatch_t const &
204
 
regular_expression_replace::get_match(regmatch_t const * match, char idx) const
205
 
{
206
 
        size_t sub_expr = subexpr_index(idx);
207
 
        if (sub_expr == size_t(-1))
208
 
                throw bad_regex("expect group index: " + idx);
209
 
        if (sub_expr >= max_match)
210
 
                throw bad_regex("illegal group index :" + idx);
211
 
        return match[sub_expr];
212
 
}
213
 
 
214
 
void regular_expression_replace::do_replace
215
 
(string & str, string const & replace, regmatch_t const * match) const
216
 
{
217
 
        string inserted;
218
 
        for (size_t i = 0 ; i < replace.length() ; ++i) {
219
 
                if (replace[i] == '\\') {
220
 
                        if (i == replace.length() - 1) {
221
 
                                throw bad_regex("illegal \\ trailer: " +
222
 
                                                replace);
223
 
                        }
224
 
                        ++i;
225
 
                        if (replace[i] == '\\') {
226
 
                                inserted += '\\';
227
 
                        }  else {
228
 
                                regmatch_t const & matched = get_match(match,
229
 
                                        replace[i]);
230
 
                                if (matched.rm_so == -1 && 
231
 
                                    matched.rm_eo == -1) {
232
 
                                        // empty match: nothing todo
233
 
                                } else if (matched.rm_so == -1 ||
234
 
                                           matched.rm_eo == -1) {
235
 
                                        throw bad_regex("illegal match: " +
236
 
                                                replace);
237
 
                                } else {
238
 
                                        inserted += str.substr(matched.rm_so,
239
 
                                            matched.rm_eo - matched.rm_so);
240
 
                                }
241
 
                        }
242
 
                } else {
243
 
                        inserted += replace[i];
244
 
                }
245
 
        }
246
 
 
247
 
        size_t first = match[0].rm_so;
248
 
        size_t count = match[0].rm_eo - match[0].rm_so;
249
 
 
250
 
        str.replace(first, count, inserted);
251
 
}
252
 
 
253
 
 
254
 
void setup_regex(regular_expression_replace & regex,
255
 
                 string const & filename)
256
 
{
257
 
        ifstream in(filename.c_str());
258
 
        if (!in) {
259
 
                throw op_runtime_error("Can't open file " + filename +
260
 
                                " for reading", errno);
261
 
        }
262
 
 
263
 
        regular_expression_replace var_name_rule;
264
 
        var_name_rule.add_pattern("^\\$([_a-zA-Z][_a-zA-Z0-9]*)[ ]*=.*", "\\1");
265
 
        regular_expression_replace var_value_rule;
266
 
        var_value_rule.add_pattern(".*=[ ]*\"(.*)\"", "\\1");
267
 
 
268
 
        regular_expression_replace left_rule;
269
 
        left_rule.add_pattern("[ ]*\"(.*)\"[ ]*=.*", "\\1");
270
 
        regular_expression_replace right_rule;
271
 
        right_rule.add_pattern(".*=[ ]*\"(.*)\"", "\\1");
272
 
 
273
 
        string line;
274
 
        while (getline(in, line)) {
275
 
                line = trim(line);
276
 
                if (line.empty() || line[0] == '#')
277
 
                        continue;
278
 
 
279
 
                string temp = line;
280
 
                var_name_rule.execute(temp);
281
 
                if (temp == line) {
282
 
                        string left = line;
283
 
                        left_rule.execute(left);
284
 
                        if (left == line) {
285
 
                                throw bad_regex("invalid input file: " +
286
 
                                                '"' + line + '"');
287
 
                        }
288
 
 
289
 
                        string right = line;
290
 
                        right_rule.execute(right);
291
 
                        if (right == line) {
292
 
                                throw bad_regex("invalid input file: "
293
 
                                                + '"' + line + '"');
294
 
                        }
295
 
 
296
 
                        regex.add_pattern(left, right);
297
 
                } else {
298
 
                        // temp != line ==> var_name_rule succeed to substitute
299
 
                        // into temp the var_name present in line
300
 
                        string var_name = temp;
301
 
                        string var_value = line;
302
 
                        var_value_rule.execute(var_value);
303
 
                        if (var_value == line) {
304
 
                                throw bad_regex("invalid input file: " +
305
 
                                                '"' + line + '"');
306
 
                        }
307
 
 
308
 
                        regex.add_definition(var_name, var_value);
309
 
                }
310
 
        }
311
 
}