Doxygen
Loading...
Searching...
No Matches
message.cpp
Go to the documentation of this file.
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2020 by Dimitri van Heesch.
4 *
5 * Permission to use, copy, modify, and distribute this software and its
6 * documentation under the terms of the GNU General Public License is hereby
7 * granted. No representations are made about the suitability of this software
8 * for any purpose. It is provided "as is" without express or implied warranty.
9 * See the GNU General Public License for more details.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16// own header
17#include "message.h"
18
19// standard includes
20#include <atomic>
21#include <mutex>
22#include <unordered_set>
23
24// other includes
25#include "config.h"
26#include "debug.h"
27#include "dir.h"
28#include "doxygen.h"
29#include "fileinfo.h"
30#include "md5hash.h"
31#include "portable.h"
32
33// globals
36static const char * g_warningStr = "warning: ";
37static const char * g_errorStr = "error: ";
38static FILE * g_warnFile = stderr;
39static WARN_AS_ERROR_t g_warnBehavior = WARN_AS_ERROR_t::NO;
41static bool g_warnlogTemp = false;
42static std::atomic_bool g_warnStat = false;
43static std::mutex g_mutex;
44static std::unordered_set<std::string> g_warnHash;
45
46//-----------------------------------------------------------------------------------------
47
48static bool checkWarnMessage(std::string_view msg)
49{
50 return g_warnHash.insert(md5str(msg).str()).second;
51}
52
53static void format_warn(const DString &file,int line,const DString &text)
54{
55 DString fileSubst = file.empty() ? "<unknown>" : file;
56 DString lineSubst; lineSubst.setNum(line);
57 DString versionSubst;
58 // substitute markers by actual values
59 DString msgText =
65 "$file",fileSubst
66 ),
67 "$line",lineSubst
68 ),
69 "$version",versionSubst
70 ),
71 "$text",text
72 );
73 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
74 {
75 msgText += " (warning treated as error, aborting now)";
76 }
77 msgText += '\n';
78
79 {
80 std::unique_lock<std::mutex> lock(g_mutex);
81 // print resulting message
82 if (checkWarnMessage(msgText.view())) fwrite(msgText.data(),1,msgText.length(),g_warnFile);
83 }
84 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
85 {
86 if (g_warnFile != stderr && !Config_getBool(QUIET))
87 {
88 msg("See '{}' for the reason of termination.\n",g_warnlogFile);
89 }
90 exit(1);
91 }
92 g_warnStat = true;
93}
94
95//-----------------------------------------------------------------------------------------
96
98{
99 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
100 {
101 {
102 std::unique_lock<std::mutex> lock(g_mutex);
103 DString msgText = " (warning treated as error, aborting now)\n";
104 fwrite(msgText.data(),1,msgText.length(),g_warnFile);
105 if (g_warnFile != stderr && !Config_getBool(QUIET))
106 {
107 // cannot use `msg` due to the mutex
108 fprintf(stdout,"See '%s' for the reason of termination.\n",qPrint(g_warnlogFile));
109 }
110 }
111 exit(1);
112 }
113 g_warnStat = true;
114}
115
116//-----------------------------------------------------------------------------------------
117
118static void do_warn(const DString &file, int line, const char *prefix, fmt::string_view fmt, fmt::format_args args)
119{
120 format_warn(file,line,prefix+fmt::vformat(fmt,args));
122}
123
124//-----------------------------------------------------------------------------------------
125
126void msg_(fmt::string_view fmt, fmt::format_args args)
127{
128 if (!Config_getBool(QUIET))
129 {
130 std::unique_lock<std::mutex> lock(g_mutex);
132 {
133 fmt::print("{:.3f} sec: ",(static_cast<double>(Debug::elapsedTime())));
134 }
135 fmt::print("{}",fmt::vformat(fmt,args));
136 }
137}
138
139//-----------------------------------------------------------------------------------------
140
141void warn_(WarningType type, const DString &file, int line, fmt::string_view fmt, fmt::format_args args)
142{
143 bool enabled = false;
144 switch (type)
145 {
146 case WarningType::Generic: enabled = Config_getBool(WARNINGS); break;
147 case WarningType::Undocumented: enabled = Config_getBool(WARN_IF_UNDOCUMENTED); break;
148 case WarningType::IncompleteDoc: enabled = Config_getBool(WARN_IF_INCOMPLETE_DOC); break;
149 case WarningType::DocError: enabled = Config_getBool(WARN_IF_DOC_ERROR); break;
150 case WarningType::Layout: enabled = Config_getBool(WARN_LAYOUT_FILE); break;
151 }
152 if (enabled)
153 {
154 do_warn(file, line, g_warningStr, fmt, args);
155 }
156}
157
158//-----------------------------------------------------------------------------------------
159
160void warn_uncond_(fmt::string_view fmt, fmt::format_args args)
161{
162 {
163 std::unique_lock<std::mutex> lock(g_mutex);
164 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile,"{}{}",g_warningStr,vformat(fmt,args));
165 }
167}
168
169//-----------------------------------------------------------------------------------------
170
171void err_(fmt::string_view fmt, fmt::format_args args)
172{
173 {
174 std::unique_lock<std::mutex> lock(g_mutex);
175 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile,"{}{}",g_errorStr,fmt::vformat(fmt,args));
176 }
178}
179
180//-----------------------------------------------------------------------------------------
181
182void err_full_(const DString &file, int line, fmt::string_view fmt, fmt::format_args args)
183{
184 format_warn(file,line,g_errorStr+fmt::vformat(fmt,args));
185}
186
187//-----------------------------------------------------------------------------------------
188
189void term_(fmt::string_view fmt, fmt::format_args args)
190{
191 {
192 std::unique_lock<std::mutex> lock(g_mutex);
193 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile, "{}{}", g_errorStr, fmt::vformat(fmt,args));
194 if (g_warnFile != stderr)
195 {
196 size_t l = strlen(g_errorStr);
197 for (size_t i=0; i<l; i++) fmt::print(g_warnFile, " ");
198 fmt::print(g_warnFile, "{}\n", "Exiting...");
199 if (!Config_getBool(QUIET))
200 {
201 // cannot use `msg` due to the mutex
202 fmt::print("See '{}' for the reason of termination.\n",g_warnlogFile);
203 }
204 }
205 }
206 exit(1);
207}
208
209//-----------------------------------------------------------------------------------------
210
211DString warn_line(const DString &file,int line)
212{
213 DString fileSubst = file.empty() ? "<unknown>" : file;
214 DString lineSubst; lineSubst.setNum(line);
215 return substitute(
218 "$file",fileSubst
219 ),
220 "$line",lineSubst
221 );
222}
223
224//-----------------------------------------------------------------------------------------
225
227{
228 fflush(g_warnFile);
229}
230
231//-----------------------------------------------------------------------------------------
232
234{
235 g_warnFormat = Config_getString(WARN_FORMAT);
236 g_warnLineFormat = Config_getString(WARN_LINE_FORMAT);
237 g_warnBehavior = Config_getEnum(WARN_AS_ERROR);
238 g_warnlogFile = Config_getString(WARN_LOGFILE);
239 if (g_warnlogFile.empty() && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT)
240 {
241 uint32_t pid = Portable::pid();
242 g_warnlogFile.sprintf("doxygen_warnings_temp_%d.tmp",pid);
243 g_warnlogTemp = true;
244 }
245
246 if (!g_warnlogFile.empty())
247 {
248 if (g_warnlogFile == "-")
249 {
250 g_warnFile = stdout;
251 }
252 else
253 {
255 Dir d(fi.dirPath());
256 if (!d.exists() && !d.mkdir(fi.dirPath()))
257 {
258 // point it to something valid, because warn() relies on it
259 g_warnFile = stderr;
260 err("Cannot create directory for '{}', redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile);
261 }
262 else if (!(g_warnFile = Portable::fopen(g_warnlogFile,"w")))
263 {
264 // point it to something valid, because warn() relies on it
265 g_warnFile = stderr;
266 err("Cannot open '{}' for writing, redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile);
267 }
268 }
269 }
270 else
271 {
272 g_warnFile = stderr;
273 }
274 if (g_warnBehavior != WARN_AS_ERROR_t::NO)
275 {
277 }
278
279 // make sure the g_warnFile is closed in case we call exit and it is still open
280 std::atexit([](){
281 if (g_warnFile && g_warnFile!=stderr && g_warnFile!=stdout)
282 {
284 g_warnFile = nullptr;
285 }
286 });
287}
288
289//-----------------------------------------------------------------------------------------
290
292{
293 fflush(stdout);
294 if (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
295 {
297 g_warnFile = nullptr;
298 }
299 if (g_warnStat && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
300 {
301
302 std::ifstream warnFile = Portable::openInputStream(g_warnlogFile);
303 if (!warnFile.is_open())
304 {
305 g_warnFile = stderr;
306 err("Cannot open warnings file '{}' for reading\n",g_warnlogFile);
307 }
308 else
309 {
310 std::string line;
311 while (getline(warnFile,line))
312 {
313 fmt::print(stderr,"{}\n",line);
314 }
315 warnFile.close();
316 }
317 }
318
320
321 if (g_warnStat && (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS ||
322 g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT))
323 {
324 exit(1);
325 }
326}
constexpr auto prefix
Definition anchor.cpp:47
A String class for use with Doxygen wrapping std::string and adding some additional functionality off...
Definition dstring.h:84
DString & setNum(short n)
Definition dstring.h:552
bool empty() const
Returns true iff the string is empty (std::string compatible alias for isEmpty()).
Definition dstring.h:148
std::string_view view() const
Definition dstring.h:162
DString & sprintf(const char *format,...)
Definition dstring.cpp:34
const std::string & str() const
Definition dstring.h:645
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition dstring.h:157
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition dstring.h:151
@ Time
Definition debug.h:36
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:132
static double elapsedTime()
Definition debug.cpp:200
Class representing a directory in the file system.
Definition dir.h:73
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:301
bool exists() const
Definition dir.cpp:263
Minimal replacement for QFileInfo.
Definition fileinfo.h:26
std::string dirPath(bool absPath=true) const
Definition fileinfo.cpp:141
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
#define Config_getEnum(name)
Definition config.h:35
DString substitute(const DString &s, const DString &src, const DString &dst)
substitute all occurrences of src in s by dst
Definition dstring.cpp:485
const char * qPrint(const char *s)
Definition dstring.h:783
DString md5str(const std::string_view &str)
Definition md5hash.h:33
static void format_warn(const DString &file, int line, const DString &text)
Definition message.cpp:53
void err_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:171
static DString g_warnFormat
Definition message.cpp:34
void err_full_(const DString &file, int line, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:182
static DString g_warnLineFormat
Definition message.cpp:35
static bool g_warnlogTemp
Definition message.cpp:41
static std::atomic_bool g_warnStat
Definition message.cpp:42
static const char * g_errorStr
Definition message.cpp:37
static WARN_AS_ERROR_t g_warnBehavior
Definition message.cpp:39
static void do_warn(const DString &file, int line, const char *prefix, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:118
void warn_uncond_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:160
static const char * g_warningStr
Definition message.cpp:36
void initWarningFormat()
Definition message.cpp:233
static bool checkWarnMessage(std::string_view msg)
Definition message.cpp:48
void warn_flush()
Definition message.cpp:226
static std::unordered_set< std::string > g_warnHash
Definition message.cpp:44
static std::mutex g_mutex
Definition message.cpp:43
static FILE * g_warnFile
Definition message.cpp:38
static DString g_warnlogFile
Definition message.cpp:40
void msg_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:126
DString warn_line(const DString &file, int line)
Definition message.cpp:211
void finishWarnExit()
Definition message.cpp:291
void term_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:189
void warn_(WarningType type, const DString &file, int line, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:141
static void handle_warn_as_error()
Definition message.cpp:97
#define msg(fmt,...)
Definition message.h:94
WarningType
Definition message.h:26
@ IncompleteDoc
Definition message.h:29
@ Undocumented
Definition message.h:28
#define err(fmt,...)
Definition message.h:127
std::ifstream openInputStream(const DString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:692
uint32_t pid()
Definition portable.cpp:264
void unlink(const DString &fileName)
Definition portable.cpp:560
FILE * fopen(const DString &fileName, const DString &mode)
Definition portable.cpp:365
int fclose(FILE *f)
Definition portable.cpp:385
Definition message.h:146
Portable versions of functions that are platform dependent.