From 815f157c05ebc20e91a050823f048a977b8ae103 Mon Sep 17 00:00:00 2001 From: Vladimir Glazounov Date: Wed, 21 Jan 2009 17:47:03 +0000 Subject: CWS-TOOLING: integrate CWS configuretoplevel 2009-01-19 15:47:39 +0100 rene r266508 : CWS-TOOLING: rebase CWS configuretoplevel to trunk@266428 (milestone: DEV300:m39) 2009-01-18 00:35:31 +0100 rene r266462 : #i10000# Mac OS X "of course" has other paths... 2009-01-16 13:24:23 +0100 rene r266415 : make OS2 use STLport... 2009-01-15 22:08:38 +0100 rene r266393 : STLport for FreeBSD 2009-01-15 01:23:51 +0100 rene r266333 : #i98048# harmonize STL default; default to *NOT* use STLport 2009-01-09 22:44:43 +0100 rene r266120 : #i97428# try to find out XLIB via pkg-config 2009-01-09 22:41:18 +0100 rene r266119 : #i97827# fail when we don't find make 2008-12-27 01:19:34 +0100 rene r265812 : add make (dis)clean; force /bin/sh as we source *Enc.Set.sh 2008-12-27 01:16:31 +0100 rene r265811 : fix makefile.rc for config.*/config_office move 2008-12-26 22:37:54 +0100 rene r265810 : #i91641# in some cases, we also need the -Xbootclasspath at the second javac call 2008-12-26 17:55:11 +0100 rene r265806 : actually commit Makefile.in 2008-12-25 19:24:24 +0100 rene r265803 : CWS-TOOLING: rebase CWS configuretoplevel to trunk@265758 (milestone: DEV300:m38) 2008-12-10 22:51:06 +0100 rene r265232 : #i96912# revert, cws swffixes02 has the right fix 2008-12-08 18:47:10 +0100 rene r265014 : xulrunner has no /plugin or /nspr 2008-12-08 17:51:28 +0100 rene r265013 : i96912# fix --with-system-mozilla 2008-12-05 13:05:55 +0100 rene r264903 : #i95339# 2008-12-04 17:53:53 +0100 rene r264865 : fix merge error #i80238# add help for --with-epm 2008-12-04 17:44:28 +0100 rene r264864 : #i91641# fix build with JDKs already including a version of rhino which conflicts with our ancient one 2008-12-04 17:40:48 +0100 rene r264863 : i93429# check for sanity for expand.exe 2008-12-04 17:34:20 +0100 rene r264862 : config_office changes from m33 to m37 2008-12-04 17:28:55 +0100 rene r264861 : CWS-TOOLING: rebase CWS configuretoplevel to trunk@264807 (milestone: DEV300:m37) 2008-12-04 16:49:03 +0100 rene r264856 : fix cws. part 5 2008-12-04 16:45:06 +0100 rene r264855 : fix cws, part 4 2008-12-04 16:01:49 +0100 rene r264850 : fix cws, part 3 2008-12-04 15:14:12 +0100 rene r264848 : fix cws, part 2 --- guw/guw.cc | 2067 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ guw/makefile | 12 + 2 files changed, 2079 insertions(+) create mode 100644 guw/guw.cc create mode 100644 guw/makefile (limited to 'guw') diff --git a/guw/guw.cc b/guw/guw.cc new file mode 100644 index 000000000000..808dc9e52e21 --- /dev/null +++ b/guw/guw.cc @@ -0,0 +1,2067 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: guw.cc,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// 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 +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +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 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 arglist(argv, argv + argc); + + // Drop the first (filename) argument + arglist.pop_front(); + + // iterarot over cmdline elements + list::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() + // execvp(nargv[0], const_cast(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 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::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=, 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 - ([-][-]=)\n" + << " " << para << endl; + + } + // find -X:, 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 - (-:)\n" + << " " << para << endl; + + } + // find -X:, and prevents translating of these. + else if (match2s(para, "^(-[[:alpha:]][[:alnum:]_]*:)(.*)$", + su1, su2)) { + + // myCygpath(su2); + // para.assign(su1 + su2); + if ( debug ) + cerr << " WinFormat - (-:)\n" + << " " << para << endl; + + } + // See iz35982 for the reason for the special treatment of this switch. + // This regex evaluates :///, 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 - (:///)\n" + << " " << para << endl; + + } + // find -X, 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)\n" + << " " << para << endl; + + } + // find -FX (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) 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 + if (match2s(para, "^(-[[:alpha:]])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not converted -X/... type switch in :" + para); + } + // Sanity check for [-]X(:|=) case + if (match2s(para, "^(-?[[:alpha:]][[:alnum:]_.]+[=:])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not processed [-]X(=|:)/... 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 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::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 ["']["']:["']["']:... 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; + } +} +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: guw.cc,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// 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 +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +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 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 arglist(argv, argv + argc); + + // Drop the first (filename) argument + arglist.pop_front(); + + // iterarot over cmdline elements + list::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() + // execvp(nargv[0], const_cast(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 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::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=, 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 - ([-][-]=)\n" + << " " << para << endl; + + } + // find -X:, 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 - (-:)\n" + << " " << para << endl; + + } + // find -X:, and prevents translating of these. + else if (match2s(para, "^(-[[:alpha:]][[:alnum:]_]*:)(.*)$", + su1, su2)) { + + // myCygpath(su2); + // para.assign(su1 + su2); + if ( debug ) + cerr << " WinFormat - (-:)\n" + << " " << para << endl; + + } + // See iz35982 for the reason for the special treatment of this switch. + // This regex evaluates :///, 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 - (:///)\n" + << " " << para << endl; + + } + // find -X, 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)\n" + << " " << para << endl; + + } + // find -FX (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) 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 + if (match2s(para, "^(-[[:alpha:]])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not converted -X/... type switch in :" + para); + } + // Sanity check for [-]X(:|=) case + if (match2s(para, "^(-?[[:alpha:]][[:alnum:]_.]+[=:])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not processed [-]X(=|:)/... 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 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::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 ["']["']:["']["']:... 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; + } +} +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: guw.cc,v $ + * $Revision: 1.7 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org 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 version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// 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 +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + + +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 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 arglist(argv, argv + argc); + + // Drop the first (filename) argument + arglist.pop_front(); + + // iterarot over cmdline elements + list::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() + // execvp(nargv[0], const_cast(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 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::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=, 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 - ([-][-]=)\n" + << " " << para << endl; + + } + // find -X:, 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 - (-:)\n" + << " " << para << endl; + + } + // find -X:, and prevents translating of these. + else if (match2s(para, "^(-[[:alpha:]][[:alnum:]_]*:)(.*)$", + su1, su2)) { + + // myCygpath(su2); + // para.assign(su1 + su2); + if ( debug ) + cerr << " WinFormat - (-:)\n" + << " " << para << endl; + + } + // See iz35982 for the reason for the special treatment of this switch. + // This regex evaluates :///, 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 - (:///)\n" + << " " << para << endl; + + } + // find -X, 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)\n" + << " " << para << endl; + + } + // find -FX (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) 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 + if (match2s(para, "^(-[[:alpha:]])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not converted -X/... type switch in :" + para); + } + // Sanity check for [-]X(:|=) case + if (match2s(para, "^(-?[[:alpha:]][[:alnum:]_.]+[=:])[\'\"]?((/[[:alnum:]_~. +-]+)+)", + su1, su2)) { + Fatal("Not processed [-]X(=|:)/... 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 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::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 ["']["']:["']["']:... 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; + } +} diff --git a/guw/makefile b/guw/makefile new file mode 100644 index 000000000000..c8f24e6ddbb2 --- /dev/null +++ b/guw/makefile @@ -0,0 +1,12 @@ +sources = guw.cc + +guw : $(sources) + g++ -Wall -o guw $(sources) +sources = guw.cc + +guw : $(sources) + g++ -Wall -o guw $(sources) +sources = guw.cc + +guw : $(sources) + g++ -Wall -o guw $(sources) -- cgit