diff --git a/ppremake/ppCommandFile.cxx b/ppremake/ppCommandFile.cxx index ab4db687e7..cedd090712 100644 --- a/ppremake/ppCommandFile.cxx +++ b/ppremake/ppCommandFile.cxx @@ -299,6 +299,26 @@ read_file(const string &filename) { return false; } + return read_stream(in, filename); +} + +//////////////////////////////////////////////////////////////////// +// Function: PPCommandFile::read_stream +// Access: Public +// Description: Reads input from the given stream. Each line is +// read, commands are processed, variables are expanded, +// and the resulting output is sent to write_line() +// one line at a time. The return value is true if the +// entire file is read with no errors, false if there is +// some problem. +// +// The filename is just informational; it is used to +// update the variables like THISFILENAME and +// THISDIRPREFIX as appropriate, and to report errors to +// the user. +//////////////////////////////////////////////////////////////////// +bool PPCommandFile:: +read_stream(istream &in, const string &filename) { PushFilename pushed(_scope, filename); if (!read_stream(in)) { @@ -307,7 +327,6 @@ read_file(const string &filename) { } return false; } - return true; } @@ -320,6 +339,10 @@ read_file(const string &filename) { // one line at a time. The return value is true if the // entire file is read with no errors, false if there is // some problem. +// +// This flavor of read_stream() does not take a +// filename. It does not, therefore, adjust +// THISFILENAME and THISDIRPREFIX. //////////////////////////////////////////////////////////////////// bool PPCommandFile:: read_stream(istream &in) { @@ -1746,13 +1769,18 @@ PushFilename(PPScope *scope, const string &filename) { _old_thisdirprefix = _scope->get_variable("THISDIRPREFIX"); _old_thisfilename = _scope->get_variable("THISFILENAME"); - _scope->define_variable("THISFILENAME", filename); + string thisfilename = filename; + string thisdirprefix; + size_t slash = filename.rfind('/'); if (slash == string::npos) { - _scope->define_variable("THISDIRPREFIX", string()); + thisdirprefix = string(); } else { - _scope->define_variable("THISDIRPREFIX", filename.substr(0, slash + 1)); + thisdirprefix = filename.substr(0, slash + 1); } + + _scope->define_variable("THISFILENAME", thisfilename); + _scope->define_variable("THISDIRPREFIX", thisdirprefix); } //////////////////////////////////////////////////////////////////// @@ -1762,6 +1790,6 @@ PushFilename(PPScope *scope, const string &filename) { //////////////////////////////////////////////////////////////////// PPCommandFile::PushFilename:: ~PushFilename() { - _scope->define_variable("THISDIRPREFIX", _old_thisdirprefix); _scope->define_variable("THISFILENAME", _old_thisfilename); + _scope->define_variable("THISDIRPREFIX", _old_thisdirprefix); } diff --git a/ppremake/ppCommandFile.h b/ppremake/ppCommandFile.h index f7576ac150..9579d7e9c2 100644 --- a/ppremake/ppCommandFile.h +++ b/ppremake/ppCommandFile.h @@ -30,6 +30,7 @@ public: PPScope *get_scope() const; bool read_file(const string &filename); + bool read_stream(istream &in, const string &filename); bool read_stream(istream &in); void begin_read(); bool read_line(string line); diff --git a/ppremake/ppDirectory.cxx b/ppremake/ppDirectory.cxx index 41919a397a..11743e5fe7 100644 --- a/ppremake/ppDirectory.cxx +++ b/ppremake/ppDirectory.cxx @@ -397,10 +397,23 @@ r_scan(const string &prefix) { return false; } + // Collect all the filenames in the directory in this vector first, + // so we can sort them. + vector filenames; + struct dirent *d; d = readdir(root); while (d != (struct dirent *)NULL) { - string filename = d->d_name; + filenames.push_back(d->d_name); + d = readdir(root); + } + closedir(root); + + sort(filenames.begin(), filenames.end()); + + vector::const_iterator fi; + for (fi = filenames.begin(); fi != filenames.end(); ++fi) { + string filename = (*fi); if (!filename.empty() && filename[0] != '.') { // Is this possibly a subdirectory with its own Sources.pp @@ -408,19 +421,16 @@ r_scan(const string &prefix) { string next_prefix = prefix + filename + "/"; string source_filename = next_prefix + SOURCE_FILENAME; if (access(source_filename.c_str(), F_OK) == 0) { + PPDirectory *subtree = new PPDirectory(filename, this); if (!subtree->r_scan(next_prefix)) { - closedir(root); return false; } } } - - d = readdir(root); } - closedir(root); return true; } @@ -451,8 +461,7 @@ read_source_file(const string &prefix, PPNamedScopes *named_scopes) { _source = new PPCommandFile(_scope); - if (!_source->read_stream(in)) { - cerr << "Error when reading " << source_filename << "\n"; + if (!_source->read_stream(in, source_filename)) { return false; } } diff --git a/ppremake/ppMain.cxx b/ppremake/ppMain.cxx index 35da5f7c53..565fbe34f8 100644 --- a/ppremake/ppMain.cxx +++ b/ppremake/ppMain.cxx @@ -14,6 +14,8 @@ #include #include // for perror +string PPMain::_root; + //////////////////////////////////////////////////////////////////// // Function: PPMain::Constructor // Access: Public @@ -81,12 +83,12 @@ read_source(const string &root) { return false; } - string cwd = get_cwd(); - cerr << "Root is " << cwd << "\n"; + _root = get_cwd(); + cerr << "Root is " << _root << "\n"; _def_scope = new PPScope(&_named_scopes); _def_scope->define_variable("PACKAGEFILE", package_file); - _def_scope->define_variable("TOPDIR", cwd); + _def_scope->define_variable("TOPDIR", _root); _defs = new PPCommandFile(_def_scope); if (!_defs->read_file(PACKAGE_FILENAME)) { @@ -218,6 +220,37 @@ report_needs(const string &dirname) const { dir->report_needs(); } +//////////////////////////////////////////////////////////////////// +// Function: PPMain::get_root +// Access: Public, Static +// Description: Returns the full path to the root directory of the +// source hierarchy; this is the directory in which the +// runs most of the time. +//////////////////////////////////////////////////////////////////// +string PPMain:: +get_root() { + return _root; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPMain::chdir_root +// Access: Public, Static +// Description: Changes the current directory to the root directory +// of the source hierarchy. This should be executed +// after a temporary change to another directory, to +// restore the current directory to a known state. +//////////////////////////////////////////////////////////////////// +void PPMain:: +chdir_root() { + if (chdir(_root.c_str()) < 0) { + perror("chdir"); + // This is a real error! We can't get back to our starting + // directory! + cerr << "Error! Source directory is invalid!\n"; + exit(1); + } +} + //////////////////////////////////////////////////////////////////// // Function: PPMain::r_process_all // Access: Private diff --git a/ppremake/ppMain.h b/ppremake/ppMain.h index f9d3c53ae9..ef3ec4e729 100644 --- a/ppremake/ppMain.h +++ b/ppremake/ppMain.h @@ -32,6 +32,9 @@ public: void report_depends(const string &dirname) const; void report_needs(const string &dirname) const; + static string get_root(); + static void chdir_root(); + private: bool r_process_all(PPDirectory *dir); bool p_process(PPDirectory *dir); @@ -46,6 +49,8 @@ private: PPDirectoryTree _tree; PPNamedScopes _named_scopes; PPScope *_parent_scope; + + static string _root; }; #endif diff --git a/ppremake/ppNamedScopes.cxx b/ppremake/ppNamedScopes.cxx index 1eedd36b5b..5d2ea1429e 100644 --- a/ppremake/ppNamedScopes.cxx +++ b/ppremake/ppNamedScopes.cxx @@ -14,7 +14,7 @@ // by directory name, used in sort_by_dependency(). class SortScopesByDependencyAndName { public: - bool operator () (const PPScope *a, const PPScope *b) const { + bool operator () (PPScope *a, PPScope *b) const { PPDirectory *da = a->get_directory(); PPDirectory *db = b->get_directory(); diff --git a/ppremake/ppScope.cxx b/ppremake/ppScope.cxx index fe27f0ff48..aafd8fc70b 100644 --- a/ppremake/ppScope.cxx +++ b/ppremake/ppScope.cxx @@ -10,6 +10,7 @@ #include "ppSubroutine.h" #include "ppCommandFile.h" #include "ppDependableFile.h" +#include "ppMain.h" #include "tokenize.h" #include "find_searchpath.h" #include "filename.h" @@ -59,7 +60,7 @@ PPScope(PPNamedScopes *named_scopes) : // NULL. //////////////////////////////////////////////////////////////////// PPNamedScopes *PPScope:: -get_named_scopes() const { +get_named_scopes() { return _named_scopes; } @@ -84,7 +85,7 @@ set_parent(PPScope *parent) { // See set_parent(). //////////////////////////////////////////////////////////////////// PPScope *PPScope:: -get_parent() const { +get_parent() { return _parent_scope; } @@ -300,7 +301,7 @@ define_formals(const string &subroutine_name, // indicated variable name. //////////////////////////////////////////////////////////////////// string PPScope:: -get_variable(const string &varname) const { +get_variable(const string &varname) { // Is it a user-defined function? const PPSubroutine *sub = PPSubroutine::get_func(varname); if (sub != (const PPSubroutine *)NULL) { @@ -337,7 +338,7 @@ get_variable(const string &varname) const { // definition is in turn expanded. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_variable(const string &varname) const { +expand_variable(const string &varname) { return expand_string(get_variable(varname)); } @@ -350,7 +351,7 @@ expand_variable(const string &varname) const { // not. //////////////////////////////////////////////////////////////////// PPScope::MapVariableDefinition &PPScope:: -find_map_variable(const string &varname) const { +find_map_variable(const string &varname) { MapVariableDefinition &def = p_find_map_variable(varname); if (&def != &_null_map_def) { return def; @@ -377,7 +378,7 @@ find_map_variable(const string &varname) const { // scope. //////////////////////////////////////////////////////////////////// PPDirectory *PPScope:: -get_directory() const { +get_directory() { if (_directory != (PPDirectory *)NULL) { return _directory; } @@ -417,7 +418,7 @@ set_directory(PPDirectory *directory) { // expanded. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_string(const string &str) const { +expand_string(const string &str) { return r_expand_string(str, (ExpandedVariable *)NULL); } @@ -431,7 +432,7 @@ expand_string(const string &str) const { // definition. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_self_reference(const string &str, const string &varname) const { +expand_self_reference(const string &str, const string &varname) { // Look for a simple reference to the named variable. A more // complex reference, like a computed variable name or something // equally loopy, won't work with this simple test. Too bad. @@ -512,7 +513,7 @@ get_bottom_scope() { //////////////////////////////////////////////////////////////////// void PPScope:: tokenize_params(const string &str, vector &tokens, - bool expand) const { + bool expand) { size_t p = 0; while (p < str.length()) { // Skip initial whitespace. @@ -564,7 +565,7 @@ tokenize_params(const string &str, vector &tokens, // error. //////////////////////////////////////////////////////////////////// bool PPScope:: -tokenize_numeric_pair(const string &str, double &a, double &b) const { +tokenize_numeric_pair(const string &str, double &a, double &b) { vector words; tokenize_params(str, words, true); if (words.size() != 2) { @@ -623,7 +624,7 @@ p_set_variable(const string &varname, const string &definition) { // false otherwise.. //////////////////////////////////////////////////////////////////// bool PPScope:: -p_get_variable(const string &varname, string &result) const { +p_get_variable(const string &varname, string &result) { Variables::const_iterator vi; vi = _variables.find(varname); if (vi != _variables.end()) { @@ -669,7 +670,7 @@ p_get_variable(const string &varname, string &result) const { // have thus far been expanded in the linked list. //////////////////////////////////////////////////////////////////// string PPScope:: -r_expand_string(const string &str, PPScope::ExpandedVariable *expanded) const { +r_expand_string(const string &str, PPScope::ExpandedVariable *expanded) { string result; // Search for a variable reference. @@ -704,7 +705,7 @@ r_expand_string(const string &str, PPScope::ExpandedVariable *expanded) const { // itself is returned. //////////////////////////////////////////////////////////////////// string PPScope:: -r_scan_variable(const string &str, size_t &vp) const { +r_scan_variable(const string &str, size_t &vp) { // Search for the end of the variable name: an unmatched square // bracket. @@ -749,7 +750,7 @@ r_scan_variable(const string &str, size_t &vp) const { //////////////////////////////////////////////////////////////////// string PPScope:: r_expand_variable(const string &str, size_t &vp, - PPScope::ExpandedVariable *expanded) const { + PPScope::ExpandedVariable *expanded) { string varname; size_t whitespace_at = 0; @@ -869,6 +870,8 @@ r_expand_variable(const string &str, size_t &vp, return expand_sort(params); } else if (funcname == "unique") { return expand_unique(params); + } else if (funcname == "matrix") { + return expand_matrix(params); } else if (funcname == "if") { return expand_if(params); } else if (funcname == "eq") { @@ -905,6 +908,10 @@ r_expand_variable(const string &str, size_t &vp, return expand_unmapped(params); } else if (funcname == "dependencies") { return expand_dependencies(params); + } else if (funcname == "foreach") { + return expand_foreach(params); + } else if (funcname == "forscopes") { + return expand_forscopes(params); } // It must be a map variable. @@ -1003,7 +1010,7 @@ r_expand_variable(const string &str, size_t &vp, //////////////////////////////////////////////////////////////////// string PPScope:: expand_variable_nested(const string &varname, - const string &scope_names) const { + const string &scope_names) { if (_named_scopes == (PPNamedScopes *)NULL) { return string(); } @@ -1051,7 +1058,7 @@ expand_variable_nested(const string &varname, // drive leterr, for windows_platform. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_isfullpath(const string ¶ms) const { +expand_isfullpath(const string ¶ms) { string filename = trim_blanks(expand_string(params)); string result; @@ -1078,7 +1085,7 @@ expand_isfullpath(const string ¶ms) const { // reverse slashes. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_osfilename(const string ¶ms) const { +expand_osfilename(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1109,7 +1116,7 @@ expand_osfilename(const string ¶ms) const { // reverse slashes. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_unixfilename(const string ¶ms) const { +expand_unixfilename(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1132,7 +1139,7 @@ expand_unixfilename(const string ¶ms) const { // not running under Cygwin. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_cygpath_w(const string ¶ms) const { +expand_cygpath_w(const string ¶ms) { string filename = trim_blanks(expand_string(params)); #ifdef __CYGWIN__ @@ -1154,7 +1161,7 @@ expand_cygpath_w(const string ¶ms) const { // not running under Cygwin. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_cygpath_p(const string ¶ms) const { +expand_cygpath_p(const string ¶ms) { string filename = trim_blanks(expand_string(params)); #ifdef __CYGWIN__ @@ -1175,7 +1182,7 @@ expand_cygpath_p(const string ¶ms) const { // with shell matching characters. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_wildcard(const string ¶ms) const { +expand_wildcard(const string ¶ms) { vector results; glob_string(expand_string(params), results); @@ -1194,7 +1201,7 @@ expand_wildcard(const string ¶ms) const { // the first expansion. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_isdir(const string ¶ms) const { +expand_isdir(const string ¶ms) { vector results; glob_string(expand_string(params), results); @@ -1227,7 +1234,7 @@ expand_isdir(const string ¶ms) const { // looks only at the first expansion. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_isfile(const string ¶ms) const { +expand_isfile(const string ¶ms) { vector results; glob_string(expand_string(params), results); @@ -1258,7 +1265,7 @@ expand_isfile(const string ¶ms) const { // indicated search path, or on the system search path. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_libtest(const string ¶ms) const { +expand_libtest(const string ¶ms) { // Get the parameters out based on commas. The first parameter is a // space-separated set of directories to search, the second // parameter is a space-separated set of library names. @@ -1347,7 +1354,7 @@ expand_libtest(const string ¶ms) const { // path. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_bintest(const string ¶ms) const { +expand_bintest(const string ¶ms) { // We only have one parameter: the filename of the executable. We // always search for it on the path. string binname = expand_string(params); @@ -1418,7 +1425,12 @@ expand_bintest(const string ¶ms) const { // standard output. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_shell(const string ¶ms) const { +expand_shell(const string ¶ms) { + // We run $[shell] commands within the directory indicated by + // $[THISDIRPREFIX]. This way, local filenames will be expanded the + // way we expect. + string dirname = trim_blanks(expand_variable("THISDIRPREFIX")); + string command = expand_string(params); int pid, status; @@ -1438,6 +1450,16 @@ expand_shell(const string ¶ms) const { if (pid == 0) { // Child. + + if (!dirname.empty()) { + // We don't have to restore the directory after we're done, + // because we're doing the chdir() call only within the child + // process. + if (chdir(dirname.c_str()) < 0) { + perror("chdir"); + } + } + close(pd[0]); dup2(pd[1], STDOUT_FILENO); char *argv[4]; @@ -1502,7 +1524,7 @@ expand_shell(const string ¶ms) const { // where possible. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_standardize(const string ¶ms) const { +expand_standardize(const string ¶ms) { string filename = trim_blanks(expand_string(params)); if (filename.empty()) { return string(); @@ -1558,7 +1580,7 @@ expand_standardize(const string ¶ms) const { // the length of the argument in characters. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_length(const string ¶ms) const { +expand_length(const string ¶ms) { string word = trim_blanks(expand_string(params)); char buffer[32]; @@ -1576,7 +1598,7 @@ expand_length(const string ¶ms) const { // character E, inclusive. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_substr(const string ¶ms) const { +expand_substr(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -1618,7 +1640,7 @@ expand_substr(const string ¶ms) const { // if the words contain no slash. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_dir(const string ¶ms) const { +expand_dir(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1647,7 +1669,7 @@ expand_dir(const string ¶ms) const { // string itself if there is no slash. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_notdir(const string ¶ms) const { +expand_notdir(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1673,7 +1695,7 @@ expand_notdir(const string ¶ms) const { // the filename extension, including a dot, if any. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_suffix(const string ¶ms) const { +expand_suffix(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1707,7 +1729,7 @@ expand_suffix(const string ¶ms) const { // directory, if any). //////////////////////////////////////////////////////////////////// string PPScope:: -expand_basename(const string ¶ms) const { +expand_basename(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1737,7 +1759,7 @@ expand_basename(const string ¶ms) const { // words in the second parameter. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_word(const string ¶ms) const { +expand_word(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -1768,7 +1790,7 @@ expand_word(const string ¶ms) const { // space-separated list of words in the third parameter. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_wordlist(const string ¶ms) const { +expand_wordlist(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -1817,7 +1839,7 @@ expand_wordlist(const string ¶ms) const { // list. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_words(const string ¶ms) const { +expand_words(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1836,7 +1858,7 @@ expand_words(const string ¶ms) const { // whitespace. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_firstword(const string ¶ms) const { +expand_firstword(const string ¶ms) { // Split the parameter into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -1853,7 +1875,7 @@ expand_firstword(const string ¶ms) const { // Description: Expands the "patsubst" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_patsubst(const string ¶ms, bool separate_words) const { +expand_patsubst(const string ¶ms, bool separate_words) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -1931,7 +1953,7 @@ expand_patsubst(const string ¶ms, bool separate_words) const { // Description: Expands the "filter" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_filter(const string ¶ms) const { +expand_filter(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -1987,7 +2009,7 @@ expand_filter(const string ¶ms) const { // Description: Expands the "filter_out" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_filter_out(const string ¶ms) const { +expand_filter_out(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2043,7 +2065,7 @@ expand_filter_out(const string ¶ms) const { // Description: Expands the "subst" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_subst(const string ¶ms) const { +expand_subst(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2084,7 +2106,7 @@ expand_subst(const string ¶ms) const { // like "subst" except it only replaces whole words. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_wordsubst(const string ¶ms) const { +expand_wordsubst(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2125,7 +2147,7 @@ expand_wordsubst(const string ¶ms) const { // into alphabetical order, and also remove duplicates. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_sort(const string ¶ms) const { +expand_sort(const string ¶ms) { // Split the string up into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -2146,7 +2168,7 @@ expand_sort(const string ¶ms) const { // remains. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_unique(const string ¶ms) const { +expand_unique(const string ¶ms) { // Split the string up into tokens based on the spaces. vector words; tokenize_whitespace(expand_string(params), words); @@ -2169,6 +2191,36 @@ expand_unique(const string ¶ms) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_matrix +// Access: Private +// Description: Expands the "matrix" function variable. This +// combines the different words of the n parameters in +// all possible ways, like the shell {a,b,c} expansion +// characters. For example, $[matrix a b,c,10 20 30] +// expands to ac10 ac20 ac30 bc10 bc20 bc30. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_matrix(const string ¶ms) { + // Split the string up into tokens based on the commas. + vector tokens; + tokenize_params(params, tokens, true); + + // Each token gets split up into words based on the spaces. + vector > words; + for (int i = 0; i < (int)tokens.size(); i++) { + words.push_back(vector()); + tokenize_whitespace(tokens[i], words.back()); + } + + // Now synthesize the results recursively. + vector results; + r_expand_matrix(results, words, 0, ""); + + string result = repaste(results, " "); + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_if // Access: Private @@ -2179,7 +2231,7 @@ expand_unique(const string ¶ms) const { // (i.e. empty). //////////////////////////////////////////////////////////////////// string PPScope:: -expand_if(const string ¶ms) const { +expand_if(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2209,7 +2261,7 @@ expand_if(const string ¶ms) const { // string equivalence. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_eq(const string ¶ms) const { +expand_eq(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2234,7 +2286,7 @@ expand_eq(const string ¶ms) const { // string equivalence. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_ne(const string ¶ms) const { +expand_ne(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2259,7 +2311,7 @@ expand_ne(const string ¶ms) const { // numeric equivalence. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_eqn(const string ¶ms) const { +expand_eqn(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2279,7 +2331,7 @@ expand_eqn(const string ¶ms) const { // numeric equivalence. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_nen(const string ¶ms) const { +expand_nen(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2299,7 +2351,7 @@ expand_nen(const string ¶ms) const { // numeric relationships. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_ltn(const string ¶ms) const { +expand_ltn(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2319,7 +2371,7 @@ expand_ltn(const string ¶ms) const { // numeric relationships. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_len(const string ¶ms) const { +expand_len(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2339,7 +2391,7 @@ expand_len(const string ¶ms) const { // numeric relationships. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_gtn(const string ¶ms) const { +expand_gtn(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2359,7 +2411,7 @@ expand_gtn(const string ¶ms) const { // numeric relationships. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_gen(const string ¶ms) const { +expand_gen(const string ¶ms) { double a, b; if (!tokenize_numeric_pair(params, a, b)) { return string(); @@ -2380,7 +2432,7 @@ expand_gen(const string ¶ms) const { // argument is nonempty. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_not(const string ¶ms) const { +expand_not(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2406,7 +2458,7 @@ expand_not(const string ¶ms) const { // Specifically, it returns the first nonempty argument. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_or(const string ¶ms) const { +expand_or(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2428,7 +2480,7 @@ expand_or(const string ¶ms) const { // Specifically, it returns the last argument. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_and(const string ¶ms) const { +expand_and(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, true); @@ -2454,7 +2506,7 @@ expand_and(const string ¶ms) const { // Description: Expands the "upcase" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_upcase(const string ¶ms) const { +expand_upcase(const string ¶ms) { string result = expand_string(params); string::iterator si; for (si = result.begin(); si != result.end(); ++si) { @@ -2469,7 +2521,7 @@ expand_upcase(const string ¶ms) const { // Description: Expands the "downcase" function variable. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_downcase(const string ¶ms) const { +expand_downcase(const string ¶ms) { string result = expand_string(params); string::iterator si; for (si = result.begin(); si != result.end(); ++si) { @@ -2491,7 +2543,7 @@ expand_downcase(const string ¶ms) const { // config.h file. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_cdefine(const string ¶ms) const { +expand_cdefine(const string ¶ms) { string varname = trim_blanks(params); string expansion = trim_blanks(expand_variable(varname)); @@ -2514,7 +2566,7 @@ expand_cdefine(const string ¶ms) const { // definitions have been encountered. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_closure(const string ¶ms) const { +expand_closure(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, false); @@ -2600,7 +2652,7 @@ expand_closure(const string ¶ms) const { // the keys in the map. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_unmapped(const string ¶ms) const { +expand_unmapped(const string ¶ms) { // Split the string up into tokens based on the commas. vector tokens; tokenize_params(params, tokens, false); @@ -2646,7 +2698,7 @@ expand_unmapped(const string ¶ms) const { // #include directives appearing within the files. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_dependencies(const string ¶ms) const { +expand_dependencies(const string ¶ms) { // Split the string up into filenames based on whitespace. vector filenames; tokenize_whitespace(expand_string(params), filenames); @@ -2674,6 +2726,90 @@ expand_dependencies(const string ¶ms) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_foreach +// Access: Private +// Description: Expands the "foreach" function variable. This +// evaluates an expression once for each word of a list. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_foreach(const string ¶ms) { + // Split the string up into tokens based on the commas. + vector tokens; + tokenize_params(params, tokens, false); + + if (tokens.size() != 3) { + cerr << "foreach requires three parameters.\n"; + return string(); + } + + // The first parameter is the temporary variable name that holds + // each word as it is expanded; the second parameter is the + // space-separated list of words. The third parameter is the + // expression to evaluate. + string varname = trim_blanks(expand_string(tokens[0])); + vector words; + tokenize_whitespace(expand_string(tokens[1]), words); + + vector results; + vector::const_iterator wi; + for (wi = words.begin(); wi != words.end(); ++wi) { + define_variable(varname, *wi); + results.push_back(expand_string(tokens[2])); + } + + string result = repaste(results, " "); + return result; +} + +//////////////////////////////////////////////////////////////////// +// Function: PPScope::expand_forscopes +// Access: Private +// Description: Expands the "forscopes" function variable. This +// evaluates an expression once within each of a number +// of named nested scopes. +//////////////////////////////////////////////////////////////////// +string PPScope:: +expand_forscopes(const string ¶ms) { + // Split the string up into tokens based on the commas. + vector tokens; + tokenize_params(params, tokens, false); + + if (tokens.size() != 2) { + cerr << "forscopes requires two parameters.\n"; + return string(); + } + + // The first parameter is the space-separated list of nested scope + // names. The second parameter is the expression to evaluate. + vector scope_names; + tokenize_whitespace(expand_string(tokens[0]), scope_names); + + if (_named_scopes == (PPNamedScopes *)NULL) { + return string(); + } + + // Now build up the list of scopes with these names. + PPNamedScopes::Scopes scopes; + vector::const_iterator wi; + for (wi = scope_names.begin(); wi != scope_names.end(); ++wi) { + _named_scopes->get_scopes(*wi, scopes); + } + PPNamedScopes::sort_by_dependency(scopes); + + // Now evaluate the expression within each scope. + + vector results; + PPNamedScopes::Scopes::const_iterator si; + for (si = scopes.begin(); si != scopes.end(); ++si) { + PPScope *scope = *si; + results.push_back(scope->expand_string(tokens[1])); + } + + string result = repaste(results, " "); + return result; +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::expand_function // Access: Private @@ -2684,7 +2820,7 @@ expand_dependencies(const string ¶ms) const { //////////////////////////////////////////////////////////////////// string PPScope:: expand_function(const string &funcname, - const PPSubroutine *sub, const string ¶ms) const { + const PPSubroutine *sub, const string ¶ms) { PPScope::push_scope((PPScope *)this); PPScope nested_scope(_named_scopes); nested_scope.define_formals(funcname, sub->_formals, params); @@ -2731,7 +2867,7 @@ expand_function(const string &funcname, // first parameter for each corresponding scope. //////////////////////////////////////////////////////////////////// string PPScope:: -expand_map_variable(const string &varname, const string ¶ms) const { +expand_map_variable(const string &varname, const string ¶ms) { // Split the string up into tokens based on the commas, but don't // expand the variables yet. vector tokens; @@ -2760,7 +2896,7 @@ expand_map_variable(const string &varname, const string ¶ms) const { //////////////////////////////////////////////////////////////////// string PPScope:: expand_map_variable(const string &varname, const string &expression, - const vector &keys) const { + const vector &keys) { const MapVariableDefinition &def = find_map_variable(varname); if (&def == &_null_map_def) { cerr << "Warning: undefined map variable: " << varname << "\n"; @@ -2788,6 +2924,31 @@ expand_map_variable(const string &varname, const string &expression, return result; } +//////////////////////////////////////////////////////////////////// +// Function: PPScope::r_expand_matrix +// Access: Private +// Description: The recursive implementation of expand_matrix(). +// This generates all of the combinations from the +// indicated index into the words array, with the given +// prefix. +//////////////////////////////////////////////////////////////////// +void PPScope:: +r_expand_matrix(vector &results, const vector > &words, + int index, const string &prefix) { + if (index >= (int)words.size()) { + // This is the terminal condition. + results.push_back(prefix); + + } else { + // Otherwise, tack on the next set of words, and recurse. + const vector &w = words[index]; + vector::const_iterator wi; + for (wi = w.begin(); wi != w.end(); ++wi) { + r_expand_matrix(results, words, index + 1, prefix + (*wi)); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: PPScope::p_find_map_variable // Access: Private @@ -2795,7 +2956,7 @@ expand_map_variable(const string &varname, const string &expression, // particular static scope, without checking the stack. //////////////////////////////////////////////////////////////////// PPScope::MapVariableDefinition &PPScope:: -p_find_map_variable(const string &varname) const { +p_find_map_variable(const string &varname) { MapVariables::const_iterator mvi; mvi = _map_variables.find(varname); if (mvi != _map_variables.end()) { @@ -2819,7 +2980,20 @@ p_find_map_variable(const string &varname) const { // files that actually match the globbing characters. //////////////////////////////////////////////////////////////////// void PPScope:: -glob_string(const string &str, vector &results) const { +glob_string(const string &str, vector &results) { + // We run glob_string() within the directory indicated by + // $[THISDIRPREFIX]. This way, local filenames will be expanded the + // way we expect. + string dirname = trim_blanks(expand_variable("THISDIRPREFIX")); + bool changed_dir = false; + if (!dirname.empty()) { + if (chdir(dirname.c_str()) < 0) { + perror("chdir"); + } else { + changed_dir = true; + } + } + vector words; tokenize_whitespace(str, words); @@ -2839,4 +3013,12 @@ glob_string(const string &str, vector &results) const { } globfree(&pglob); + + // Sort the results into alphabetical order. + sort(results.begin(), results.end()); + + if (changed_dir) { + // Now restore the current directory back to where it should be. + PPMain::chdir_root(); + } } diff --git a/ppremake/ppScope.h b/ppremake/ppScope.h index 06c5524196..a5bc396c06 100644 --- a/ppremake/ppScope.h +++ b/ppremake/ppScope.h @@ -28,10 +28,10 @@ public: PPScope(PPNamedScopes *named_scopes); - PPNamedScopes *get_named_scopes() const; + PPNamedScopes *get_named_scopes(); void set_parent(PPScope *parent); - PPScope *get_parent() const; + PPScope *get_parent(); void define_variable(const string &varname, const string &definition); bool set_variable(const string &varname, const string &definition); @@ -43,23 +43,23 @@ public: void define_formals(const string &subroutine_name, const vector &formals, const string &actuals); - string get_variable(const string &varname) const; - string expand_variable(const string &varname) const; - MapVariableDefinition &find_map_variable(const string &varname) const; + string get_variable(const string &varname); + string expand_variable(const string &varname); + MapVariableDefinition &find_map_variable(const string &varname); - PPDirectory *get_directory() const; + PPDirectory *get_directory(); void set_directory(PPDirectory *directory); - string expand_string(const string &str) const; - string expand_self_reference(const string &str, const string &varname) const; + string expand_string(const string &str); + string expand_self_reference(const string &str, const string &varname); static void push_scope(PPScope *scope); static PPScope *pop_scope(); static PPScope *get_bottom_scope(); void tokenize_params(const string &str, vector &tokens, - bool expand) const; - bool tokenize_numeric_pair(const string &str, double &a, double &b) const; + bool expand); + bool tokenize_numeric_pair(const string &str, double &a, double &b); static MapVariableDefinition _null_map_def; @@ -71,72 +71,80 @@ private: }; bool p_set_variable(const string &varname, const string &definition); - bool p_get_variable(const string &varname, string &result) const; + bool p_get_variable(const string &varname, string &result); - string r_expand_string(const string &str, ExpandedVariable *expanded) const; - string r_scan_variable(const string &str, size_t &vp) const; + string r_expand_string(const string &str, ExpandedVariable *expanded); + string r_scan_variable(const string &str, size_t &vp); string r_expand_variable(const string &str, size_t &vp, - PPScope::ExpandedVariable *expanded) const; + PPScope::ExpandedVariable *expanded); string expand_variable_nested(const string &varname, - const string &scope_names) const; + const string &scope_names); - string expand_isfullpath(const string ¶ms) const; - string expand_osfilename(const string ¶ms) const; - string expand_unixfilename(const string ¶ms) const; - string expand_cygpath_w(const string ¶ms) const; - string expand_cygpath_p(const string ¶ms) const; - string expand_wildcard(const string ¶ms) const; - string expand_isdir(const string ¶ms) const; - string expand_isfile(const string ¶ms) const; - string expand_libtest(const string ¶ms) const; - string expand_bintest(const string ¶ms) const; - string expand_shell(const string ¶ms) const; - string expand_standardize(const string ¶ms) const; - string expand_length(const string ¶ms) const; - string expand_substr(const string ¶ms) const; - string expand_dir(const string ¶ms) const; - string expand_notdir(const string ¶ms) const; - string expand_suffix(const string ¶ms) const; - string expand_basename(const string ¶ms) const; - string expand_word(const string ¶ms) const; - string expand_wordlist(const string ¶ms) const; - string expand_words(const string ¶ms) const; - string expand_firstword(const string ¶ms) const; - string expand_patsubst(const string ¶ms, bool separate_words) const; - string expand_filter(const string ¶ms) const; - string expand_filter_out(const string ¶ms) const; - string expand_wordsubst(const string ¶ms) const; - string expand_subst(const string ¶ms) const; - string expand_sort(const string ¶ms) const; - string expand_unique(const string ¶ms) const; - string expand_if(const string ¶ms) const; - string expand_eq(const string ¶ms) const; - string expand_ne(const string ¶ms) const; - string expand_eqn(const string ¶ms) const; - string expand_nen(const string ¶ms) const; - string expand_ltn(const string ¶ms) const; - string expand_len(const string ¶ms) const; - string expand_gtn(const string ¶ms) const; - string expand_gen(const string ¶ms) const; - string expand_not(const string ¶ms) const; - string expand_or(const string ¶ms) const; - string expand_and(const string ¶ms) const; - string expand_upcase(const string ¶ms) const; - string expand_downcase(const string ¶ms) const; - string expand_cdefine(const string ¶ms) const; - string expand_closure(const string ¶ms) const; - string expand_unmapped(const string ¶ms) const; - string expand_dependencies(const string ¶ms) const; + string expand_isfullpath(const string ¶ms); + string expand_osfilename(const string ¶ms); + string expand_unixfilename(const string ¶ms); + string expand_cygpath_w(const string ¶ms); + string expand_cygpath_p(const string ¶ms); + string expand_wildcard(const string ¶ms); + string expand_isdir(const string ¶ms); + string expand_isfile(const string ¶ms); + string expand_libtest(const string ¶ms); + string expand_bintest(const string ¶ms); + string expand_shell(const string ¶ms); + string expand_standardize(const string ¶ms); + string expand_length(const string ¶ms); + string expand_substr(const string ¶ms); + string expand_dir(const string ¶ms); + string expand_notdir(const string ¶ms); + string expand_suffix(const string ¶ms); + string expand_basename(const string ¶ms); + string expand_word(const string ¶ms); + string expand_wordlist(const string ¶ms); + string expand_words(const string ¶ms); + string expand_firstword(const string ¶ms); + string expand_patsubst(const string ¶ms, bool separate_words); + string expand_filter(const string ¶ms); + string expand_filter_out(const string ¶ms); + string expand_wordsubst(const string ¶ms); + string expand_subst(const string ¶ms); + string expand_sort(const string ¶ms); + string expand_unique(const string ¶ms); + string expand_matrix(const string ¶ms); + string expand_if(const string ¶ms); + string expand_eq(const string ¶ms); + string expand_ne(const string ¶ms); + string expand_eqn(const string ¶ms); + string expand_nen(const string ¶ms); + string expand_ltn(const string ¶ms); + string expand_len(const string ¶ms); + string expand_gtn(const string ¶ms); + string expand_gen(const string ¶ms); + string expand_not(const string ¶ms); + string expand_or(const string ¶ms); + string expand_and(const string ¶ms); + string expand_upcase(const string ¶ms); + string expand_downcase(const string ¶ms); + string expand_cdefine(const string ¶ms); + string expand_closure(const string ¶ms); + string expand_unmapped(const string ¶ms); + string expand_dependencies(const string ¶ms); + string expand_foreach(const string ¶ms); + string expand_forscopes(const string ¶ms); string expand_function(const string &funcname, const PPSubroutine *sub, - const string ¶ms) const; - string expand_map_variable(const string &varname, const string ¶ms) const; + const string ¶ms); + string expand_map_variable(const string &varname, const string ¶ms); string expand_map_variable(const string &varname, const string &expression, - const vector &keys) const; + const vector &keys); + + void + r_expand_matrix(vector &results, + const vector > &words, + int index, const string &prefix); MapVariableDefinition & - p_find_map_variable(const string &varname) const; + p_find_map_variable(const string &varname); - void glob_string(const string &str, vector &results) const; + void glob_string(const string &str, vector &results); PPNamedScopes *_named_scopes;