add some 1.05 features: #push, better #output .. #end matching, #printvar

This commit is contained in:
David Rose 2002-05-31 22:32:35 +00:00
parent 563772fd77
commit 988658f58e
7 changed files with 220 additions and 54 deletions

View File

@ -80,5 +80,5 @@
** Also be sure to change the version number **
** at the beginning of configure.in. **
**************** ****************/
#define VERSION "1.04"
#define VERSION "1.05"
/**************** UPDATE VERSION NUMBER HERE ****************/

View File

@ -5,7 +5,7 @@ dnl **************** UPDATE VERSION NUMBER HERE ****************
dnl ** Also be sure to change the version number **
dnl ** at the end of config_msvc.h. **
dnl **************** ****************
AM_INIT_AUTOMAKE(ppremake, 1.04)
AM_INIT_AUTOMAKE(ppremake, 1.05)
dnl **************** UPDATE VERSION NUMBER HERE ****************
AM_CONFIG_HEADER(config.h)

View File

@ -59,7 +59,7 @@
// pathnames.
#ifdef HAVE_CYGWIN
extern "C" void cygwin_conv_to_win32_path(const char *path, char *win32);
//extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
extern "C" void cygwin_conv_to_posix_path(const char *path, char *posix);
#endif
static string
@ -1294,7 +1294,21 @@ bool Filename::
touch() const {
#ifdef HAVE_UTIME_H
// Most Unix systems can do this explicitly.
string os_specific = to_os_specific();
#ifdef HAVE_CYGWIN
// In the Cygwin case, it seems we need to be sure to use the
// Cygwin-style name; some broken utime() implementation. That's
// almost the same thing as the original Panda-style name, but not
// exactly, so we first convert the Panda name to a Windows name,
// then convert it back to Cygwin, to ensure we get it exactly right
// by Cygwin rules.
{
char result[4096] = "";
cygwin_conv_to_posix_path(os_specific.c_str(), result);
os_specific = result;
}
#endif // HAVE_CYGWIN
int result = utime(os_specific.c_str(), NULL);
if (result < 0) {
if (errno == ENOENT) {
@ -1311,14 +1325,14 @@ touch() const {
return false;
}
return true;
#else
#else // HAVE_UTIME_H
// Other systems may not have an explicit control over the
// modification time. For these systems, we'll just temporarily
// open the file in append mode, then close it again (it gets closed
// when the ofstream goes out of scope).
ofstream file;
return open_append(file);
#endif
#endif // HAVE_UTIME_H
}
////////////////////////////////////////////////////////////////////

View File

@ -74,7 +74,7 @@ pop(PPCommandFile *file) {
////////////////////////////////////////////////////////////////////
PPCommandFile::WriteState::
WriteState() {
_out = &cout;
_out = NULL;
_format = WF_collapse;
_last_blank = true;
}
@ -99,6 +99,13 @@ WriteState(const WriteState &copy) :
////////////////////////////////////////////////////////////////////
bool PPCommandFile::WriteState::
write_line(const string &line) {
if (_out == (ostream *)NULL || _format == WF_error) {
if (!line.empty()) {
cerr << "Ignoring: " << line << "\n";
}
return true;
} else {
switch (_format) {
case WF_straight:
(*_out) << line << "\n";
@ -114,6 +121,7 @@ write_line(const string &line) {
cerr << "Unsupported write format: " << (int)_format << "\n";
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: PPCommandFile::WriteState::write_collapse_line
@ -276,8 +284,8 @@ set_output(ostream *out) {
////////////////////////////////////////////////////////////////////
void PPCommandFile::
set_scope(PPScope *scope) {
_scope = scope;
_native_scope = scope;
_scope = scope;
}
////////////////////////////////////////////////////////////////////
@ -622,6 +630,9 @@ handle_command(const string &line) {
} else if (_command == "print") {
return handle_print_command();
} else if (_command == "printvar") {
return handle_printvar_command();
} else if (_command == "include") {
return handle_include_command();
@ -648,6 +659,9 @@ handle_command(const string &line) {
} else if (_command == "addmap") {
return handle_addmap_command();
} else if (_command == "push") {
return handle_push_command();
}
cerr << "Invalid command: " << COMMAND_PREFIX << _command << "\n";
@ -792,7 +806,7 @@ handle_endif_command() {
////////////////////////////////////////////////////////////////////
bool PPCommandFile::
handle_begin_command() {
string name = trim_blanks(_scope->expand_string(_params));
string name = trim_blanks(_params);
BlockNesting *nest = new BlockNesting(BS_begin, name);
if (contains_whitespace(name)) {
@ -828,7 +842,7 @@ handle_begin_command() {
bool PPCommandFile::
handle_forscopes_command() {
BlockState state = _in_for ? BS_nested_forscopes : BS_forscopes;
string name = trim_blanks(_scope->expand_string(_params));
string name = trim_blanks(_params);
BlockNesting *nest = new BlockNesting(state, name);
nest->push(this);
@ -985,18 +999,25 @@ handle_defsub_command(bool is_defsub) {
////////////////////////////////////////////////////////////////////
bool PPCommandFile::
handle_output_command() {
vector<string> words;
tokenize_whitespace(_scope->expand_string(_params), words);
// We must get the filename out (the first parameter) without
// expanding it, because it might involve a string that has to be
// expanded later.
size_t p = _scope->scan_to_whitespace(_params);
string name = _params.substr(0, p);
if (words.empty()) {
if (name.empty()) {
cerr << "#output command requires one parameter.\n";
return false;
}
BlockNesting *nest = new BlockNesting(BS_output, words[0]);
// Now get the remaining parameters out; these we will expand immediately.
vector<string> words;
tokenize_whitespace(_scope->expand_string(_params.substr(p)), words);
BlockNesting *nest = new BlockNesting(BS_output, name);
// Also check the output flags.
for (int i = 1; i < (int)words.size(); i++) {
for (int i = 0; i < (int)words.size(); i++) {
if (words[i] == "notouch") {
nest->_flags |= OF_notouch;
} else {
@ -1007,7 +1028,7 @@ handle_output_command() {
nest->push(this);
if (!_in_for) {
string filename = nest->_name;
string filename = trim_blanks(_scope->expand_string(nest->_name));
if (filename.empty()) {
cerr << "Attempt to output to empty filename\n";
return false;
@ -1041,7 +1062,13 @@ handle_end_command() {
return false;
}
string name = trim_blanks(_scope->expand_string(_params));
// We don't expand the closing name string, because we didn't expand
// the opening string. (This is especially true for an #output
// statement. On some of the other statements, we might have
// inadvertently expanded this string, but probably that was a
// mistake; and there's no reason for programmers to take advantage
// of an expansion there.)
string name = trim_blanks(_params);
if (name != _block_nesting->_name) {
cerr << "end " << name << " encountered where end "
<< _block_nesting->_name << " expected.\n";
@ -1158,6 +1185,33 @@ handle_print_command() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPCommandFile::handle_printvar_command
// Access: Protected
// Description: Writes the literal contents of the named variable(s)
// (the variables are named directly without enclosing
// $[ ... ] syntax) to cerr, for debugging.
////////////////////////////////////////////////////////////////////
bool PPCommandFile::
handle_printvar_command() {
size_t p = 0;
while (p < _params.length()) {
// Pull off the next varname.
size_t q = _scope->scan_to_whitespace(_params, p);
string varname = trim_blanks(_scope->expand_string(_params.substr(p, q)));
cerr << varname << " = \"" << _scope->get_variable(varname)
<< "\" ";
p = q;
while (p < _params.length() && isspace(_params[p])) {
p++;
}
}
cerr << "\n";
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPCommandFile::handle_include_command
// Access: Protected
@ -1288,11 +1342,8 @@ handle_error_command() {
bool PPCommandFile::
handle_defer_command() {
// Pull off the first word and the rest of the params.
size_t p = 0;
while (p < _params.length() && !isspace(_params[p])) {
p++;
}
string varname = _params.substr(0, p);
size_t p = _scope->scan_to_whitespace(_params);
string varname = trim_blanks(_scope->expand_string(_params.substr(0, p)));
if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) {
cerr << "Warning: variable " << varname
@ -1310,7 +1361,6 @@ handle_defer_command() {
// should expand any simple self-reference immediately, to allow for
// recursive definitions.
def = _scope->expand_self_reference(def, varname);
_scope->define_variable(varname, def);
return true;
@ -1327,11 +1377,8 @@ handle_defer_command() {
bool PPCommandFile::
handle_define_command() {
// Pull off the first word and the rest of the params.
size_t p = 0;
while (p < _params.length() && !isspace(_params[p])) {
p++;
}
string varname = _params.substr(0, p);
size_t p = _scope->scan_to_whitespace(_params);
string varname = trim_blanks(_scope->expand_string(_params.substr(0, p)));
if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) {
cerr << "Warning: variable " << varname
@ -1366,11 +1413,8 @@ handle_define_command() {
bool PPCommandFile::
handle_set_command() {
// Pull off the first word and the rest of the params.
size_t p = 0;
while (p < _params.length() && !isspace(_params[p])) {
p++;
}
string varname = _params.substr(0, p);
size_t p = _scope->scan_to_whitespace(_params);
string varname = trim_blanks(_scope->expand_string(_params.substr(0, p)));
if (PPSubroutine::get_func(varname) != (const PPSubroutine *)NULL) {
cerr << "Warning: variable " << varname
@ -1403,18 +1447,14 @@ handle_set_command() {
bool PPCommandFile::
handle_map_command() {
// Pull off the first word and the rest of the params.
size_t p = 0;
while (p < _params.length() && !isspace(_params[p])) {
p++;
}
string varname = _params.substr(0, p);
size_t p = _scope->scan_to_whitespace(_params);
string varname = trim_blanks(_scope->expand_string(_params.substr(0, p)));
// Skip whitespace between the variable name and its definition.
while (p < _params.length() && isspace(_params[p])) {
p++;
}
string def = trim_blanks(_params.substr(p));
_scope->define_map_variable(varname, def);
return true;
}
@ -1428,11 +1468,8 @@ handle_map_command() {
bool PPCommandFile::
handle_addmap_command() {
// Pull off the first word and the rest of the params.
size_t p = 0;
while (p < _params.length() && !isspace(_params[p])) {
p++;
}
string varname = _params.substr(0, p);
size_t p = _scope->scan_to_whitespace(_params);
string varname = trim_blanks(_scope->expand_string(_params.substr(0, p)));
// Skip whitespace between the variable name and the key.
while (p < _params.length() && isspace(_params[p])) {
@ -1444,6 +1481,61 @@ handle_addmap_command() {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPCommandFile::handle_push_command
// Access: Protected
// Description: Handles the #push command: push a variable definition
// out to the enclosing scope. Useful for defining
// variables within a #forscopes block that you want to
// persist longer than the block itself.
//
// Syntax is:
//
// #push n varname [varname2 ... ]
//
// Where n is the number of levels out to push.
////////////////////////////////////////////////////////////////////
bool PPCommandFile::
handle_push_command() {
// The first word is the number of levels.
size_t p = _scope->scan_to_whitespace(_params);
string levels_str = trim_blanks(_scope->expand_string(_params.substr(0, p)));
// Validate the number.
const char *param = levels_str.c_str();
char *n;
int levels = strtol(param, &n, 10);
if (n == param || levels < 0) {
// Invalid integer.
cerr << "#push with invalid level count: " << levels_str << "\n";
return false;
}
PPScope *enclosing_scope = _scope;
if (levels > 0) {
enclosing_scope = _scope->get_enclosing_scope(levels - 1);
}
// Skip whitespace to the first variable name.
while (p < _params.length() && isspace(_params[p])) {
p++;
}
while (p < _params.length()) {
// Pull off the next varname.
size_t q = _scope->scan_to_whitespace(_params, p);
string varname = trim_blanks(_scope->expand_string(_params.substr(p, q)));
string def = _scope->get_variable(varname);
enclosing_scope->define_variable(varname, def);
p = q;
while (p < _params.length() && isspace(_params[p])) {
p++;
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPCommandFile::include_file

View File

@ -54,6 +54,7 @@ protected:
bool handle_format_command();
bool handle_print_command();
bool handle_printvar_command();
bool handle_include_command();
bool handle_sinclude_command();
bool handle_call_command();
@ -64,6 +65,7 @@ protected:
bool handle_set_command();
bool handle_map_command();
bool handle_addmap_command();
bool handle_push_command();
bool include_file(Filename filename);
bool replay_forscopes(const string &name);
@ -121,6 +123,7 @@ private:
};
enum WriteFormat {
WF_error, // anything other than whitespace is an error.
WF_straight, // write lines directly as they come in
WF_collapse, // collapse out consecutive blank lines
WF_makefile // fancy makefile formatting

View File

@ -571,6 +571,25 @@ get_bottom_scope() {
return _scope_stack.front();
}
////////////////////////////////////////////////////////////////////
// Function: PPScope::get_enclosing_scope
// Access: Public, Static
// Description: Returns the scope n below the top of the stack, or
// the bottom scope if the stack has exactly n or fewer
// scopes.
//
// This will be the scope associated with the nth
// enclosing syntax in the source file.
////////////////////////////////////////////////////////////////////
PPScope *PPScope::
get_enclosing_scope(int n) {
assert(n >= 0);
if (n >= _scope_stack.size()) {
return get_bottom_scope();
}
return _scope_stack[_scope_stack.size() - 1 - n];
}
////////////////////////////////////////////////////////////////////
// Function: PPScope::tokenize_params
// Access: Public
@ -665,6 +684,42 @@ tokenize_numeric_pair(const string &str, double &a, double &b) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PPScope::scan_to_whitespace
// Access: Public
// Description: Scans to the end of the first whitespace-delimited
// word in the indicated string, even if it includes a
// nested variable reference (which is itself allowed to
// contain whitespace).
//
// On input, str is a string, and start is the starting
// position within the string of the scan; it should
// point to a non-whitespace character.
//
// The return value is the position within the string of
// the first whitespace character encountered at its
// original position or later, that is not part of a
// variable reference. All variable references are left
// unexpanded.
////////////////////////////////////////////////////////////////////
size_t PPScope::
scan_to_whitespace(const string &str, size_t start) {
size_t p = start;
while (p < str.length() && !isspace(str[p])) {
string token;
if (p + 1 < str.length() && str[p] == VARIABLE_PREFIX &&
str[p + 1] == VARIABLE_OPEN_BRACE) {
// Skip a nested variable reference.
r_scan_variable(str, p);
} else {
p++;
}
}
return p;
}
////////////////////////////////////////////////////////////////////
// Function: PPScope::p_set_variable
// Access: Private

View File

@ -56,10 +56,12 @@ public:
static void push_scope(PPScope *scope);
static PPScope *pop_scope();
static PPScope *get_bottom_scope();
static PPScope *get_enclosing_scope(int n);
void tokenize_params(const string &str, vector<string> &tokens,
bool expand);
bool tokenize_numeric_pair(const string &str, double &a, double &b);
size_t scan_to_whitespace(const string &str, size_t start = 0);
static MapVariableDefinition _null_map_def;