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