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
42{
43 g_warnFormat = Config_getString(WARN_FORMAT);
44 g_warnLineFormat = Config_getString(WARN_LINE_FORMAT);
45 g_warnBehavior = Config_getEnum(WARN_AS_ERROR);
46 g_warnlogFile = Config_getString(WARN_LOGFILE);
47 if (g_warnlogFile.isEmpty() && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT)
48 {
49 uint32_t pid = Portable::pid();
50 g_warnlogFile.sprintf("doxygen_warnings_temp_%d.tmp",pid);
51 g_warnlogTemp = true;
52 }
53
54 if (!g_warnlogFile.isEmpty())
55 {
56 if (g_warnlogFile == "-")
57 {
58 g_warnFile = stdout;
59 }
60 else
61 {
62 FileInfo fi(g_warnlogFile.str());
63 Dir d(fi.dirPath().c_str());
64 if (!d.exists() && !d.mkdir(fi.dirPath().c_str()))
65 {
66 // point it to something valid, because warn() relies on it
67 g_warnFile = stderr;
68 err("Cannot create directory for '%s', redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile.data());
69 }
70 else if (!(g_warnFile = Portable::fopen(g_warnlogFile,"w")))
71 {
72 // point it to something valid, because warn() relies on it
73 g_warnFile = stderr;
74 err("Cannot open '%s' for writing, redirecting 'WARN_LOGFILE' output to 'stderr'\n",g_warnlogFile.data());
75 }
76 }
77 }
78 else
79 {
80 g_warnFile = stderr;
81 }
82 if (g_warnBehavior != WARN_AS_ERROR_t::NO)
83 {
85 }
86
87 // make sure the g_warnFile is closed in case we call exit and it is still open
88 std::atexit([](){
89 if (g_warnFile && g_warnFile!=stderr && g_warnFile!=stdout)
90 {
92 g_warnFile = nullptr;
93 }
94 });
95}
96
97
98void msg(const char *fmt, ...)
99{
100 if (!Config_getBool(QUIET))
101 {
102 std::unique_lock<std::mutex> lock(g_mutex);
104 {
105 printf("%.3f sec: ",(static_cast<double>(Debug::elapsedTime())));
106 }
107 va_list args;
108 va_start(args, fmt);
109 vfprintf(stdout, fmt, args);
110 va_end(args);
111 }
112}
113
114static void format_warn(const QCString &file,int line,const QCString &text)
115{
116 QCString fileSubst = file.isEmpty() ? "<unknown>" : file;
117 QCString lineSubst; lineSubst.setNum(line);
118 QCString textSubst = text;
119 QCString versionSubst;
120 // substitute markers by actual values
121 QCString msgText =
127 "$file",fileSubst
128 ),
129 "$line",lineSubst
130 ),
131 "$version",versionSubst
132 ),
133 "$text",textSubst
134 );
135 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
136 {
137 msgText += " (warning treated as error, aborting now)";
138 }
139 msgText += '\n';
140
141 {
142 std::unique_lock<std::mutex> lock(g_mutex);
143 // print resulting message
144 fwrite(msgText.data(),1,msgText.length(),g_warnFile);
145 }
146 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
147 {
148 if (g_warnFile != stderr && !Config_getBool(QUIET))
149 {
150 msg("See '%s' for the reason of termination.\n",qPrint(g_warnlogFile));
151 }
152 exit(1);
153 }
154 g_warnStat = true;
155}
156
158{
159 if (g_warnBehavior == WARN_AS_ERROR_t::YES)
160 {
161 {
162 std::unique_lock<std::mutex> lock(g_mutex);
163 QCString msgText = " (warning treated as error, aborting now)\n";
164 fwrite(msgText.data(),1,msgText.length(),g_warnFile);
165 if (g_warnFile != stderr && !Config_getBool(QUIET))
166 {
167 // cannot use `msg` due to the mutex
168 fprintf(stdout,"See '%s' for the reason of termination.\n",qPrint(g_warnlogFile));
169 }
170 }
171 exit(1);
172 }
173 g_warnStat = true;
174}
175
176static void do_warn(bool enabled, const QCString &file, int line, const char *prefix, const char *fmt, va_list args)
177{
178 if (!enabled) return; // warning type disabled
179
180 va_list argsCopy;
181 va_copy(argsCopy, args);
182
183 size_t l=0;
184 if (prefix)
185 {
186 l=strlen(prefix);
187 }
188 // determine needed buffersize based on:
189 // format + arguments
190 // prefix
191 // 1 position for `\0`
192 size_t bufSize = vsnprintf(nullptr, 0, fmt, args) + l;
193 QCString text(bufSize, QCString::ExplicitSize);
194 if (prefix)
195 {
196 qstrncpy(text.rawData(),prefix,bufSize);
197 }
198 vsnprintf(text.rawData()+l, bufSize-l+1, fmt, argsCopy);
199 text[bufSize]='\0';
200 format_warn(file,line,text);
201
202 va_end(argsCopy);
203}
204
205QCString warn_line(const QCString &file,int line)
206{
207 QCString fileSubst = file.isEmpty() ? "<unknown>" : file;
208 QCString lineSubst; lineSubst.setNum(line);
209 return substitute(
212 "$file",fileSubst
213 ),
214 "$line",lineSubst
215 );
216}
217void warn_(const QCString &file,int line,const char *fmt, ...)
218{
219 va_list args;
220 va_start(args, fmt);
221 do_warn(Config_getBool(WARNINGS), file, line, g_warningStr, fmt, args);
222 va_end(args);
223}
224
225void va_warn(const QCString &file,int line,const char *fmt,va_list args)
226{
227 do_warn(Config_getBool(WARNINGS), file, line, g_warningStr, fmt, args);
228}
229
230void warn_undoc_(const QCString &file,int line,const char *fmt, ...)
231{
232 va_list args;
233 va_start(args, fmt);
234 do_warn(Config_getBool(WARN_IF_UNDOCUMENTED), file, line, g_warningStr, fmt, args);
235 va_end(args);
236}
237
238void warn_incomplete_doc_(const QCString &file,int line,const char *fmt, ...)
239{
240 va_list args;
241 va_start(args, fmt);
242 do_warn(Config_getBool(WARN_IF_INCOMPLETE_DOC), file, line, g_warningStr, fmt, args);
243 va_end(args);
244}
245
246void warn_doc_error_(const QCString &file,int line,const char *fmt, ...)
247{
248 va_list args;
249 va_start(args, fmt);
250 do_warn(Config_getBool(WARN_IF_DOC_ERROR), file, line, g_warningStr, fmt, args);
251 va_end(args);
252}
253
254void warn_uncond_(const char *fmt, ...)
255{
256 va_list args;
257 va_start(args, fmt);
258 vfprintf(g_warnFile, (QCString(g_warningStr) + fmt).data(), args);
259 va_end(args);
261}
262
263void err_(const char *fmt, ...)
264{
265 va_list args;
266 va_start(args, fmt);
267 vfprintf(g_warnFile, (QCString(g_errorStr) + fmt).data(), args);
268 va_end(args);
270}
271
272extern void err_full_(const QCString &file,int line,const char *fmt, ...)
273{
274 va_list args;
275 va_start(args, fmt);
276 do_warn(TRUE, file, line, g_errorStr, fmt, args);
277 va_end(args);
278}
279
280void term_(const char *fmt, ...)
281{
282 {
283 std::unique_lock<std::mutex> lock(g_mutex);
284 va_list args;
285 va_start(args, fmt);
286 vfprintf(g_warnFile, (QCString(g_errorStr) + fmt).data(), args);
287 va_end(args);
288 if (g_warnFile != stderr)
289 {
290 size_t l = strlen(g_errorStr);
291 for (size_t i=0; i<l; i++) fprintf(g_warnFile, " ");
292 fprintf(g_warnFile, "%s\n", "Exiting...");
293 if (!Config_getBool(QUIET))
294 {
295 // cannot use `msg` due to the mutex
296 fprintf(stdout,"See '%s' for the reason of termination.\n",qPrint(g_warnlogFile));
297 }
298 }
299 }
300 exit(1);
301}
302
304{
305 fflush(g_warnFile);
306}
307
308
309
310extern void finishWarnExit()
311{
312 fflush(stdout);
313 if (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
314 {
316 g_warnFile = nullptr;
317 }
318 if (g_warnStat && g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT && g_warnlogFile != "-")
319 {
320
321 std::ifstream warnFile = Portable::openInputStream(g_warnlogFile);
322 if (!warnFile.is_open())
323 {
324 g_warnFile = stderr;
325 err("Cannot open warnings file '%s' for reading\n",g_warnlogFile.data());
326 }
327 else
328 {
329 std::string line;
330 while (getline(warnFile,line))
331 {
332 fprintf(stderr,"%s\n",line.c_str());
333 }
334 warnFile.close();
335 }
336 }
337
339
340 if (g_warnStat && (g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS ||
341 g_warnBehavior == WARN_AS_ERROR_t::FAIL_ON_WARNINGS_PRINT))
342 {
343 exit(1);
344 }
345}
constexpr auto prefix
Definition anchor.cpp:44
@ Time
Definition debug.h:34
static bool isFlagSet(const DebugMask mask)
Definition debug.cpp:135
static double elapsedTime()
Definition debug.cpp:204
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
char * rawData()
Returns a writable pointer to the data.
Definition qcstring.h:165
bool isEmpty() const
Returns TRUE iff the string is empty.
Definition qcstring.h:150
QCString & setNum(short n)
Definition qcstring.h:444
@ ExplicitSize
Definition qcstring.h:133
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_(const char *fmt,...)
Definition message.cpp:263
void warn_uncond_(const char *fmt,...)
Definition message.cpp:254
QCString warn_line(const QCString &file, int line)
Definition message.cpp:205
void err_full_(const QCString &file, int line, const char *fmt,...)
Definition message.cpp:272
static bool g_warnlogTemp
Definition message.cpp:37
static QCString g_warnLineFormat
Definition message.cpp:31
static std::atomic_bool g_warnStat
Definition message.cpp:38
void warn_(const QCString &file, int line, const char *fmt,...)
Definition message.cpp:217
void warn_incomplete_doc_(const QCString &file, int line, const char *fmt,...)
Definition message.cpp:238
static const char * g_errorStr
Definition message.cpp:33
static WARN_AS_ERROR_t g_warnBehavior
Definition message.cpp:35
void va_warn(const QCString &file, int line, const char *fmt, va_list args)
Definition message.cpp:225
static const char * g_warningStr
Definition message.cpp:32
void initWarningFormat()
Definition message.cpp:41
static QCString g_warnFormat
Definition message.cpp:30
void warn_flush()
Definition message.cpp:303
void warn_doc_error_(const QCString &file, int line, const char *fmt,...)
Definition message.cpp:246
void msg(const char *fmt,...)
Definition message.cpp:98
static std::mutex g_mutex
Definition message.cpp:39
void warn_undoc_(const QCString &file, int line, const char *fmt,...)
Definition message.cpp:230
static FILE * g_warnFile
Definition message.cpp:34
void term_(const char *fmt,...)
Definition message.cpp:280
static void format_warn(const QCString &file, int line, const QCString &text)
Definition message.cpp:114
void finishWarnExit()
Definition message.cpp:310
static void handle_warn_as_error()
Definition message.cpp:157
static QCString g_warnlogFile
Definition message.cpp:36
static void do_warn(bool enabled, const QCString &file, int line, const char *prefix, const char *fmt, va_list args)
Definition message.cpp:176
#define err(fmt,...)
Definition message.h:84
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 trace.h:153
Portable versions of functions that are platform dependent.
char * qstrncpy(char *dst, const char *src, size_t len)
Definition qcstring.cpp:432
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
#define TRUE
Definition qcstring.h:37