/**
* @file op_regex.h
* This file contains various definitions and interface for a
* lightweight wrapper around libc regex, providing match
* and replace facility.
*
* @remark Copyright 2003 OProfile authors
* @remark Read the file COPYING
* @remark Idea comes from TextFilt project <http://textfilt.sourceforge.net>
*
* @author Philippe Elie
*/
#ifndef OP_REGEX_H
#define OP_REGEX_H
// required by posix before including regex.h
#include <sys/types.h>
#include <regex.h>
#include <string>
#include <vector>
#include <map>
#include "op_exception.h"
/**
* ill formed regular expression or expression throw such exception
*/
struct bad_regex : op_exception {
bad_regex(std::string const & pattern);
};
/**
* lightweight encapsulation of regex lib search and replace
*
* See stl.pat for further details and examples of used syntax.
*/
class regular_expression_replace {
public:
/**
* @param limit limit on number of search and replace done
* @param limit_defs_expansion limit on number of expansion done
* during replacement of regular definition name by their expansion
*
* build an object holding regular defintion and regular expression
* & replace, preparing it for substitution ala sed
*/
regular_expression_replace(size_t limit = 100,
size_t limit_defs_expansion = 100);
~regular_expression_replace();
/**
* @param name a regular definition name
* @param replace the string to subsitute in other regular definition
* or regular exepression when this regular defintion name is
* encoutered.
*/
void add_definition(std::string const & name,
std::string const & replace);
/**
* @param pattern a regular expression pattern, POSIX extended notation
* @param replace the replace string to use when this regular
* expression is matched
*
* You can imbed regular definition in pattern but not in replace.
*/
void add_pattern(std::string const & pattern,
std::string const & replace);
/**
* @param str the input/output string where we search pattern and
* replace them.
*
* Execute loop at max limit time on the set of regular expression
*
* Return true if too many match occur and replacing has been stopped
* due to reach limit_defs_expansion. You can test if some pattern has
* been matched by saving the input string and comparing it to the new
* value. There is no way to detect s/a/a because the output string
* will be identical to the input string.
*/
bool execute(std::string & str) const;
private:
struct replace_t {
// when this regexp is matched
regex_t regexp;
// replace the matched part with this string
std::string replace;
};
// helper to execute
bool do_execute(std::string & str, replace_t const & regexp) const;
void do_replace(std::string & str, std::string const & replace,
regmatch_t const * match) const;
// helper to add_definition() and add_pattern()
std::string expand_string(std::string const & input);
// helper to add_pattern
std::string substitute_definition(std::string const & pattern);
// return the match of throw if idx is invalid
regmatch_t const & get_match(regmatch_t const * match, char idx) const;
// don't increase too, it have direct impact on performance. This limit
// the number of grouping expression allowed in a regular expression
// Note than you can use grouping match operator > 9 only in the
// replace rule not in match regular expression since POSIX don't allow
// more than \9 in matching sequence.
static const size_t max_match = 16;
size_t limit;
size_t limit_defs_expansion;
std::vector<replace_t> regex_replace;
/// dictionary of regular definition
typedef std::map<std::string, std::string> defs_dict;
defs_dict defs;
};
/**
* @param regex the regular_expression_replace to fill
* @param filename the filename from where the deifnition and pattern are read
*
* add to regex pattern and regular definition read from the given file
*/
void setup_regex(regular_expression_replace& regex,
std::string const & filename);
#endif /* !OP_REGEX_H */