<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/decryptemailcommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra 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.

    Kleopatra 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 Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "decryptcommand.h"
#include "assuancommandprivatebase_p.h"

#include <QObject>
#include <QIODevice>
#include <QHash>
#include <QStringList>
#include <QDebug>

#include <kleo/decryptjob.h>

#include <gpgme++/error.h>
#include <gpgme++/decryptionresult.h>

#include <gpg-error.h>

#include <cassert>

using namespace Kleo;

class DecryptionResultCollector : public QObject
{
    Q_OBJECT
public:
    explicit DecryptionResultCollector( QObject* parent = 0 );

    struct Result {
        QString id;
        GpgME::DecryptionResult result;
        QByteArray stuff;
    };

    void registerJob( const QString& id, DecryptJob* job );
Q_SIGNALS:
    void finished( const QHash<QString, DecryptionResultCollector::Result> & );

private Q_SLOTS:
    void slotDecryptResult(const GpgME::DecryptionResult &, const QByteArray &);

private:
    QHash<QString, Result> m_results;
    QHash<QObject*, QString> m_senderToId;
    int m_unfinished;
};

DecryptionResultCollector::DecryptionResultCollector( QObject* parent )
: QObject( parent ), m_unfinished( 0 )
{
}

void DecryptionResultCollector::registerJob( const QString& id, DecryptJob* job )
{
    connect( job, SIGNAL( result( GpgME::DecryptionResult,QByteArray ) ),
             this, SLOT( slotDecryptResult( GpgME::DecryptionResult, QByteArray ) ) );
    m_senderToId[job] = id;
    ++m_unfinished;
}

void DecryptionResultCollector::slotDecryptResult(const GpgME::DecryptionResult & result,
                                                  const QByteArray & stuff )
{
    assert( m_senderToId.contains( sender( ) ) );
    const QString id = m_senderToId[sender()];

    Result res;
    res.id = id;
    res.stuff = stuff;
    res.result = result;
    m_results[id] = res;

    --m_unfinished;
    assert( m_unfinished >= 0 );
    if ( m_unfinished == 0 ) {
        emit finished( m_results );
        deleteLater();
    }
}

class DecryptCommand::Private
  : public AssuanCommandPrivateBaseMixin<DecryptCommand::Private, DecryptCommand>
{
    Q_OBJECT
public:
    Private( DecryptCommand * qq )
        :AssuanCommandPrivateBaseMixin<DecryptCommand::Private, DecryptCommand>(), q( qq )
    {}

    DecryptCommand *q;
    QList<Input> analyzeInput( GpgME::Error& error, QString& errorDetails ) const;
    int startDecryption();

public Q_SLOTS:
    void slotDecryptionCollectionResult( const QHash<QString, DecryptionResultCollector::Result>& );
    void slotProgress( const QString& what, int current, int total );

};

DecryptCommand::DecryptCommand()
    : AssuanCommandMixin<DecryptCommand>(),
      d( new Private( this ) )
{
}

DecryptCommand::~DecryptCommand() {}

QList<AssuanCommandPrivateBase::Input> DecryptCommand::Private::analyzeInput( GpgME::Error& error, QString& errorDetails ) const
{
    error = GpgME::Error();
    errorDetails = QString();

    const int numInputs = q->numBulkInputDevices( "INPUT" );
    const int numOutputs = q->numBulkInputDevices( "OUTPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    if ( numMessages != 0 )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "Only --input can be provided to the decrypt command, no --message";
        return QList<Input>();
    }

    // either the output is discarded, or there ar as many as inputs
    if ( numOutputs > 0 && numInputs != numOutputs )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "For each --input there needs to be an --output";
        return QList<Input>();
    }

    QList<Input> inputs;

    for ( int i = 0; i < numInputs; ++i )
    {
        Input input;
        input.message = q->bulkInputDevice( "INPUT", i );
        input.messageFileName = q->bulkInputDeviceFileName( "INPUT", i );
        assert( input.message );
        input.type = Input::Opaque; // by definition
        inputs.append( input );
    }

    return inputs;
}

void DecryptCommand::Private::slotProgress( const QString& what, int current, int total )
{
    // FIXME report progress, via sendStatus()
}

static QString resultToString( const GpgME::DecryptionResult & result )
{
    QString resStr( "GREY ");
    for ( int i = 0; i<result.numRecipients(); i++ ) {
        const GpgME::DecryptionResult::Recipient r = result.recipient( i );
        resStr += QString( r.keyID() );
    }
    return resStr;
}

void DecryptCommand::Private::slotDecryptionCollectionResult( const QHash<QString, DecryptionResultCollector::Result>& results )
{
    assert( !results.isEmpty() );
    QStringList resultStrings;
    QString errorString;
    try {
        QList<DecryptionResultCollector::Result> values = results.values();
        QList<DecryptionResultCollector::Result>::const_iterator it = values.begin();
        QList<DecryptionResultCollector::Result>::const_iterator end = values.end();
        for ( ; it != end; ++it ) {
            const DecryptionResultCollector::Result result = *it;

            const GpgME::Error decryptionError = result.result.error();
            if ( decryptionError ) {
                errorString = decryptionError.asString();
                throw( decryptionError );
            }

            //handle result, send status
            QIODevice * const outdevice = q->bulkOutputDevice( "OUTPUT", result.id.toInt() );
            if ( outdevice ) {
                if ( const int bytesWritten = outdevice->write( result.stuff ) != result.stuff.size() ) {
                    const int err = GPG_ERR_ASS_WRITE_ERROR;
                    errorString = outdevice->errorString();
                    throw( err );
                }
            } else {
                if ( const char * filename = result.result.fileName() ) {
                    // FIXME sanitize, percent-encode, etc
                    // FIXME write out to given file name
                } else {
                    // no output specified, and no filename given, ask the user
                }

            }
            if ( const int err = q->sendStatus( "DECRYPT", resultToString( result.result ) ) ){
                errorString = "Problem writing out decryption status.";
                throw( err );
            }
        }

        q->done();
    } catch ( int err ) {
        q->done( err, errorString );
    }
}

int DecryptCommand::Private::startDecryption()
{
    assert( !inputList.isEmpty() );
    DecryptionResultCollector* collector = new DecryptionResultCollector;
    connect( collector, SIGNAL( finished( QHash<QString, DecryptionResultCollector::Result> ) ),
             SLOT( slotDecryptionCollectionResult( QHash<QString, DecryptionResultCollector::Result> ) ) );

    try {
        int i = 0;
        Q_FOREACH ( const Private::Input input, inputList )
        {
            assert( input.backend );

            //fire off appropriate kleo decrypt verify job
            DecryptJob * const job = input.backend->decryptJob();
            assert(job);
            collector->registerJob( QString::number(i), job );

            // FIXME handle file names
            const QByteArray encrypted = input.message->readAll(); // FIXME safe enough?
            const GpgME::Error error = job->start( encrypted );
            if ( error ) throw error;

            ++i;
        }
    } catch ( const GpgME::Error & error ) {
        delete collector;
        q->done( error );
        return error;
    }

    return 0;
}

int DecryptCommand::doStart()
{
    /*
    d->parseCommandLine("");
    d->showDetails = !hasOption("silent");
    */

    GpgME::Error error;
    QString details;
    d->inputList = d->analyzeInput( error, details );
    if ( error ) {
        done( error, details );
        return error;
    }

    int err = d->determineInputsAndProtocols( details );
    if ( err ) {
        done( err, details );
        return err;
    }
    err = d->startDecryption();
    return 0;

}

void DecryptCommand::doCanceled()
{
}

#include "decryptcommand.moc"

<commit_msg>Send out results for each succesful decryption job immediately, but collect results for all of them. Show aggregated dialog at the end of all jobs. Prepare offering continue/cancel on errors.<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    uiserver/decryptemailcommand.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra 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.

    Kleopatra 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 Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "decryptcommand.h"
#include "assuancommandprivatebase_p.h"

#include <QObject>
#include <QIODevice>
#include <QHash>
#include <QStringList>
#include <QDebug>
#include <QMessageBox>

#include <kleo/decryptjob.h>
#include <utils/stl_util.h>

#include <klocale.h>

#include <gpgme++/error.h>
#include <gpgme++/decryptionresult.h>

#include <gpg-error.h>

#include <boost/bind.hpp>

#include <cassert>

using namespace Kleo;

class DecryptCommand::Private;

struct DecryptCommandException : public std::exception
{
    DecryptCommandException( int i, const QString& s = QString() )
        :err(i), errorString(s)
    {}
    virtual ~DecryptCommandException() throw()
    {}
    int err;
    QString errorString;
};

class DecryptionResultCollector : public QObject
{
    Q_OBJECT
public:
    explicit DecryptionResultCollector( DecryptCommand::Private* parent = 0 );

    struct Result {
        Result() : error(0) { }
        QString id;
        GpgME::DecryptionResult result;
        QByteArray stuff;
        int error;
        QString errorString;
        bool isError() const { return error || result.error(); }
    };

    void registerJob( const QString& id, DecryptJob* job );
Q_SIGNALS:
    void finished( const QHash<QString, DecryptionResultCollector::Result> & );

private Q_SLOTS:
    void slotDecryptResult(const GpgME::DecryptionResult &, const QByteArray &);

private:
    QHash<QString, Result> m_results;
    QHash<QObject*, QString> m_senderToId;
    int m_unfinished;
    DecryptCommand::Private* m_command;
};

