39 #define ERR_PREPROC LOG_STREAM(err, log_preprocessor)
40 #define WRN_PREPROC LOG_STREAM(warn, log_preprocessor)
41 #define LOG_PREPROC LOG_STREAM(info, log_preprocessor)
42 #define DBG_PREPROC LOG_STREAM(debug, log_preprocessor)
80 static int current_file_number = 0;
84 fnum = ++current_file_number;
86 std::ostringstream shex;
87 shex << std::hex << fnum;
98 std::vector< std::string >::const_iterator
i = pos.begin(),
end = pos.end();
160 value = cfg[
"value"].str();
174 return preproc_map::value_type(cfg[
"name"], second);
179 return stream <<
"value: " << def.
value <<
" arguments: " << def.
location;
184 return stream << def.second;
253 unsigned nested_level = 0;
263 if(pos.size() <= 2*nested_level) {
310 if (
char *gp = gptr()) {
331 const int desired_fill_amount = 2000;
347 setg(begin, begin + sz, begin + bs);
350 return static_cast<unsigned char>(*(begin + sz));
356 std::vector< std::string >::const_iterator
i = pos.begin(),
end = pos.end();
363 res += included_from;
370 if (res.empty()) res =
"???";
377 std::ostringstream
pos;
380 error = error_type +
'\n';
381 error +=
"at " + position;
389 std::ostringstream
pos;
392 warning = warning_type +
'\n';
393 warning +=
"at " + position;
404 old_preprocessor_(t.current_),
405 old_textdomain_(t.textdomain_),
406 old_location_(t.location_),
407 old_linenum_(t.linenum_),
443 std::vector< std::string >::const_iterator
pos_,
end_;
472 , stack_pos(stack_pos)
533 std::map<std::string, std::string> *defines,
bool is_define =
false);
536 virtual int is_macro() {
return is_define_ ? 1 : 0; }
545 throw std::logic_error(
"don't compare tokens with characters");
562 size_t cpos = fname.rfind(
" ");
563 if (cpos != std::string::npos && cpos >= symbol_index) {
564 std::stringstream ss;
565 ss <<
"Found filename containing whitespace: '" <<
filesystem::base_name(fname) <<
"' in included directory '" << name <<
"'.\nThe included symbol probably looks similar to '"
574 if (!file_stream->good()) {
575 ERR_PREPROC <<
"Could not open file " << name << std::endl;
596 unsigned sz = name.size();
598 if (sz < 5 || !std::equal(name.rbegin(), name.rbegin() + 4,
"gfc."))
609 std::map<std::string, std::string> *defines,
bool is_define) :
613 directory_(directory),
615 local_defines_(defines),
620 is_define_(is_define)
622 std::ostringstream
s;
626 if (!history.empty())
639 t.
buffer_ <<
"\376textdomain " << domain <<
'\n';
668 std::ostringstream
s;
679 unsigned stack_pos =
tokens_.back().stack_pos;
689 assert(stack_pos ==
strings_.size());
702 assert(stack_pos + 1 ==
strings_.size());
713 if (
in_.
eof() || (c !=
' ' && c !=
'\t'))
742 res +=
static_cast<char>(
c);
758 res +=
static_cast<char>(
c);
768 res +=
static_cast<char>(
c);
825 switch (token.
type) {
846 if (
in_.
eof() || d ==
'\n')
855 if (c ==
'>' &&
in_.
peek() ==
'>') {
859 }
else if (c ==
'<' &&
in_.
peek() ==
'<') {
864 }
else if (c ==
'"') {
876 }
else if (c ==
'{') {
883 bool comment =
false;
884 if (command ==
"define") {
889 target_.
error(
"No macro name found after #define directive", linenum);
892 items.erase(items.begin());
893 int found_enddef = 0;
904 else if (found_enddef > 0)
905 if (++found_enddef == 7) {
906 if (std::equal(buffer.end() - 6, buffer.end(),
"enddef"))
910 if (std::equal(buffer.end()-6, buffer.end(),
"define")) {
911 target_.
error(
"Preprocessor error: #define is not allowed inside a #define/#enddef pair", linenum);
916 if (found_enddef != 7) {
922 std::ostringstream new_pos, old_pos;
929 <<
" without explicit #undef at "
931 <<
"previously defined at "
935 buffer.erase(buffer.end() - 7, buffer.end());
940 }
else if (command ==
"ifdef") {
944 DBG_PREPROC <<
"testing for macro " << symbol <<
": "
945 << (found ?
"defined" :
"not defined") <<
'\n';
947 }
else if (command ==
"ifndef") {
951 DBG_PREPROC <<
"testing for macro " << symbol <<
": "
952 << (found ?
"defined" :
"not defined") <<
'\n';
954 }
else if (command ==
"ifhave") {
958 DBG_PREPROC <<
"testing for file or directory " << symbol <<
": "
959 << (found ?
"found" :
"not found") <<
'\n';
961 }
else if (command ==
"ifnhave") {
965 DBG_PREPROC <<
"testing for file or directory " << symbol <<
": "
966 << (found ?
"found" :
"not found") <<
'\n';
968 }
else if (command ==
"ifver" || command ==
"ifnver") {
991 DBG_PREPROC <<
"testing version '" << version1.
str() <<
"' against '" << version2.
str() <<
"' (" << vopstr <<
"): "
992 << (found ?
"match" :
"no match") <<
'\n';
996 std::string err =
"Undefined macro in #ifver/#ifnver first argument: '";
1001 }
else if (command ==
"else") {
1013 }
else if (command ==
"endif") {
1014 switch (token.
type) {
1023 }
else if (command ==
"textdomain") {
1027 put(
"#textdomain ");
1032 }
else if (command ==
"enddef") {
1034 }
else if (command ==
"undef") {
1041 }
else if (command ==
"error") {
1044 std::ostringstream
error;
1049 }
else if (command ==
"warning") {
1052 std::ostringstream warning;
1070 }
else if (c ==
'}') {
1093 std::string::size_type
pos;
1094 while ((pos = symbol.find(
'\376')) != std::string::npos) {
1096 symbol.erase(b + pos, b + symbol.find(
'\n', pos + 1) + 1);
1098 std::map<std::string, std::string>::const_iterator arg;
1099 preproc_map::const_iterator macro;
1115 std::ostringstream
error;
1116 error <<
"Macro argument '" << symbol
1117 <<
"' does not expect any arguments";
1120 std::ostringstream
v;
1133 std::ostringstream
error;
1134 error <<
"Preprocessor symbol '" << symbol <<
"' defined at "
1136 << val.
arguments.size() <<
" arguments, but has "
1137 << nb_arg <<
" arguments";
1140 std::istringstream *
buffer =
new std::istringstream(val.
value);
1141 std::map<std::string, std::string> *defines =
1142 new std::map<std::string, std::string>;
1143 for (
size_t i = 0;
i < nb_arg; ++
i) {
1149 DBG_PREPROC <<
"substituting macro " << symbol <<
'\n';
1153 DBG_PREPROC <<
"substituting (slow) macro " << symbol <<
'\n';
1154 std::ostringstream
res;
1160 { std::istream
in(buf);
1163 res << in.rdbuf(); }
1168 LOG_PREPROC <<
"Macro definition not found for " << symbol <<
" , attempting to open as file.\n";
1171 if (!nfname.empty())
1178 std::ostringstream
res;
1181 { std::istream
in(buf);
1183 res << in.rdbuf(); }
1190 std::ostringstream
error;
1191 error <<
"Macro/file '" << symbol <<
"' is missing";
1202 std::ostringstream
s;
1225 :
std::basic_istream<char>(buf), buf_(buf), defines_(defines)
1231 clear(std::ios_base::goodbit);
1232 exceptions(std::ios_base::goodbit);
1240 log_scope(
"preprocessing file " + fname +
" ...");
1248 defines = owned_defines;
1257 bool write_cfg,
bool write_plain_cfg,
std::string target_directory)
1261 std::vector<std::string> dirs,files;
1268 LOG_PREPROC <<
"processing sub-dir: " << dir <<
'\n';
1284 LOG_PREPROC <<
"processing resource: " << res_name <<
'\n';
1290 std::stringstream ss;
1295 ss.exceptions(std::ios_base::failbit);
1297 ss << (*stream).rdbuf();
1301 if (write_cfg ==
true || write_plain_cfg ==
true)
1306 read(cfg, streamContent);
1310 if (write_cfg ==
true)
1312 LOG_PREPROC <<
"writing cfg file: " << preproc_res_name <<
'\n';
1315 write(*outStream, cfg);
1319 if (write_plain_cfg ==
true)
1321 LOG_PREPROC <<
"writing plain cfg file: " << (preproc_res_name +
".plain") <<
'\n';
static std::string current_file_str
std::string lineno_string(const std::string &lineno)
child_itors child_range(const std::string &key)
std::vector< std::string >::const_iterator end_
std::map< std::string, std::string > * local_defines_
Mapping of macro arguments to their content.
bool operator==(preproc_define const &) const
preprocessor_data(preprocessor_streambuf &, std::istream *, std::string const &history, std::string const &name, int line, std::string const &dir, std::string const &domain, std::map< std::string, std::string > *defines, bool is_define=false)
preprocessor_streambuf & target_
virtual ~preprocessor()
Restores the old preprocessing context of target_.
VERSION_COMP_OP parse_version_op(const std::string &op_str)
Specialized preprocessor for handling a file or a set of files.
void read(const config &)
GLuint GLuint GLsizei GLenum type
preproc_map default_defines_
virtual int is_macro()
retruns 1 if this parses a macro, -1 if this doesnt parse text (if this is no preprocessor_data). 0 otherwise (this parses a file).
static l_noret error(LoadState *S, const char *why)
buffered_istream in_
Input stream.
bool ends_with(const std::string &str, const std::string &suffix)
preprocessor_streambuf * buf_
int peek()
Gets a character from the buffer.
Specialized preprocessor for handling any kind of input stream.
std::string out_buffer_
Buffer read by the STL stream.
void clear(const std::string &key)
Helper class for buffering a std::istream.
void write_argument(config_writer &, const std::string &) const
GLuint const GLfloat * val
bool operator<(preproc_define const &) const
bool eof() const
Is the end of input reached?
void read_argument(const config &)
const std::vector< std::string > items
Definitions for the interface to Wesnoth Markup Language (WML).
Description of a preprocessing chunk.
std::map< std::string, preproc_define > preproc_map
std::vector< std::string >::const_iterator pos_
GLdouble GLdouble GLdouble b
int slowpath_
Set to true whenever input tokens cannot be directly sent to the target buffer.
bool is_define_
true iff we are currently parsing a macros content, otherwise false.
void write_key_val(const std::string &key, const T &value)
This template function will work with any type that can be assigned to an attribute_value.
int get()
Gets and consumes a character from the buffer.
void conditional_skip(bool skip)
bool quoted_
Set to true if one preprocessor for this target started to read a string.
void close_child(const std::string &key)
bool create_directory_if_missing_recursive(const std::string &dirname)
Creates a recursive directory tree if it does not exist already.
static lg::log_domain log_preprocessor("preprocessor")
preprocessor_file(preprocessor_streambuf &, std::string const &, size_t)
Class for writing a config out to a file in pieces.
std::vector< token_desc > tokens_
Stack of nested preprocessing chunks.
void write_file(const std::string &fname, const std::string &data)
Throws io_exception if an error occurs.
GLsizei const GLfloat * value
int skipping_
Non-zero when the preprocessor has to skip some input text.
void push_token(token_desc::TOKEN_TYPE)
std::string base_name(const std::string &file)
Returns the base filename of a file, with directory name stripped.
std::istream * istream_file(const std::string &fname, bool treat_failure_as_error=true)
void open_child(const std::string &key)
std::ostream * ostream_file(std::string const &fname, bool create_directory=true)
bool is_directory(const std::string &fname)
Returns true if the given file is a directory.
GLenum GLuint GLsizei const char * buf
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::vector< std::string > strings_
Buffer for delayed input processing.
std::map< std::string, int > t_file_number_map
preprocessor * current_
Input preprocessor.
Templates and utility-routines for strings and numbers.
GLsizei const GLint * locations
std::string str() const
Serializes the version number into string form.
Encapsulates the map of the game.
std::string escape(const std::string &str, const char *special_chars)
Prepends a configurable set of characters with a backslash.
virtual int is_macro()
retruns 1 if this parses a macro, -1 if this doesnt parse text (if this is no preprocessor_data). 0 otherwise (this parses a file).
static std::string get_file_code(const std::string &filename)
Some defines: VERSION, PACKAGE, MIN_SAVEGAME_VERSION.
std::vector< std::string > quoted_split(std::string const &val, char c, int flags, char quote)
This function is identical to split(), except it does not split when it otherwise would if the previo...
std::vector< std::string > arguments
preprocessor_deleter(preprocessor_streambuf *buf, preproc_map *defines)
token_desc(TOKEN_TYPE type, const int stack_pos, const int linenum)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs=nullptr, file_name_option mode=FILE_NAME_ONLY, file_filter_option filter=NO_FILTER, file_reorder_option reorder=DONT_REORDER, file_tree_checksum *checksum=nullptr)
Populates 'files' with all the files and 'dirs' with all the directories in dir.
std::string get_wml_location(const std::string &filename, const std::string ¤t_dir=std::string())
Returns a complete path to the actual WML file or directory or an empty string if the file isn't pres...
std::string read_rest_of_line()
bool operator!=(preprocessor_data::token_desc::TOKEN_TYPE rhs, char lhs)
static std::string get_location(const std::string &loc)
filesystem::scoped_istream in_scope_
Manages the lifetime of the std::istream pointer we own.
virtual int underflow()
Called by an STL stream whenever it has reached the end of out_buffer_.
#define log_scope(description)
void write(config_writer &, const std::string &) const
Helper class for buffering a std::istream.
Declarations for File-IO.
void read(config &cfg, std::istream &in, abstract_validator *validator)
static int writer(lua_State *L, const void *b, size_t size, void *B)
void warning(const std::string &, int)
Base class for preprocessing an input.
preprocessor_streambuf(preprocessor_streambuf const &)
Represents version numbers.
std::ostream & operator<<(std::ostream &stream, const preproc_define &def)
static std::string current_dir_str
virtual bool get_chunk()
preprocessor_file::get_chunk()
GLuint const GLchar * name
static std::string get_filename(const std::string &file_code)
std::vector< std::string > files_
std::istream * preprocess_file(std::string const &fname, preproc_map *defines)
Standard logging facilities (interface).
virtual bool get_chunk()=0
preprocessor(preprocessor_streambuf &)
Sets up a new preprocessor for stream buffer t.
int stack_pos
Starting position in strings_ of the delayed text for this chunk.
friend bool operator==(preprocessor_data::token_desc::TOKEN_TYPE, char)
void error(const std::string &, int)
Target for sending preprocessed output.
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
bool do_version_check(const version_info &a, VERSION_COMP_OP op, const version_info &b)
bool portable_isspace(const char c)
bool operator==(preprocessor_data::token_desc::TOKEN_TYPE, char)
std::string get_current_file()
preprocessor * get_old_preprocessor()
Preprocesses and sends some text to the target_ buffer.
std::string old_location_
A config object defines a single node in a WML file, with access to child nodes.
static preproc_map::value_type read_pair(const config &)
preprocessor *const old_preprocessor_
static t_file_number_map file_number_map
std::string old_textdomain_
Interfaces for manipulating version numbers of engine, add-ons, etc.
void write(std::ostream &out, configr_of const &cfg, unsigned int level)
static bool encode_filename
GLsizei const GLcharARB ** string
void preprocess_resource(const std::string &res_name, preproc_map *defines_map, bool write_cfg, bool write_plain_cfg, std::string target_directory)
std::stringstream buffer_
Buffer filled by the current_ preprocessor.
std::string directory_name(const std::string &file)
Returns the directory name of a file, with filename stripped.
friend bool operator!=(preprocessor_data::token_desc::TOKEN_TYPE, char)
static std::string preprocessor_error_detail_prefix