--- /dev/null
+#ifndef CALLSTACK_TRACKER_CLASS
+#define CALLSTACK_TRACKER_CLASS
+
+/*****************************************************************************\
+* *
+* Name : callstack_tracker *
+* Author : Chris Koeritz *
+* *
+*******************************************************************************
+* Copyright (c) 2007-$now By Author. 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 is online at: *
+* http://www.fsf.org/copyleft/gpl.html *
+* Please send any updates to: fred@gruntose.com *
+\*****************************************************************************/
+
+#include "definitions.h"
+
+#ifdef ENABLE_CALLSTACK_TRACKING
+
+#include "build_configuration.h"
+#include "root_object.h"
+
+namespace application {
+
+// forward.
+class callstack_records;
+class callstack_tracker;
+
+//////////////
+
+callstack_tracker BASIS_EXTERN &program_wide_stack_trace();
+ //!< a global object that can be used to track the runtime callstack.
+
+//////////////
+
+//! This object can provide a backtrace at runtime of the invoking methods.
+/*!
+ The callstack tracking is hooked in through the FUNCDEF macros used to
+ set function names for logging. Thus it will only be visible if those
+ macros are used fairly carefully or if people invoke the stack frame addition
+ method themselves.
+*/
+
+class callstack_tracker
+{
+public:
+ callstack_tracker();
+ virtual ~callstack_tracker();
+
+ DEFINE_CLASS_NAME("callstack_tracker");
+
+ bool push_frame(const char *class_name, const char *func, const char *file,
+ int line);
+ //!< adds a new stack from for the "class_name" in "function" at the "line".
+ /*!< this function should be invoked when entering a new stack frame. the
+ "file" can be gotten from the __FILE__ macro and the "line" number can come
+ from __LINE__, but the "class_name" and "func" must be tracked some other
+ way. we recommend the FUNCDEF macro. this function might return false if
+ there is no longer any room for tracking more frames; that is a serious
+ issue that might indicate a runaway recursion or infinite loop. */
+
+ bool pop_frame();
+ //!< removes the last callstack frame off from our tracking.
+
+ bool update_line(int line);
+ //!< sets the line number within the current stack frame.
+ /*!< the current frame can reside across several line numbers, so this
+ allows the code to be more specific about the location of an invocation. */
+
+ char *full_trace() const;
+ //!< provides the current stack trace in a newly malloc'd string.
+ /*!< the user *must* free() the string returned. */
+
+ int full_trace_size() const;
+ //!< this returns the number of bytes needed for the above full_trace().
+
+ int depth() const { return _depth; }
+ //!< the current number of frames we know of.
+
+ double frames_in() const { return _frames_in; }
+ //!< reports the number of call stack frames that were added, total.
+
+ double frames_out() const { return _frames_out; }
+ //!< reports the number of call stack frames that were removed, total.
+
+ double highest() const { return _highest; }
+ //!< reports the maximum stack depth seen during the runtime so far.
+
+private:
+ callstack_records *_bt; //!< the backtrace records for current program.
+ int _depth; //!< the current number of frames we know of.
+ double _frames_in; //!< number of frame additions.
+ double _frames_out; //!< number of frame removals.
+ double _highest; //!< the most number of frames in play at once.
+ bool _unusable; //!< object has already been destroyed.
+};
+
+//////////////
+
+//! a small object that represents a stack trace in progress.
+/*! the object will automatically be destroyed when the containing scope
+exits. this enables a users of the stack tracker to simply label their
+function name and get the frame added. if they want finer grained tracking,
+they should update the line number periodically through their function,
+especially when memory is about to be allocated or where something might go
+wrong. */
+
+class frame_tracking_instance
+{
+public:
+ // these are not encapsulated, but be careful with the contents.
+ bool _frame_involved; //!< has this object been added to the tracker?
+ char *_class, *_func, *_file; //!< newly allocated copies.
+ int _line;
+
+ frame_tracking_instance(const char *class_name = "", const char *func = "",
+ const char *file = "", int line = 0, bool add_frame = false);
+ //!< as an automatic variable, this can hang onto frame information.
+ /*!< if "add_frame" is true, then this actually adds the stack frame in
+ question to the tracker. thus if you use this class at the top of your
+ function, such as via the FUNCDEF macro, then you can forget about having
+ to pop the frame later. */
+
+ frame_tracking_instance(const frame_tracking_instance &to_copy);
+
+ ~frame_tracking_instance();
+ //!< releases the information *and* this stack frame in the tracker.
+
+ frame_tracking_instance &operator =(const frame_tracking_instance &to_copy);
+
+ void assign(const char *class_name, const char *func, const char *file,
+ int line);
+ //!< similar to assignment operator but doesn't require an object.
+
+ void clean();
+ //!< throws out our accumulated memory and pops frame if applicable.
+};
+
+void update_current_stack_frame_line_number(int line);
+ //!< sets the line number for the current frame in the global stack trace.
+
+#else // ENABLE_CALLSTACK_TRACKING
+ // bogus replacements for most commonly used callstack tracking support.
+ #define frame_tracking_instance
+ #define __trail_of_function(p1, p2, p3, p4, p5) if (func) {}
+ // the above actually trades on the name of the object we'd normally
+ // define. it must match the object name in the FUNCDEF macro.
+ #define update_current_stack_frame_line_number(line)
+#endif // ENABLE_CALLSTACK_TRACKING
+
+} //namespace.
+
+#endif // outer guard.
+