class DecryptCommand::Private
  : public AssuanCommandPrivateBaseMixin<DecryptCommand::Private, DecryptCommand>
{
    Q_OBJECT
public:
    Private( DecryptCommand * qq )
        :AssuanCommandPrivateBaseMixin<DecryptCommand::Private, DecryptCommand>()
        , q( qq )
        , collector( new DecryptionResultCollector(this) )
    {}

    DecryptCommand *q;
    QList<Input> analyzeInput( GpgME::Error& error, QString& errorDetails ) const;
    int startDecryption();
    void tryDecryptResult(const GpgME::DecryptionResult &, const QByteArray &, const QString& );

public Q_SLOTS:
    void slotDecryptionCollectionResult( const QHash<QString, DecryptionResultCollector::Result>& );
    void slotProgress( const QString& what, int current, int total );
private:
    DecryptionResultCollector* collector;

};

DecryptionResultCollector::DecryptionResultCollector( DecryptCommand::Private * parent )
: QObject( parent ), m_command( parent ), m_unfinished( 0 )
{
}

void DecryptionResultCollector::registerJob( const QString& id, DecryptJob* job )
{
    connect( job, SIGNAL( result( GpgME::DecryptionResult,QByteArray ) ),
             this, SLOT( slotDecryptResult( GpgME::DecryptionResult, QByteArray ) ) );
    m_senderToId[job] = id;
    ++m_unfinished;
}

void DecryptionResultCollector::slotDecryptResult(const GpgME::DecryptionResult & result,
                                                  const QByteArray & stuff )
{
    assert( m_senderToId.contains( sender( ) ) );
    const QString id = m_senderToId[sender()];

    Result res;
    res.id = id;
    res.stuff = stuff;
    res.result = result;
    m_results[id] = res;

    try {
        m_command->tryDecryptResult( result, stuff, id );
    } catch ( const DecryptCommandException& e ) {
        res.error = e.err;
        res.errorString = e.errorString;
        // FIXME ask to continue or cancel
    }

    --m_unfinished;
    assert( m_unfinished >= 0 );
    if ( m_unfinished == 0 ) {
        emit finished( m_results );
    }
}

DecryptCommand::DecryptCommand()
    : AssuanCommandMixin<DecryptCommand>(),
      d( new Private( this ) )
{
}

DecryptCommand::~DecryptCommand() {}

QList<AssuanCommandPrivateBase::Input> DecryptCommand::Private::analyzeInput( GpgME::Error& error, QString& errorDetails ) const
{
    error = GpgME::Error();
    errorDetails = QString();

    const int numInputs = q->numBulkInputDevices( "INPUT" );
    const int numOutputs = q->numBulkInputDevices( "OUTPUT" );
    const int numMessages = q->numBulkInputDevices( "MESSAGE" );

    if ( numMessages != 0 )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "Only --input can be provided to the decrypt command, no --message";
        return QList<Input>();
    }

    // either the output is discarded, or there ar as many as inputs
    if ( numOutputs > 0 && numInputs != numOutputs )
    {
        error = GpgME::Error( GPG_ERR_ASS_NO_INPUT ); //TODO use better error code if possible
        errorDetails = "For each --input there needs to be an --output";
        return QList<Input>();
    }

    QList<Input> inputs;

    for ( int i = 0; i < numInputs; ++i )
    {
        Input input;
        input.message = q->bulkInputDevice( "INPUT", i );
        input.messageFileName = q->bulkInputDeviceFileName( "INPUT", i );
        assert( input.message );
        input.type = Input::Opaque; // by definition
        inputs.append( input );
    }

    return inputs;
}

void DecryptCommand::Private::slotProgress( const QString& what, int current, int total )
{
    // FIXME report progress, via sendStatus()
}

static QString resultToString( const GpgME::DecryptionResult & result )
{
    QString resStr( "GREY ");
    for ( unsigned int i = 0; i<result.numRecipients(); i++ ) {
        const GpgME::DecryptionResult::Recipient r = result.recipient( i );
        resStr += QString( r.keyID() );
    }
    return resStr;
}

void DecryptCommand::Private::tryDecryptResult(const GpgME::DecryptionResult & result,
                                               const QByteArray & stuff, const QString & id )
{
    assert( !id.isEmpty() );

    // report status on the comman line immediately, and write out results, but
    // only show dialog once all operations are completed, so it can be aggregated
    const GpgME::Error decryptionError = result.error();
    if ( decryptionError )
        throw DecryptCommandException( static_cast<int>(decryptionError) );

    //handle result, send status
    QIODevice * const outdevice = q->bulkOutputDevice( "OUTPUT", id.toInt() );
    if ( outdevice ) {
        if ( const int bytesWritten = outdevice->write( stuff ) != stuff.size() ) {
            throw DecryptCommandException( makeError( GPG_ERR_ASS_WRITE_ERROR ), outdevice->errorString()) ;
        }
    } else {
        if ( const char * filename = result.fileName() ) {
            // FIXME sanitize, percent-encode, etc
            // FIXME write out to given file name
        } else {
            // no output specified, and no filename given, ask the user
        }

    }
    if ( const int err = q->sendStatus( "DECRYPT", resultToString( result ) ) ){
        QString errorString = "Problem writing out decryption status.";
        throw DecryptCommandException( err, errorString ) ;
    }
}

void DecryptCommand::Private::slotDecryptionCollectionResult( const QHash<QString, DecryptionResultCollector::Result>& results )
{
    assert( !results.isEmpty() );

    std::vector<DecryptionResultCollector::Result> theGood;
    std::vector<DecryptionResultCollector::Result> theBad;

    kdtools::copy_if( results.begin(), results.end(),
                      std::back_inserter( theBad ),
                      boost::bind( &DecryptionResultCollector::Result::isError, _1 ) );
    kdtools::copy_if( results.begin(), results.end(),
                      std::back_inserter( theGood ),
                      !boost::bind( &DecryptionResultCollector::Result::isError, _1 ) );

    // FIXME find all errors and all successes and display result dialog, unless --silent
    QMessageBox::information( 0, i18n( "Decryption Result" ), QString("%1 files processed. %2 were ok, %3 failed")
            .arg( results.size() ).arg( theGood.size() ).arg( theBad.size() ) );

    if ( !theBad.empty() )
        q->done( makeError( GPG_ERR_DECRYPT_FAILED ) );
    else
        q->done();
}

int DecryptCommand::Private::startDecryption()
{
    assert( !inputList.isEmpty() );
    connect( collector, SIGNAL( finished( QHash<QString, DecryptionResultCollector::Result> ) ),
             SLOT( slotDecryptionCollectionResult( QHash<QString, DecryptionResultCollector::Result> ) ) );

    try {
        int i = 0;
        Q_FOREACH ( const Private::Input input, inputList )
        {
            assert( input.backend );

            //fire off appropriate kleo decrypt verify job
            DecryptJob * const job = input.backend->decryptJob();
            assert(job);
            collector->registerJob( QString::number(i), job );

            // FIXME handle file names
            const QByteArray encrypted = input.message->readAll(); // FIXME safe enough?
            const GpgME::Error error = job->start( encrypted );
            if ( error ) throw error;

            ++i;
        }
    } catch ( const GpgME::Error & error ) {
        q->done( error );
        return error;
    }

    return 0;
}

int DecryptCommand::doStart()
{
    /*
    d->parseCommandLine("");
    d->showDetails = !hasOption("silent");
    */

    GpgME::Error error;
    QString details;
    d->inputList = d->analyzeInput( error, details );
    if ( error ) {
        done( error, details );
        return error;
    }

    int err = d->determineInputsAndProtocols( details );
    if ( err ) {
        done( err, details );
        return err;
    }
    err = d->startDecryption();
    return 0;

}

void DecryptCommand::doCanceled()
{
}

#include "decryptcommand.moc"

<|endoftext|>


<commit_before><?hh //strict

