]> git.donarmstrong.com Git - lilypond.git/blob - flower/warn.cc
Issue 4550 (2/2) Avoid "using namespace std;" in included files
[lilypond.git] / flower / warn.cc
1 /*
2   This file is part of LilyPond, the GNU music typesetter.
3
4   Copyright (C) 1997--2015 Han-Wen Nienhuys <hanwen@xs4all.nl>
5
6   LilyPond is free software: you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation, either version 3 of the License, or
9   (at your option) any later version.
10
11   LilyPond is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "warn.hh"
21
22 #include <cstdlib>
23 #include <cstdio>
24
25 #include "std-vector.hh"
26 #include "international.hh"
27
28 using std::string;
29 using std::vector;
30
31 /** We have several different loglevels, each with its own message function(s):
32       ERROR: error, non_fatal_error, programming_error
33       WARN: warning
34       BASIC_PROGRESS: success/...
35       PROGRESS: progress_indication
36       INFO: message
37       DEBUG: debug
38   All these functions check whether the corresponding loglevel bit is set
39   and print the message only if that's the case
40 */
41
42 /* Define the loglevel (default is INFO) */
43 int loglevel = LOGLEVEL_INFO;
44 bool warning_as_error = false;
45
46 bool
47 is_loglevel (int level)
48 {
49   // Check the bitmask containing the loglevel
50   return (loglevel & level);
51 }
52
53 void
54 set_loglevel (int level)
55 {
56   loglevel = level;
57   debug_output (_f ("Log level set to %d\n", loglevel));
58 }
59
60 void
61 set_loglevel (string level)
62 {
63   /* Convert the loglevel string to lower-case, so we allow
64      both upper- and lower-case loglevels */
65   std::transform (level.begin (), level.end (), level.begin (), ::tolower);
66
67   /* Compare just the first few characters, so the loglevels
68      can be abbreviated */
69   if (level.compare (0, 5, "debug") == 0) // debug
70     set_loglevel (LOGLEVEL_DEBUG);
71   else if (level.compare (0, 4, "info") == 0) // info
72     set_loglevel (LOGLEVEL_INFO);
73   else if (level.compare (0, 4, "prog") == 0) // progress
74     set_loglevel (LOGLEVEL_PROGRESS);
75   else if (level.compare (0, 5, "basic") == 0) // basic progress
76     set_loglevel (LOGLEVEL_BASIC);
77   else if (level.compare (0, 4, "warn") == 0) // warning
78     set_loglevel (LOGLEVEL_WARN);
79   else if (level.compare (0, 3, "err") == 0) // error
80     set_loglevel (LOGLEVEL_ERROR);
81   else if (level.compare (0, 4, "none") == 0) // none
82     set_loglevel (LOGLEVEL_NONE);
83   else
84     {
85       int l;
86       if (sscanf (level.c_str (), "%d", &l))
87         set_loglevel (l);
88       else
89         {
90           non_fatal_error (_f ("unknown log level `%s', using default (INFO)",
91                                level));
92           set_loglevel (LOGLEVEL_INFO);
93         }
94     }
95 }
96
97 /**
98  * Register a warning string to be expected and the output suppressed.
99  * If the warning is encountered, it will be removed from the list of
100  * expected warnings again.
101  */
102 vector<string> expected_warnings;
103 void expect_warning (const string &msg)
104 {
105   expected_warnings.push_back (msg);
106 }
107
108 void check_expected_warnings ()
109 {
110   if (expected_warnings.size () > 0)
111     {
112       /* Some expected warning was not triggered, so print out a warning. */
113       string msg = _f ("%d expected warning(s) not encountered: ",
114                        expected_warnings.size ());
115       for (vsize i = 0; i < expected_warnings.size (); i++)
116         msg += "\n        " + expected_warnings[i];
117
118       warning (msg);
119     }
120   expected_warnings.clear ();
121 }
122
123 bool is_expected (const string &s)
124 {
125   bool expected = false;
126   for (vsize i = 0; i < expected_warnings.size (); i++)
127     {
128       // Compare the msg with the suppressed string; If the beginning matches,
129       // i.e. the msg can have additional content AFTER the full (exact)
130       // suppressed message, suppress the warning.
131       // This is needed for the Input class, where the message contains
132       // the input file contents after the real message.
133       if (s.compare (0, expected_warnings[i].size (), expected_warnings[i]) == 0)
134         {
135           expected = true;
136           expected_warnings.erase (expected_warnings.begin () + i);
137           break;
138         }
139     }
140   return expected;
141 }
142
143 /**
144  * Helper functions: print_message_part (no newline prepended)
145  *                   print_message (always starts on a new line)
146  */
147
148 /* Is output message at NEWLINE?  */
149 static bool message_newline = true;
150
151 /* Display user information as a full message.
152    if newline is true, start the message on a new line.
153 */
154 void
155 print_message (int level, const string &location, string s, bool newline)
156 {
157   /* Only print the message if the current loglevel allows it: */
158   if (!is_loglevel (level))
159     return;
160   if (newline && !message_newline)
161     fputc ('\n', stderr);
162
163   /* Test if all silly progress_indication ("\n") can be dropped now.  */
164   if (s == "\n")
165     return;
166
167   if (!location.empty ())
168     s = location + ": " + s;
169   fputs (s.c_str (), stderr);
170   fflush (stderr);
171   if (s.length ())
172     message_newline = s[s.length () - 1] == '\n';
173 }
174
175 /** The actual output functions to be called in lilypond code.
176  *  Sorted in descending order of importance (errors, warnings, progress, info,
177  *  debug). Each prints a message on a separate line.
178  */
179
180 /* Display a fatal error message.  Also exits lilypond.  */
181 void
182 error (string s, const string &location)
183 {
184   print_message (LOG_ERROR, location, _f ("fatal error: %s", s) + "\n");
185   exit (1);
186 }
187
188 /* Display a severe programming error message, but don't exit.  */
189 void
190 programming_error (const string &s, const string &location)
191 {
192   if (is_expected (s))
193     print_message (LOG_DEBUG, location, _f ("suppressed programming error: %s", s) + "\n");
194   else if (warning_as_error)
195     error (s, location);
196   else
197     {
198       print_message (LOG_ERROR, location, _f ("programming error: %s", s) + "\n");
199       print_message (LOG_ERROR, location, _ ("continuing, cross fingers") + "\n");
200     }
201 }
202
203 /* Display a non-fatal error message, don't exit.  */
204 void
205 non_fatal_error (const string &s, const string &location)
206 {
207   if (is_expected (s))
208     print_message (LOG_DEBUG, location, _f ("suppressed error: %s", s) + "\n");
209   else if (warning_as_error)
210     error (s, location);
211   else
212     print_message (LOG_ERROR, location, _f ("error: %s", s) + "\n");
213 }
214
215 /* Display a warning message. */
216 void
217 warning (const string &s, const string &location)
218 {
219   if (is_expected (s))
220     print_message (LOG_DEBUG, location, _f ("suppressed warning: %s", s) + "\n");
221   else if (warning_as_error)
222     error (s, location);
223   else
224     print_message (LOG_WARN, location, _f ("warning: %s", s) + "\n");
225 }
226
227 /* Display a success message.  */
228 void
229 basic_progress (const string &s, const string &location)
230 {
231   print_message (LOG_BASIC, location, s + "\n", true);
232 }
233
234 /* Display information about the progress.  */
235 void
236 progress_indication (const string &s, bool newline, const string &location)
237 {
238   print_message (LOG_PROGRESS, location, s, newline);
239 }
240
241 /* Display a single info message.  */
242 void
243 message (const string &s, bool newline, const string &location)
244 {
245   // Use the progress loglevel for all normal messages (including progress msg)
246   print_message (LOG_INFO, location, s, newline);
247 }
248
249 /* Display a debug information, not necessarily on a new line.  */
250 void
251 debug_output (const string &s, bool newline, const string &location)
252 {
253   print_message (LOG_DEBUG, location, s, newline);
254 }