// balst_stacktraceprintutil.h                                        -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#ifndef INCLUDED_BALST_STACKTRACEPRINTUTIL
#define INCLUDED_BALST_STACKTRACEPRINTUTIL

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a single function to perform and print a stack trace.
//
//@CLASSES:
//  balst::StackTracePrintUtil: namespace for functions to print a stack trace
//
//@SEE_ALSO: balst_stacktraceutil
//
//@DESCRIPTION: This component defines a namespace 'struct',
// 'balst::StackTracePrintUtil', containing static platform-independent
// functions that will perform a stack trace and print it to a supplied stream.
// Not all properties of a stack trace are printed on all platforms because the
// set of properties describing a stack trace that are obtainable varies
// according to both the platform and build parameters.  For example, on
// Solaris, source file names and line numbers are not provided.  Function
// names and addresses are provided on all platforms.  The 'printStackTrace'
// function always prints a description of the stack of the calling thread.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Printing a Stack Trace
///- - - - - - - - - - - - - - - - -
// This example shows how to obtain a stack trace and print it to a stream, all
// by calling just the static function
// 'balst::StackTracePrintUtil::printStackTrace'.
//
// First, we define a recursive function 'recurseAndPrintStack' that recurses
// to the specified 'depth', then calls
// 'balst::StackTracePrintUtil::printStackTrace' to obtain a stack trace and
// print it to 'cout'.  When we call 'printStackTrace', neither of the optional
// arguments corresponding to 'maxFrames' or 'demanglingPreferredFlag' are
// supplied; 'maxFrames' defaults to at least 1024 (which is more than we
// need), and 'demanglingPreferredFlag' defaults to 'true'.
//..
//  static
//  void recurseAndPrintStack(int *depth)
//      // Recurse to the specified 'depth', then print out the stack trace to
//      // 'cout'.
//  {
//      if (--*depth > 0) {
//          recurseAndPrintStack(depth);
//      }
//      else {
//          balst::StackTracePrintUtil::printStackTrace(cout);
//      }
//
//      ++*depth;   // Prevent compiler from optimizing tail recursion as a
//                  // loop.
//  }
//..
// Then, we call 'recurseAndPrintStack' from the main program.
//..
//  int main()
//  {
//      int depth = 5;
//      recurseAndPrintStack(&depth);
//      assert(5 == depth);
//  }
//..
// Now, invoking the main program on AIX produces the following output:
//..
//  (0): BloombergLP::balst::StackTracePrintUtil::.printStackTrace(
//       std::basic_ostream<char,std::char_traits<char> >&,int,bool)+0x170 at
//       0x1000a2c8 source:balst_stacktraceprintutil.cpp:52 in
//       balst_stacktraceprintutil.t.dbg_
//  (1): .recurseAndPrintStack(int*)+0x58 at 0x1000a118
//       source:balst_stacktraceprintutil.t.cpp:652 in
//       balst_stacktraceprintutil.t.dbg_
//  (2): .recurseAndPrintStack(int*)+0x40 at 0x1000a100
//       source:balst_stacktraceprintutil.t.cpp:650
//       in balst_stacktraceprintutil.t.dbg_
//  (3): .recurseAndPrintStack(int*)+0x40 at 0x1000a100
//       source:balst_stacktraceprintutil.t.cpp:650 in
//       balst_stacktraceprintutil.t.dbg_
//  (4): .recurseAndPrintStack(int*)+0x40 at 0x1000a100
//       source:balst_stacktraceprintutil.t.cpp:650 in
//       balst_stacktraceprintutil.t.dbg_
//  (5): .recurseAndPrintStack(int*)+0x40 at 0x1000a100
//       source:balst_stacktraceprintutil.t.cpp:650 in
//       balst_stacktraceprintutil.t.dbg_
//  (6): .main+0x2f4 at 0x10000a4c source:balst_stacktraceprintutil.t.cpp:724
//       in balst_stacktraceprintutil.t.dbg_
//  (7): .__start+0x6c at 0x1000020c source:crt0main.s in
//       balst_stacktraceprintutil.t.dbg_
//..
// Finally, we observe the following about the above output to 'cout'.  Notice
// that since the actual output would write each stack trace frame all on a
// single line, and all the lines here were longer than 80 characters, it has
// been manually edited to wrap and have every line be less than 80 columns.
// Also note the program name is truncated to 32 characters in length.

#include <balscm_version.h>

#include <bslma_allocator.h>
#include <bslma_defaultallocatorguard.h>

#include <bsl_iosfwd.h>
#include <bsl_sstream.h>
#include <bsl_string.h>

namespace BloombergLP {

namespace balst {
                         // =========================
                         // class StackTracePrintUtil
                         // =========================

struct StackTracePrintUtil {
    // This 'struct' serves as a namespace for static methods that perform and
    // print a description of a stack trace.

    // CLASS METHODS
    static bsl::ostream& printStackTrace(
                                 bsl::ostream& stream,
                                 int           maxFrames = -1,
                                 bool          demanglingPreferredFlag = true,
                                 int           additionalIgnoreFrames = 0);
        // Obtain a trace of the stack and print it to the specified 'stream'.
        // Optionally specify 'maxFrames' indicating the maximum number of
        // frames from the top of the stack that will be printed.  If
        // 'maxFrames' is not specified, a value of at least 1024 is used.
        // Optionally specify 'demanglingPreferredFlag', indicating a
        // preference whether to attempt to demangle function names.  If
        // 'damanglingPreferredFlag' is not specified, an attempt to demangle
        // is assumed.  If an error occurs, a single-line error message is
        // printed to 'stream'.  Optionally specify 'additionalIgnoreFrames'
        // which is added to 'bsls::StackAddressUtil::k_IGNORE_FRAMES' to
        // ignore frames of the caller.  Return a reference to 'stream.  The
        // behavior is undefined unless '-1 <= maxFrames' and
        // '0 <= additionalIgnoreFrames'.  Note that attempting to demangle
        // symbol names could involve calling 'malloc', and that symbol names
        // are always demangled on the Windows platform.
};

                       // ==============================
                       // class StackTracePrintUtil_Test
                       // ==============================

struct StackTracePrintUtil_Test {
    // This 'struct' is not intended for use by clients of this component; it
    // exists only for testing purposes.

    // CLASS METHODS
    static void printStackTraceToString(bsl::string *string);
        // Obtain a stack trace and assign a description of the stack to the
        // specified 'string'.  Note that this method is for testing only, and
        // must be declared inline in an include file in order to test source
        // file name resolution of a routine in an include file.
};

// ============================================================================
//                        INLINE FUNCTION DEFINITIONS
// ============================================================================

                      // -------------------------------
                      // struct StackTracePrintUtil_Test
                      // -------------------------------

// CLASS METHOD
inline
void StackTracePrintUtil_Test::printStackTraceToString(bsl::string *string)
{
    bslma::Allocator *a = string->get_allocator().mechanism();
    bslma::DefaultAllocatorGuard guard(a);

    bsl::ostringstream os;
    StackTracePrintUtil::printStackTrace(os);
    *string = os.str();
}

}  // close package namespace
}  // close enterprise namespace

#endif

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------