?? cl.cpp
字號:
/******************************************************************************
* cl.cpp: "Proxy CL" STL Error Filter Driver for VC++6/7
*
* Framework by Leor Zolman
* BD Software
* (leor@bdsoft.com)
*
* Win32 piping logic by Thomas Becker
*
* (C) Copyright Leor Zolman 2002. Permission to copy, use, modify, sell and
* distribute this software is granted provided this copyright notice appears
* in all copies. This software is provided "as is" without express or implied
* warranty, and with no claim as to its suitability for any purpose.
*/
#define CL_ID "BD Software Proxy CL v2.43a"
/* Release 2.43a - 1/15/2004
*
* Calls native CL (renamed to CL2.EXE) to perform compilation; for
* files with applicable extensions, filters output through a Perl
* script to simplify cryptic STL messages
*
* Options: /silent Disables STL filtering status message and auto-
* or -silent matically adds /nologo option to NATIVE_CL command line
*
* /nf "No Filtering" - behaves as if filtering were disabled
* /iter:x Sets iterator policy to x (S, M or L)
* /alloc:x Sets allocator policy to x (S or L) [for .NET only]
* /func:x Sets "common functor" policy to x (S or L) [for .NET only]
* /with:x Set "with" clause policy
* /width:xx Sets column to wrap output lines. 0=no wrap (the default).
* /break:x Line break algorithm (D or P)
* /cbreak:x Comma break policy (B or A)
* /closewrap:x Wrap before unmatched close delims (Y or N)
* /meta:x Choose metaprogramming pre-config (Y or N)
* /lognative Create debugging log file NativeLog.txt in current dir
*
* If the file designated by the CONFIG_FILE symbol (PROXY-CL.INI as
* distributed) is present in the Windows directory upon startup, CL reads
* configuration information from the file to override like-named defaults
* as #defined later in this source file. The allowed configuration options,
* in their respective sections (with default settings shown) are:
*
* [common]
* FILTER_SCRIPT=c:\STLFilt.pl
* TOGGLE_FILE_DIR=c:\
* NATIVE_CL=cl2
* PERL_EXE=c:\perl\bin\perl
*
* [proxy.cl]
* SILENT=false
* DEBUG=false
* DEBUG_DIR=c:\
* OUTPUT_WIDTH=0
* ITERATOR_POLICY=M
* ALLOCATOR_POLICY=S
* FUNCTOR_POLICY=S
* WITH_POLICY=S
* LOG_NATIVE_MSGS=N
* BREAK=P
* CBREAK=B
* CLOSEWRAP=Y
*
* For more details on the Proxy-CL.INI options, see the sample Proxy-CL.INI file.
* For general information, see README.txt.
* The Quick Start guide is QUICKSTART.txt.
*
* Error filtering is toggled by the presence (or absence) of
* the file FILTERING.ON in the TOGGLE_FILE_DIR directory.
* Toggling the existence of this file is managed either by the STLFilt.BAT
* batch file or the STLTask.EXE taskbar icon app.
*
* Compile: cl /Ox /GX cl.cpp setargv.obj
*
* Note: Be careful not to compile this cl.cpp file using any version
* of CL.EXE resident in the current directory, or the linker won't
* be able to overwrite it to create the new CL.EXE...
*****************************************************************************/
#include <iostream>
#include <fstream>
#include <string>
#include <process.h> // for _spawnvp()
#include <windows.h> // needed to create processes
#include <sys/stat.h>
////////////////////////////////////////////////////////////////////////////////////////////
//
// User-configurable settings: The next four #defines specify default settings for each
// of the given options. They may be overriden by settings in the configuation file.
//
// Note: Regardless of whether or not any of the pathnames defined below contain embedded
// spaces, NEVER use "extra" quotes (as required in older versions of CL.CPP)
//
// Remember to use double-backslashes (\\) for directory delimiters in pathnames!
//
#define PERL_EXE "c:\\perl\\bin\\perl" // Your Perl interpreter
#define FILTER_SCRIPT "c:\\STLFilt.pl" // Perl script pathname
#define TOGGLE_FILE_DIR "c:\\" // filtering toggle file directory
// (see companion variable FILT_BASE
// in STLFILT.BAT)
#define FILT_FILE "filtering.on" // Toggle file in "enabled" state
#define NATIVE_CL "cl2" // name of standard CL.EXE, must
#define CONFIG_FILE "PROXY-CL.INI" // if full path not specified, default
// is Windows directory
#define SILENT false // true to surpress sign-on message (when
// filtering C++ source files)
#define DEBUG false // if true, logging enabled by default
#define DEBUG_CAPABLE 1 // 1 to compile with debugging features
#define DEBUG_DIR "C:\\" // default directory to log debug info to
#define DEBUG_LOGFILE "cl-dblog.txt" // main debugging log file
#define DEBUG_ATFILE "atfile.txt" // project @file copied to this file
#define LOG_NATIVE_MSGS false // if true, log native message by default
#define OUTPUT_WIDTH "0" // default column to wrap output at (0: no wrap)
#define ITERATOR_POLICY "M" // default iterator policy
#define ALLOCATOR_POLICY "S" // default allocator policy (.NET only)
#define FUNCTOR_POLICY "S" // default functor policy (.NET only)
#define WITH_POLICY "S"
#define BREAK "P" // default break algorithm
#define CBREAK "A" // default comma break policy
#define CLOSEWRAP "N" // default closewrap policy
const std::string filterExt[] = // Filter only output from compiling
{ // files with these extensions
".cpp",
".cxx",
".cc"
};
const std::string objExt[] = // If we see these extensions on any
{ // CL arguments at the end of the line,
".lib", // keep searching for some other
".obj", // extension to qualify for filtering...
".o"
};
const std::string exeExt[] = // for checking for .EXE extensions
{ // in configuration pathnames
".exe"
};
// END User-configurable settings
////////////////////////////////////////////////////////////////////////////////////////////
const size_t nfilter = sizeof(filterExt) / sizeof(std::string);
const size_t nobj = sizeof(objExt) / sizeof(std::string);
BOOL WriteEofToPipe(HANDLE hPipe);
bool hasExt(const std::string &filename, const std::string extensions[], int);
int doWin32Stuff(char *full_filt_cmd, char *cmdline);
void chompSpace(std::string &pathname); // remove trailing whitespace, if any
void chompSlash(std::string &pathname); // remove trailing slash, if any
void stripComment(std::string &txt); // remove trailing comment, if any
void stripQuotes(std::string &txt, const std::string &unprocessed_line); // strip quotation marks
void massage_pathname(std::string &txt); // give path/file names the full treatment:
#if DEBUG_CAPABLE
void logit(const std::string &msg);
std::string toString(int n);
#define log(s) logit(s)
#else
#define log(s)
#endif
std::string native_cl;
std::string debug_dir;
std::string debug_log;
std::string configFile = CONFIG_FILE;
bool debug;
int main(int argc, char *argv[])
{
using namespace std;
const int MAXLINE = 200; // max length of config file line
char linebuf[MAXLINE] = "";
FILE *fp;
bool filtering = false; // not filtering by default
bool silent = false; // not silent by default
bool log_native_msgs;
string full_filt_cmd;
string filename; // file to compile
string perl_exe;
string filter_script;
string toggle_file;
string toggle_file_dir;
int output_width;
string iterator_policy;
string allocator_policy;
string functor_policy;
string with_policy;
string break_algorithm;
string cbreak;
string closewrap;
bool use_meta = false;
string meta;
int i;
if (argc == 1)
{
cerr << CL_ID << endl;
cerr << "usage: cl [ /lognative /silent /nf /iter:x /alloc:x /func:x /width:nn \n"
" /break:x /cbreak:x /closewrap;x /meta[:x] ] [MSVC opts] file(s)" << endl;
exit(1);
}
GetPrivateProfileString( "proxy.cl", "debug_dir", DEBUG_DIR,
linebuf, sizeof(linebuf), configFile.c_str() );
debug_dir = linebuf;
massage_pathname(debug_dir);
GetPrivateProfileString( "proxy.cl", "debug", DEBUG ? "true" : "false",
linebuf, sizeof(linebuf), configFile.c_str() );
char c;
debug = (c = tolower(linebuf[0])) == 't' || c == 'y' || c == '1';
if (debug)
#if DEBUG_CAPABLE
{
debug_log = debug_dir + "\\" + DEBUG_LOGFILE;
log("-------------------------------------------------------------------");
log(string("debug = ") + (debug ? "true" : "false"));
log("debug_log = " + debug_log);
}
#else
cerr << "Proxy CL: WARNING: debug option specified, but Proxy CL not debug capable!" << endl;
#endif
log("configFile is: " + configFile);
GetPrivateProfileString( "proxy.cl", "log_native_msgs",
LOG_NATIVE_MSGS ? "true" : "false",
linebuf, sizeof(linebuf), configFile.c_str() );
log_native_msgs = (c = tolower(linebuf[0])) == 't' || c == 'y' || c == '1';
log(string("log_native_msgs = ") + (log_native_msgs ? "true" : "false"));
GetPrivateProfileString( "common", "perl_exe", PERL_EXE,
linebuf, sizeof(linebuf), configFile.c_str() );
perl_exe = linebuf;
massage_pathname(perl_exe);
if (!hasExt(perl_exe, exeExt, 1)) // make sure we have an .EXE extension
perl_exe += ".exe";
log("perl_exe = '" + perl_exe + "'");
GetPrivateProfileString( "common", "filter_script", FILTER_SCRIPT,
linebuf, sizeof(linebuf), configFile.c_str() );
filter_script = linebuf;
massage_pathname(filter_script);
log("filter_script = '" + filter_script + "'");
GetPrivateProfileString( "common", "toggle_file_dir", TOGGLE_FILE_DIR,
linebuf, sizeof(linebuf), configFile.c_str() );
toggle_file_dir = linebuf;
massage_pathname(toggle_file_dir);
log("toggle_file_dir = '" + toggle_file_dir + "'");
GetPrivateProfileString( "common", "native_cl", NATIVE_CL,
linebuf, sizeof(linebuf), configFile.c_str() );
native_cl = linebuf;
massage_pathname(native_cl);
log("native_cl = '" + native_cl + "'");
GetPrivateProfileString( "proxy.cl", "iterator_policy", ITERATOR_POLICY,
linebuf, sizeof(linebuf), configFile.c_str() );
iterator_policy = linebuf;
stripComment(iterator_policy);
log("iterator_policy = " + iterator_policy);
GetPrivateProfileString( "proxy.cl", "allocator_policy", ALLOCATOR_POLICY,
linebuf, sizeof(linebuf), configFile.c_str() );
allocator_policy = linebuf;
stripComment(allocator_policy);
log("allocator_policy = " + allocator_policy);
GetPrivateProfileString( "proxy.cl", "functor_policy", FUNCTOR_POLICY,
linebuf, sizeof(linebuf), configFile.c_str() );
functor_policy = linebuf;
stripComment(functor_policy);
log("functor_policy = " + functor_policy);
GetPrivateProfileString( "proxy.cl", "with_policy", WITH_POLICY,
linebuf, sizeof(linebuf), configFile.c_str() );
with_policy = linebuf;
stripComment(with_policy);
log("with_policy = " + with_policy);
GetPrivateProfileString( "proxy.cl", "break", BREAK,
linebuf, sizeof(linebuf), configFile.c_str() );
break_algorithm = linebuf;
stripComment(break_algorithm);
log("break algorithm = " + break_algorithm);
GetPrivateProfileString( "proxy.cl", "cbreak", CBREAK,
linebuf, sizeof(linebuf), configFile.c_str() );
cbreak = linebuf;
stripComment(cbreak);
log("cbreak policy = " + cbreak);
GetPrivateProfileString( "proxy.cl", "closewrap", CLOSEWRAP,
linebuf, sizeof(linebuf), configFile.c_str() );
closewrap = linebuf;
stripComment(functor_policy);
log("functor_policy = " + functor_policy);
GetPrivateProfileString( "proxy.cl", "silent", SILENT ? "true" : "false",
linebuf, sizeof(linebuf), configFile.c_str() );
silent = (c = tolower(linebuf[0])) == 't' || c == 'y' || c == '1';
log(string("silent = ") + (silent ? "true" : "false"));
GetPrivateProfileString( "proxy.cl", "output_width", OUTPUT_WIDTH,
linebuf, sizeof(linebuf), configFile.c_str() );
output_width = atoi(linebuf);
log("output_width = " + output_width);
full_filt_cmd = "\"" + perl_exe + "\" \"" + filter_script + "\"";
log("full_filt_cmd = '" + full_filt_cmd + "'");
toggle_file = toggle_file_dir + "\\" + FILT_FILE;
log("toggle_file = '" + toggle_file + "'");
#if DEBUG_CAPABLE
for (i = 1; i < argc; i++)
log("Arg #" + toString(i) + " is '" + argv[i] + "'");
#endif
log("-----------");
if (argv[1][0] == '@') // indirect command line?
{
log(string("Indirect command line detected:") + argv[1] + "\nContents:");
#if DEBUG_CAPABLE // replicate the @file produced by VC, since it is deleted immediately:
if (debug)
system((string("copy ") + &argv[1][1] + " " + debug_dir +
"\\" + DEBUG_ATFILE).c_str());
#endif
ifstream fin(&argv[1][1]);
if (!fin)
{
string msg = string("Proxy CL: Bad @ filename? First Command line arg:") +
argv[1];
log(msg);
cerr << msg << endl;
exit(1);
}
string linebuf, lastline;
while (getline(fin, linebuf))
{
lastline = linebuf;
log(linebuf);
}
fin.close();
log("The complete final line from the indirect file:\n" + lastline);
bool seenquote = false;
for (i = lastline.length() - 1; i >= 0; i--)
if (lastline[i] == '"')
if (!seenquote)
{
seenquote = true;
lastline.resize(i);
}
else
break;
else if (lastline[i] == ' ' && !seenquote)
break;
filename = lastline.substr(i + 1);
log("filename detected indirectly: '" + filename + "'");
}
else
for (i = argc - 1; i > 0; i--)
{
if (hasExt(argv[i], objExt, nobj )) // ignore libraries, obj files
continue;
if (strchr(argv[i], '.') == NULL) // ignore options (no extensions)
continue;
filename = argv[i]; // first non-lib/obj/option is the filename
break;
}
if (filename.length() == 0 || !hasExt(filename, filterExt, nfilter )) // if extension of filename is not in the
silent = true; // approved list, never filter it
else
{
log("about to open toggle_file '"+toggle_file+"'");
if((fp = fopen(toggle_file.c_str(), "r")) != NULL)
{ // otherwise, filter iff
filtering = true; // toggle_file exists
fclose(fp);
}
}
string args = " "; // replicate CL command line args
char **new_argv = new char *[argc + 1]; // also create a new "argv" with each arg in
size_t new_argc = 0; // quotes in case we're not filtering and
// have to use _spawnvp()
for (i = 0; i < argc; i++)
{
if (!stricmp(argv[i],"/silent") || !stricmp(argv[i],"-silent"))
{
string nologo = "/nologo";
silent = true;
args += nologo;
new_argv[new_argc] = new char[nologo.length()];
strcpy(new_argv[new_argc++], nologo.c_str());
}
else if (!stricmp(argv[i],"/nf") || !stricmp(argv[i],"-nf"))
{
filtering = false;
silent = true;
}
else if (!strnicmp(argv[i], "/iter:", 6) || !strnicmp(argv[i], "-iter:", 6))
{
iterator_policy = &argv[i][6];
}
else if (!strnicmp(argv[i], "/alloc:", 7) || !strnicmp(argv[i], "-alloc:", 7))
{
allocator_policy = &argv[i][7];
}
else if (!strnicmp(argv[i], "/func:", 6) || !strnicmp(argv[i], "-func:", 6))
{
functor_policy = &argv[i][6];
}
else if (!strnicmp(argv[i], "/with:", 5) || !strnicmp(argv[i], "-with:", 5))
{
with_policy = &argv[i][6];
}
else if (!strnicmp(argv[i], "/break:", 7) || !strnicmp(argv[i], "-break:", 7))
{
break_algorithm = &argv[i][7];
}
else if (!strnicmp(argv[i], "/cbreak:", 8) || !strnicmp(argv[i], "-cbreak:", 8))
{
cbreak = &argv[i][8];
}
else if (!strnicmp(argv[i], "/closewrap:", 11) || !strnicmp(argv[i], "-closewrap:", 11))
{
closewrap = &argv[i][11];
}
else if (!strnicmp(argv[i], "/meta:", 6) || !strnicmp(argv[i], "-meta:", 6))
{
meta = &argv[i][6];
use_meta = true;
}
else if (!strnicmp(argv[i], "/meta", 5) || !strnicmp(argv[i], "-meta", 5))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -