*** empty log message ***

This commit is contained in:
David Rose 2000-10-25 01:35:44 +00:00
parent 8c39825532
commit 28b9f21a54
13 changed files with 943 additions and 20 deletions

View File

@ -1,15 +1,17 @@
bin_PROGRAMS = ppremake
ppremake_SOURCES = \
check_include.cxx check_include.h filename.cxx filename.h \
find_searchpath.cxx find_searchpath.h \
gnu_getopt.c gnu_getopt.h \
ppCommandFile.cxx ppCommandFile.h ppDependableFile.cxx \
ppDependableFile.h ppDirectory.cxx \
ppDirectory.h ppDirectoryTree.cxx ppDirectoryTree.h \
ppMain.cxx ppMain.h \
ppFilenamePattern.cxx \
ppFilenamePattern.h ppNamedScopes.cxx ppNamedScopes.h \
ppScope.cxx ppScope.h ppSubroutine.cxx ppSubroutine.h \
ppremake.cxx ppremake.h tokenize.cxx \
ppremake_SOURCES = \
check_include.cxx check_include.h filename.cxx filename.h \
find_searchpath.cxx find_searchpath.h \
gnu_getopt.c gnu_getopt.h \
ppCommandFile.cxx ppCommandFile.h ppDependableFile.cxx \
ppDependableFile.h ppDirectory.cxx \
ppDirectory.h ppDirectoryTree.cxx ppDirectoryTree.h \
ppMain.cxx ppMain.h \
ppFilenamePattern.cxx \
ppFilenamePattern.h ppNamedScopes.cxx ppNamedScopes.h \
ppScope.cxx ppScope.h ppSubroutine.cxx ppSubroutine.h \
ppremake.cxx ppremake.h sedAddress.cxx sedAddress.h sedCommand.cxx \
sedCommand.h sedContext.cxx sedContext.h sedProcess.cxx \
sedProcess.h sedScript.cxx sedScript.h tokenize.cxx \
tokenize.h

View File

@ -1,6 +1,6 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(ppremake.cxx)
AM_INIT_AUTOMAKE(ppremake, 0.52)
AM_INIT_AUTOMAKE(ppremake, 0.54)
AM_CONFIG_HEADER(config.h)
AC_PREFIX_DEFAULT(/usr/local/panda)

View File

