aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2012-03-09 14:39:41 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2012-03-09 14:39:41 +0200
commit1ec2ca23bbc6d81ccc4cf2384228f8034188687d (patch)
tree9fd5456906ec801bc73e9039c0f8e08b448e0bdb
parente89a00af0b935183af40479f634db0a098c34e4a (diff)
Add support for --show-sloc and --sloc-limit options
-rw-r--r--odb/generator.cxx57
-rw-r--r--odb/odb.cxx180
-rw-r--r--odb/options.cli13
3 files changed, 216 insertions, 34 deletions
diff --git a/odb/generator.cxx b/odb/generator.cxx
index 2ab272d..c63b52f 100644
--- a/odb/generator.cxx
+++ b/odb/generator.cxx
@@ -12,6 +12,7 @@
#include <cutl/compiler/code-stream.hxx>
#include <cutl/compiler/cxx-indenter.hxx>
+#include <cutl/compiler/sloc-counter.hxx>
#include <odb/version.hxx>
#include <odb/context.hxx>
@@ -231,7 +232,10 @@ generate (options const& ops, semantics::unit& unit, path const& p)
if (sep_schema)
sch << file_header;
- typedef compiler::ostream_filter<compiler::cxx_indenter, char> cxx_filter;
+ typedef compiler::ostream_filter<compiler::cxx_indenter, char> ind_filter;
+ typedef compiler::ostream_filter<compiler::sloc_counter, char> sloc_filter;
+
+ size_t sloc_total (0);
// Include settings.
//
@@ -242,7 +246,9 @@ generate (options const& ops, semantics::unit& unit, path const& p)
// HXX
//
{
- cxx_filter filt (hxx);
+ sloc_filter sloc (hxx);
+ ind_filter ind (hxx);
+
auto_ptr<context> ctx (create_context (hxx, unit, ops, model.get ()));
string guard (make_guard (gp + hxx_name, *ctx));
@@ -307,12 +313,21 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< endl;
hxx << "#endif // " << guard << endl;
+
+ ind.stream ().unbuffer (); // Flush buffers to get correct SLOC.
+
+ if (ops.show_sloc ())
+ cerr << hxx_name << ": " << sloc.stream ().count () << endl;
+
+ sloc_total += sloc.stream ().count ();
}
// IXX
//
{
- cxx_filter filt (ixx);
+ sloc_filter sloc (ixx);
+ ind_filter ind (ixx);
+
auto_ptr<context> ctx (create_context (ixx, unit, ops, model.get ()));
// Copy prologue.
@@ -346,12 +361,21 @@ generate (options const& ops, semantics::unit& unit, path const& p)
append (ixx, ops.ixx_epilogue (), ops.ixx_epilogue_file ());
ixx << "//" << endl
<< "// End epilogue." << endl;
+
+ ind.stream ().unbuffer (); // Flush buffers to get correct SLOC.
+
+ if (ops.show_sloc ())
+ cerr << ixx_name << ": " << sloc.stream ().count () << endl;
+
+ sloc_total += sloc.stream ().count ();
}
// CXX
//
{
- cxx_filter filt (cxx);
+ sloc_filter sloc (cxx);
+ ind_filter ind (cxx);
+
auto_ptr<context> ctx (create_context (cxx, unit, ops, model.get ()));
cxx << "#include <odb/pre.hxx>" << endl
@@ -392,13 +416,22 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< endl;
cxx << "#include <odb/post.hxx>" << endl;
+
+ ind.stream ().unbuffer (); // Flush buffers to get correct SLOC.
+
+ if (ops.show_sloc ())
+ cerr << cxx_name << ": " << sloc.stream ().count () << endl;
+
+ sloc_total += sloc.stream ().count ();
}
// SCH
//
if (sep_schema)
{
- cxx_filter filt (sch);
+ sloc_filter sloc (sch);
+ ind_filter ind (sch);
+
auto_ptr<context> ctx (create_context (sch, unit, ops, model.get ()));
// Copy prologue.
@@ -441,6 +474,13 @@ generate (options const& ops, semantics::unit& unit, path const& p)
<< endl;
sch << "#include <odb/post.hxx>" << endl;
+
+ ind.stream ().unbuffer (); // Flush buffers to get correct SLOC.
+
+ if (ops.show_sloc ())
+ cerr << sch_name << ": " << sloc.stream ().count () << endl;
+
+ sloc_total += sloc.stream ().count ();
}
// SQL
@@ -471,6 +511,13 @@ generate (options const& ops, semantics::unit& unit, path const& p)
append (sql, ops.sql_epilogue (), ops.sql_epilogue_file ());
}
+ // Communicate the sloc count to the driver. This is necessary to
+ // correctly handle the total if we are compiling multiple files in
+ // one invocation.
+ //
+ if (ops.show_sloc () || ops.sloc_limit_specified ())
+ cout << "odb:sloc:" << sloc_total << endl;
+
auto_rm.cancel ();
}
catch (operation_failed const&)
diff --git a/odb/odb.cxx b/odb/odb.cxx
index c0e2388..7a42c2d 100644
--- a/odb/odb.cxx
+++ b/odb/odb.cxx
@@ -83,7 +83,8 @@ struct process_info
#endif
int out_fd;
- int in_fd;
+ int in_efd;
+ int in_ofd;
};
struct process_failure {};
@@ -95,7 +96,10 @@ struct process_failure {};
// name argument is the name of the current process for diagnostics.
//
static process_info
-start_process (char const* args[], char const* name, bool connect_out = false);
+start_process (char const* args[],
+ char const* name,
+ bool connect_stderr = false,
+ bool connect_stdout = false);
// Wait for the process to terminate. Return true if the process terminated
// normally and with the zero exit status. Issue diagnostics and throw
@@ -670,6 +674,8 @@ main (int argc, char* argv[])
// Iterate over the input files and compile each of them.
//
+ size_t sloc_total (0);
+
for (; end < plugin_args.size (); ++end)
{
path input (plugin_args[end]);
@@ -700,7 +706,7 @@ main (int argc, char* argv[])
}
}
- process_info pi (start_process (&exec_args[0], argv[0]));
+ process_info pi (start_process (&exec_args[0], argv[0], false, true));
{
__gnu_cxx::stdio_filebuf<char> fb (
@@ -866,9 +872,74 @@ main (int argc, char* argv[])
os << "#include <odb/container-traits.hxx>" << endl;
}
+ // Filter the output stream looking for communication from the
+ // plugin.
+ //
+ {
+ __gnu_cxx::stdio_filebuf<char> fb (pi.in_ofd, ios_base::in);
+ istream is (&fb);
+
+ for (bool first (true); !is.eof (); )
+ {
+ string line;
+ getline (is, line);
+
+ if (is.fail () && !is.eof ())
+ {
+ e << argv[0] << ": error: io failure while parsing output" << endl;
+ wait_process (pi, argv[0]);
+ return 1;
+ }
+
+ if (line.compare (0, 9, "odb:sloc:") == 0)
+ {
+ if (ops.show_sloc () || ops.sloc_limit_specified ())
+ {
+ size_t n;
+ istringstream is (string (line, 9, string::npos));
+
+ if (!(is >> n && is.eof ()))
+ {
+ e << argv[0] << ": error: invalid odb:sloc value" << endl;
+ wait_process (pi, argv[0]);
+ return 1;
+ }
+
+ sloc_total += n;
+ }
+
+ continue;
+ }
+
+ if (first)
+ first = false;
+ else
+ cout << endl;
+
+ cout << line;
+ }
+ }
+
if (!wait_process (pi, argv[0]))
return 1;
}
+
+ // Handle SLOC.
+ //
+ if (ops.show_sloc ())
+ e << "total: " << sloc_total << endl;
+
+ if (ops.sloc_limit_specified () && ops.sloc_limit () < sloc_total)
+ {
+ e << argv[0] << ": error: SLOC limit of " << ops.sloc_limit ()
+ << " lines has been exceeded" << endl;
+
+ if (!ops.show_sloc ())
+ e << argv[0] << ": info: use the --show-sloc option to see the "
+ << "current total" << endl;
+
+ return 1;
+ }
}
catch (profile_failure const&)
{
@@ -974,7 +1045,7 @@ profile_paths (strings const& sargs, char const* name)
//
stringstream ss;
{
- __gnu_cxx::stdio_filebuf<char> fb (pi.in_fd, ios_base::in);
+ __gnu_cxx::stdio_filebuf<char> fb (pi.in_efd, ios_base::in);
istream is (&fb);
for (bool first (true); !is.eof (); )
@@ -1179,6 +1250,7 @@ driver_path (path const& drv)
return drv.directory ().empty () ? path_search (drv) : drv;
}
+#ifndef STATIC_PLUGIN
static path
plugin_path (path const& drv)
{
@@ -1215,6 +1287,7 @@ plugin_path (path const& drv)
return path ();
}
+#endif
//
// Process manipulation.
@@ -1223,12 +1296,15 @@ plugin_path (path const& drv)
#ifndef _WIN32
static process_info
-start_process (char const* args[], char const* name, bool out)
+start_process (char const* args[], char const* name, bool err, bool out)
{
int out_fd[2];
- int in_fd[2];
+ int in_efd[2];
+ int in_ofd[2];
- if (pipe (out_fd) == -1 || (out && pipe (in_fd) == -1))
+ if (pipe (out_fd) == -1 ||
+ (err && pipe (in_efd) == -1) ||
+ (out && pipe (in_ofd) == -1))
{
char const* err (strerror (errno));
cerr << name << ": error: " << err << endl;
@@ -1258,14 +1334,27 @@ start_process (char const* args[], char const* name, bool out)
throw process_failure ();
}
- // Do the same for the out if requested.
+ // Do the same for the stderr if requested.
+ //
+ if (err)
+ {
+ if (close (in_efd[0]) == -1 ||
+ dup2 (in_efd[1], STDERR_FILENO) == -1 ||
+ close (in_efd[1]) == -1)
+ {
+ char const* err (strerror (errno));
+ cerr << name << ": error: " << err << endl;
+ throw process_failure ();
+ }
+ }
+
+ // Do the same for the stdout if requested.
//
if (out)
{
- if (close (in_fd[0]) == -1 ||
- dup2 (in_fd[1], STDOUT_FILENO) == -1 ||
- dup2 (in_fd[1], STDERR_FILENO) == -1 ||
- close (in_fd[1]) == -1)
+ if (close (in_ofd[0]) == -1 ||
+ dup2 (in_ofd[1], STDOUT_FILENO) == -1 ||
+ close (in_ofd[1]) == -1)
{
char const* err (strerror (errno));
cerr << name << ": error: " << err << endl;
@@ -1284,7 +1373,9 @@ start_process (char const* args[], char const* name, bool out)
{
// Parent. Close the other ends of the pipes.
//
- if (close (out_fd[0]) == -1 || (out && close (in_fd[1]) == -1))
+ if (close (out_fd[0]) == -1 ||
+ (err && close (in_efd[1]) == -1) ||
+ (out && close (in_ofd[1]) == -1))
{
char const* err (strerror (errno));
cerr << name << ": error: " << err << endl;
@@ -1295,7 +1386,8 @@ start_process (char const* args[], char const* name, bool out)
process_info r;
r.id = pid;
r.out_fd = out_fd[1];
- r.in_fd = out ? in_fd[0] : 0;
+ r.in_efd = err ? in_efd[0] : 0;
+ r.in_ofd = out ? in_ofd[0] : 0;
return r;
}
@@ -1342,10 +1434,11 @@ print_error (char const* name)
}
static process_info
-start_process (char const* args[], char const* name, bool out)
+start_process (char const* args[], char const* name, bool err, bool out)
{
HANDLE out_h[2];
- HANDLE in_h[2];
+ HANDLE in_eh[2];
+ HANDLE in_oh[2];
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
@@ -1359,10 +1452,20 @@ start_process (char const* args[], char const* name, bool out)
throw process_failure ();
}
+ if (err)
+ {
+ if (!CreatePipe (&in_eh[0], &in_eh[1], &sa, 0) ||
+ !SetHandleInformation (in_eh[0], HANDLE_FLAG_INHERIT, 0))
+ {
+ print_error (name);
+ throw process_failure ();
+ }
+ }
+
if (out)
{
- if (!CreatePipe (&in_h[0], &in_h[1], &sa, 0) ||
- !SetHandleInformation (in_h[0], HANDLE_FLAG_INHERIT, 0))
+ if (!CreatePipe (&in_oh[0], &in_oh[1], &sa, 0) ||
+ !SetHandleInformation (in_oh[0], HANDLE_FLAG_INHERIT, 0))
{
print_error (name);
throw process_failure ();
@@ -1424,16 +1527,17 @@ start_process (char const* args[], char const* name, bool out)
memset (&pi, 0, sizeof (PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
- if (out)
- {
- si.hStdError = in_h[1];
- si.hStdOutput = in_h[1];
- }
+
+ if (err)
+ si.hStdError = in_eh[1];
else
- {
si.hStdError = GetStdHandle (STD_ERROR_HANDLE);
+
+ if (out)
+ si.hStdOutput = in_oh[1];
+ else
si.hStdOutput = GetStdHandle (STD_OUTPUT_HANDLE);
- }
+
si.hStdInput = out_h[0];
si.dwFlags |= STARTF_USESTDHANDLES;
@@ -1456,8 +1560,11 @@ start_process (char const* args[], char const* name, bool out)
CloseHandle (pi.hThread);
CloseHandle (out_h[0]);
+ if (err)
+ CloseHandle (in_eh[1]);
+
if (out)
- CloseHandle (in_h[1]);
+ CloseHandle (in_oh[1]);
process_info r;
r.id = pi.hProcess;
@@ -1469,20 +1576,35 @@ start_process (char const* args[], char const* name, bool out)
throw process_failure ();
}
+ if (err)
+ {
+ // Pass _O_TEXT to get newline translation.
+ //
+ r.in_efd = _open_osfhandle ((intptr_t) (in_eh[0]), _O_TEXT);
+
+ if (r.in_efd == -1)
+ {
+ cerr << name << ": error: unable to obtain C file handle" << endl;
+ throw process_failure ();
+ }
+ }
+ else
+ r.in_efd = 0;
+
if (out)
{
// Pass _O_TEXT to get newline translation.
//
- r.in_fd = _open_osfhandle ((intptr_t) (in_h[0]), _O_TEXT);
+ r.in_ofd = _open_osfhandle ((intptr_t) (in_oh[0]), _O_TEXT);
- if (r.in_fd == -1)
+ if (r.in_ofd == -1)
{
cerr << name << ": error: unable to obtain C file handle" << endl;
throw process_failure ();
}
}
else
- r.in_fd = 0;
+ r.in_ofd = 0;
return r;
}
diff --git a/odb/options.cli b/odb/options.cli
index ae72e25..95a5d4c 100644
--- a/odb/options.cli
+++ b/odb/options.cli
@@ -5,6 +5,7 @@
include <set>;
include <vector>;
include <string>;
+include <cstddef>;
include <odb/option-types.hxx>;
@@ -451,6 +452,18 @@ class options
preprocessor macro name are replaced with underscores."
};
+ bool --show-sloc
+ {
+ "Print the number of generated physical source lines of code (SLOC)."
+ };
+
+ std::size_t --sloc-limit
+ {
+ "<num>",
+ "Check that the number of generated physical source lines of code (SLOC)
+ does not exceed <num>."
+ };
+
// The following option is "fake" in that it is actually handled by
// argv_file_scanner. We have it here to get the documentation.
//