rendered paste bodyin preprocessor_data::get_chunk()
if (macro != unknown_macro) {
ERR_CF<<called_macros_.size();
for(std::vector<std::string>::iterator iter=called_macros_.begin(); iter!=called_macros_.end(); ++iter)
{
ERR_CF<<*iter;
}
preproc_define const &val = macro->second;
size_t nb_arg = strings_.size() - token.stack_pos - 1;
if (nb_arg != val.arguments.size()) {
std::ostringstream error;
error << "preprocessor symbol '" << symbol << "' expects "
<< val.arguments.size() << " arguments, but has "
<< nb_arg << " arguments";
std::ostringstream location;
location<<linenum_<<' '<<target_.location_;
target_.error(error.str(), location.str());
}
std::stringstream *buffer = new std::stringstream;
std::string::const_iterator i_bra = val.value.end();
int macro_num = val.linenum;
std::string macro_textdomain = val.textdomain;
bool quoting = false;
for(std::string::const_iterator i = val.value.begin(),
i_end = val.value.end(); i != i_end; ++i) {
char c = *i;
if (c == '\n') {
++macro_num;
} else if (c == '"') {
quoting = !quoting;
}
if (c == '{') {
if (i_bra != i_end)
buffer->write(&*i_bra - 1, i - i_bra + 1);
i_bra = i + 1;
} else if (i_bra == i_end) {
if (c == '#' && !quoting) {
// Keep track of textdomain changes in the body of the
// macro, so they can be restored after each substitution
// of a macro argument.
std::string::const_iterator i_beg = i + 1;
if (i_end - i_beg >= 13 &&
std::equal(i_beg, i_beg + 10, "textdomain")) {
i_beg += 10;
i = std::find(i_beg, i_end, '\n');
if (i_beg != i)
++i_beg;
macro_textdomain = std::string(i_beg, i);
*buffer << "#textdomain " << macro_textdomain;
++macro_num;
c = '\n';
} else if((i_end - i_beg < 6 || (!std::equal(i_beg, i_beg + 6, "define")
&& !std::equal(i_beg, i_beg + 6, "ifndef")))
&& (i_end - i_beg < 5 || (!std::equal(i_beg, i_beg + 5, "ifdef")
&& !std::equal(i_beg, i_beg + 5, "endif") && !std::equal(i_beg, i_beg + 5, "undef")))
&& (i_end - i_beg < 4 || !std::equal(i_beg, i_beg + 4, "else"))) {
// Check for define, ifdef, ifndef, endif, undef, else.
// Otherwise, this is a comment and should be skipped.
i = std::find(i_beg, i_end, '\n');
++macro_num;
c = '\n';
}
}
buffer->put(c);
} else if (c == '}') {
size_t sz = i - i_bra;
for(size_t n = 0; n < nb_arg; ++n) {
std::string const &arg = val.arguments[n];
if (arg.size() != sz ||
!std::equal(i_bra, i, arg.begin()))
continue;
*buffer << strings_[token.stack_pos + n + 1]
<< "\376line " << macro_num
<< ' ' << val.location << "\n\376textdomain "
<< macro_textdomain << '\n';
i_bra = i_end;
break;
}
if (i_bra != i_end) {
// The bracketed text was no macro argument
buffer->write(&*i_bra - 1, sz + 2);
i_bra = i_end;
}
}
}
pop_token();
called_macros_.push_back(symbol);
std::string const &dir = directory_name(val.location.substr(0, val.location.find(' ')));
if (!slowpath_) {
DBG_CF << "substituting macro " << symbol << '\n';
new preprocessor_data(target_, called_macros_, buffer, val.location, "",
val.linenum, dir, val.textdomain);
} else {
DBG_CF << "substituting (slow) macro " << symbol << '\n';
std::ostringstream res;
preprocessor_streambuf *buf =
new preprocessor_streambuf(target_);
{ std::istream in(buf);
new preprocessor_data(*buf, called_macros_, buffer, val.location, "",
val.linenum, dir, val.textdomain);
res << in.rdbuf(); }
delete buf;
strings_.back() += res.str();
}
called_macros_.pop_back();
preprocessor::preprocessor(preprocessor_streambuf &t, std::vector<std::string> &callstack) :
old_preprocessor_(t.current_),
old_textdomain_(t.textdomain_),
old_location_(t.location_),
old_linenum_(t.linenum_),
target_(t),
called_macros_(callstack)
{
++target_.depth_;
target_.current_ = this;
}
preprocessor_file::preprocessor_file(preprocessor_streambuf &t, std::vector< std::string > &callstack,
std::string const &name) :
preprocessor(t,callstack),
files_(),
pos_(),
end_()
{
if (is_directory(name))
get_files_in_dir(name, &files_, NULL, ENTIRE_FILE_PATH, SKIP_MEDIA_DIR, DO_REORDER);
else
new preprocessor_data(t, called_macros_, istream_file(name), "", name, 1, directory_name(name), t.textdomain_);
pos_ = files_.begin();
end_ = files_.end();
}
preprocessor_data::preprocessor_data(preprocessor_streambuf &t, std::vector< std::string > &callstack, std::istream *i,
std::string const &history, std::string const &name, int linenum,
std::string const &directory, std::string const &domain) :
preprocessor(t, callstack),
in_(i),
directory_(directory),
strings_(),
tokens_(),
slowpath_(0),
skipping_(0),
linenum_(linenum)
{
std::ostringstream s;
s << history;
if (!name.empty()) {
std::string ename(name);
if (!history.empty())
s << ' ';
s << utils::escape(ename, " \\");
}
if (!t.location_.empty())
s << ' ' << t.linenum_ << ' ' << t.location_;
t.location_ = s.str();
t.linenum_ = linenum;
t.textdomain_ = domain;
t.buffer_ << "\376line " << linenum
<< ' ' << t.location_ << "\n\376textdomain " << domain << '\n';
const int fixed_char_count = 22;
count_extra_digits(linenum, t.buffer_size_);
t.buffer_size_ += t.location_.size() + domain.size() + fixed_char_count;
push_token('*');
}
std::istream *preprocess_file(std::string const &fname,
preproc_map *defines, std::string *error_log)
{
log_scope("preprocessing file...");
preproc_map *owned_defines = NULL;
if (!defines) {
// If no preproc_map has been given, create a new one,
// and ensure it is destroyed when the stream is
// ??
// by giving it to the deleter.
owned_defines = new preproc_map;
defines = owned_defines;
}
preprocessor_streambuf *buf = new preprocessor_streambuf(defines, error_log);
std::vector<std::string> call_stack;
new preprocessor_file(*buf, call_stack, fname);
if(error_log!=NULL&&error_log->empty()==false)
throw preproc_config::error("Error preprocessing files.");
return new preprocessor_deleter(buf, owned_defines);
}