#include <cstdlib>
#include <cstdio>
+#include "std-vector.hh"
#include "international.hh"
using namespace std;
}
}
+/**
+ * Register a warning string to be expected and the output suppressed.
+ * If the warning is encountered, it will be removed from the list of
+ * expected warnings again.
+ */
+vector<string> expected_warnings;
+void expect_warning (string msg)
+{
+ expected_warnings.push_back (msg);
+}
+
+void check_expected_warnings ()
+{
+ if (expected_warnings.size () > 0)
+ {
+ /* Some expected warning was not triggered, so print out a warning. */
+ string msg = _f ("%d expected warning(s) not encountered: ",
+ expected_warnings.size ());
+ for (vsize i = 0; i< expected_warnings.size (); i++)
+ msg += "\n " + expected_warnings[i];
+
+ warning (msg);
+ }
+ expected_warnings.clear ();
+}
+
+bool is_expected (string s)
+{
+ bool expected = false;
+ for (vsize i = 0; i< expected_warnings.size (); i++)
+ {
+ // Compare the msg with the suppressed string; If the beginning matches,
+ // i.e. the msg can have additional content AFTER the full (exact)
+ // suppressed message, suppress the warning.
+ // This is needed for the Input class, where the message contains
+ // the input file contents after the real message.
+ if (s.compare (0, expected_warnings[i].size (), expected_warnings[i]) == 0 ) {
+ expected = true;
+ expected_warnings.erase (expected_warnings.begin () + i);
+ break;
+ }
+ }
+ return expected;
+}
+
/**
* Helper functions: print_message_part (no newline prepended)
void
programming_error (string s, string location)
{
- print_message (LOG_ERROR, location, _f ("programming error: %s", s) + "\n");
- print_message (LOG_ERROR, location, _ ("continuing, cross fingers") + "\n");
+ if (is_expected (s)) {
+ print_message (LOG_DEBUG, location, _f ("suppressed programming error: %s", s) + "\n");
+ } else {
+ print_message (LOG_ERROR, location, _f ("programming error: %s", s) + "\n");
+ print_message (LOG_ERROR, location, _ ("continuing, cross fingers") + "\n");
+ }
}
/* Display a non-fatal error message, don't exit. */
void
non_fatal_error (string s, string location)
{
- print_message (LOG_ERROR, location, _f ("error: %s", s) + "\n");
+ if (is_expected (s))
+ print_message (LOG_DEBUG, location, _f ("suppressed error: %s", s) + "\n");
+ else {
+ print_message (LOG_ERROR, location, _f ("error: %s", s) + "\n");
+ }
}
/* Display a warning message. */
void
warning (string s, string location)
{
- print_message (LOG_WARN, location, _f ("warning: %s", s) + "\n");
+ if (is_expected (s))
+ print_message (LOG_DEBUG, location, _f ("suppressed warning: %s", s) + "\n");
+ else {
+ // TODO: Add warning-as-error check here
+ print_message (LOG_WARN, location, _f ("warning: %s", s) + "\n");
+ }
}
/* Display a success message. */
#include "lily-guile.hh"
#include "program-option.hh"
#include "version.hh"
+#include "international.hh"
#include "warn.hh"
/*
return SCM_UNSPECIFIED;
}
+
+LY_DEFINE (ly_expect_warning, "ly:expect-warning",
+ 1, 0, 1, (SCM str, SCM rest),
+ "A Scheme callable function to register a warning to be expected"
+ " and subsequently suppressed. If the warning is not encountered,"
+ " a warning about the missing warning will be shown. The message"
+ " should be translated with @code{(_ ...)} and changing parameters"
+ " given after the format string.")
+{
+ LY_ASSERT_TYPE (scm_is_string, str, 1);
+ str = scm_simple_format (SCM_BOOL_F, str, rest);
+ expect_warning (ly_scm2string (str));
+ return SCM_UNSPECIFIED;
+}
+
+LY_DEFINE (ly_check_expected_warnings, "ly:check-expected-warnings",
+ 0, 0, 0, (),
+ "Check whether all expected warnings have really been triggered.")
+{
+ check_expected_warnings ();
+ return SCM_UNSPECIFIED;
+}
+
+LY_DEFINE (ly_translate_cpp_warning_scheme, "ly:translate-cpp-warning-scheme",
+ 1, 0, 0, (SCM str),
+ "Translates a string in C++ printf format and modifies it to use"
+ " it for scheme formatting.")
+{
+ LY_ASSERT_TYPE (scm_is_string, str, 1);
+ string s = _ (ly_scm2string (str).c_str ());
+
+ /* Now replace all printf placeholders by scheme placeholders (~a).
+ * Guile's format syntax is pretty similar to C's printf, only with
+ * a tilde as the placeholder instead of a percent sign.
+ * There is no easy way to replace all ~ -> ~~, %% -> %, % -> ~,
+ * so simply walk through each character.
+ */
+// size_t pos = 0;
+ const char *pos = s.c_str ();
+ string result = "";
+ while (*pos != '\0')
+ {
+ // In some cases (%%, %s) we need to do a lookahead. As the C string is
+ // always \0-terminated the next char is never beyond the end of the
+ // memory!
+ switch (*pos) {
+ case '~':
+ result += "~~";
+ break;
+ case '%':
+ if (*(pos+1) == '%') {
+ result += "%";
+ // Skip the second '%'
+ pos++;
+ } else if (*(pos+1) == 's' || *(pos+1) == 'd') {
+ // %s in C++ corresponds to ~a; ~s would add quotes!
+ // ~d is only supported by ice-9, use ~a instead
+ result += "~a";
+ // Skip the following 's'
+ pos++;
+ } else
+ result += "~";
+ break;
+ default:
+ result += *pos;
+ }
+ pos++;
+ }
+ return ly_string2scm (result);
+}