+#include <cstdlib>
+#include <cstdio>
+
+#include "std-vector.hh"
+#include "international.hh"
+
+using namespace std;
+
+/** We have several different loglevels, each with its own message function(s):
+ ERROR: error, non_fatal_error, programming_error
+ WARN: warning
+ BASIC_PROGRESS: success/...
+ PROGRESS: progress_indication
+ INFO: message
+ DEBUG: debug
+ All these functions check whether the corresponding loglevel bit is set
+ and print the message only if that's the case
+*/
+
+/* Define the loglevel (default is INFO) */
+int loglevel = LOGLEVEL_INFO;
+bool warning_as_error = false;
+
+bool
+is_loglevel (int level)
+{
+ // Check the bitmask containing the loglevel
+ return (loglevel & level);
+}
+
+void
+set_loglevel (int level)
+{
+ loglevel = level;
+ debug_output (_f ("Log level set to %d\n", loglevel));
+}
+
+void
+set_loglevel (string level)
+{
+ /* Convert the loglevel string to lower-case, so we allow
+ both upper- and lower-case loglevels */
+ std::transform (level.begin (), level.end (), level.begin (), ::tolower);
+
+ /* Compare just the first few characters, so the loglevels
+ can be abbreviated */
+ if (level.compare (0, 5, "debug") == 0) // debug
+ set_loglevel (LOGLEVEL_DEBUG);
+ else if (level.compare (0, 4, "info") == 0) // info
+ set_loglevel (LOGLEVEL_INFO);
+ else if (level.compare (0, 4, "prog") == 0) // progress
+ set_loglevel (LOGLEVEL_PROGRESS);
+ else if (level.compare (0, 5, "basic") == 0) // basic progress
+ set_loglevel (LOGLEVEL_BASIC);
+ else if (level.compare (0, 4, "warn") == 0) // warning
+ set_loglevel (LOGLEVEL_WARN);
+ else if (level.compare (0, 3, "err") == 0) // error
+ set_loglevel (LOGLEVEL_ERROR);
+ else if (level.compare (0, 4, "none") == 0) // none
+ set_loglevel (LOGLEVEL_NONE);
+ else
+ {
+ int l;
+ if (sscanf (level.c_str (), "%d", &l))
+ set_loglevel (l);
+ else
+ {
+ non_fatal_error (_f ("unknown log level `%s', using default (INFO)",
+ level));
+ set_loglevel (LOGLEVEL_INFO);
+ }
+ }
+}
+
+/**
+ * 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 (const 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 (const 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)
+ * print_message (always starts on a new line)
+ */
+
+/* Is output message at NEWLINE? */
+static bool message_newline = true;