/**
 * This file is part of hhpack\typechecker package.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\typechecker;

use hhpack\typechecker\check\Result;
use hhpack\process\Process;
use RuntimeException;

final class TypeCheckerClient implements ClientBehavior
{

    const PROGRAM = 'hh_client';

    public function __construct(
        private string $cwd = (string) getcwd()
    )
    {
    }

    public async function version() : Awaitable<Version>
    {
        $result = await Process::exec( $this->command('', [ '--version' ]), $this->cwd );
        $version = (string) $result->getStdout();

        return trim($version);
    }

    public async function init() : Awaitable<ConfigurationPath>
    {
        $path = realpath($this->cwd) . '/.hhconfig';

        if (touch($path) === false) {
            throw new RuntimeException('Failed to generate .hhconfig');
        }

        return $path;
    }

    public async function start() : Awaitable<void>
    {
        await Process::exec( $this->command('start'), $this->cwd );
    }

    public async function stop() : Awaitable<void>
    {
        await Process::exec( $this->command('stop'), $this->cwd );
    }

    public async function restart() : Awaitable<void>
    {
        await Process::exec( $this->command('restart'), $this->cwd );
    }

    public async function check() : Awaitable<Result>
    {
        $result = await Process::exec( $this->command('check', [ '--json' ]), $this->cwd);
        return Result::fromString((string) $result->getStderr());
    }

    private function command(string $command, Traversable<string> $args = []) : string
    {
        $builder = Set {};
        $builder->add('%s %s %s');
        $builder->addAll([ static::PROGRAM, $command, implode(' ', $args) ]);

        return call_user_func_array('sprintf', $builder->toValuesArray());
    }

}
<commit_msg>Update for process package<commit_after><?hh //strict

/**
 * This file is part of hhpack\typechecker package.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\typechecker;

use hhpack\typechecker\check\Result;
use hhpack\process;
use hhpack\process\ExecOptions;
use RuntimeException;

final class TypeCheckerClient implements ClientBehavior
{

    const PROGRAM = 'hh_client';

    public function __construct(
        private string $cwd = (string) getcwd()
    )
    {
    }

    public async function version() : Awaitable<Version>
    {
        $options = new ExecOptions($this->cwd);

        $result = await process\exec( $this->command('', [ '--version' ]), $options );
        $version = (string) $result->stdout();

        return trim($version);
    }

    public async function init() : Awaitable<ConfigurationPath>
    {
        $path = realpath($this->cwd) . '/.hhconfig';

        if (touch($path) === false) {
            throw new RuntimeException('Failed to generate .hhconfig');
        }

        return $path;
    }

    public async function start() : Awaitable<void>
    {
        $options = new ExecOptions($this->cwd);
        await process\exec( $this->command('start'), $options );
    }

    public async function stop() : Awaitable<void>
    {
        $options = new ExecOptions($this->cwd);
        await process\exec( $this->command('stop'), $options );
    }

    public async function restart() : Awaitable<void>
    {
        $options = new ExecOptions($this->cwd);
        await process\exec( $this->command('restart'), $options );
    }

    public async function check() : Awaitable<Result>
    {
        $options = new ExecOptions($this->cwd);

        $result = await process\exec( $this->command('check', [ '--json' ]), $options);
        return Result::fromString((string) $result->stderr());
    }

    private function command(string $command, Traversable<string> $args = []) : string
    {
        $builder = Set {};
        $builder->add('%s %s %s');
        $builder->addAll([ static::PROGRAM, $command, implode(' ', $args) ]);

        return call_user_func_array('sprintf', $builder->toValuesArray());
    }

}
<|endoftext|>


<commit_before>//===--------------------------- libuwind.cpp -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
//  Implements unw_* functions from <libunwind.h>
//
//===----------------------------------------------------------------------===//

#include <libunwind.h>

#include <new>

#include "libunwind_ext.h"
#include "config.h"

#if _LIBUNWIND_BUILD_ZERO_COST_APIS

#include "UnwindCursor.hpp"

using namespace libunwind;

/// internal object to represent this processes address space
LocalAddressSpace LocalAddressSpace::sThisAddressSpace;

/// record the registers and stack position of the caller
extern int unw_getcontext(unw_context_t *);
// note: unw_getcontext() implemented in assembly

/// Create a cursor of a thread in this process given 'context' recorded by
/// unw_getcontext().
_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
                                     unw_context_t *context) {
  _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n",
                              cursor, context);
  // Use "placement new" to allocate UnwindCursor in the cursor buffer.
#if __i386__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __x86_64__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __ppc__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __arm64__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#endif
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->setInfoBasedOnIPRegister();

  return UNW_ESUCCESS;
}

#if UNW_REMOTE

_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
    (unw_addr_space_t) & sThisAddressSpace;

/// Create a cursor into a thread in another process.
_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
                                             unw_addr_space_t as,
                                             void *arg) {
  // special case: unw_init_remote(xx, unw_local_addr_space, xx)
  if (as == (unw_addr_space_t) & sThisAddressSpace)
    return unw_init_local(cursor, NULL); //FIXME

  // use "placement new" to allocate UnwindCursor in the cursor buffer
  switch (as->cpuType) {
  case CPU_TYPE_I386:
    new ((void *)cursor)
        UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
                     Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
    break;
  case CPU_TYPE_X86_64:
    new ((void *)cursor) UnwindCursor<
        OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
        ((unw_addr_space_x86_64 *)as)->oas, arg);
    break;
  case CPU_TYPE_POWERPC:
    new ((void *)cursor)
        UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
            ((unw_addr_space_ppc *)as)->oas, arg);
    break;
  default:
    return UNW_EUNSPEC;
  }
  return UNW_ESUCCESS;
}

static bool is64bit(task_t task) {
  return false; // FIXME
}

/// Create an address_space object for use in examining another task.
_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
#if __i386__
  if (is64bit(task)) {
    unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
    as->taskPort = task;
    as->cpuType = CPU_TYPE_X86_64;
    //as->oas
  } else {
    unw_addr_space_i386 *as = new unw_addr_space_i386(task);
    as->taskPort = task;
    as->cpuType = CPU_TYPE_I386;
    //as->oas
  }
#else
// FIXME
#endif
}

/// Delete an address_space object.
_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
  switch (asp->cpuType) {
#if __i386__ || __x86_64__
  case CPU_TYPE_I386: {
    unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
    delete as;
  }
  break;
  case CPU_TYPE_X86_64: {
    unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
    delete as;
  }
  break;
#endif
  case CPU_TYPE_POWERPC: {
    unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
    delete as;
  }
  break;
  }
}
#endif // UNW_REMOTE

/// Get value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                  unw_word_t *value) {
  _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n",
                              cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validReg(regNum)) {
    *value = co->getReg(regNum);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Set value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                  unw_word_t value) {
  _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n",
                             cursor, regNum, value);
  typedef LocalAddressSpace::pint_t pint_t;
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validReg(regNum)) {
    co->setReg(regNum, (pint_t)value);
    // specical case altering IP to re-find info (being called by personality
    // function)
    if (regNum == UNW_REG_IP)
      co->setInfoBasedOnIPRegister(false);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Get value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                    unw_fpreg_t *value) {
  _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n",
                             cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validFloatReg(regNum)) {
    *value = co->getFloatReg(regNum);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Set value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                    unw_fpreg_t value) {
  _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
                             cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validFloatReg(regNum)) {
    co->setFloatReg(regNum, value);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Move cursor to next frame.
_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->step();
}

/// Get unwind info at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
                                        unw_proc_info_t *info) {
  _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n",
                             cursor, info);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->getInfo(info);
  if (info->end_ip == 0)
    return UNW_ENOINFO;
  else
    return UNW_ESUCCESS;
}

/// Resume execution at cursor position (aka longjump).
_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->jumpto();
  return UNW_EUNSPEC;
}

/// Get name of function at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
                                        size_t bufLen, unw_word_t *offset) {
  _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p,"
                             "bufLen=%ld)\n", cursor, buf, bufLen);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->getFunctionName(buf, bufLen, offset))
    return UNW_ESUCCESS;
  else
    return UNW_EUNSPEC;
}

/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
  _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n",
                             cursor, regNum);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->validFloatReg(regNum);
}

/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
                                          unw_regnum_t regNum) {
  _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n",
                             cursor, regNum);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->getRegisterName(regNum);
}

/// Checks if current frame is signal trampoline.
_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->isSignalFrame();
}

#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
/// SPI: walks cached dwarf entries
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
  _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
  DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
}

/// IPI: for __register_frame()
void _unw_add_dynamic_fde(unw_word_t fde) {
  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
  const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
                           LocalAddressSpace::sThisAddressSpace,
                          (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
  if (message == NULL) {
    // dynamically registered FDEs don't have a mach_header group they are in.
    // Use fde as mh_group
    unw_word_t mh_group = fdeInfo.fdeStart;
    DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
                                          fdeInfo.pcStart, fdeInfo.pcEnd,
                                          fdeInfo.fdeStart);
  } else {
    _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
  }
}

/// IPI: for __deregister_frame()
void _unw_remove_dynamic_fde(unw_word_t fde) {
  // fde is own mh_group
  DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
}
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND

#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS

// Add logging hooks in Debug builds only
#ifndef NDEBUG

_LIBUNWIND_HIDDEN
bool logAPIs() {
  // do manual lock to avoid use of _cxa_guard_acquire or initializers
  static bool checked = false;
  static bool log = false;
  if (!checked) {
    log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
    checked = true;
  }
  return log;
}

_LIBUNWIND_HIDDEN
bool logUnwinding() {
  // do manual lock to avoid use of _cxa_guard_acquire or initializers
  static bool checked = false;
  static bool log = false;
  if (!checked) {
    log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
    checked = true;
  }
  return log;
}

#endif // NDEBUG

<commit_msg>Include stdlib.h for getenv when !NDEBUG.<commit_after>//===--------------------------- libuwind.cpp -----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
//
//  Implements unw_* functions from <libunwind.h>
//
//===----------------------------------------------------------------------===//

#include <libunwind.h>

#include <new>

#include "libunwind_ext.h"
#include "config.h"

#if _LIBUNWIND_BUILD_ZERO_COST_APIS

#include "UnwindCursor.hpp"

using namespace libunwind;

/// internal object to represent this processes address space
LocalAddressSpace LocalAddressSpace::sThisAddressSpace;

/// record the registers and stack position of the caller
extern int unw_getcontext(unw_context_t *);
// note: unw_getcontext() implemented in assembly

/// Create a cursor of a thread in this process given 'context' recorded by
/// unw_getcontext().
_LIBUNWIND_EXPORT int unw_init_local(unw_cursor_t *cursor,
                                     unw_context_t *context) {
  _LIBUNWIND_TRACE_API("unw_init_local(cursor=%p, context=%p)\n",
                              cursor, context);
  // Use "placement new" to allocate UnwindCursor in the cursor buffer.
#if __i386__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __x86_64__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_x86_64>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __ppc__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_ppc>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#elif __arm64__
  new ((void *)cursor) UnwindCursor<LocalAddressSpace, Registers_arm64>(
                                 context, LocalAddressSpace::sThisAddressSpace);
#endif
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->setInfoBasedOnIPRegister();

  return UNW_ESUCCESS;
}

#if UNW_REMOTE

_LIBUNWIND_EXPORT unw_addr_space_t unw_local_addr_space =
    (unw_addr_space_t) & sThisAddressSpace;

/// Create a cursor into a thread in another process.
_LIBUNWIND_EXPORT int unw_init_remote_thread(unw_cursor_t *cursor,
                                             unw_addr_space_t as,
                                             void *arg) {
  // special case: unw_init_remote(xx, unw_local_addr_space, xx)
  if (as == (unw_addr_space_t) & sThisAddressSpace)
    return unw_init_local(cursor, NULL); //FIXME

  // use "placement new" to allocate UnwindCursor in the cursor buffer
  switch (as->cpuType) {
  case CPU_TYPE_I386:
    new ((void *)cursor)
        UnwindCursor<OtherAddressSpace<Pointer32<LittleEndian> >,
                     Registers_x86>(((unw_addr_space_i386 *)as)->oas, arg);
    break;
  case CPU_TYPE_X86_64:
    new ((void *)cursor) UnwindCursor<
        OtherAddressSpace<Pointer64<LittleEndian> >, Registers_x86_64>(
        ((unw_addr_space_x86_64 *)as)->oas, arg);
    break;
  case CPU_TYPE_POWERPC:
    new ((void *)cursor)
        UnwindCursor<OtherAddressSpace<Pointer32<BigEndian> >, Registers_ppc>(
            ((unw_addr_space_ppc *)as)->oas, arg);
    break;
  default:
    return UNW_EUNSPEC;
  }
  return UNW_ESUCCESS;
}

static bool is64bit(task_t task) {
  return false; // FIXME
}

/// Create an address_space object for use in examining another task.
_LIBUNWIND_EXPORT unw_addr_space_t unw_create_addr_space_for_task(task_t task) {
#if __i386__
  if (is64bit(task)) {
    unw_addr_space_x86_64 *as = new unw_addr_space_x86_64(task);
    as->taskPort = task;
    as->cpuType = CPU_TYPE_X86_64;
    //as->oas
  } else {
    unw_addr_space_i386 *as = new unw_addr_space_i386(task);
    as->taskPort = task;
    as->cpuType = CPU_TYPE_I386;
    //as->oas
  }
#else
// FIXME
#endif
}

/// Delete an address_space object.
_LIBUNWIND_EXPORT void unw_destroy_addr_space(unw_addr_space_t asp) {
  switch (asp->cpuType) {
#if __i386__ || __x86_64__
  case CPU_TYPE_I386: {
    unw_addr_space_i386 *as = (unw_addr_space_i386 *)asp;
    delete as;
  }
  break;
  case CPU_TYPE_X86_64: {
    unw_addr_space_x86_64 *as = (unw_addr_space_x86_64 *)asp;
    delete as;
  }
  break;
#endif
  case CPU_TYPE_POWERPC: {
    unw_addr_space_ppc *as = (unw_addr_space_ppc *)asp;
    delete as;
  }
  break;
  }
}
#endif // UNW_REMOTE

/// Get value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                  unw_word_t *value) {
  _LIBUNWIND_TRACE_API("unw_get_reg(cursor=%p, regNum=%d, &value=%p)\n",
                              cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validReg(regNum)) {
    *value = co->getReg(regNum);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Set value of specified register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_reg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                  unw_word_t value) {
  _LIBUNWIND_TRACE_API("unw_set_reg(cursor=%p, regNum=%d, value=0x%llX)\n",
                             cursor, regNum, value);
  typedef LocalAddressSpace::pint_t pint_t;
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validReg(regNum)) {
    co->setReg(regNum, (pint_t)value);
    // specical case altering IP to re-find info (being called by personality
    // function)
    if (regNum == UNW_REG_IP)
      co->setInfoBasedOnIPRegister(false);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Get value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                    unw_fpreg_t *value) {
  _LIBUNWIND_TRACE_API("unw_get_fpreg(cursor=%p, regNum=%d, &value=%p)\n",
                             cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validFloatReg(regNum)) {
    *value = co->getFloatReg(regNum);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Set value of specified float register at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_set_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum,
                                    unw_fpreg_t value) {
  _LIBUNWIND_TRACE_API("unw_set_fpreg(cursor=%p, regNum=%d, value=%g)\n",
                             cursor, regNum, value);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->validFloatReg(regNum)) {
    co->setFloatReg(regNum, value);
    return UNW_ESUCCESS;
  }
  return UNW_EBADREG;
}

/// Move cursor to next frame.
_LIBUNWIND_EXPORT int unw_step(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_step(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->step();
}

/// Get unwind info at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_info(unw_cursor_t *cursor,
                                        unw_proc_info_t *info) {
  _LIBUNWIND_TRACE_API("unw_get_proc_info(cursor=%p, &info=%p)\n",
                             cursor, info);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->getInfo(info);
  if (info->end_ip == 0)
    return UNW_ENOINFO;
  else
    return UNW_ESUCCESS;
}

/// Resume execution at cursor position (aka longjump).
_LIBUNWIND_EXPORT int unw_resume(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_resume(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  co->jumpto();
  return UNW_EUNSPEC;
}

/// Get name of function at cursor position in stack frame.
_LIBUNWIND_EXPORT int unw_get_proc_name(unw_cursor_t *cursor, char *buf,
                                        size_t bufLen, unw_word_t *offset) {
  _LIBUNWIND_TRACE_API("unw_get_proc_name(cursor=%p, &buf=%p,"
                             "bufLen=%ld)\n", cursor, buf, bufLen);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  if (co->getFunctionName(buf, bufLen, offset))
    return UNW_ESUCCESS;
  else
    return UNW_EUNSPEC;
}

/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT int unw_is_fpreg(unw_cursor_t *cursor, unw_regnum_t regNum) {
  _LIBUNWIND_TRACE_API("unw_is_fpreg(cursor=%p, regNum=%d)\n",
                             cursor, regNum);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->validFloatReg(regNum);
}

/// Checks if a register is a floating-point register.
_LIBUNWIND_EXPORT const char *unw_regname(unw_cursor_t *cursor,
                                          unw_regnum_t regNum) {
  _LIBUNWIND_TRACE_API("unw_regname(cursor=%p, regNum=%d)\n",
                             cursor, regNum);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->getRegisterName(regNum);
}

/// Checks if current frame is signal trampoline.
_LIBUNWIND_EXPORT int unw_is_signal_frame(unw_cursor_t *cursor) {
  _LIBUNWIND_TRACE_API("unw_is_signal_frame(cursor=%p)\n", cursor);
  AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
  return co->isSignalFrame();
}

#if _LIBUNWIND_SUPPORT_DWARF_UNWIND
/// SPI: walks cached dwarf entries
_LIBUNWIND_EXPORT void unw_iterate_dwarf_unwind_cache(void (*func)(
    unw_word_t ip_start, unw_word_t ip_end, unw_word_t fde, unw_word_t mh)) {
  _LIBUNWIND_TRACE_API("unw_iterate_dwarf_unwind_cache(func=%p)\n", func);
  DwarfFDECache<LocalAddressSpace>::iterateCacheEntries(func);
}

/// IPI: for __register_frame()
void _unw_add_dynamic_fde(unw_word_t fde) {
  CFI_Parser<LocalAddressSpace>::FDE_Info fdeInfo;
  CFI_Parser<LocalAddressSpace>::CIE_Info cieInfo;
  const char *message = CFI_Parser<LocalAddressSpace>::decodeFDE(
                           LocalAddressSpace::sThisAddressSpace,
                          (LocalAddressSpace::pint_t) fde, &fdeInfo, &cieInfo);
  if (message == NULL) {
    // dynamically registered FDEs don't have a mach_header group they are in.
    // Use fde as mh_group
    unw_word_t mh_group = fdeInfo.fdeStart;
    DwarfFDECache<LocalAddressSpace>::add((LocalAddressSpace::pint_t)mh_group,
                                          fdeInfo.pcStart, fdeInfo.pcEnd,
                                          fdeInfo.fdeStart);
  } else {
    _LIBUNWIND_DEBUG_LOG("_unw_add_dynamic_fde: bad fde: %s", message);
  }
}

/// IPI: for __deregister_frame()
void _unw_remove_dynamic_fde(unw_word_t fde) {
  // fde is own mh_group
  DwarfFDECache<LocalAddressSpace>::removeAllIn((LocalAddressSpace::pint_t)fde);
}
#endif // _LIBUNWIND_SUPPORT_DWARF_UNWIND

#endif // _LIBUNWIND_BUILD_ZERO_COST_APIS

// Add logging hooks in Debug builds only
#ifndef NDEBUG
#include <stdlib.h>

_LIBUNWIND_HIDDEN
bool logAPIs() {
  // do manual lock to avoid use of _cxa_guard_acquire or initializers
  static bool checked = false;
  static bool log = false;
  if (!checked) {
    log = (getenv("LIBUNWIND_PRINT_APIS") != NULL);
    checked = true;
  }
  return log;
}

_LIBUNWIND_HIDDEN
bool logUnwinding() {
  // do manual lock to avoid use of _cxa_guard_acquire or initializers
  static bool checked = false;
  static bool log = false;
  if (!checked) {
    log = (getenv("LIBUNWIND_PRINT_UNWINDING") != NULL);
    checked = true;
  }
  return log;
}

#endif // NDEBUG

<|endoftext|>


<commit_before>// @(#)root/cont:$Name:  $:$Id: TObjectTable.cxx,v 1.1.1.1 2000/05/16 17:00:40 rdm Exp $
// Author: Fons Rademakers   11/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// This class registers all instances of TObject and its derived        //
// classes in a hash table. The Add() and Remove() members are called   //
// from the TObject ctor and dtor, repectively. Using the Print()       //
// member one can see all currently active objects in the system.       //
// Using the resource (in .rootrc): Root.ObjectStat one can toggle this //
// feature on or off.                                                   //
// Using the compile option R__NOSTATS one can de-active this feature   //
// for the entire system (for maximum performance in highly time        //
// critical applications).                                              //
//                                                                      //
// The following output has been produced in a ROOT interactive session
// via the command gObjectTable->Print()
//   class                     cnt    on heap     size    total size    heap size
//   ============================================================================
//   TKey                        4          4       72           288          288
//   TClass                     84         84       80          6720         6720
//   TDataMember               276        276       24          6624         6624
//   TObject                    11         11       12           132          132
//   TMethod                  1974       1974       64        126336       126336
//   TDataType                  34         34       56          1904         1904
//   TList                    2328       2328       36         83808        83808
//   TH1F                        1          1      448           448          448
//   TText                    2688       2688       56        150528       150528
//   TGaxis                      1          0      120           120            0
//   TAxis                       6          3       88           528          264
//   TBox                       57         57       52          2964         2964
//   TLine                     118        118       40          4720         4720
//   TWbox                       1          1       56            56           56
//   TArrow                      1          1       64            64           64
//   TPaveText                  59         59      124          7316         7316
//   TPave                       1          1       92            92           92
//   TFile                       1          1      136           136          136
//   TCanvas                     3          3      444          1332         1332
//   TPad                        1          1      312           312          312
//   TContextMenu                3          3       48           144          144
//   TMethodArg               2166       2166       44         95304        95304
//   TPaveLabel                  1          1      120           120          120
//   THtml                       1          1       32            32           32
//   TROOT                       1          0      208           208            0
//   TApplication                1          1       28            28           28
//   TFileHandler                1          1       20            20           20
//   TColor                    163        163       40          6520         6520
//   TStyle                      1          1      364           364          364
//   TRealData                 117        117       28          3276         3276
//   TBaseClass                 88         88       36          3168         3168
//   THashList                   5          5       40           200          200
//   THashTable                  5          5       36           180          180
//   TGeometry                   1          1       64            64           64
//   TLink                       7          7       60           420          420
//   TPostScript                 1          1      764           764          764
//   TMinuit                     1          1      792           792          792
//   TStopwatch                  1          0       56            56            0
//   TRootGuiFactory             1          1       28            28           28
//   TGX11                       1          1      172           172          172
//   TUnixSystem                 1          1      252           252          252
//   TSignalHandler              1          1       20            20           20
//   TOrdCollection              3          3       40           120          120
//   TEnv                        1          1       24            24           24
//   TCint                       1          1      208           208          208
//   TBenchmark                  1          1       52            52           52
//   TClassTable                 1          1       12            12           12
//   TObjectTable                1          1       12            12           12
//   ----------------------------------------------------------------------------
//   Total:                  10225      10219     5976        506988       506340
//   ============================================================================
//////////////////////////////////////////////////////////////////////////

#include "TObjectTable.h"
#include "TROOT.h"
#include "TClass.h"
#include "TMath.h"
#include "TError.h"

TObjectTable *gObjectTable;

ClassImp(TObjectTable)

//______________________________________________________________________________
TObjectTable::TObjectTable(Int_t tableSize)
{
   // Create an object table.

   fSize  = (Int_t)TMath::NextPrime(tableSize);
   fTable = new TObject* [fSize];
   memset(fTable, 0, fSize*sizeof(TObject*));
   fTally = 0;
}

//______________________________________________________________________________
TObjectTable::~TObjectTable()
{
   // Delete TObjectTable.

   delete [] fTable; fTable = 0;
}

//______________________________________________________________________________
void TObjectTable::Print(Option_t *) const
{
   // Print the object table.

   InstanceStatistics();
}

//______________________________________________________________________________
void TObjectTable::Add(TObject *op)
{
   // Add an object to the object table.

   if (!op) {
      Error("Add", "op is 0");
      return;
   }
   if (!fTable)
      return;

   Int_t slot = FindElement(op);
   if (fTable[slot] == 0) {
      fTable[slot] = op;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   }
}

//______________________________________________________________________________
void TObjectTable::AddObj(TObject *op)
{
   // Add an object to the global object table gObjectTable. If the global
   // table does not exist create it first. This member function may only
   // be used by TObject::TObject. Use Add() to add objects to any other
   // TObjectTable object. This is a static function.

   static Bool_t olock = kFALSE;

   if (!op) {
      ::Error("TObjectTable::AddObj", "op is 0");
      return;
   }
   if (olock)
      return;

   if (!gObjectTable) {
      olock = kTRUE;
      gObjectTable = new TObjectTable(10000);
      olock = kFALSE;
      gObjectTable->Add(gObjectTable);
   }

   gObjectTable->Add(op);
}

//______________________________________________________________________________
void TObjectTable::Delete(Option_t *)
{
   // Delete all objects stored in the TObjectTable.

   for (int i = 0; i < fSize; i++) {
      if (fTable[i]) {
         delete fTable[i];
         fTable[i] = 0;
      }
   }
   fTally = 0;
}

//______________________________________________________________________________
void TObjectTable::Remove(TObject *op)
{
   // Remove an object from the object table.

   if (op == 0) {
      Error("Remove", "remove 0 from TObjectTable");
      return;
   }

   if (!fTable)
      return;

   Int_t i = FindElement(op);
   if (fTable[i] == 0) {
      Warning("Remove", "0x%08x not found at %d", (long)op, i);
      for (int j = 0; j < fSize; j++) {
         if (fTable[j] == op) {
            Error("Remove", "%d found at %d !!!", (long)op, j);
            i = j;
         }
      }
   }

   if (fTable[i]) {
      fTable[i] = 0;
      FixCollisions(i);
      fTally--;
   }
}

//______________________________________________________________________________
void TObjectTable::RemoveQuietly(TObject *op)
{
   // Remove an object from the object table. If op is 0 or not in the table
   // don't complain. Currently only used by the TClonesArray dtor. Should not
   // be used anywhere else, except in places where "special" allocation and
   // de-allocation tricks are performed.

   if (op == 0) return;

   if (!fTable)
      return;

   Int_t i = FindElement(op);
   if (fTable[i] == 0)
      for (int j = 0; j < fSize; j++)
         if (fTable[j] == op)
            i = j;

   fTable[i] = 0;
   FixCollisions(i);
   fTally--;
}

//______________________________________________________________________________
void TObjectTable::Terminate()
{
   // Deletes the object table (this static class function calls the dtor).

   InstanceStatistics();
   delete [] fTable; fTable = 0;
}

//______________________________________________________________________________
Int_t TObjectTable::FindElement(TObject *op)
{
   // Find an object in the object table. Returns the slot where to put
   // the object. To test if the object is actually already in the table
   // use PtrIsValid().

   Int_t    slot, n;
   TObject *slotOp;

   if (!fTable)
      return 0;

   //slot = Int_t(((ULong_t) op >> 2) % fSize);
   slot = Int_t(TMath::Hash(&op, sizeof(TObject*)) % fSize);
   for (n = 0; n < fSize; n++) {
      if ((slotOp = fTable[slot]) == 0)
         break;
      if (op == slotOp)
         break;
      if (++slot == fSize)
         slot = 0;
   }
   return slot;
}

//______________________________________________________________________________
void TObjectTable::FixCollisions(Int_t index)
{
   // Rehash the object table in case an object has been removed.

   Int_t oldIndex, nextIndex;
   TObject *nextObject;

   for (oldIndex = index+1; ;oldIndex++) {
      if (oldIndex >= fSize)
         oldIndex = 0;
      nextObject = fTable[oldIndex];
      if (nextObject == 0)
         break;
      nextIndex = FindElement(nextObject);
      if (nextIndex != oldIndex) {
         fTable[nextIndex] = nextObject;
         fTable[oldIndex] = 0;
      }
   }
}

//______________________________________________________________________________
void TObjectTable::Expand(Int_t newSize)
{
   // Expand the object table.

   TObject **oldTable = fTable, *op;
   int oldsize = fSize;
   newSize = (Int_t)TMath::NextPrime(newSize);
   fTable  = new TObject* [newSize];
   memset(fTable, 0, newSize*sizeof(TObject*));
   fSize   = newSize;
   fTally  = 0;
   for (int i = 0; i < oldsize; i++)
      if ((op = oldTable[i]))
         Add(op);
   delete [] oldTable;
}

//______________________________________________________________________________
void TObjectTable::InstanceStatistics() const
{
   // Print the object table.

   int n, h, s, ncum = 0, hcum = 0, scum = 0, tcum = 0, thcum = 0;

   if (fTally == 0 || !fTable)
      return;

   UpdateInstCount();

   Printf("");
   Printf("Object statistics");
   Printf("class                     cnt    on heap     size    total size    heap size");
   Printf("============================================================================");
   TIter next(gROOT->GetListOfClasses());
   TClass *cl;
   while ((cl = (TClass*) next())) {
      n = cl->GetInstanceCount();
      h = cl->GetHeapInstanceCount();
      s = cl->Size();
      if (n > 0) {
         Printf("%-20s %8d%11d%9d%14d%13d", cl->GetName(), n, h, s, n*s, h*s);
         ncum  += n;
         hcum  += h;
         scum  += s;
         tcum  += n*s;
         thcum += h*s;
      }
   }
   Printf("----------------------------------------------------------------------------");
   Printf("Total:               %8d%11d%9d%14d%13d", ncum, hcum, scum, tcum, thcum);
   Printf("============================================================================");
   Printf("");
}

//______________________________________________________________________________
void TObjectTable::UpdateInstCount() const
{
   // Histogram all objects according to their classes.

   TObject *op;

   if (!fTable || !TROOT::Initialized())
      return;

   gROOT->GetListOfClasses()->ForEach(TClass,ResetInstanceCount)();

   for (int i = 0; i < fSize; i++)
      if ((op = fTable[i])) {                // attention: no ==
         if (op->TestBit(TObject::kNotDeleted))
            op->IsA()->AddInstance(op->IsOnHeap());
         else
            Error("UpdateInstCount", "oops 0x%08x\n", op);
      }
}

//______________________________________________________________________________
void *TObjectTable::CheckPtrAndWarn(const char *msg, void *vp)
{
   // Issue a warning in case an object still appears in the table
   // while it should not.

   if (fTable && vp && fTable[FindElement((TObject*)vp)]) {
      Remove((TObject*)vp);
      Warning("CheckPtrAndWarn", "%s (0x%08x)\n", msg, vp);
   }
   return vp;
}
<commit_msg>Add new option in TObjectTable::Print    // Print the object table.    // if option ="all" prints the list of all objects with the format    //  object number, pointer, class name, object name<commit_after>// @(#)root/cont:$Name:  $:$Id: TObjectTable.cxx,v 1.2 2000/12/13 15:56:17 brun Exp $
// Author: Fons Rademakers   11/08/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// This class registers all instances of TObject and its derived        //
// classes in a hash table. The Add() and Remove() members are called   //
// from the TObject ctor and dtor, repectively. Using the Print()       //
// member one can see all currently active objects in the system.       //
// Using the resource (in .rootrc): Root.ObjectStat one can toggle this //
// feature on or off.                                                   //
// Using the compile option R__NOSTATS one can de-active this feature   //
// for the entire system (for maximum performance in highly time        //
// critical applications).                                              //
//                                                                      //
// The following output has been produced in a ROOT interactive session
// via the command gObjectTable->Print()
//   class                     cnt    on heap     size    total size    heap size
//   ============================================================================
//   TKey                        4          4       72           288          288
//   TClass                     84         84       80          6720         6720
//   TDataMember               276        276       24          6624         6624
//   TObject                    11         11       12           132          132
//   TMethod                  1974       1974       64        126336       126336
//   TDataType                  34         34       56          1904         1904
//   TList                    2328       2328       36         83808        83808
//   TH1F                        1          1      448           448          448
//   TText                    2688       2688       56        150528       150528
//   TGaxis                      1          0      120           120            0
//   TAxis                       6          3       88           528          264
//   TBox                       57         57       52          2964         2964
//   TLine                     118        118       40          4720         4720
//   TWbox                       1          1       56            56           56
//   TArrow                      1          1       64            64           64
//   TPaveText                  59         59      124          7316         7316
//   TPave                       1          1       92            92           92
//   TFile                       1          1      136           136          136
//   TCanvas                     3          3      444          1332         1332
//   TPad                        1          1      312           312          312
//   TContextMenu                3          3       48           144          144
//   TMethodArg               2166       2166       44         95304        95304
//   TPaveLabel                  1          1      120           120          120
//   THtml                       1          1       32            32           32
//   TROOT                       1          0      208           208            0
//   TApplication                1          1       28            28           28
//   TFileHandler                1          1       20            20           20
//   TColor                    163        163       40          6520         6520
//   TStyle                      1          1      364           364          364
//   TRealData                 117        117       28          3276         3276
//   TBaseClass                 88         88       36          3168         3168
//   THashList                   5          5       40           200          200
//   THashTable                  5          5       36           180          180
//   TGeometry                   1          1       64            64           64
//   TLink                       7          7       60           420          420
//   TPostScript                 1          1      764           764          764
//   TMinuit                     1          1      792           792          792
//   TStopwatch                  1          0       56            56            0
//   TRootGuiFactory             1          1       28            28           28
//   TGX11                       1          1      172           172          172
//   TUnixSystem                 1          1      252           252          252
//   TSignalHandler              1          1       20            20           20
//   TOrdCollection              3          3       40           120          120
//   TEnv                        1          1       24            24           24
//   TCint                       1          1      208           208          208
//   TBenchmark                  1          1       52            52           52
//   TClassTable                 1          1       12            12           12
//   TObjectTable                1          1       12            12           12
//   ----------------------------------------------------------------------------
//   Total:                  10225      10219     5976        506988       506340
//   ============================================================================
//////////////////////////////////////////////////////////////////////////

#include "TObjectTable.h"
#include "TROOT.h"
#include "TClass.h"
#include "TMath.h"
#include "TError.h"

TObjectTable *gObjectTable;

ClassImp(TObjectTable)

//______________________________________________________________________________
TObjectTable::TObjectTable(Int_t tableSize)
{
   // Create an object table.

   fSize  = (Int_t)TMath::NextPrime(tableSize);
   fTable = new TObject* [fSize];
   memset(fTable, 0, fSize*sizeof(TObject*));
   fTally = 0;
}

//______________________________________________________________________________
TObjectTable::~TObjectTable()
{
   // Delete TObjectTable.

   delete [] fTable; fTable = 0;
}

//______________________________________________________________________________
void TObjectTable::Print(Option_t *option) const
{
   // Print the object table.
   // if option ="all" prints the list of all objects with the format
   //  object number, pointer, class name, object name

   TString opt = option;
   opt.ToLower();
   if (opt.Contains("all")) {
      TObject *obj;
      int i,num=0;
      for (i=0;i<fSize;i++) {
         if (!fTable[i]) continue;
         num++;
         obj = fTable[i];
         printf("obj[%5d] at %x %s : %s\n",num,obj,obj->ClassName(),obj->GetName());
      }
   }

   //print the number of instances per class
   InstanceStatistics();
}

//______________________________________________________________________________
void TObjectTable::Add(TObject *op)
{
   // Add an object to the object table.

   if (!op) {
      Error("Add", "op is 0");
      return;
   }
   if (!fTable)
      return;

   Int_t slot = FindElement(op);
   if (fTable[slot] == 0) {
      fTable[slot] = op;
      fTally++;
      if (HighWaterMark())
         Expand(2 * fSize);
   }
}

//______________________________________________________________________________
void TObjectTable::AddObj(TObject *op)
{
   // Add an object to the global object table gObjectTable. If the global
   // table does not exist create it first. This member function may only
   // be used by TObject::TObject. Use Add() to add objects to any other
   // TObjectTable object. This is a static function.

   static Bool_t olock = kFALSE;

   if (!op) {
      ::Error("TObjectTable::AddObj", "op is 0");
      return;
   }
   if (olock)
      return;

   if (!gObjectTable) {
      olock = kTRUE;
      gObjectTable = new TObjectTable(10000);
      olock = kFALSE;
      gObjectTable->Add(gObjectTable);
   }

   gObjectTable->Add(op);
}

//______________________________________________________________________________
void TObjectTable::Delete(Option_t *)
{
   // Delete all objects stored in the TObjectTable.

   for (int i = 0; i < fSize; i++) {
      if (fTable[i]) {
         delete fTable[i];
         fTable[i] = 0;
      }
   }
   fTally = 0;
}

//______________________________________________________________________________
void TObjectTable::Remove(TObject *op)
{
   // Remove an object from the object table.

   if (op == 0) {
      Error("Remove", "remove 0 from TObjectTable");
      return;
   }

   if (!fTable)
      return;

   Int_t i = FindElement(op);
   if (fTable[i] == 0) {
      Warning("Remove", "0x%08x not found at %d", (long)op, i);
      for (int j = 0; j < fSize; j++) {
         if (fTable[j] == op) {
            Error("Remove", "%d found at %d !!!", (long)op, j);
            i = j;
         }
      }
   }

   if (fTable[i]) {
      fTable[i] = 0;
      FixCollisions(i);
      fTally--;
   }
}

//______________________________________________________________________________
void TObjectTable::RemoveQuietly(TObject *op)
{
   // Remove an object from the object table. If op is 0 or not in the table
   // don't complain. Currently only used by the TClonesArray dtor. Should not
   // be used anywhere else, except in places where "special" allocation and
   // de-allocation tricks are performed.

   if (op == 0) return;

   if (!fTable)
      return;

   Int_t i = FindElement(op);
   if (fTable[i] == 0)
      for (int j = 0; j < fSize; j++)
         if (fTable[j] == op)
            i = j;

   fTable[i] = 0;
   FixCollisions(i);
   fTally--;
}

//______________________________________________________________________________
void TObjectTable::Terminate()
{
   // Deletes the object table (this static class function calls the dtor).

   InstanceStatistics();
   delete [] fTable; fTable = 0;
}

//______________________________________________________________________________
Int_t TObjectTable::FindElement(TObject *op)
{
   // Find an object in the object table. Returns the slot where to put
   // the object. To test if the object is actually already in the table
   // use PtrIsValid().

   Int_t    slot, n;
   TObject *slotOp;

   if (!fTable)
      return 0;

   //slot = Int_t(((ULong_t) op >> 2) % fSize);
   slot = Int_t(TMath::Hash(&op, sizeof(TObject*)) % fSize);
   for (n = 0; n < fSize; n++) {
      if ((slotOp = fTable[slot]) == 0)
         break;
      if (op == slotOp)
         break;
      if (++slot == fSize)
         slot = 0;
   }
   return slot;
}

//______________________________________________________________________________
void TObjectTable::FixCollisions(Int_t index)
{
   // Rehash the object table in case an object has been removed.

   Int_t oldIndex, nextIndex;
   TObject *nextObject;

   for (oldIndex = index+1; ;oldIndex++) {
      if (oldIndex >= fSize)
         oldIndex = 0;
      nextObject = fTable[oldIndex];
      if (nextObject == 0)
         break;
      nextIndex = FindElement(nextObject);
      if (nextIndex != oldIndex) {
         fTable[nextIndex] = nextObject;
         fTable[oldIndex] = 0;
      }
   }
}

//______________________________________________________________________________
void TObjectTable::Expand(Int_t newSize)
{
   // Expand the object table.

   TObject **oldTable = fTable, *op;
   int oldsize = fSize;
   newSize = (Int_t)TMath::NextPrime(newSize);
   fTable  = new TObject* [newSize];
   memset(fTable, 0, newSize*sizeof(TObject*));
   fSize   = newSize;
   fTally  = 0;
   for (int i = 0; i < oldsize; i++)
      if ((op = oldTable[i]))
         Add(op);
   delete [] oldTable;
}

//______________________________________________________________________________
void TObjectTable::InstanceStatistics() const
{
   // Print the object table.

   int n, h, s, ncum = 0, hcum = 0, scum = 0, tcum = 0, thcum = 0;

   if (fTally == 0 || !fTable)
      return;

   UpdateInstCount();

   Printf("");
   Printf("Object statistics");
   Printf("class                     cnt    on heap     size    total size    heap size");
   Printf("============================================================================");
   TIter next(gROOT->GetListOfClasses());
   TClass *cl;
   while ((cl = (TClass*) next())) {
      n = cl->GetInstanceCount();
      h = cl->GetHeapInstanceCount();
      s = cl->Size();
      if (n > 0) {
         Printf("%-20s %8d%11d%9d%14d%13d", cl->GetName(), n, h, s, n*s, h*s);
         ncum  += n;
         hcum  += h;
         scum  += s;
         tcum  += n*s;
         thcum += h*s;
      }
   }
   Printf("----------------------------------------------------------------------------");
   Printf("Total:               %8d%11d%9d%14d%13d", ncum, hcum, scum, tcum, thcum);
   Printf("============================================================================");
   Printf("");
}

//______________________________________________________________________________
void TObjectTable::UpdateInstCount() const
{
   // Histogram all objects according to their classes.

   TObject *op;

   if (!fTable || !TROOT::Initialized())
      return;

   gROOT->GetListOfClasses()->ForEach(TClass,ResetInstanceCount)();

   for (int i = 0; i < fSize; i++)
      if ((op = fTable[i])) {                // attention: no ==
         if (op->TestBit(TObject::kNotDeleted))
            op->IsA()->AddInstance(op->IsOnHeap());
         else
            Error("UpdateInstCount", "oops 0x%08x\n", op);
      }
}

//______________________________________________________________________________
void *TObjectTable::CheckPtrAndWarn(const char *msg, void *vp)
{
   // Issue a warning in case an object still appears in the table
   // while it should not.

   if (fTable && vp && fTable[FindElement((TObject*)vp)]) {
      Remove((TObject*)vp);
      Warning("CheckPtrAndWarn", "%s (0x%08x)\n", msg, vp);
   }
   return vp;
}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Data Differential YATL (i.e. libtest)  library
 *
 *  Copyright (C) 2012 Data Differential, http://datadifferential.com/
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "libtest/yatlcon.h"
#include <libtest/common.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fnmatch.h>
#include <iostream>
#include <fstream>
#include <memory>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <signal.h>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

using namespace libtest;

static void stats_print(libtest::Framework *frame)
{
  if (frame->failed() == 0 and frame->success() == 0)
  {
    return;
  }

  Outn();
  Out << "Collections\t\t\t\t\t" << frame->total();
  Out << "\tFailed\t\t\t\t\t" << frame->failed();
  Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
  Out << "\tSucceeded\t\t\t\t" << frame->success();
  Outn();
  Out << "Tests\t\t\t\t\t" << frame->sum_total();
  Out << "\tFailed\t\t\t\t" << frame->sum_failed();
  Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
  Out << "\tSucceeded\t\t\t" << frame->sum_success();
}

#include <getopt.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  bool opt_massive= false;
  unsigned long int opt_repeat= 1; // Run all tests once
  bool opt_quiet= false;
  std::string collection_to_run;
  std::string wildcard;
  std::string binary_name;

  const char *just_filename= rindex(argv[0], '/');
  if (just_filename)
  {
    just_filename++;
  }
  else
  {
    just_filename= argv[0];
  }

  if (just_filename[0] == 'l' and just_filename[1] == 't' and  just_filename[2] == '-')
  {
    just_filename+= 3;
  }
  binary_name.append(just_filename);

  /*
    Valgrind does not currently work reliably, or sometimes at all, on OSX
    - Fri Jun 15 11:24:07 EDT 2012
  */
