/****************************************************************************** * * Copyright (C) 1997-2020 by Dimitri van Heesch. * * Permission to use, copy, modify, and distribute this software and its * documentation under the terms of the GNU General Public License is hereby * granted. No representations are made about the suitability of this software * for any purpose. It is provided "as is" without express or implied warranty. * See the GNU General Public License for more details. * * Documents produced by Doxygen are derivative works derived from the * input used in their production; they are not affected by this license. * */ #include #include "config.h" #include "debug.h" #include "portable.h" #include "message.h" #include "doxygen.h" #include static QCString outputFormat; static const char *warning_str = "warning: "; static const char *error_str = "error: "; //static int warnFormatOrder; // 1 = $file,$line,$text // // 2 = $text,$line,$file // // 3 = $line,$text,$file // // 4 = $file,$text,$line // // 5 = $text,$file,$line // // 6 = $line,$file,$text static FILE *warnFile = stderr; enum warn_as_error { WARN_NO, WARN_YES, FAIL_ON_WARNINGS, }; static warn_as_error warnBehavior = WARN_NO; static bool warnStat = false; static std::mutex g_mutex; void initWarningFormat() { // int filePos = Config_getString(WARN_FORMAT).find("$file"); // int linePos = Config_getString(WARN_FORMAT).find("$line"); // int textPos = Config_getString(WARN_FORMAT).find("$text"); // // // sort items on position (there are 6 cases) // warnFormatOrder = 1; // if (filePos>linePos && filePos>textPos) // { // if (linePos>textPos) // $text,$line,$file // { // warnFormatOrder = 2; // } // else // $line,$text,$file // { // warnFormatOrder = 3; // } // } // else if (filePostextPos) // $file,$text,$line // { // warnFormatOrder = 4; // } // } // else if (filePostextPos) // $text,$file,$line // { // warnFormatOrder = 5; // } // else // $line,$file,$text // { // warnFormatOrder = 6; // } // outputFormat = // substitute( // substitute( // substitute( // Config_getString(WARN_FORMAT), // "$file","%s" // ), // "$text","%s" // ), // "$line","%d" // )+'\n'; // replace(QRegExp("\\$file"),"%s"). // replace(QRegExp("\\$text"),"%s"). // replace(QRegExp("\\$line"),"%d")+ // '\n'; outputFormat = Config_getString(WARN_FORMAT); if (!Config_getString(WARN_LOGFILE).isEmpty()) { warnFile = Portable::fopen(Config_getString(WARN_LOGFILE),"w"); } if (!warnFile) // point it to something valid, because warn() relies on it { warnFile = stderr; } QCString warnStr = Config_getEnum(WARN_AS_ERROR).upper(); if (warnStr =="NO") warnBehavior=WARN_NO; else if (warnStr =="YES") warnBehavior=WARN_YES; else if (warnStr =="FAIL_ON_WARNINGS") warnBehavior=FAIL_ON_WARNINGS; if (warnBehavior == WARN_YES) { warning_str = error_str; } } void msg(const char *fmt, ...) { if (!Config_getBool(QUIET)) { std::unique_lock lock(g_mutex); if (Debug::isFlagSet(Debug::Time)) { printf("%.3f sec: ",((double)Debug::elapsedTime())); } va_list args; va_start(args, fmt); vfprintf(stdout, fmt, args); va_end(args); } } static void format_warn(const char *file,int line,const char *text) { QCString fileSubst = file==0 ? "" : file; QCString lineSubst; lineSubst.setNum(line); QCString textSubst = text; QCString versionSubst; // substitute markers by actual values QCString msgText = substitute( substitute( substitute( substitute( outputFormat, "$file",fileSubst ), "$line",lineSubst ), "$version",versionSubst ), "$text",textSubst ); if (warnBehavior == WARN_YES) { msgText += " (warning treated as error, aborting now)"; } msgText += '\n'; { std::unique_lock lock(g_mutex); // print resulting message fwrite(msgText.data(),1,msgText.length(),warnFile); } if (warnBehavior == WARN_YES) { exit(1); } warnStat = true; } static void handle_warn_as_error() { if (warnBehavior == WARN_YES) { std::unique_lock lock(g_mutex); QCString msgText = " (warning treated as error, aborting now)\n"; fwrite(msgText.data(),1,msgText.length(),warnFile); exit(1); } warnStat = true; } static void do_warn(bool enabled, const char *file, int line, const char *prefix, const char *fmt, va_list args) { if (!enabled) return; // warning type disabled va_list argsCopy; va_copy(argsCopy, args); int l=0; if (prefix) { l=(int)strlen(prefix); } // determine needed buffersize based on: // format + arguments // prefix // 1 position for `\0` int bufSize = vsnprintf(NULL, 0, fmt, args) + l + 1; char *text = (char *)malloc(sizeof(char) * bufSize); if (prefix) { qstrncpy(text,prefix,bufSize); } vsnprintf(text+l, bufSize-l, fmt, argsCopy); text[bufSize-1]='\0'; format_warn(file,line,text); free(text); } void warn(const char *file,int line,const char *fmt, ...) { va_list args; va_start(args, fmt); do_warn(Config_getBool(WARNINGS), file, line, warning_str, fmt, args); va_end(args); } void va_warn(const char *file,int line,const char *fmt,va_list args) { do_warn(Config_getBool(WARNINGS), file, line, warning_str, fmt, args); } void warn_simple(const char *file,int line,const char *text) { if (!Config_getBool(WARNINGS)) return; // warning type disabled format_warn(file,line,QCString(warning_str) + text); } void warn_undoc(const char *file,int line,const char *fmt, ...) { va_list args; va_start(args, fmt); do_warn(Config_getBool(WARN_IF_UNDOCUMENTED), file, line, warning_str, fmt, args); va_end(args); } void warn_doc_error(const char *file,int line,const char *fmt, ...) { va_list args; va_start(args, fmt); do_warn(Config_getBool(WARN_IF_DOC_ERROR), file, line, warning_str, fmt, args); va_end(args); } void warn_uncond(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(warnFile, (QCString(warning_str) + fmt).data(), args); va_end(args); handle_warn_as_error(); } void err(const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(warnFile, (QCString(error_str) + fmt).data(), args); va_end(args); handle_warn_as_error(); } extern void err_full(const char *file,int line,const char *fmt, ...) { va_list args; va_start(args, fmt); do_warn(TRUE, file, line, error_str, fmt, args); va_end(args); } void term(const char *fmt, ...) { { std::unique_lock lock(g_mutex); va_list args; va_start(args, fmt); vfprintf(warnFile, (QCString(error_str) + fmt).data(), args); va_end(args); if (warnFile != stderr) { for (int i = 0; i < (int)strlen(error_str); i++) fprintf(warnFile, " "); fprintf(warnFile, "%s\n", "Exiting..."); } } exit(1); } void warn_flush() { fflush(warnFile); } void printlex(int dbg, bool enter, const char *lexName, const char *fileName) { const char *enter_txt = "entering"; const char *enter_txt_uc = "Entering"; if (!enter) { enter_txt = "finished"; enter_txt_uc = "Finished"; } std::unique_lock lock(g_mutex); if (dbg) { if (fileName) fprintf(stderr,"--%s lexical analyzer: %s (for: %s)\n",enter_txt, qPrint(lexName), qPrint(fileName)); else fprintf(stderr,"--%s lexical analyzer: %s\n",enter_txt, qPrint(lexName)); } else { if (fileName) Debug::print(Debug::Lex,0,"%s lexical analyzer: %s (for: %s)\n",enter_txt_uc, qPrint(lexName), qPrint(fileName)); else Debug::print(Debug::Lex,0,"%s lexical analyzer: %s\n",enter_txt_uc, qPrint(lexName)); } } extern void finishWarnExit() { if (warnStat && warnBehavior == FAIL_ON_WARNINGS) { exit(1); } }