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