#if defined(TARGET_OS_OSX) && TARGET_OS_OSX
  if (valgrind_is_caller())
  {
    return EXIT_SKIP;
  }
#endif

  // Options parsing
  {
    enum long_option_t {
      OPT_LIBYATL_VERSION,
      OPT_LIBYATL_MATCH_COLLECTION,
      OPT_LIBYATL_MASSIVE,
      OPT_LIBYATL_QUIET,
      OPT_LIBYATL_MATCH_WILDCARD,
      OPT_LIBYATL_REPEAT
    };

    static struct option long_options[]=
    {
      { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
      { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
      { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT },
      { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
      { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
      { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
      { 0, 0, 0, 0 }
    };

    int option_index= 0;
    while (1)
    {
      int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
      if (option_rv == -1)
      {
        break;
      }

      switch (option_rv)
      {
      case OPT_LIBYATL_VERSION:
        break;

      case OPT_LIBYATL_QUIET:
        opt_quiet= true;
        break;

      case OPT_LIBYATL_REPEAT:
        opt_repeat= strtoul(optarg, (char **) NULL, 10);
        break;

      case OPT_LIBYATL_MATCH_COLLECTION:
        collection_to_run= optarg;
        break;

      case OPT_LIBYATL_MATCH_WILDCARD:
        wildcard= optarg;
        break;

      case OPT_LIBYATL_MASSIVE:
        opt_massive= true;
        break;

      case '?':
        /* getopt_long already printed an error message. */
        Error << "unknown option to getopt_long()";
        exit(EXIT_FAILURE);

      default:
        break;
      }
    }
  }

  srandom((unsigned int)time(NULL));

  if (bool(getenv("YATL_REPEAT")) and (strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10) > 1))
  {
    opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
  }

  if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
  {
    opt_quiet= true;
  }
  else if (getenv("JENKINS_URL"))
  {
    if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
    { }
    else
    {
      opt_quiet= true;
    }
  }

  if ((bool(getenv("YATL_RUN_MASSIVE_TESTS"))) or opt_massive)
  {
    opt_massive= true;
  }

  if (opt_quiet)
  {
    close(STDOUT_FILENO);
  }

  if (opt_massive)
  {
    is_massive(opt_massive);
  }

  libtest::vchar_t tmp_directory;
  tmp_directory.resize(1024);
  if (getenv("LIBTEST_TMP"))
  {
    snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP"));
  }
  else
  {
    snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP);
  }

  if (chdir(&tmp_directory[0]) == -1)
  {
    libtest::vchar_t getcwd_buffer;
    getcwd_buffer.resize(1024);
    char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size());

    Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno);
    return EXIT_FAILURE;
  }

  if (libtest::libtool() == NULL)
  {
    Error << "Failed to locate libtool";
    return EXIT_FAILURE;
  }

  if (getenv("YATL_COLLECTION_TO_RUN"))
  {
    if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
    {
      collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
    }
  }

  if (collection_to_run.compare("none") == 0)
  {
    return EXIT_SUCCESS;
  }

  if (collection_to_run.empty() == false)
  {
    Out << "Only testing " <<  collection_to_run;
  }

  int exit_code;

  try
  {
    do
    {
      exit_code= EXIT_SUCCESS;
      fatal_assert(sigignore(SIGPIPE) == 0);

      libtest::SignalThread signal;
      if (signal.setup() == false)
      {
        Error << "Failed to setup signals";
        return EXIT_FAILURE;
      }

      std::auto_ptr<libtest::Framework> frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard));

      // Run create(), bail on error.
      try
      {
        switch (frame->create())
        {
        case TEST_SUCCESS:
          break;

        case TEST_SKIPPED:
          return EXIT_SKIP;

        case TEST_FAILURE:
          std::cerr << "Could not call frame->create()" << std::endl;
          return EXIT_FAILURE;
        }
      }
      catch (const libtest::__skipped& e)
      {
        return EXIT_SKIP;
      }

      frame->exec();

      if (signal.is_shutdown() == false)
      {
        signal.set_shutdown(SHUTDOWN_GRACEFUL);
      }

      shutdown_t status= signal.get_shutdown();
      if (status == SHUTDOWN_FORCED)
      {
        Out << "Tests were aborted.";
        exit_code= EXIT_FAILURE;
      }
      else if (frame->failed())
      {
        Out << "Some test failed.";
        exit_code= EXIT_FAILURE;
      }
      else if (frame->skipped() and frame->failed() and frame->success())
      {
        Out << "Some tests were skipped.";
      }
      else if (frame->success() and (frame->failed() == 0))
      {
        Out;
        Out << "All tests completed successfully.";
      }

      stats_print(frame.get());

      std::ofstream xml_file;
      std::string file_name;
      file_name.append(&tmp_directory[0]);
      file_name.append(frame->name());
      file_name.append(".xml");
      xml_file.open(file_name.c_str(), std::ios::trunc);
      libtest::Formatter::xml(*frame, xml_file);

      Outn(); // Generate a blank to break up the messages if make check/test has been run
    } while (exit_code == EXIT_SUCCESS and --opt_repeat);
  }
  catch (const libtest::__skipped& e)
  {
    return EXIT_SKIP;
  }
  catch (const libtest::__failure& e)
  {
    libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
    exit_code= EXIT_FAILURE;
  }
  catch (const libtest::fatal& e)
  {
    std::cerr << "FATAL:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (const libtest::disconnected& e)
  {
    std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cerr << "std::exception:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (char const*)
  {
    std::cerr << "Exception:" << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (...)
  {
    std::cerr << "Unknown exception halted execution." << std::endl;
    exit_code= EXIT_FAILURE;
  }

  return exit_code;
}
<commit_msg>Fix output for main.cc errors which are strings.<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Data Differential YATL (i.e. libtest)  library
 *
 *  Copyright (C) 2012 Data Differential, http://datadifferential.com/
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 *
 *      * Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *
 *      * Redistributions in binary form must reproduce the above
 *  copyright notice, this list of conditions and the following disclaimer
 *  in the documentation and/or other materials provided with the
 *  distribution.
 *
 *      * The names of its contributors may not be used to endorse or
 *  promote products derived from this software without specific prior
 *  written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include "libtest/yatlcon.h"
#include <libtest/common.h>

#include <cassert>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <fnmatch.h>
#include <iostream>
#include <fstream>
#include <memory>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include <signal.h>

#ifndef __INTEL_COMPILER
#pragma GCC diagnostic ignored "-Wold-style-cast"
#endif

using namespace libtest;

static void stats_print(libtest::Framework *frame)
{
  if (frame->failed() == 0 and frame->success() == 0)
  {
    return;
  }

  Outn();
  Out << "Collections\t\t\t\t\t" << frame->total();
  Out << "\tFailed\t\t\t\t\t" << frame->failed();
  Out << "\tSkipped\t\t\t\t\t" << frame->skipped();
  Out << "\tSucceeded\t\t\t\t" << frame->success();
  Outn();
  Out << "Tests\t\t\t\t\t" << frame->sum_total();
  Out << "\tFailed\t\t\t\t" << frame->sum_failed();
  Out << "\tSkipped\t\t\t\t" << frame->sum_skipped();
  Out << "\tSucceeded\t\t\t" << frame->sum_success();
}

#include <getopt.h>
#include <unistd.h>

int main(int argc, char *argv[])
{
  bool opt_massive= false;
  unsigned long int opt_repeat= 1; // Run all tests once
  bool opt_quiet= false;
  std::string collection_to_run;
  std::string wildcard;
  std::string binary_name;

  const char *just_filename= rindex(argv[0], '/');
  if (just_filename)
  {
    just_filename++;
  }
  else
  {
    just_filename= argv[0];
  }

  if (just_filename[0] == 'l' and just_filename[1] == 't' and  just_filename[2] == '-')
  {
    just_filename+= 3;
  }
  binary_name.append(just_filename);

  /*
    Valgrind does not currently work reliably, or sometimes at all, on OSX
    - Fri Jun 15 11:24:07 EDT 2012
  */
#if defined(TARGET_OS_OSX) && TARGET_OS_OSX
  if (valgrind_is_caller())
  {
    return EXIT_SKIP;
  }
#endif

  // Options parsing
  {
    enum long_option_t {
      OPT_LIBYATL_VERSION,
      OPT_LIBYATL_MATCH_COLLECTION,
      OPT_LIBYATL_MASSIVE,
      OPT_LIBYATL_QUIET,
      OPT_LIBYATL_MATCH_WILDCARD,
      OPT_LIBYATL_REPEAT
    };

    static struct option long_options[]=
    {
      { "version", no_argument, NULL, OPT_LIBYATL_VERSION },
      { "quiet", no_argument, NULL, OPT_LIBYATL_QUIET },
      { "repeat", required_argument, NULL, OPT_LIBYATL_REPEAT },
      { "collection", required_argument, NULL, OPT_LIBYATL_MATCH_COLLECTION },
      { "wildcard", required_argument, NULL, OPT_LIBYATL_MATCH_WILDCARD },
      { "massive", no_argument, NULL, OPT_LIBYATL_MASSIVE },
      { 0, 0, 0, 0 }
    };

    int option_index= 0;
    while (1)
    {
      int option_rv= getopt_long(argc, argv, "", long_options, &option_index);
      if (option_rv == -1)
      {
        break;
      }

      switch (option_rv)
      {
      case OPT_LIBYATL_VERSION:
        break;

      case OPT_LIBYATL_QUIET:
        opt_quiet= true;
        break;

      case OPT_LIBYATL_REPEAT:
        opt_repeat= strtoul(optarg, (char **) NULL, 10);
        break;

      case OPT_LIBYATL_MATCH_COLLECTION:
        collection_to_run= optarg;
        break;

      case OPT_LIBYATL_MATCH_WILDCARD:
        wildcard= optarg;
        break;

      case OPT_LIBYATL_MASSIVE:
        opt_massive= true;
        break;

      case '?':
        /* getopt_long already printed an error message. */
        Error << "unknown option to getopt_long()";
        exit(EXIT_FAILURE);

      default:
        break;
      }
    }
  }

  srandom((unsigned int)time(NULL));

  if (bool(getenv("YATL_REPEAT")) and (strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10) > 1))
  {
    opt_repeat= strtoul(getenv("YATL_REPEAT"), (char **) NULL, 10);
  }

  if ((bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "0") == 0)) or opt_quiet)
  {
    opt_quiet= true;
  }
  else if (getenv("JENKINS_URL"))
  {
    if (bool(getenv("YATL_QUIET")) and (strcmp(getenv("YATL_QUIET"), "1") == 0))
    { }
    else
    {
      opt_quiet= true;
    }
  }

  if ((bool(getenv("YATL_RUN_MASSIVE_TESTS"))) or opt_massive)
  {
    opt_massive= true;
  }

  if (opt_quiet)
  {
    close(STDOUT_FILENO);
  }

  if (opt_massive)
  {
    is_massive(opt_massive);
  }

  libtest::vchar_t tmp_directory;
  tmp_directory.resize(1024);
  if (getenv("LIBTEST_TMP"))
  {
    snprintf(&tmp_directory[0], tmp_directory.size(), "%s", getenv("LIBTEST_TMP"));
  }
  else
  {
    snprintf(&tmp_directory[0], tmp_directory.size(), "%s", LIBTEST_TEMP);
  }

  if (chdir(&tmp_directory[0]) == -1)
  {
    libtest::vchar_t getcwd_buffer;
    getcwd_buffer.resize(1024);
    char *dir= getcwd(&getcwd_buffer[0], getcwd_buffer.size());

    Error << "Unable to chdir() from " << dir << " to " << &tmp_directory[0] << " errno:" << strerror(errno);
    return EXIT_FAILURE;
  }

  if (libtest::libtool() == NULL)
  {
    Error << "Failed to locate libtool";
    return EXIT_FAILURE;
  }

  if (getenv("YATL_COLLECTION_TO_RUN"))
  {
    if (strlen(getenv("YATL_COLLECTION_TO_RUN")))
    {
      collection_to_run= getenv("YATL_COLLECTION_TO_RUN");
    }
  }

  if (collection_to_run.compare("none") == 0)
  {
    return EXIT_SUCCESS;
  }

  if (collection_to_run.empty() == false)
  {
    Out << "Only testing " <<  collection_to_run;
  }

  int exit_code;

  try
  {
    do
    {
      exit_code= EXIT_SUCCESS;
      fatal_assert(sigignore(SIGPIPE) == 0);

      libtest::SignalThread signal;
      if (signal.setup() == false)
      {
        Error << "Failed to setup signals";
        return EXIT_FAILURE;
      }

      std::auto_ptr<libtest::Framework> frame(new libtest::Framework(signal, binary_name, collection_to_run, wildcard));

      // Run create(), bail on error.
      try
      {
        switch (frame->create())
        {
        case TEST_SUCCESS:
          break;

        case TEST_SKIPPED:
          return EXIT_SKIP;

        case TEST_FAILURE:
          std::cerr << "Could not call frame->create()" << std::endl;
          return EXIT_FAILURE;
        }
      }
      catch (const libtest::__skipped& e)
      {
        return EXIT_SKIP;
      }

      frame->exec();

      if (signal.is_shutdown() == false)
      {
        signal.set_shutdown(SHUTDOWN_GRACEFUL);
      }

      shutdown_t status= signal.get_shutdown();
      if (status == SHUTDOWN_FORCED)
      {
        Out << "Tests were aborted.";
        exit_code= EXIT_FAILURE;
      }
      else if (frame->failed())
      {
        Out << "Some test failed.";
        exit_code= EXIT_FAILURE;
      }
      else if (frame->skipped() and frame->failed() and frame->success())
      {
        Out << "Some tests were skipped.";
      }
      else if (frame->success() and (frame->failed() == 0))
      {
        Out;
        Out << "All tests completed successfully.";
      }

      stats_print(frame.get());

      std::ofstream xml_file;
      std::string file_name;
      file_name.append(&tmp_directory[0]);
      file_name.append(frame->name());
      file_name.append(".xml");
      xml_file.open(file_name.c_str(), std::ios::trunc);
      libtest::Formatter::xml(*frame, xml_file);

      Outn(); // Generate a blank to break up the messages if make check/test has been run
    } while (exit_code == EXIT_SUCCESS and --opt_repeat);
  }
  catch (const libtest::__skipped& e)
  {
    return EXIT_SKIP;
  }
  catch (const libtest::__failure& e)
  {
    libtest::stream::make_cout(e.file(), e.line(), e.func()) << e.what();
    exit_code= EXIT_FAILURE;
  }
  catch (const libtest::fatal& e)
  {
    std::cerr << "FATAL:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (const libtest::disconnected& e)
  {
    std::cerr << "Unhandled disconnection occurred:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (const std::exception& e)
  {
    std::cerr << "std::exception:" << e.what() << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (char const* s)
  {
    std::cerr << "Exception:" << s << std::endl;
    exit_code= EXIT_FAILURE;
  }
  catch (...)
  {
    std::cerr << "Unknown exception halted execution." << std::endl;
    exit_code= EXIT_FAILURE;
  }

  return exit_code;
}
<|endoftext|>