diff --git a/NEWS b/NEWS
index 51d180819..519322801 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,7 @@
New in spot 1.2a (not released)
- Nothing yet.
+ * Bug fixes:
+ - ltlcross' CSV output now stricly follows RFC 4180.
New in spot 1.2 (2013-10-01)
diff --git a/src/bin/ltlcross.cc b/src/bin/ltlcross.cc
index 0a6b66f1d..69c263b48 100644
--- a/src/bin/ltlcross.cc
+++ b/src/bin/ltlcross.cc
@@ -275,46 +275,46 @@ struct statistics
static void
fields(std::ostream& os)
{
- os << (" \"states\","
- " \"edges\","
- " \"transitions\","
- " \"acc\","
- " \"scc\","
- " \"nonacc_scc\","
- " \"terminal_scc\","
- " \"weak_scc\","
- " \"strong_scc\","
- " \"nondet_states\","
- " \"nondet_aut\","
- " \"terminal_aut\","
- " \"weak_aut\","
- " \"strong_aut\","
- " \"time\","
- " \"product_states\","
- " \"product_transitions\","
- " \"product_scc\"");
+ os << ("\"states\","
+ "\"edges\","
+ "\"transitions\","
+ "\"acc\","
+ "\"scc\","
+ "\"nonacc_scc\","
+ "\"terminal_scc\","
+ "\"weak_scc\","
+ "\"strong_scc\","
+ "\"nondet_states\","
+ "\"nondet_aut\","
+ "\"terminal_aut\","
+ "\"weak_aut\","
+ "\"strong_aut\","
+ "\"time\","
+ "\"product_states\","
+ "\"product_transitions\","
+ "\"product_scc\"");
}
void
to_csv(std::ostream& os)
{
- os << states << ", "
- << edges << ", "
- << transitions << ", "
- << acc << ", "
- << scc << ", "
- << nonacc_scc << ", "
- << terminal_scc << ", "
- << weak_scc << ", "
- << strong_scc << ", "
- << nondetstates << ", "
- << nondeterministic << ", "
- << terminal_aut << ", "
- << weak_aut << ", "
- << strong_aut << ", "
- << time << ", "
- << product_states << ", "
- << product_transitions << ", "
+ os << states << ','
+ << edges << ','
+ << transitions << ','
+ << acc << ','
+ << scc << ','
+ << nonacc_scc << ','
+ << terminal_scc << ','
+ << weak_scc << ','
+ << strong_scc << ','
+ << nondetstates << ','
+ << nondeterministic << ','
+ << terminal_aut << ','
+ << weak_aut << ','
+ << strong_aut << ','
+ << time << ','
+ << product_states << ','
+ << product_transitions << ','
<< product_scc;
}
};
@@ -935,7 +935,7 @@ namespace
if (first)
first = false;
else
- err << ",";
+ err << ',';
err << l << i;
}
err << "} disagree with {";
@@ -946,7 +946,7 @@ namespace
if (first)
first = false;
else
- err << ",";
+ err << ',';
err << l << i;
}
err << "} when evaluating ";
@@ -1322,6 +1322,7 @@ namespace
};
}
+// Output an RFC4180-compatible CSV file.
static void
print_stats_csv(const char* filename)
{
@@ -1342,20 +1343,20 @@ print_stats_csv(const char* filename)
unsigned rounds = vstats.size();
assert(rounds == formulas.size());
- *out << "\"formula\", \"tool\", ";
+ *out << "\"formula\",\"tool\",";
statistics::fields(*out);
- *out << "\n";
+ *out << "\r\n";
for (unsigned r = 0; r < rounds; ++r)
for (unsigned t = 0; t < ntrans; ++t)
if (vstats[r][t].ok)
{
*out << "\"";
- spot::escape_str(*out, formulas[r]);
- *out << "\", \"";
- spot::escape_str(*out, translators[t]);
- *out << "\", ";
+ spot::escape_rfc4180(*out, formulas[r]);
+ *out << "\",\"";
+ spot::escape_rfc4180(*out, translators[t]);
+ *out << "\",";
vstats[r][t].to_csv(*out);
- *out << "\n";
+ *out << "\r\n";
}
delete outfile;
}
@@ -1394,7 +1395,7 @@ print_stats_json(const char* filename)
*out << "\",\n \"";
spot::escape_str(*out, formulas[r]);
}
- *out << ("\"\n ],\n \"fields\": [\n \"formula\", \"tool\",");
+ *out << ("\"\n ],\n \"fields\": [\n \"formula\",\"tool\",");
statistics::fields(*out);
*out << "\n ],\n \"inputs\": [ 0, 1 ],";
*out << "\n \"results\": [";
@@ -1404,9 +1405,9 @@ print_stats_json(const char* filename)
if (vstats[r][t].ok)
{
if (notfirst)
- *out << ",";
+ *out << ',';
notfirst = true;
- *out << "\n [ " << r << ", " << t << ", ";
+ *out << "\n [ " << r << ',' << t << ',';
vstats[r][t].to_csv(*out);
*out << " ]";
}
diff --git a/src/misc/escape.cc b/src/misc/escape.cc
index 1e90e298b..921addcfc 100644
--- a/src/misc/escape.cc
+++ b/src/misc/escape.cc
@@ -31,6 +31,22 @@
namespace spot
{
+ std::ostream&
+ escape_rfc4180(std::ostream& os, const std::string& str)
+ {
+ for (std::string::const_iterator i = str.begin(); i != str.end(); ++i)
+ switch (*i)
+ {
+ case '"':
+ os << "\"\"";
+ break;
+ default:
+ os << *i;
+ break;
+ }
+ return os;
+ }
+
std::ostream&
escape_str(std::ostream& os, const std::string& str)
{
diff --git a/src/misc/escape.hh b/src/misc/escape.hh
index c603d9e52..37f086f29 100644
--- a/src/misc/escape.hh
+++ b/src/misc/escape.hh
@@ -32,16 +32,26 @@ namespace spot
/// \addtogroup misc_tools
/// @{
- /// \brief Escape characters ", \\, and
- /// \\n in \a str.
- SPOT_API std::ostream& escape_str(std::ostream& os, const std::string& str);
+ /// \brief Double characters " in strings.
+ ///
+ /// In CSV files, as defined by RFC4180, double-quoted string that
+ /// contain double-quotes should simply duplicate those quotes.
+ SPOT_API std::ostream&
+ escape_rfc4180(std::ostream& os, const std::string& str);
/// \brief Escape characters ", \\, and
/// \\n in \a str.
- SPOT_API std::string escape_str(const std::string& str);
+ SPOT_API std::ostream&
+ escape_str(std::ostream& os, const std::string& str);
+
+ /// \brief Escape characters ", \\, and
+ /// \\n in \a str.
+ SPOT_API std::string
+ escape_str(const std::string& str);
/// \brief Remove spaces at the front and back of \a str.
- SPOT_API void trim(std::string& str);
+ SPOT_API void
+ trim(std::string& str);
/// @}
}