mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-27 23:34:57 -04:00
*** empty log message ***
This commit is contained in:
parent
8c39825532
commit
28b9f21a54
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
152
ppremake/sedAddress.cxx
Normal 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
44
ppremake/sedAddress.h
Normal 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
341
ppremake/sedCommand.cxx
Normal 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
57
ppremake/sedCommand.h
Normal 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
19
ppremake/sedContext.cxx
Normal 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
31
ppremake/sedContext.h
Normal 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
70
ppremake/sedProcess.cxx
Normal 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
30
ppremake/sedProcess.h
Normal 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
97
ppremake/sedScript.cxx
Normal 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
39
ppremake/sedScript.h
Normal 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
|
Loading…
x
Reference in New Issue
Block a user