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#include <cstdio>
17#include <cstdlib>
18#include <mutex>
19#include <atomic>
20#include <unordered_set>
21
22#include "config.h"
23#include "debug.h"
24#include "portable.h"
25#include "message.h"
26#include "doxygen.h"
27#include "fileinfo.h"
28#include "dir.h"
29#include "md5.h"
30
31// globals
34static const char * g_warningStr = "warning: ";
35static const char * g_errorStr = "error: ";
36static FILE * g_warnFile = stderr;
37static WARN_AS_ERROR_t g_warnBehavior = WARN_AS_ERROR_t::NO;
39static bool g_warnlogTemp = false;
40static std::atomic_bool g_warnStat = false;
41static std::mutex g_mutex;
42static std::unordered_set<std::string> g_warnHash;
43
44//-----------------------------------------------------------------------------------------
45
46static bool checkWarnMessage(QCString result)
47{
48 uint8_t md5_sig[16];
49 char sigStr[33];
50 MD5Buffer(result.data(),result.length(),md5_sig);
51 MD5SigToString(md5_sig,sigStr);
52
53 return g_warnHash.insert(sigStr).second;
54}
55
56static void format_warn(const QCString &file,int line,const QCString &text)
57{
58 QCString fileSubst = file.isEmpty() ? "<unknown>" : file;
59 QCString lineSubst; lineSubst.setNum(line);
60 QCString versionSubst;
61 // substitute markers by actual values
62 QCString msgText =
68 "$file",fileSubst
69 ),
70 "$line",lineSubst
71 ),
72 "$version",versionSubst
73 ),
74 "$text",text
75 );
76 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
77 {
78 msgText += " (warning treated as error, aborting now)";
79 }
80 msgText += '\n';
81
82 {
83 std::unique_lock<std::mutex> lock(g_mutex);
84 // print resulting message
85 if (checkWarnMessage(msgText)) fwrite(msgText.data(),1,msgText.length(),g_warnFile);
86 }
87 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
88 {
89 if (g_warnFile != stderr && !Config_getBool(QUIET))
90 {
91 msg("See '{}' for the reason of termination.\n",g_warnlogFile);
92 }
93 exit(1);
94 }
95 g_warnStat = true;
96}
97
98//-----------------------------------------------------------------------------------------
99
101{
102 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
103 {
104 {
105 std::unique_lock<std::mutex> lock(g_mutex);
106 QCString msgText = " (warning treated as error, aborting now)\n";
107 fwrite(msgText.data(),1,msgText.length(),g_warnFile);
108 if (g_warnFile != stderr && !Config_getBool(QUIET))
109 {
110 // cannot use `msg` due to the mutex
111 fprintf(stdout,"See '%s' for the reason of termination.\n",qPrint(g_warnlogFile));
112 }
113 }
114 exit(1);
115 }
116 g_warnStat = true;
117}
118
119//-----------------------------------------------------------------------------------------
120
121static void do_warn(const QCString &file, int line, const char *prefix, fmt::string_view fmt, fmt::format_args args)
122{
123 format_warn(file,line,prefix+fmt::vformat(fmt,args));
125}
126
127//-----------------------------------------------------------------------------------------
128
129void msg_(fmt::string_view fmt, fmt::format_args args)
130{
131 if (!Config_getBool(QUIET))
132 {
133 std::unique_lock<std::mutex> lock(g_mutex);
135 {
136 fmt::print("{:.3f} sec: ",(static_cast<double>(Debug::elapsedTime())));
137 }
138 fmt::print("{}",fmt::vformat(fmt,args));
139 }
140}
141
142//-----------------------------------------------------------------------------------------
143
144void warn_(WarningType type, const QCString &file, int line, fmt::string_view fmt, fmt::format_args args)
145{
146 bool enabled = false;
147 switch (type)
148 {
149 case WarningType::Generic: enabled = Config_getBool(WARNINGS); break;
150 case WarningType::Undocumented: enabled = Config_getBool(WARN_IF_UNDOCUMENTED); break;
151 case WarningType::IncompleteDoc: enabled = Config_getBool(WARN_IF_INCOMPLETE_DOC); break;
152 case WarningType::DocError: enabled = Config_getBool(WARN_IF_DOC_ERROR); break;
153 case WarningType::Layout: enabled = Config_getBool(WARN_LAYOUT_FILE); break;
154 }
155 if (enabled)
156 {
157 do_warn(file, line, g_warningStr, fmt, args);
158 }
159}
160
161//-----------------------------------------------------------------------------------------
162
163void warn_uncond_(fmt::string_view fmt, fmt::format_args args)
164{
165 {
166 std::unique_lock<std::mutex> lock(g_mutex);
167 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile,"{}{}",g_warningStr,vformat(fmt,args));
168 }
170}
171
172//-----------------------------------------------------------------------------------------
173
174void err_(fmt::string_view fmt, fmt::format_args args)
175{
176 {
177 std::unique_lock<std::mutex> lock(g_mutex);
178 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile,"{}{}",g_errorStr,fmt::vformat(fmt,args));
179 }
181}
182
183//-----------------------------------------------------------------------------------------
184
185void err_full_(const QCString &file, int line, fmt::string_view fmt, fmt::format_args args)
186{
187 format_warn(file,line,g_errorStr+fmt::vformat(fmt,args));
188}
189
190//-----------------------------------------------------------------------------------------
191
192void term_(fmt::string_view fmt, fmt::format_args args)
193{
194 {
195 std::unique_lock<std::mutex> lock(g_mutex);
196 if (checkWarnMessage(g_errorStr+fmt::vformat(fmt,args))) fmt::print(g_warnFile, "{}{}", g_errorStr, fmt::vformat(fmt,args));
197 if (g_warnFile != stderr)
198 {
199 size_t l = strlen(g_errorStr);
200 for (size_t i=0; i<l; i++) fmt::print(g_warnFile, " ");
201 fmt::print(g_warnFile, "{}\n", "Exiting...");
202 if (!Config_getBool(QUIET))
203 {
204 // cannot use `msg` due to the mutex
205 fmt::print("See '{}' for the reason of termination.\n",g_warnlogFile);
206 }
207 }
208 }
209 exit(1);
210}
211
212//-----------------------------------------------------------------------------------------
213
214QCString warn_line(const QCString &file,int line)
215{
216 QCString fileSubst = file.isEmpty() ? "<unknown>" : file;
217 QCString lineSubst; lineSubst.setNum(line);
218 return substitute(
221 "$file",fileSubst
222 ),
223 "$line",lineSubst
224 );
225}
226
227//-----------------------------------------------------------------------------------------
228
230{
231 fflush(g_warnFile);
232}
233
234//-----------------------------------------------------------------------------------------
235
237{
238 g_warnFormat = Config_getString(WARN_FORMAT);
239 g_warnLineFormat = Config_getString(WARN_LINE_FORMAT);
240 g_warnBehavior = Config_getEnum(WARN_AS_ERROR);
241 g_warnlogFile = Config_getString(WARN_LOGFILE);
242 if (g_warnlogFile.isEmpty() && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT)
243 {
244 uint32_t pid = Portable::pid();
245 g_warnlogFile.sprintf("doxygen_warnings_temp_%d.tmp",pid);
246 g_warnlogTemp = true;
247 }
248
249 if (!g_warnlogFile.isEmpty())
250 {
251 if (g_warnlogFile == "-")
252 {
253 g_warnFile = stdout;
254 }
255 else
256 {
257 FileInfo fi(g_warnlogFile.str());
258 Dir d(fi.dirPath());
259 if (!d.exists() && !d.mkdir(fi.dirPath()))
260 {
261 // point it to something valid, because warn() relies on it
262 g_warnFile = stderr;
263 err("Cannot create directory for '{}', redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile);
264 }
265 else if (!(g_warnFile = Portable::fopen(g_warnlogFile,"w")))
266 {
267 // point it to something valid, because warn() relies on it
268 g_warnFile = stderr;
269 err("Cannot open '{}' for writing, redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile);
270 }
271 }
272 }
273 else
274 {
275 g_warnFile = stderr;
276 }
277 if (g_warnBehavior != WARN_AS_ERROR_t::NO)
278 {
280 }
281
282 // make sure the g_warnFile is closed in case we call exit and it is still open
283 std::atexit([](){
284 if (g_warnFile && g_warnFile!=stderr && g_warnFile!=stdout)
285 {
287 g_warnFile = nullptr;
288 }
289 });
290}
291
292//-----------------------------------------------------------------------------------------
293
295{
296 fflush(stdout);
297 if (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
298 {
300 g_warnFile = nullptr;
301 }
302 if (g_warnStat && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
303 {
304
305 std::ifstream warnFile = Portable::openInputStream(g_warnlogFile);
306 if (!warnFile.is_open())
307 {
308 g_warnFile = stderr;
309 err("Cannot open warnings file '{}' for reading\n",g_warnlogFile);
310 }
311 else
312 {
313 std::string line;
314 while (getline(warnFile,line))
315 {
316 fmt::print(stderr,"{}\n",line);
317 }
318 warnFile.close();
319 }
320 }
321
323
324 if (g_warnStat && (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS ||
325 g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT))
326 {
327 exit(1);
328 }
329}
constexpr auto prefix
Definition anchor.cpp:44
@ Time
Definition debug.h:35
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:75
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition dir.cpp:295
bool exists() const
Definition dir.cpp:257
Minimal replacement for QFileInfo.
Definition fileinfo.h:23
std::string dirPath(bool absPath=true) const
Definition fileinfo.cpp:137
This is an alternative implementation of QCString.
Definition qcstring.h:101
size_t length() const
Returns the length of the string, not counting the 0-terminator.
Definition qcstring.h:166
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:163
QCString & setNum(short n)
Definition qcstring.h:459
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string.
Definition qcstring.h:172
#define Config_getBool(name)
Definition config.h:33
#define Config_getString(name)
Definition config.h:32
#define Config_getEnum(name)
Definition config.h:35
static bool checkWarnMessage(QCString result)
Definition message.cpp:46
void err_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:174
QCString warn_line(const QCString &file, int line)
Definition message.cpp:214
static void do_warn(const QCString &file, int line, const char *prefix, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:121
static bool g_warnlogTemp
Definition message.cpp:39
static QCString g_warnLineFormat
Definition message.cpp:33
void warn_(WarningType type, const QCString &file, int line, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:144
static std::atomic_bool g_warnStat
Definition message.cpp:40
static const char * g_errorStr
Definition message.cpp:35
static WARN_AS_ERROR_t g_warnBehavior
Definition message.cpp:37
void warn_uncond_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:163
static const char * g_warningStr
Definition message.cpp:34
void initWarningFormat()
Definition message.cpp:236
static QCString g_warnFormat
Definition message.cpp:32
void warn_flush()
Definition message.cpp:229
static std::unordered_set< std::string > g_warnHash
Definition message.cpp:42
static std::mutex g_mutex
Definition message.cpp:41
static FILE * g_warnFile
Definition message.cpp:36
void msg_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:129
static void format_warn(const QCString &file, int line, const QCString &text)
Definition message.cpp:56
void finishWarnExit()
Definition message.cpp:294
void term_(fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:192
static void handle_warn_as_error()
Definition message.cpp:100
void err_full_(const QCString &file, int line, fmt::string_view fmt, fmt::format_args args)
Definition message.cpp:185
static QCString g_warnlogFile
Definition message.cpp:38
#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 QCString &name, bool binary=false, bool openAtEnd=false)
Definition portable.cpp:660
void unlink(const QCString &fileName)
Definition portable.cpp:545
FILE * fopen(const QCString &fileName, const QCString &mode)
Definition portable.cpp:350
uint32_t pid()
Definition portable.cpp:249
int fclose(FILE *f)
Definition portable.cpp:370
Definition message.h:144
Portable versions of functions that are platform dependent.
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition qcstring.cpp:571
const char * qPrint(const char *s)
Definition qcstring.h:687