694 lines
20 KiB
C++
694 lines
20 KiB
C++
/*************************************************************************
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: guw.cc,v $
|
|
*
|
|
* $Revision: 1.5 $
|
|
*
|
|
* last change: $Author: rt $ $Date: 2007-11-05 08:16:22 $
|
|
*
|
|
* The Contents of this file are made available subject to
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
|
*
|
|
*
|
|
* GNU Lesser General Public License Version 2.1
|
|
* =============================================
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2.1, as published by the Free Software Foundation.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
* MA 02111-1307 USA
|
|
*
|
|
************************************************************************/
|
|
|
|
// guw - A wrapper program to execute windows programs with parameters that
|
|
// contain cygwin (POSIX) style pathnames.
|
|
|
|
// Todo: Add a -? switch to guw to issue a help page.
|
|
|
|
#include <string>
|
|
#include <list>
|
|
#include <vector>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
|
|
#include <cstddef>
|
|
#include <cerrno>
|
|
|
|
#include <sys/cygwin.h>
|
|
#include <windows.h>
|
|
#include <regex.h>
|
|
|
|
|
|
using std::string;
|
|
using std::list;
|
|
using std::vector;
|
|
using std::cout;
|
|
using std::cerr;
|
|
using std::endl;
|
|
using std::size_t;
|
|
|
|
void init_ignorepara(string command);
|
|
bool is_ignorepara(const string ¶);
|
|
int winFormat(string ¶);
|
|
void do_atcommand(string ¶);
|
|
void myCygpath(string &path, int shortname = 1 );
|
|
void replace_cyg_env( void );
|
|
void Fatal( const string text );
|
|
|
|
int match2s(const string argument, const char *pattern, string &sub1, string &sub2);
|
|
void rep_subn_cyg(string &argument);
|
|
void rep_subn( string &argument, const char *pattern, int subexp, const char repl);
|
|
void rep_char( string &argument, const char from, const char to);
|
|
|
|
bool debug = false;
|
|
bool debug_light = false;
|
|
|
|
// The commands are treated case insensitive, the parameters
|
|
// are case sensitive.
|
|
const string ignorepara[] = { "echo /TEST",
|
|
"cl -clr: -Z",
|
|
"climaker StarOffice/OpenOffice",
|
|
"csc -target:",
|
|
"g++ -DLOCAL_RULE_LANGS -DUPD -DMINOR"
|
|
" -DBUILD_ID -DSC_INFO_OSVERSION",
|
|
"gcc -DUDATA_SO_SUFFIX -DSTATIC_O"
|
|
" -DPACKAGE -DU_MAKE",
|
|
"lib /OUT: -out: -def: -machine:",
|
|
"link /BASE: /COMMENT: /DEBUG: /DLL /ENTRY:"
|
|
" /MACHINE: /MAP /NODEFAULTLIB /OPT: /RELEASE"
|
|
" /STACK: /SUBSYSTEM: -NODEFAULTLIB:"
|
|
" -def: delayload: -implib: -map: -out:",
|
|
"rc -D",
|
|
"regcomp -env: vnd.sun.star.expand:"
|
|
" vnd.openoffice.pymodule: file:",
|
|
"regmerge /UCR",
|
|
"rsc -DOOO_" };
|
|
|
|
vector<string> ignorepara_vec;
|
|
|
|
// environment variables that are "winformatted" when -env is given
|
|
const string transformvars[] = { "SOLAR_VERSION",
|
|
"SOLARVERSION",
|
|
"SOLARVER",
|
|
"SRC_ROOT",
|
|
"LOCALINI",
|
|
"GLOBALINI",
|
|
"SOLARENV",
|
|
"STAR_INSTPATH",
|
|
"STAR_SOLARPATH",
|
|
"STAR_PACKMISC",
|
|
"STAR_SOLARENVPATH",
|
|
"STAR_INITROOT",
|
|
"STAR_STANDLST",
|
|
"CLASSPATH",
|
|
"JAVA_HOME" };
|
|
|
|
|
|
int main(int argc, char **argv) {
|
|
|
|
// initialize arglist with arguments
|
|
list<string> arglist(argv, argv + argc);
|
|
|
|
// Drop the first (filename) argument
|
|
arglist.pop_front();
|
|
|
|
// iterarot over cmdline elements
|
|
list<string>::iterator ele = arglist.begin();
|
|
|
|
// Allowed switch values
|
|
bool conv_cyg_arg = false;
|
|
|
|
// Look for switches to guw
|
|
// Supported: -env
|
|
// -dbg
|
|
// -ldbg
|
|
while ( !arglist.empty()
|
|
&& ele!=arglist.end()
|
|
&& (ele->find("-", 0) == 0) ) {
|
|
if (ele->find("-env", 0) == 0) {
|
|
if ( conv_cyg_arg )
|
|
Fatal("-env used twice!");
|
|
|
|
conv_cyg_arg = true;
|
|
ele = arglist.erase(ele);
|
|
continue;
|
|
}
|
|
else if (ele->find("-dbg", 0) == 0) {
|
|
|
|
debug = true;
|
|
ele = arglist.erase(ele);
|
|
continue;
|
|
}
|
|
else if (ele->find("-ldbg", 0) == 0) {
|
|
|
|
debug_light = true;
|
|
ele = arglist.erase(ele);
|
|
continue;
|
|
}
|
|
else {
|
|
// Ignore this switch
|
|
++ele;
|
|
}
|
|
}
|
|
|
|
// The next entry must be the program
|
|
string command;
|
|
if ( !arglist.empty() ) {
|
|
command.assign(*arglist.begin());
|
|
arglist.pop_front();
|
|
}
|
|
else
|
|
Fatal("guw needs at least one parameter.");
|
|
|
|
if ( debug )
|
|
cerr << "Command: " << command << "\n" << endl;
|
|
// Initialize parameter exception list (for this command)
|
|
init_ignorepara(command);
|
|
|
|
|
|
// Do something if -env was found
|
|
if ( conv_cyg_arg )
|
|
replace_cyg_env();
|
|
|
|
|
|
// loop and and DOSify the parameters
|
|
if ( debug )
|
|
cerr << "Transform the parameter\n" << endl;
|
|
|
|
ele=arglist.begin();
|
|
while ( ele != arglist.end() ) {
|
|
|
|
if ((*ele)[0] == '@')
|
|
do_atcommand(*ele);
|
|
else if (!is_ignorepara(*ele)) {
|
|
if ( debug ) {
|
|
cerr << "----------------" << endl;
|
|
cerr << "Process parameter: " << *ele << endl;
|
|
}
|
|
winFormat(*ele);
|
|
if ( debug )
|
|
cerr << "Transformed to: " << *ele << "\n" << endl;
|
|
}
|
|
|
|
++ele;
|
|
}
|
|
|
|
// create the argv[] for execvp(argv[0], argv);
|
|
ele=arglist.begin();
|
|
|
|
// const char *nargv[arglist.size()+2]; // or ..
|
|
char *nargv[arglist.size()+2];
|
|
|
|
// nargv[0] = command.c_str(); // or ..
|
|
nargv[0] = new char[command.length()+1];
|
|
// strcpy(nargv[0], command.c_str());
|
|
command.copy(nargv[0], command.length());
|
|
nargv[0][command.length()] = 0;
|
|
|
|
if ( debug )
|
|
cerr << "----------------\n" << endl;
|
|
if ( debug || debug_light )
|
|
cerr << "Execute: " << nargv[0];
|
|
|
|
int count = 1, sLen;
|
|
while ( ele != arglist.end() ) {
|
|
// nargv[count] = ele->c_str(); // or ..
|
|
sLen = ele->length();
|
|
nargv[count] = new char[sLen+1];
|
|
// strcpy(nargv[count], ele->c_str());
|
|
ele->copy(nargv[count], sLen);
|
|
nargv[count][sLen] = 0;
|
|
|
|
if ( debug || debug_light )
|
|
cerr << " " << nargv[count];
|
|
|
|
++count;
|
|
++ele;
|
|
}
|
|
// last nargv[] must be NULL
|
|
nargv[count] = NULL;
|
|
if ( debug || debug_light )
|
|
cerr << endl;
|
|
|
|
// Unfortunately the prototype of execvp does not like const char*,
|
|
// actually not const char* nargv[] coming from .c_str(). So either
|
|
// we copy everything into newly allocated variables or we force it
|
|
// with a cast. const_cast<char * const *>()
|
|
// execvp(nargv[0], const_cast<char * const *>(nargv) );
|
|
if ( execvp(nargv[0], nargv ) < 0 ) {
|
|
perror("Execvp error. Aborting.");
|
|
exit(1);
|
|
}
|
|
|
|
// Omit the deleting of the dynamically allocated nargv[] elements
|
|
// here as this part will never be reached.
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Initialize exception list from global var ignorepara[]
|
|
void init_ignorepara(string fullcommand) {
|
|
const size_t kplen = sizeof(ignorepara)/sizeof(string *);
|
|
string shortcommand, cmd, para, sub2;
|
|
|
|
// First lowercase everything
|
|
for(size_t i=0;i<fullcommand.length();i++)
|
|
fullcommand[i] = tolower(fullcommand[i]);
|
|
|
|
// Remove a potential .exe
|
|
size_t slen = fullcommand.length();
|
|
|
|
// for slen == 3 this would yield string::npos otherwise
|
|
if ( slen > 4 && fullcommand.rfind(".exe") == slen - 4 )
|
|
fullcommand.erase(slen-4);
|
|
|
|
// get the program name - Only one subexpression
|
|
if (!match2s(fullcommand, "([[:alnum:]_~. +-]+)$",
|
|
shortcommand, sub2)) {
|
|
Fatal("No basename found in: " + fullcommand);
|
|
}
|
|
|
|
for (size_t i=0; i != kplen; ++i) {
|
|
std::istringstream line(ignorepara[i]);
|
|
line >> cmd;
|
|
if (shortcommand == cmd)
|
|
while (line >> para) {
|
|
ignorepara_vec.push_back(para);
|
|
}
|
|
}
|
|
return ;
|
|
}
|
|
|
|
// Check if command/parameter is in exception list.
|
|
bool is_ignorepara(const string ¶) {
|
|
|
|
for( vector<string>::iterator it = ignorepara_vec.begin();
|
|
it != ignorepara_vec.end(); it++ ) {
|
|
if ( para.find(*it) != string::npos ) {
|
|
if ( debug )
|
|
cerr << "Found execption para: " << para << endl;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// Reformat para to DOSish format
|
|
int winFormat(string ¶) {
|
|
string su1, su2;
|
|
|
|
// Instead of ([/[:alnum:]_~. +-]+) use ((/?[[:alnum:]_~. +-]+)+)
|
|
|
|
// find [-][-]X<something>=<path>, sometimes with quotes or "/" at the end
|
|
if (match2s(para, "^(-?-?[[:alpha:]][[:alnum:]_.-]*=)[\'\"]?((/?[[:alnum:]_~. +-]+)+)[\'\"]?$",
|
|
su1, su2)) {
|
|
|
|
myCygpath(su2);
|
|
para.assign(su1 + su2);
|
|
if ( debug )
|
|
cerr << " WinFormat - ([-][-]<something>=<path>)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
// find -X<something>:<path>, sometimes with quotes or "/" at the end
|
|
else if (match2s(para, "^(-[[:alpha:]][[:alnum:]_.]*:)[\'\"]?((/?[[:alnum:]_~. +-]+)+)[\'\"]?$",
|
|
su1, su2)) {
|
|
|
|
myCygpath(su2);
|
|
para.assign(su1 + su2);
|
|
if ( debug )
|
|
cerr << " WinFormat - (-<something>:<path>)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
// find -X<something>:<NO-path>, and prevents translating of these.
|
|
else if (match2s(para, "^(-[[:alpha:]][[:alnum:]_]*:)(.*)$",
|
|
su1, su2)) {
|
|
|
|
// myCygpath(su2);
|
|
// para.assign(su1 + su2);
|
|
if ( debug )
|
|
cerr << " WinFormat - (-<something>:<NO-path>)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
// See iz35982 for the reason for the special treatment of this switch.
|
|
// This regex evaluates <something>:///<path>, sometimes with
|
|
// quotes or "/" at the end
|
|
else if (match2s(para, "^([[:alpha:]][[:alnum:]_]*:)[\'\"]?///((/?[[:alnum:]_~. +-]+)+)[\'\"]?$",
|
|
su1, su2)) {
|
|
|
|
myCygpath(su2);
|
|
para.assign(su1 + "///" + su2);
|
|
// Replace \ to /
|
|
rep_char( para, '\\', '/');
|
|
|
|
if ( debug )
|
|
cerr << " WinFormat - (<something>:///<path>)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
// find -X<absolute path>, sometimes with quotes or "/" at the end
|
|
else if (match2s(para, "^(-[[:alpha:]])[\'\"]?((/[[:alnum:]_~. +-]+)+)[\'\"]?$",
|
|
su1, su2)) {
|
|
|
|
myCygpath(su2);
|
|
para.assign(su1 + su2);
|
|
if ( debug )
|
|
cerr << " WinFormat - (-X<absolute path>)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
// find -FX<path> (MSVC switches for output naming), sometimes with quotes
|
|
// or "/" at the end
|
|
else if (match2s(para, "^(-F[ARdemopr])[\'\"]?(/[/[:alnum:]_~. +-]+)[\'\"]?$",
|
|
su1, su2)) {
|
|
|
|
myCygpath(su2);
|
|
para.assign(su1 + su2);
|
|
if ( debug )
|
|
cerr << " WinFormat - (compiler naming (-FX<absolute path>) path)\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
else{
|
|
// No parameter found, assume a path
|
|
|
|
// replace the colon in drives with 0x1F"
|
|
// (Unused ascii US - unit separator)
|
|
rep_subn( para, "(^|[;,])[[:alpha:]](:)", 2, 0x1F);
|
|
|
|
// Replace remaining : to ;
|
|
rep_char( para, ':', ';');
|
|
|
|
// Replace back US to ':';
|
|
rep_char( para, 0x1F, ':');
|
|
|
|
/* Search for posix path ;entry; (The regex accepts valid paths with at
|
|
* least one /) and replace with DOS path, accept quotes.
|
|
* since iz28717 we also accept ',' as path seperator. */
|
|
rep_subn_cyg(para);
|
|
|
|
if ( debug )
|
|
cerr << " WinFormat - full path\n"
|
|
<< " " << para << endl;
|
|
|
|
}
|
|
|
|
// Sanity check for -X<abspath>
|
|
if (match2s(para, "^(-[[:alpha:]])[\'\"]?((/[[:alnum:]_~. +-]+)+)",
|
|
su1, su2)) {
|
|
Fatal("Not converted -X/... type switch in :" + para);
|
|
}
|
|
// Sanity check for [-]X<something>(:|=)<abspath> case
|
|
if (match2s(para, "^(-?[[:alpha:]][[:alnum:]_.]*[=:])[\'\"]?((/[[:alnum:]_~. +-]+)+)",
|
|
su1, su2)) {
|
|
Fatal("Not processed [-]X<something>(=|:)/... in :" + para);
|
|
}
|
|
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Reformat para to DOSish format
|
|
void do_atcommand(string ¶) {
|
|
string at, filename, token;
|
|
|
|
// Workaround, iz28717, keep number of @'s.
|
|
match2s(para, "^(@+)(.*)",at ,filename);
|
|
if ( debug ) {
|
|
cerr << "----------------" << endl;
|
|
cerr << "Process @-file" << endl;
|
|
cerr << " :" << at << ": before filename :" << filename << ":" << endl;
|
|
}
|
|
|
|
// Read at file into memory
|
|
std::ifstream atin(filename.c_str());
|
|
list<string> newtoken;
|
|
while (atin >> token) {
|
|
// Read / transform tokens
|
|
if ( debug )
|
|
cerr << "@ token :" << token << ":" << endl;
|
|
if (!is_ignorepara(token))
|
|
winFormat(token);
|
|
|
|
newtoken.push_back(token);
|
|
}
|
|
atin.close();
|
|
|
|
// Write token tokens bak to file
|
|
if ( debug || debug_light )
|
|
cerr << "New @-file parameter:" << endl;
|
|
|
|
// for debugging ..
|
|
// filename += ".bak";
|
|
|
|
std::ofstream atout(filename.c_str());
|
|
list<string>::iterator tok = newtoken.begin();
|
|
while ( tok != newtoken.end() ) {
|
|
if ( debug || debug_light )
|
|
cerr << ( tok != newtoken.begin() ? " " : "" ) << *tok ;
|
|
|
|
atout << ( tok != newtoken.begin() ? " " : "" ) << *tok ;
|
|
++tok;
|
|
}
|
|
// We want a dos file
|
|
atout << '\r' << endl;
|
|
atout.close();
|
|
|
|
// Transform the filename
|
|
winFormat(filename);
|
|
para = at + filename;
|
|
if ( debug || debug_light ) {
|
|
cerr << "\nNew @-file name: " << para << "\n" << endl;
|
|
}
|
|
}
|
|
|
|
void myCygpath(string &path, int shortname /* =1 */ )
|
|
{
|
|
static char convpath[MAX_PATH];
|
|
static char buf[MAX_PATH];
|
|
int err;
|
|
|
|
// Only use cygwin_conv_to_win32_path() on absolute paths as it errors
|
|
// out if its path doen't exist. Unfortunatelt there are a lot of not
|
|
// existing relative pathes used as parameters during an OOo build.
|
|
if( path.find("/", 0) == 0) {
|
|
err = cygwin_conv_to_win32_path( path.c_str(), convpath );
|
|
}
|
|
else {
|
|
rep_char( path, '/', '\\');
|
|
// see below, we copy convpath back to path, that's stupid
|
|
path.copy( convpath, path.length());
|
|
convpath[path.length()] = 0;
|
|
err = 0;
|
|
}
|
|
|
|
if (err)
|
|
Fatal("converting: " + path + " - " + strerror(errno) );
|
|
|
|
// Only convert to short dos names when space is present
|
|
if (shortname && (path.find(" ", 0) != string::npos) ) {
|
|
DWORD len = GetShortPathName (convpath, buf, MAX_PATH);
|
|
if (!len) {
|
|
Fatal("cannot create short name of " + string(convpath) );
|
|
}
|
|
|
|
path.assign(buf);
|
|
}
|
|
else
|
|
path.assign(convpath);
|
|
|
|
}
|
|
|
|
void replace_cyg_env( void ) {
|
|
// Transform certain environment variables
|
|
if ( debug )
|
|
cerr << "Transforming some environment variables" << endl;
|
|
|
|
const size_t nvars = sizeof(transformvars)/sizeof(string *);
|
|
|
|
char *currvar;
|
|
string newvar;
|
|
|
|
for (size_t i=0; i != nvars; ++i) {
|
|
if ( currvar = getenv(transformvars[i].c_str() ) ) {
|
|
// Only transform existent vars
|
|
if ( debug )
|
|
cerr << "Transform variable: " << transformvars[i] << "="
|
|
<< currvar << endl;
|
|
newvar.assign(currvar);
|
|
winFormat(newvar);
|
|
if( setenv(transformvars[i].c_str(), newvar.c_str(), 1) )
|
|
Fatal("setenv failed on " + transformvars[i] + "=" + newvar +
|
|
" with error: " + strerror(errno));
|
|
if ( debug )
|
|
cerr << "To: " << transformvars[i] << "="
|
|
<< newvar << "\n" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Fatal( const string text ) {
|
|
// End with error
|
|
cerr << "Error: " << text << endl;
|
|
exit(1);
|
|
}
|
|
|
|
|
|
int
|
|
match2s(const string argument, const char *pattern, string &sub1, string &sub2)
|
|
{
|
|
int status;
|
|
regex_t re;
|
|
|
|
const int maxsub = 3; // Only 3 needed, 4 is for debug
|
|
regmatch_t match[maxsub];
|
|
|
|
if (regcomp(&re, pattern, REG_EXTENDED) != 0) {
|
|
Fatal("regcomp had a problem."); /* report error */
|
|
}
|
|
status = regexec(&re, argument.c_str(), maxsub, match, 0);
|
|
regfree(&re);
|
|
|
|
if (status == REG_NOMATCH) {
|
|
return(0); /* no match */
|
|
} else if (status == 0) {
|
|
string tstr(argument.c_str() + match[0].rm_so,
|
|
match[0].rm_eo - match[0].rm_so);
|
|
// cout << "Match: " << tstr << endl;
|
|
|
|
sub1.assign(argument.c_str() + match[1].rm_so, match[1].rm_eo - match[1].rm_so);
|
|
// cout << "Match1: " << sub1 << endl;
|
|
|
|
sub2.assign(argument.c_str() + match[2].rm_so, match[2].rm_eo - match[2].rm_so);
|
|
// cout << "Match2: " << sub2 << endl;
|
|
|
|
return(1); /* match found */
|
|
} else {
|
|
Fatal("regexec had a problem.");
|
|
}
|
|
|
|
// Not reached.
|
|
return(1);
|
|
}
|
|
|
|
|
|
// Replace path entry with myCygpath() version
|
|
void rep_subn_cyg(string &argument)
|
|
{
|
|
// accept ["']<entry>["']:["']<entry>["']:... to make the
|
|
// $(WRAPCMD) echo 1 ICON $(EMQ)"$(APP1ICON)$(EMQ)"
|
|
// work in ?tg_app.mk.
|
|
// FIXME: Better would be to use a DOSified $(APP1ICON) there and remove
|
|
// the special " treatment here.
|
|
const char *pattern = "(^|[;,])[\'\"]?([[:alnum:]_~. +-]*(/[[:alnum:]_~. +-]+)+/?)[\'\"]?([;,]|$)";
|
|
const int subexp = 2;
|
|
|
|
int status, pos=0;
|
|
regex_t re;
|
|
|
|
string repstr;
|
|
string::size_type oLen, nLen;
|
|
|
|
const int maxsub = subexp+1; // One more than the maximal subexpression
|
|
regmatch_t match[maxsub];
|
|
|
|
if (regcomp(&re, pattern, REG_EXTENDED) != 0) {
|
|
Fatal("regcomp had a problem."); /* report error */
|
|
}
|
|
status = regexec (&re, argument.c_str() + pos, maxsub, match, 0);
|
|
while (status == 0) { /* While matches found. */
|
|
// Classical assert()
|
|
if (match[subexp].rm_eo == -1) {
|
|
Fatal("Nonexisting subexpression specified!");
|
|
}
|
|
|
|
oLen = match[subexp].rm_eo - match[subexp].rm_so;
|
|
repstr.assign(argument.c_str() + pos + match[subexp].rm_so, oLen);
|
|
|
|
// Do not replace with shortpaths
|
|
myCygpath(repstr, 0);
|
|
nLen = repstr.length();
|
|
|
|
// replace
|
|
argument.replace( pos + match[subexp].rm_so, oLen, repstr );
|
|
|
|
/* Substring found between match[0].rm_so and match[0].rm_eo. */
|
|
/* This call to regexec() finds the next match. */
|
|
|
|
pos += match[0].rm_eo + nLen - oLen ;
|
|
|
|
// Either the last match did end in ';' or we are at the end of para.
|
|
// REG_NOTBOL is not used because we skip over the ';' by using pos.
|
|
status = regexec (&re, argument.c_str() + pos, maxsub, match, 0);
|
|
}
|
|
|
|
if (status != REG_NOMATCH) {
|
|
Fatal("regexec had a problem.");
|
|
}
|
|
|
|
regfree(&re);
|
|
}
|
|
|
|
// Replace all occurences of subexpression number "subexp" with "repl"
|
|
void rep_subn( string &argument, const char *pattern, int subexp, const char repl)
|
|
{
|
|
int status, pos=0;
|
|
regex_t re;
|
|
|
|
const int maxsub = subexp+1; // One more than the maximal subexpression
|
|
regmatch_t match[maxsub];
|
|
|
|
if (regcomp(&re, pattern, REG_EXTENDED) != 0) {
|
|
Fatal("regcomp had a problem."); /* report error */
|
|
}
|
|
status = regexec (&re, argument.c_str() + pos, maxsub, match, 0);
|
|
while (status == 0) { /* While matches found. */
|
|
// Classical assert()
|
|
if (match[subexp].rm_eo == -1) {
|
|
Fatal("Nonexisting subexpression specified!");
|
|
}
|
|
|
|
argument[pos + match[subexp].rm_so] = repl;
|
|
|
|
/* Substring found between match[0].rm_so and match[0].rm_eo. */
|
|
/* This call to regexec() finds the next match. */
|
|
pos += match[0].rm_eo;
|
|
status = regexec (&re, argument.c_str() + pos, maxsub, match, REG_NOTBOL);
|
|
}
|
|
|
|
if (status != REG_NOMATCH) {
|
|
Fatal("regexec had a problem.");
|
|
}
|
|
|
|
regfree(&re);
|
|
}
|
|
|
|
// Replace all char1 with char2
|
|
void rep_char( string &argument, const char from, const char to)
|
|
{
|
|
string::size_type loc = 0;
|
|
|
|
while ( (loc = argument.find( from, loc )) != string::npos ) {
|
|
argument[loc] = to;
|
|
}
|
|
}
|