@ -8,6 +8,7 @@
#include "ppScope.h"
#include "check_include.h"
#include "tokenize.h"
#include "sedProcess.h"
#ifdef HAVE_GETOPT
#include <getopt.h>
@ -30,6 +31,7 @@ usage() {
"\n"
"ppremake [opts] subdir-name [subdir-name..]\n"
"ppremake\n"
"ppremake -s 'sed-command' <input >output\n"
"\n"
"This is Panda pre-make: a script preprocessor that scans the source\n"
"directory hierarchy containing the current directory, looking for\n"
@ -51,6 +53,11 @@ usage() {
"generated. If no parameter is given, then all directories will be\n"
"processed.\n\n"
"ppremake -s is a special form of the command that runs as a very limited\n"
"sed. It has nothing to do with building makefiles, but is provided mainly\n"
"so platforms that don't have sed built in can still portably run simple sed\n"
"scripts.\n\n"
"Options:\n\n"
" -h Display this page.\n"
@ -66,7 +73,11 @@ usage() {
" depend on (need) the named subdirectory. Options -d and\n"
" -n may be combined, and you may also name multiple\n"
" subdirectories to scan at once.\n\n"
" -p platform Build as if for the indicated platform name.\n\n";
" -p platform Build as if for the indicated platform name.\n"
" -c config.pp Read the indicated user-level config.pp file after reading\n"
" the system config.pp file. If this is omitted, the value\n"
" given in the environment variable PPREMAKE_CONFIG is used\n"
" instead.\n\n";
}
static void
@ -188,13 +199,17 @@ main(int argc, char *argv[]) {
string progname = argv[0];
extern char *optarg;
extern int optind;
const char *optstr = "hVPD:p:dn";
const char *optstr = "hVPD:dnp:c:s:";
bool any_d = false;
bool dependencies_stale = false;
string platform = PLATFORM;
bool report_depends = false;
bool report_needs = false;
string platform = PLATFORM;
string ppremake_config;
bool got_ppremake_config = false;
string sed_command;
bool got_sed_command = false;
int flag = getopt(argc, argv, optstr);
while (flag != EOF) {
@ -220,10 +235,6 @@ main(int argc, char *argv[]) {
any_d = true;
break;
case 'p':
platform = optarg;
break;
case 'd':
report_depends = true;
break;
@ -232,6 +243,20 @@ main(int argc, char *argv[]) {
report_needs = true;
break;
case 'p':
platform = optarg;
break;
case 'c':
ppremake_config = optarg;
got_ppremake_config = true;
break;
case 's':
sed_command = optarg;
got_sed_command = true;
break;
default:
exit(1);
}
@ -241,6 +266,15 @@ main(int argc, char *argv[]) {
argc -= (optind-1);
argv += (optind-1);
if (got_sed_command) {
SedProcess sp;
if (!sp.add_script_line(sed_command)) {
exit(1);
}
sp.run(cin, cout);
exit(0);
}
// If the user supplied one or more -d parameters, then we should
// not continue unless some of the dependencies were stale.
if (any_d) {
@ -257,6 +291,13 @@ main(int argc, char *argv[]) {
global_scope.define_variable("PACKAGE_FILENAME", PACKAGE_FILENAME);
global_scope.define_variable("SOURCE_FILENAME", SOURCE_FILENAME);
if (got_ppremake_config) {
// If this came in on the command line, define a variable as such.
// Otherwise, the system scripts can pull this value in from the
// similarly-named environment variable.
global_scope.define_variable("PPREMAKE_CONFIG", ppremake_config);
}
PPMain ppmain(&global_scope);
if (!ppmain.read_source(".")) {
exit(1);

152
ppremake/sedAddress.cxx Normal file
View File

@ -0,0 +1,152 @@
// Filename: sedAddress.cxx
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#include "sedAddress.h"
#include "sedContext.h"
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
////////////////////////////////////////////////////////////////////
// Function: SedAddress::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedAddress::
SedAddress() {
_address_type = AT_invalid;
}
////////////////////////////////////////////////////////////////////
// Function: SedAddress::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedAddress::
~SedAddress() {
if (_address_type == AT_re) {
regfree(&_re);
}
}
////////////////////////////////////////////////////////////////////
// Function: SedAddress::parse_address
// Access: Public
// Description: Scans the indicated string beginning at the indicated
// character position for an address specification,
// e.g. a number, $, or a regular expression. If a
// correct address is found, increments p to the first
// non-whitespace character past it and returns true;
// otherwise, returns false.
////////////////////////////////////////////////////////////////////
bool SedAddress::
parse_address(const string &line, size_t &p) {
assert(p < line.length());
if (line[p] == '$') {
p++;
_address_type = AT_last;
} else if (isdigit(line[p])) {
const char *str = line.c_str() + p;
char *end;
_number = strtol(str, &end, 10);
_address_type = AT_numeric;
p += (end - str);
} else {
// It must be a regular expression.
size_t p0 = p;
char delimiter = line[p];
p++;
if (p < line.length() && delimiter == '\\') {
// A backslash might escape the opening character.
delimiter = line[p];
p++;
}
size_t begin = p;
while (p < line.length() && line[p] != delimiter) {
if (line[p] == '\\') {
p++;
// A backslash could escape the closing character.
}
p++;
}
if (p >= line.length()) {
cerr << "Could not find terminating character '" << delimiter
<< "' in regular expression: " << line.substr(p0) << "\n";
return false;
}
string re = line.substr(begin, p - begin);
p++;
int error = regcomp(&_re, re.c_str(), REG_NOSUB);
if (error != 0) {
static const int errbuf_size = 512;
char errbuf[errbuf_size];
regerror(error, &_re, errbuf, errbuf_size);
cerr << "Invalid regular expression: " << re << "\n"
<< errbuf << "\n";
return false;
}
_address_type = AT_re;
}
// Skip whitespace following the address.
while (p < line.length() && isspace(line[p])) {
p++;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: SedAddress::matches
// Access: Public
// Description: Returns true if this address exactly matches the
// current pattern space.
////////////////////////////////////////////////////////////////////
bool SedAddress::
matches(const SedContext &context) const {
switch (_address_type) {
case AT_invalid:
cerr << "Internal error!\n";
assert(false);
return false;
case AT_numeric:
return (_number == context._line_number);
case AT_last:
return context._is_last_line;
case AT_re:
return (regexec(&_re, context._pattern_space.c_str(), 0, (regmatch_t *)NULL, 0) == 0);
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: SedAddress::precedes
// Access: Public
// Description: Returns true if this address exactly matches the
// current line or refers to a previous line. This
// never returns true if the address is a regular
// expression type.
////////////////////////////////////////////////////////////////////
bool SedAddress::
precedes(const SedContext &context) const {
if (_address_type == AT_numeric) {
return (_number <= context._line_number);
}
return false;
}

44
ppremake/sedAddress.h Normal file
View File

@ -0,0 +1,44 @@
// Filename: sedAddress.h
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#ifndef SEDADDRESS_H
#define SEDADDRESS_H
#include "ppremake.h"
#include <sys/types.h>
#include <regex.h>
class SedContext;
///////////////////////////////////////////////////////////////////
// Class : SedAddress
// Description : This represents a single address in a sed command,
// something like a line number or a regular expression.
////////////////////////////////////////////////////////////////////
class SedAddress {
public:
SedAddress();
~SedAddress();
bool parse_address(const string &line, size_t &p);
bool matches(const SedContext &context) const;
bool precedes(const SedContext &context) const;
private:
enum AddressType {
AT_invalid,
AT_numeric,
AT_last,
AT_re,
};
AddressType _address_type;
int _number;
regex_t _re;
};
#endif

341
ppremake/sedCommand.cxx Normal file
View File

@ -0,0 +1,341 @@
// Filename: sedCommand.cxx
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#include "sedCommand.h"
#include "sedAddress.h"
#include "sedContext.h"
#include "sedScript.h"
#include <regex.h>
////////////////////////////////////////////////////////////////////
// Function: SedCommand::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedCommand::
SedCommand() {
_addr1 = (SedAddress *)NULL;
_addr2 = (SedAddress *)NULL;
_command = '\0';
_flags = 0;
_active = false;
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedCommand::
~SedCommand() {
if (_addr1 != (SedAddress *)NULL) {
delete _addr1;
}
if (_addr2 != (SedAddress *)NULL) {
delete _addr2;
}
if ((_flags & F_have_re) != 0) {
regfree(&_re);
}
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::parse_command
// Access: Public
// Description: Scans the indicated string at the given character
// position for a legal command. If a legal command is
// found, stores it and increments p to the first
// non-whitespace character after the command, returning
// true. Otherwise, returns false.
////////////////////////////////////////////////////////////////////
bool SedCommand::
parse_command(const string &line, size_t &p) {
// First, skip initial whitespace.
while (p < line.length() && isspace(line[p])) {
p++;
}
// Now, check for an address.
if (p < line.length() &&
(isdigit(line[p]) || line[p] == '/' || line[p] == '\\')) {
_addr1 = new SedAddress;
if (!_addr1->parse_address(line, p)) {
return false;
}
if (p < line.length() && line[p] == ',') {
// Another address.
// Skip the comma and more whitespace.
p++;
while (p < line.length() && isspace(line[p])) {
p++;
}
_addr2 = new SedAddress;
if (!_addr2->parse_address(line, p)) {
return false;
}
}
}
if (p >= line.length()) {
// It's a null command, which is acceptable; ignore it.
return true;
}
_command = line[p];
// Skip more whitespace after the command letter.
p++;
while (p < line.length() && isspace(line[p])) {
p++;
}
// At the moment, we only accept a small subset of sed commands. We
// can add more later as we see the need.
switch (_command) {
case 'd':
// No arguments.
return true;
case 's':
// /regexp/repl/flags
return parse_s_params(line, p);
default:
cerr << "Unknown command: " << _command << "\n";
return false;
}
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::run
// Access: Public
// Description: Runs the script command, modifying the context and/or
// the script position as appropriate.
////////////////////////////////////////////////////////////////////
void SedCommand::
run(SedScript &script, SedContext &context) {
// First, see if this command matches the pattern space.
bool matches = false;
if (_addr1 != (SedAddress *)NULL && _addr2 != (SedAddress *)NULL) {
// If the user supplied two addresses, all lines inclusive between
// the lines matched by the two addresses are considered matching.
if (_active) {
// We have previously matched _addr1. Therefore this line is
// in, but are the rest of the lines following this one?
matches = true;
if (_addr2->matches(context)) {
// If this line matches addr2, that's the end of our range for
// next time.
_active = false;
}
} else {
// We have not yet matched _addr1. This line and subsequent
// lines are in only if we match now.
if (_addr1->matches(context)) {
matches = true;
if (!_addr2->precedes(context)) {
_active = true;
}
}
}
} else if (_addr1 != (SedAddress *)NULL) {
// If the user supplied only one address, only those lines that
// exactly match the address are considered matching.
matches = _addr1->matches(context);
} else {
// If the user supplied no addresses, all lines are considered
// matching.
matches = true;
}
if (matches) {
do_command(script, context);
}
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::parse_s_params
// Access: Private
// Description: Parses the /regexp/replacement/flags parameters that
// follow the 's' command.
////////////////////////////////////////////////////////////////////
bool SedCommand::
parse_s_params(const string &line, size_t &p) {
size_t p0 = p;
char delimiter = line[p];
p++;
if (p < line.length() && delimiter == '\\') {
// A backslash might escape the opening character.
delimiter = line[p];
p++;
}
size_t begin = p;
while (p < line.length() && line[p] != delimiter) {
if (line[p] == '\\') {
p++;
// A backslash could escape the closing character.
}
p++;
}
if (p >= line.length()) {
cerr << "Could not find terminating character '" << delimiter
<< "' in regular expression: " << line.substr(p0) << "\n";
return false;
}
string re = line.substr(begin, p - begin);
p++;
int error = regcomp(&_re, re.c_str(), 0);
if (error != 0) {
static const int errbuf_size = 512;
char errbuf[errbuf_size];
regerror(error, &_re, errbuf, errbuf_size);
cerr << "Invalid regular expression: " << re << "\n"
<< errbuf << "\n";
return false;
}
_flags |= F_have_re;
// Get the replacement string.
begin = p;
while (p < line.length() && line[p] != delimiter) {
if (line[p] == '\\') {
p++;
// A backslash could escape the closing character.
}
p++;
}
if (p >= line.length()) {
cerr << "Could not find terminating character '" << delimiter
<< "' in replacement string: " << line.substr(p0) << "\n";
return false;
}
_string2 = line.substr(begin, p - begin);
// Skip the final delimiter.
p++;
if (p < line.length() && line[p] == 'g') {
// Global flag.
p++;
_flags |= F_g;
}
// Skip any more whitespace after the parameters.
while (p < line.length() && isspace(line[p])) {
p++;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::do_command
// Access: Private
// Description: Actually invokes the command, once it has been
// determined that the command applied to the current
// pattern space.
////////////////////////////////////////////////////////////////////
void SedCommand::
do_command(SedScript &script, SedContext &context) {
switch (_command) {
case '\0':
// Null command.
return;
case 'd':
// Delete line.
context._deleted = true;
script._next_command = script._commands.end();
return;
case 's':
// Substitute.
do_s_command(context);
return;
}
cerr << "Undefined command: " << _command << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: SedCommand::do_s_command
// Access: Private
// Description: Invokes the s command, which performs a
// pattern/replacement substitution.
////////////////////////////////////////////////////////////////////
void SedCommand::
do_s_command(SedContext &context) {
size_t nmatch = _re.re_nsub + 1;
regmatch_t pmatch[nmatch];
string result;
const char *str = context._pattern_space.c_str();
int error = regexec(&_re, str, nmatch, pmatch, 0);
while (error == 0) {
// Here's a match. Determine the replacement.
string repl;
size_t p = 0;
while (p < _string2.length()) {
if (_string2[p] == '\\') {
p++;
if (p < _string2.length()) {
if (isdigit(_string2[p])) {
// Here's a subexpression reference.
const char *numstr = _string2.c_str() + p;
char *numend;
int ref = strtol(numstr, &numend, 10);
p += (numend - numstr);
if (ref <= 0 || ref >= (int)nmatch) {
cerr << "Invalid subexpression number: " << ref << "\n";
} else {
repl += string(str + pmatch[ref].rm_so,
pmatch[ref].rm_eo - pmatch[ref].rm_so);
}
} else {
// Here's an escaped character.
repl += _string2[p];
p++;
}
}
} else {
// Here's a normal character.
repl += _string2[p];
p++;
}
}
// Store the result so far.
result += string(str, pmatch[0].rm_so);
result += repl;
str += pmatch[0].rm_eo;
if ((_flags & F_g) == 0) {
// If we don't have the global flag set, stop after the first iteration.
result += str;
context._pattern_space = result;
return;
}
error = regexec(&_re, str, nmatch, pmatch, 0);
}
// All done.
result += str;
context._pattern_space = result;
}

57
ppremake/sedCommand.h Normal file
View File

@ -0,0 +1,57 @@
// Filename: sedCommand.h
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#ifndef SEDCOMMAND_H
#define SEDCOMMAND_H
#include "ppremake.h"
#include <sys/types.h>
#include <regex.h>
class SedScript;
class SedContext;
class SedAddress;
///////////////////////////////////////////////////////////////////
// Class : SedCommand
// Description : This represents a single command (of several
// possible, separated by semicolons) to a SedProgram.
////////////////////////////////////////////////////////////////////
class SedCommand {
public:
SedCommand();
~SedCommand();
bool parse_command(const string &line, size_t &p);
void run(SedScript &script, SedContext &context);
private:
bool parse_s_params(const string &line, size_t &p);
void do_command(SedScript &script, SedContext &context);
void do_s_command(SedContext &context);
SedAddress *_addr1;
SedAddress *_addr2;
char _command;
string _text;
regex_t _re;
string _string1;
string _string2;
enum Flags {
F_have_re = 0x001,
F_g = 0x002,
};
int _flags;
bool _active;
};
#endif

19
ppremake/sedContext.cxx Normal file
View File

@ -0,0 +1,19 @@
// Filename: sedContext.cxx
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#include "sedContext.h"
////////////////////////////////////////////////////////////////////
// Function: SedContext::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedContext::
SedContext(ostream &out) : _out(out) {
_line_number = 0;
_is_last_line = false;
_deleted = false;
}

31
ppremake/sedContext.h Normal file
View File

@ -0,0 +1,31 @@
// Filename: sedContext.h
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#ifndef SEDCONTEXT_H
#define SEDCONTEXT_H
#include "ppremake.h"
///////////////////////////////////////////////////////////////////
// Class : SedContext
// Description : This contains the current context of the sed process
// as it is running: the pattern space, the hold space,
// and the current line numbers, etc. It is updated as
// each line is read in and as each command is executed.
////////////////////////////////////////////////////////////////////
class SedContext {
public:
SedContext(ostream &out);
int _line_number;
bool _is_last_line;
string _pattern_space;
string _hold_space;
bool _deleted;
ostream &_out;
};
#endif

70
ppremake/sedProcess.cxx Normal file
View File

@ -0,0 +1,70 @@
// Filename: sedProcess.cxx
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#include "sedProcess.h"
#include "sedContext.h"
////////////////////////////////////////////////////////////////////
// Function: SedProcess::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedProcess::
SedProcess() {
}
////////////////////////////////////////////////////////////////////
// Function: SedProcess::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedProcess::
~SedProcess() {
}
////////////////////////////////////////////////////////////////////
// Function: SedProcess::add_script_line
// Access: Public
// Description: Appends the indicated line to the end of the script
// that will be executed for each line of the input
// stream. This may be called as many times as you
// like.
//
// The return value is true if the line was added
// successfully, or false if there was an error in the
// line (in which case, some commands on the line might
// have been added, and others not).
////////////////////////////////////////////////////////////////////
bool SedProcess::
add_script_line(const string &line) {
return _script.add_line(line);
}
////////////////////////////////////////////////////////////////////
// Function: SedProcess::run
// Access: Public
// Description: Reads the input stream and executes the script once
// for each line on the input stream. Output is written
// to the indicated output stream.
////////////////////////////////////////////////////////////////////
void SedProcess::
run(istream &in, ostream &out) {
SedContext context(out);
string line;
getline(in, line);
while (!in.fail() && !in.eof()) {
context._pattern_space = line;
context._line_number++;
getline(in, line);
if (in.eof()) {
context._is_last_line = true;
}
_script.run(context);
}
}

30
ppremake/sedProcess.h Normal file
View File

@ -0,0 +1,30 @@
// Filename: sedProcess.h
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#ifndef SEDPROCESS_H
#define SEDPROCESS_H
#include "ppremake.h"
#include "sedScript.h"
///////////////////////////////////////////////////////////////////
// Class : SedProcess
// Description : This supervises the whole sed process, from beginning
// to end.
////////////////////////////////////////////////////////////////////
class SedProcess {
public:
SedProcess();
~SedProcess();
bool add_script_line(const string &line);
void run(istream &in, ostream &out);
private:
SedScript _script;
};
#endif

97
ppremake/sedScript.cxx Normal file
View File

@ -0,0 +1,97 @@
// Filename: sedScript.cxx
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#include "sedScript.h"
#include "sedCommand.h"
#include "sedContext.h"
////////////////////////////////////////////////////////////////////
// Function: SedScript::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedScript::
SedScript() {
_quit = false;
}
////////////////////////////////////////////////////////////////////
// Function: SedScript::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
SedScript::
~SedScript() {
Commands::iterator ci;
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
delete (*ci);
}
}
////////////////////////////////////////////////////////////////////
// Function: SedScript::add_line
// Access: Public
// Description: Adds the indicated script line to the script.
// Returns true if it is a valid line, false if there is
// an error.
////////////////////////////////////////////////////////////////////
bool SedScript::
add_line(const string &line) {
size_t p = 0;
SedCommand *command = new SedCommand;
if (!command->parse_command(line, p)) {
// That's an invalid command.
delete command;
return false;
}
_commands.push_back(command);
while (p < line.length()) {
// There's more to the line.
if (line[p] != ';') {
// But it's an error.
cerr << "Invalid character at: " << line.substr(p) << "\n";
return false;
}
p++;
command = new SedCommand;
if (!command->parse_command(line, p)) {
// That's an invalid command.
delete command;
return false;
}
_commands.push_back(command);
}
// Everything parsed ok.
return true;
}
////////////////////////////////////////////////////////////////////
// Function: SedScript::run
// Access: Public
// Description: Runs the script, modifying the context as
// appropriate. Returns true if the process should
// continue with the next line, or false if we have quit
// and we should terminate.
////////////////////////////////////////////////////////////////////
bool SedScript::
run(SedContext &context) {
context._deleted = false;
_next_command = _commands.begin();
while (!_quit && _next_command != _commands.end()) {
SedCommand *command = (*_next_command);
++_next_command;
command->run(*this, context);
}
if (!context._deleted) {
context._out << context._pattern_space << "\n";
}
return !_quit;
}

39
ppremake/sedScript.h Normal file
View File

@ -0,0 +1,39 @@
// Filename: sedScript.h
// Created by: drose (24Oct00)
//
////////////////////////////////////////////////////////////////////
#ifndef SEDSCRIPT_H
#define SEDSCRIPT_H
#include "ppremake.h"
#include <vector>
class SedCommand;
class SedContext;
///////////////////////////////////////////////////////////////////
// Class : SedScript
// Description : This is a complete sed script: a linear list of
// commands that are to be applied for each line read
// from input.
////////////////////////////////////////////////////////////////////
class SedScript {
public:
SedScript();
~SedScript();
bool add_line(const string &line);
bool run(SedContext &context);
public:
bool _quit;
typedef vector<SedCommand *> Commands;
Commands _commands;
Commands::const_iterator _next_command;
};
#endif