X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=flower%2Fwarn.cc;h=9ff173bf358b0d3560d101355f30ff963d60cd22;hb=9e781b7dc83b60a543ce218aa1a5f139f74c760f;hp=aef1f3833399f36c0ddc26b12d63517c34d4e243;hpb=8bcab38894d0ec3451045356146d875c1d4f08b9;p=lilypond.git diff --git a/flower/warn.cc b/flower/warn.cc index aef1f38333..9ff173bf35 100644 --- a/flower/warn.cc +++ b/flower/warn.cc @@ -1,46 +1,253 @@ /* - warn.cc -- implement warnings + This file is part of LilyPond, the GNU music typesetter. - source file of the Flower Library + Copyright (C) 1997--2014 Han-Wen Nienhuys - (c) 1997--2000 Han-Wen Nienhuys -*/ + LilyPond is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + LilyPond is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -#include -#include + You should have received a copy of the GNU General Public License + along with LilyPond. If not, see . +*/ #include "warn.hh" +#include +#include + +#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 -message (String s) +set_loglevel (int level) { - fputs (s.ch_C (), stderr); + loglevel = level; + debug_output (_f ("Log level set to %d\n", loglevel)); } void -warning (String s) +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 expected_warnings; +void expect_warning (const string &msg) { - message (_f ("warning: %s\n", s.ch_C ())); + 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; + +/* Display user information as a full message. + if newline is true, start the message on a new line. +*/ void -non_fatal_error (String s) +print_message (int level, const string &location, string s, bool newline) { - message (_f ("error: %s\n", s.ch_C ())); + /* Only print the message if the current loglevel allows it: */ + if (!is_loglevel (level)) + return; + if (newline && !message_newline) + fputc ('\n', stderr); + + /* Test if all silly progress_indication ("\n") can be dropped now. */ + if (s == "\n") + return; + + if (!location.empty ()) + s = location + ": " + s; + fputs (s.c_str (), stderr); + fflush (stderr); + if (s.length ()) + message_newline = s[s.length () - 1] == '\n'; } +/** The actual output functions to be called in lilypond code. + * Sorted in descending order of importance (errors, warnings, progress, info, + * debug). Each prints a message on a separate line. + */ + +/* Display a fatal error message. Also exits lilypond. */ void -error (String s) +error (string s, const string &location) { - non_fatal_error (s); + print_message (LOG_ERROR, location, _f ("fatal error: %s", s) + "\n"); exit (1); } +/* Display a severe programming error message, but don't exit. */ void -programming_error (String s) +programming_error (const string &s, const string &location) { - message (_f ("programming error: %s (Continuing; cross thumbs)\n", - s.ch_C ())); + if (is_expected (s)) + print_message (LOG_DEBUG, location, _f ("suppressed programming error: %s", s) + "\n"); + else if (warning_as_error) + error (s, location); + 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 (const string &s, const string &location) +{ + if (is_expected (s)) + print_message (LOG_DEBUG, location, _f ("suppressed error: %s", s) + "\n"); + else if (warning_as_error) + error (s, location); + else + print_message (LOG_ERROR, location, _f ("error: %s", s) + "\n"); +} + +/* Display a warning message. */ +void +warning (const string &s, const string &location) +{ + if (is_expected (s)) + print_message (LOG_DEBUG, location, _f ("suppressed warning: %s", s) + "\n"); + else if (warning_as_error) + error (s, location); + else + print_message (LOG_WARN, location, _f ("warning: %s", s) + "\n"); +} + +/* Display a success message. */ +void +basic_progress (const string &s, const string &location) +{ + print_message (LOG_BASIC, location, s + "\n", true); +} + +/* Display information about the progress. */ +void +progress_indication (const string &s, bool newline, const string &location) +{ + print_message (LOG_PROGRESS, location, s, newline); +} + +/* Display a single info message. */ +void +message (const string &s, bool newline, const string &location) +{ + // Use the progress loglevel for all normal messages (including progress msg) + print_message (LOG_INFO, location, s, newline); +} + +/* Display a debug information, not necessarily on a new line. */ +void +debug_output (const string &s, bool newline, const string &location) +{ + print_message (LOG_DEBUG, location, s, newline); +}