summaryrefslogtreecommitdiff
path: root/src/common/fqterm_trace.h
diff options
context:
space:
mode:
authoriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
committeriroul <iroul@iroul-VirtualBox.(none)>2014-04-04 07:35:14 -0700
commitafd34f2893a06a3aecf17e8e83b1df6ed2ae91a2 (patch)
tree851102abc55d91a1b76e63e9e89f9a7733da95b5 /src/common/fqterm_trace.h
parentc4b028ad53f7b362a864de24828d7cc39ff67b0a (diff)
downloadfqterm-afd34f2893a06a3aecf17e8e83b1df6ed2ae91a2.tar.xz
move to my github.
Diffstat (limited to 'src/common/fqterm_trace.h')
-rw-r--r--src/common/fqterm_trace.h331
1 files changed, 331 insertions, 0 deletions
diff --git a/src/common/fqterm_trace.h b/src/common/fqterm_trace.h
new file mode 100644
index 0000000..287a8a8
--- /dev/null
+++ b/src/common/fqterm_trace.h
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * fqterm, a terminal emulator for both BBS and *nix. *
+ * Copyright (C) 2008 fqterm development group. *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program; if not, write to the *
+ * Free Software Foundation, Inc., *
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. *
+ ***************************************************************************/
+
+#ifndef FQTERM_TRACE_H
+#define FQTERM_TRACE_H
+
+#include <cassert>
+#ifndef WIN32
+#include <unistd.h>
+#endif // WIN32
+
+#include <QtDebug>
+#include <QFileInfo>
+
+namespace FQTerm {
+
+// define NO_FQTERM_TRACE to avoid all trace output.
+// #define NO_FQTERM_TRACE
+
+// define NO_FQTERM_TRACE_FILE_LINE_NUM to avoid file line number in trace
+// output.
+
+// define NO_FQTERM_TRACE_FUNCTION_NAME to avoid function name in trace output.
+// define integer FQTERM_MAX_TRACE_LEVEL to determine the maximize outputed
+// trace level.
+//#define NO_FQTERM_TRACE
+#if defined(NDEBUG)
+#define FQTERM_MAX_TRACE_LEVEL 1
+#endif
+
+#ifndef FQTERM_MAX_TRACE_LEVEL
+#define FQTERM_MAX_TRACE_LEVEL 20
+#endif // FQTERM_MAX_TRACE_LEVEL
+
+int getMaxTraceLevel();
+
+void setMaxTraceLevel(int max_trace_level);
+
+long long getTraceTime();
+
+int isAllowedCategory(const char *category, int trace_level);
+
+void addAllowedCategory(const char *category);
+
+static void soft_break() {
+#if defined(WIN32)
+ __asm int 03h;
+#else
+ pause();
+#endif
+}
+
+template<int trace_level>
+class FQTermTrace {
+ public:
+ FQTermTrace(const char *category, const char *file_name, int line_num, const char *func_name)
+ : category_(category),
+ is_dummy_(!isAllowedCategory(category, trace_level)),
+ trace_output_((trace_level <= FQTERM_MAX_TRACE_LEVEL
+ && trace_level <= getMaxTraceLevel())
+ ? new QDebug(qDebug().nospace())
+ : NULL),
+ dump_string_(false) {
+
+ if (is_dummy_) return;
+
+#ifdef NO_FQTERM_TRACE_FILE_LINE_NUM
+#ifdef NO_FQTERM_TRACE_FUNCTION_NAME
+ return;
+#endif // NO_FQTERM_TRACE_FUNCTION_NAME
+#endif // NO_FQTERM_TRACE_FILE_LINE_NUM
+
+ (*this) << "[" << category_ << " " << trace_level << " ";
+
+#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM
+ (*this) << QFileInfo(file_name).fileName().toAscii().constData()
+ << ": " << line_num;
+#endif // NO_FQTERM_TRACE_FILE_LINE_NUM
+
+#ifndef NO_FQTERM_TRACE_FUNCTION_NAME
+#ifndef NO_FQTERM_TRACE_FILE_LINE_NUM
+ (*this) << ", ";
+#endif // NO_FQTERM_TRACE_FILE_LINE_NUM
+ (*this) << func_name;
+#endif // NO_FQTERM_TRACE_FUNCTION_NAME
+
+ (*this) << "] ";
+ }
+
+ ~FQTermTrace() {
+ if (is_dummy_) return;
+
+ if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) {
+ delete trace_output_;
+
+ if (trace_level < 0) {
+ soft_break();
+ assert(false);
+ qFatal("Fatal error occured!\n");
+ }
+ }
+ }
+
+ template<class T>
+ FQTermTrace &operator << (const T &t) {
+ if (is_dummy_) return *this;
+
+ if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) {
+ *trace_output_ << t;
+ }
+ return *this;
+ }
+
+ FQTermTrace &operator << (const std::string &t) {
+ return output_raw_string(t);
+ }
+
+ FQTermTrace &operator << (const char *t) {
+ return output_raw_string(t);
+ }
+
+ FQTermTrace &operator << (void (*setter)(FQTermTrace<trace_level> &)) {
+ (*setter)(*this);
+ return *this;
+ }
+
+ private:
+ FQTermTrace &output_raw_string(const std::string &t) {
+ if (is_dummy_) return *this;
+
+ if (trace_level <= FQTERM_MAX_TRACE_LEVEL && trace_level <= getMaxTraceLevel()) {
+ if (!dump_string_) {
+ for (std::string::size_type i = 0; i < t.size(); ++i) {
+ *trace_output_ << t[i];
+ }
+ } else {
+ for (std::string::size_type i = 0; i < t.size(); ++i) {
+ unsigned char a = t[i];
+ unsigned char b = a / 0x10;
+ unsigned char c = a % 0x10;
+ char h = (char) (b < 10 ? '0' + b : 'A' + b - 10);
+ char l = (char) (c < 10 ? '0' + c : 'A' + c - 10);
+
+ *trace_output_ << h << l << ' ';
+ }
+ }
+ }
+ return *this;
+ }
+
+ private:
+ const char *category_;
+ bool is_dummy_;
+ QDebug *trace_output_;
+
+ public:
+ bool dump_string_; // whether we print string in hex mode.
+
+};
+
+template<int trace_level>
+class FQTermDummyTrace {
+ public:
+ template<class T>
+ FQTermDummyTrace &operator << (const T &) {
+ return *this;
+ }
+
+ FQTermDummyTrace &operator << (void (*setter)(FQTermTrace<trace_level> &)) {
+ return *this;
+ }
+};
+
+template<int trace_level>
+void dumpHexString(FQTermTrace<trace_level> &tracer) {
+ tracer.dump_string_ = true;
+}
+
+template<int trace_level>
+void dumpNormalString(FQTermTrace<trace_level> &tracer) {
+ tracer.dump_string_ = false;
+}
+
+template<int trace_level>
+class FQTermScopeTrace {
+ public:
+ FQTermScopeTrace(const char *category, const char *file_name, int line_num,
+ const char *func_name, const char *scope_name)
+ : category_(category),
+ is_dummy_(!isAllowedCategory(category, trace_level)),
+ file_name_(file_name),
+ line_num_(line_num),
+ func_name_(func_name),
+ scope_name_(scope_name) {
+ if (is_dummy_) return;
+ FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_)
+ << "Entering " << scope_name_;
+ }
+
+ ~FQTermScopeTrace() {
+ if (is_dummy_) return;
+ FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_)
+ << "Leaving " << scope_name_;
+ }
+
+ private:
+ const char *category_;
+ bool is_dummy_;
+
+ const char *file_name_;
+ const int line_num_;
+ const char *func_name_;
+ const char *scope_name_;
+};
+
+template<int trace_level>
+class FQTermTimerTrace {
+ public:
+ FQTermTimerTrace(const char *category, const char *file_name, int line_num,
+ const char *func_name, const char *msg)
+ : category_(category),
+ is_dummy_(!isAllowedCategory(category, trace_level)),
+ file_name_(file_name),
+ line_num_(line_num),
+ func_name_(func_name),
+ msg_(msg),
+ start_time(is_dummy_? 0: getTraceTime()) {
+ }
+
+ ~FQTermTimerTrace() {
+ if (is_dummy_) return;
+
+ long long total_time = getTraceTime() - start_time;
+
+ long long num_sec = total_time / 1000;
+ long long num_ms = total_time % 1000;
+
+ FQTermTrace<trace_level>(category_, file_name_, line_num_, func_name_)
+ << msg_ << num_sec << "s" << num_ms << "ms";
+ }
+
+ private:
+ const char *category_;
+ bool is_dummy_;
+
+ const char *file_name_;
+ const int line_num_;
+ const char *func_name_;
+ const char *msg_;
+
+ long long start_time; // in millisecond.
+};
+
+// Some macros work in both debug & release version.
+#define FQ_FATAL(file, line, func) \
+ do {FQTerm::soft_break(); qFatal("%s", (QString(file) + ": %1 " + QString(func)).arg(line).toUtf8().constData());} while(false)
+
+#define FQ_VERIFY(expr) do { \
+ if(!(expr)) { \
+ FQ_FATAL(__FILE__, __LINE__, __FUNCTION__); \
+ } \
+ } while(false)
+
+
+
+#ifdef NO_FQTERM_TRACE
+
+#define FQ_TRACE(category, trace_level) FQTermDummyTrace<trace_level>()
+#define FQ_SCOPE_TRACE(category, trace_level, scope_name) do {} while (false)
+#define FQ_FUNC_TRACE(category, trace_level) do {} while(false)
+
+#define FQ_ASSERT(expr) do {} while(false)
+
+#define FQ_SCOPE_TIMER(category, trace_level, msg) do {} while(false)
+#define FQ_FUNC_TIMER(category, trace_level) do {} while(false)
+
+
+#else // NO_FQTERM_TRACE
+
+#define FQ_TRACE(category, trace_level) \
+ FQTermTrace<trace_level>(category, __FILE__, __LINE__, __FUNCTION__)
+
+#define FQ_SCOPE_TRACE_PRIVATE(file, line, func, category, trace_level, scope_name) \
+ FQTermScopeTrace<trace_level> file##line##func(category, file, line, func, scope_name);
+
+#define FQ_SCOPE_TRACE(category, trace_level, scope_name) \
+ FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, scope_name)
+
+#define FQ_FUNC_TRACE(category, trace_level) \
+ FQ_SCOPE_TRACE_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "function")
+
+
+#define FQ_ASSERT(expr) \
+ do {if(!(expr)) {FQ_TRACE("assert", -1) << "assertion failed." << #expr;}} while(false)
+
+
+#define FQ_SCOPE_TIMER_PRIVATE(file, line, func, category, trace_level, msg) \
+ FQTermTimerTrace<trace_level> file##line##func(category, file, line, func, msg);
+
+#define FQ_SCOPE_TIMER(category, trace_level, msg) \
+ FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, msg)
+
+#define FQ_FUNC_TIMER(category, trace_level) \
+ FQ_SCOPE_TIMER_PRIVATE(__FILE__, __LINE__, __FUNCTION__, category, trace_level, "The function runs for ")
+
+
+#endif // NO_FQTERM_TRACE
+
+
+const char *getEventName(unsigned int type);
+
+} // namespace FQTerm
+
+#endif // FQTERM_TRACE_H