<commit_before>/**
 * @file llthread.cpp
 *
 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"
#include "llapr.h"

#include "apr_portable.h"

#include "llthread.h"

#include "lltimer.h"

#if LL_LINUX || LL_SOLARIS
#include <sched.h>
#endif

//----------------------------------------------------------------------------
// Usage:
// void run_func(LLThread* thread)
// {
// }
// LLThread* thread = new LLThread();
// thread->run(run_func);
// ...
// thread->setQuitting();
// while(!timeout)
// {
//   if (thread->isStopped())
//   {
//     delete thread;
//     break;
//   }
// }
//
//----------------------------------------------------------------------------

//
// Handed to the APR thread creation function
//
void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
{
	LLThread *threadp = (LLThread *)datap;

	// Set thread state to running
	threadp->mStatus = RUNNING;

	// Run the user supplied function
	threadp->run();

	llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;

	// We're done with the run function, this thread is done executing now.
	threadp->mStatus = STOPPED;

	return NULL;
}

LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
	mPaused(FALSE),
	mName(name),
	mAPRThreadp(NULL),
	mStatus(STOPPED)
{
	// Thread creation probably CAN be paranoid about APR being initialized, if necessary
	if (poolp)
	{
		mIsLocalPool = FALSE;
		mAPRPoolp = poolp;
	}
	else
	{
		mIsLocalPool = TRUE;
		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
	}
	mRunCondition = new LLCondition(mAPRPoolp);

	mLocalAPRFilePoolp = NULL ;
}

LLThread::~LLThread()
{
	shutdown();

	if(mLocalAPRFilePoolp)
	{
		delete mLocalAPRFilePoolp ;
		mLocalAPRFilePoolp = NULL ;
	}
}

void LLThread::shutdown()
{
	// Warning!  If you somehow call the thread destructor from itself,
	// the thread will die in an unclean fashion!
	if (mAPRThreadp)
	{
		if (!isStopped())
		{
			// The thread isn't already stopped
			// First, set the flag that indicates that we're ready to die
			setQuitting();

			llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
			// Now wait a bit for the thread to exit
			// It's unclear whether I should even bother doing this - this destructor
			// should netver get called unless we're already stopped, really...
			S32 counter = 0;
			const S32 MAX_WAIT = 600;
			while (counter < MAX_WAIT)
			{
				if (isStopped())
				{
					break;
				}
				// Sleep for a tenth of a second
				ms_sleep(100);
				yield();
				counter++;
			}
		}

		if (!isStopped())
		{
			// This thread just wouldn't stop, even though we gave it time
			llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
			return;
		}
		mAPRThreadp = NULL;
	}

	delete mRunCondition;

	if (mIsLocalPool)
	{
		apr_pool_destroy(mAPRPoolp);
	}
}

void LLThread::start()
{
	apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);

	// We won't bother joining
	apr_thread_detach(mAPRThreadp);
}

//============================================================================
// Called from MAIN THREAD.

// Request that the thread pause/resume.
// The thread will pause when (and if) it calls checkPause()
void LLThread::pause()
{
	if (!mPaused)
	{
		// this will cause the thread to stop execution as soon as checkPause() is called
		mPaused = 1;		// Does not need to be atomic since this is only set/unset from the main thread
	}
}

void LLThread::unpause()
{
	if (mPaused)
	{
		mPaused = 0;
	}

	wake(); // wake up the thread if necessary
}

// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
bool LLThread::runCondition(void)
{
	// by default, always run.  Handling of pause/unpause is done regardless of this function's result.
	return true;
}

//============================================================================
// Called from run() (CHILD THREAD).
// Stop thread execution if requested until unpaused.
void LLThread::checkPause()
{
	mRunCondition->lock();

	// This is in a while loop because the pthread API allows for spurious wakeups.
	while(shouldSleep())
	{
		mRunCondition->wait(); // unlocks mRunCondition
		// mRunCondition is locked when the thread wakes up
	}

 	mRunCondition->unlock();
}

//============================================================================

void LLThread::setQuitting()
{
	mRunCondition->lock();
	if (mStatus == RUNNING)
	{
		mStatus = QUITTING;
	}
	mRunCondition->unlock();
	wake();
}

// static
U32 LLThread::currentID()
{
	return (U32)apr_os_thread_current();
}

// static
void LLThread::yield()
{
#if LL_LINUX || LL_SOLARIS
	sched_yield(); // annoyingly, apr_thread_yield  is a noop on linux...
#else
	apr_thread_yield();
#endif
}

void LLThread::wake()
{
	mRunCondition->lock();
	if(!shouldSleep())
	{
		mRunCondition->signal();
	}
	mRunCondition->unlock();
}

void LLThread::wakeLocked()
{
	if(!shouldSleep())
	{
		mRunCondition->signal();
	}
}

//============================================================================

LLMutex::LLMutex(apr_pool_t *poolp) :
	mAPRMutexp(NULL)
{
	//if (poolp)
	//{
	//	mIsLocalPool = FALSE;
	//	mAPRPoolp = poolp;
	//}
	//else
	{
		mIsLocalPool = TRUE;
		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
	}
	apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
}

LLMutex::~LLMutex()
{
#if MUTEX_DEBUG
	llassert_always(!isLocked()); // better not be locked!
#endif
	apr_thread_mutex_destroy(mAPRMutexp);
	mAPRMutexp = NULL;
	if (mIsLocalPool)
	{
		apr_pool_destroy(mAPRPoolp);
	}
}

void LLMutex::lock()
{
	apr_thread_mutex_lock(mAPRMutexp);
#if MUTEX_DEBUG
	// Have to have the lock before we can access the debug info
	U32 id = LLThread::currentID();
	if (mIsLocked[id] != FALSE)
		llerrs << "Already locked in Thread: " << id << llendl;
	mIsLocked[id] = TRUE;
#endif
}

void LLMutex::unlock()
{
#if MUTEX_DEBUG
	// Access the debug info while we have the lock
	U32 id = LLThread::currentID();
	if (mIsLocked[id] != TRUE)
		llerrs << "Not locked in Thread: " << id << llendl;
	mIsLocked[id] = FALSE;
#endif
	apr_thread_mutex_unlock(mAPRMutexp);
}

bool LLMutex::isLocked()
{
	apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
	if (APR_STATUS_IS_EBUSY(status))
	{
		return true;
	}
	else
	{
		apr_thread_mutex_unlock(mAPRMutexp);
		return false;
	}
}

//============================================================================

LLCondition::LLCondition(apr_pool_t *poolp) :
	LLMutex(poolp)
{
	// base class (LLMutex) has already ensured that mAPRPoolp is set up.

	apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
}

LLCondition::~LLCondition()
{
	apr_thread_cond_destroy(mAPRCondp);
	mAPRCondp = NULL;
}

void LLCondition::wait()
{
	apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
}

void LLCondition::signal()
{
	apr_thread_cond_signal(mAPRCondp);
}

void LLCondition::broadcast()
{
	apr_thread_cond_broadcast(mAPRCondp);
}

//============================================================================

//----------------------------------------------------------------------------

//static
LLMutex* LLThreadSafeRefCount::sMutex = 0;

//static
void LLThreadSafeRefCount::initThreadSafeRefCount()
{
	if (!sMutex)
	{
		sMutex = new LLMutex(0);
	}
}

//static
void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
{
	delete sMutex;
	sMutex = NULL;
}

//----------------------------------------------------------------------------

LLThreadSafeRefCount::LLThreadSafeRefCount() :
	mRef(0)
{
}

LLThreadSafeRefCount::~LLThreadSafeRefCount()
{
	if (mRef != 0)
	{
		llerrs << "deleting non-zero reference" << llendl;
	}
}

//============================================================================

LLResponder::~LLResponder()
{
}

//============================================================================
<commit_msg>Fix crash if thread is manually shut down before it is destroyed.<commit_after>/**
 * @file llthread.cpp
 *
 * $LicenseInfo:firstyear=2004&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2010, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#include "linden_common.h"
#include "llapr.h"

#include "apr_portable.h"

#include "llthread.h"

#include "lltimer.h"

#if LL_LINUX || LL_SOLARIS
#include <sched.h>
#endif

//----------------------------------------------------------------------------
// Usage:
// void run_func(LLThread* thread)
// {
// }
// LLThread* thread = new LLThread();
// thread->run(run_func);
// ...
// thread->setQuitting();
// while(!timeout)
// {
//   if (thread->isStopped())
//   {
//     delete thread;
//     break;
//   }
// }
//
//----------------------------------------------------------------------------

//
// Handed to the APR thread creation function
//
void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap)
{
	LLThread *threadp = (LLThread *)datap;

	// Set thread state to running
	threadp->mStatus = RUNNING;

	// Run the user supplied function
	threadp->run();

	llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;

	// We're done with the run function, this thread is done executing now.
	threadp->mStatus = STOPPED;

	return NULL;
}

LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
	mPaused(FALSE),
	mName(name),
	mAPRThreadp(NULL),
	mStatus(STOPPED)
{
	// Thread creation probably CAN be paranoid about APR being initialized, if necessary
	if (poolp)
	{
		mIsLocalPool = FALSE;
		mAPRPoolp = poolp;
	}
	else
	{
		mIsLocalPool = TRUE;
		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
	}
	mRunCondition = new LLCondition(mAPRPoolp);

	mLocalAPRFilePoolp = NULL ;
}

LLThread::~LLThread()
{
	shutdown();

	if(mLocalAPRFilePoolp)
	{
		delete mLocalAPRFilePoolp ;
		mLocalAPRFilePoolp = NULL ;
	}
}

void LLThread::shutdown()
{
	// Warning!  If you somehow call the thread destructor from itself,
	// the thread will die in an unclean fashion!
	if (mAPRThreadp)
	{
		if (!isStopped())
		{
			// The thread isn't already stopped
			// First, set the flag that indicates that we're ready to die
			setQuitting();

			llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
			// Now wait a bit for the thread to exit
			// It's unclear whether I should even bother doing this - this destructor
			// should netver get called unless we're already stopped, really...
			S32 counter = 0;
			const S32 MAX_WAIT = 600;
			while (counter < MAX_WAIT)
			{
				if (isStopped())
				{
					break;
				}
				// Sleep for a tenth of a second
				ms_sleep(100);
				yield();
				counter++;
			}
		}

		if (!isStopped())
		{
			// This thread just wouldn't stop, even though we gave it time
			llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl;
			return;
		}
		mAPRThreadp = NULL;
	}

	delete mRunCondition;
	mRunCondition = 0;

	if (mIsLocalPool && mAPRPoolp)
	{
		apr_pool_destroy(mAPRPoolp);
		mAPRPoolp = 0;
	}
}

void LLThread::start()
{
	apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, mAPRPoolp);

	// We won't bother joining
	apr_thread_detach(mAPRThreadp);
}

//============================================================================
// Called from MAIN THREAD.

// Request that the thread pause/resume.
// The thread will pause when (and if) it calls checkPause()
void LLThread::pause()
{
	if (!mPaused)
	{
		// this will cause the thread to stop execution as soon as checkPause() is called
		mPaused = 1;		// Does not need to be atomic since this is only set/unset from the main thread
	}
}

void LLThread::unpause()
{
	if (mPaused)
	{
		mPaused = 0;
	}

	wake(); // wake up the thread if necessary
}

// virtual predicate function -- returns true if the thread should wake up, false if it should sleep.
bool LLThread::runCondition(void)
{
	// by default, always run.  Handling of pause/unpause is done regardless of this function's result.
	return true;
}

//============================================================================
// Called from run() (CHILD THREAD).
// Stop thread execution if requested until unpaused.
void LLThread::checkPause()
{
	mRunCondition->lock();

	// This is in a while loop because the pthread API allows for spurious wakeups.
	while(shouldSleep())
	{
		mRunCondition->wait(); // unlocks mRunCondition
		// mRunCondition is locked when the thread wakes up
	}

 	mRunCondition->unlock();
}

//============================================================================

void LLThread::setQuitting()
{
	mRunCondition->lock();
	if (mStatus == RUNNING)
	{
		mStatus = QUITTING;
	}
	mRunCondition->unlock();
	wake();
}

// static
U32 LLThread::currentID()
{
	return (U32)apr_os_thread_current();
}

// static
void LLThread::yield()
{
#if LL_LINUX || LL_SOLARIS
	sched_yield(); // annoyingly, apr_thread_yield  is a noop on linux...
#else
	apr_thread_yield();
#endif
}

void LLThread::wake()
{
	mRunCondition->lock();
	if(!shouldSleep())
	{
		mRunCondition->signal();
	}
	mRunCondition->unlock();
}

void LLThread::wakeLocked()
{
	if(!shouldSleep())
	{
		mRunCondition->signal();
	}
}

//============================================================================

LLMutex::LLMutex(apr_pool_t *poolp) :
	mAPRMutexp(NULL)
{
	//if (poolp)
	//{
	//	mIsLocalPool = FALSE;
	//	mAPRPoolp = poolp;
	//}
	//else
	{
		mIsLocalPool = TRUE;
		apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread
	}
	apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp);
}

LLMutex::~LLMutex()
{
#if MUTEX_DEBUG
	llassert_always(!isLocked()); // better not be locked!
#endif
	apr_thread_mutex_destroy(mAPRMutexp);
	mAPRMutexp = NULL;
	if (mIsLocalPool)
	{
		apr_pool_destroy(mAPRPoolp);
	}
}

void LLMutex::lock()
{
	apr_thread_mutex_lock(mAPRMutexp);
#if MUTEX_DEBUG
	// Have to have the lock before we can access the debug info
	U32 id = LLThread::currentID();
	if (mIsLocked[id] != FALSE)
		llerrs << "Already locked in Thread: " << id << llendl;
	mIsLocked[id] = TRUE;
#endif
}

void LLMutex::unlock()
{
#if MUTEX_DEBUG
	// Access the debug info while we have the lock
	U32 id = LLThread::currentID();
	if (mIsLocked[id] != TRUE)
		llerrs << "Not locked in Thread: " << id << llendl;
	mIsLocked[id] = FALSE;
#endif
	apr_thread_mutex_unlock(mAPRMutexp);
}

bool LLMutex::isLocked()
{
	apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp);
	if (APR_STATUS_IS_EBUSY(status))
	{
		return true;
	}
	else
	{
		apr_thread_mutex_unlock(mAPRMutexp);
		return false;
	}
}

//============================================================================

LLCondition::LLCondition(apr_pool_t *poolp) :
	LLMutex(poolp)
{
	// base class (LLMutex) has already ensured that mAPRPoolp is set up.

	apr_thread_cond_create(&mAPRCondp, mAPRPoolp);
}

LLCondition::~LLCondition()
{
	apr_thread_cond_destroy(mAPRCondp);
	mAPRCondp = NULL;
}

void LLCondition::wait()
{
	apr_thread_cond_wait(mAPRCondp, mAPRMutexp);
}

void LLCondition::signal()
{
	apr_thread_cond_signal(mAPRCondp);
}

void LLCondition::broadcast()
{
	apr_thread_cond_broadcast(mAPRCondp);
}

//============================================================================

//----------------------------------------------------------------------------

//static
LLMutex* LLThreadSafeRefCount::sMutex = 0;

//static
void LLThreadSafeRefCount::initThreadSafeRefCount()
{
	if (!sMutex)
	{
		sMutex = new LLMutex(0);
	}
}

//static
void LLThreadSafeRefCount::cleanupThreadSafeRefCount()
{
	delete sMutex;
	sMutex = NULL;
}

//----------------------------------------------------------------------------

LLThreadSafeRefCount::LLThreadSafeRefCount() :
	mRef(0)
{
}

LLThreadSafeRefCount::~LLThreadSafeRefCount()
{
	if (mRef != 0)
	{
		llerrs << "deleting non-zero reference" << llendl;
	}
}

//============================================================================

LLResponder::~LLResponder()
{
}

//============================================================================
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <stdio.h>

#include <QtCore>
#include <QTextStream>
#include <qservicemanager.h>
#include <QString>

QT_USE_NAMESPACE

QTM_USE_NAMESPACE

class CommandProcessor : public QObject
{
    Q_OBJECT

public:
    CommandProcessor(QObject *parent = 0);
    ~CommandProcessor();

    void execute(const QStringList &options, const QString &cmd, const QStringList &args);
    void showUsage();
    static void showUsage(QTextStream *stream);

public slots:
    void browse(const QStringList &args);
    void search(const QStringList &args);
    void add(const QStringList &args);
    void remove(const QStringList &args);

private:
    bool setOptions(const QStringList &options);
    void showAllEntries();
    void showInterfaceInfo(const QServiceFilter &filter);
    void showServiceInfo(const QString &service);

    QServiceManager *serviceManager;
    QTextStream *stdoutStream;
};

CommandProcessor::CommandProcessor(QObject *parent)
    : QObject(parent),
      serviceManager(0),
      stdoutStream(new QTextStream(stdout))
{
}

CommandProcessor::~CommandProcessor()
{
    delete stdoutStream;
}

void CommandProcessor::execute(const QStringList &options, const QString &cmd, const QStringList &args)
{
    if (cmd.isEmpty()) {
        *stdoutStream << "Error: no command given\n\n";
        showUsage();
        return;
    }

    if (!setOptions(options))
        return;

    int methodIndex = metaObject()->indexOfMethod(cmd.toAscii() + "(QStringList)");
    if (methodIndex < 0) {
        *stdoutStream << "Bad command: " << cmd << "\n\n";
        showUsage();
        return;
    }

    if (!metaObject()->method(methodIndex).invoke(this, Q_ARG(QStringList, args)))
        *stdoutStream << "Cannot invoke method for command:" << cmd << '\n';
}

void CommandProcessor::showUsage()
{
    showUsage(stdoutStream);
}

void CommandProcessor::showUsage(QTextStream *stream)
{
    *stream << "Usage: servicefw [options] <command> [command parameters]\n\n"
            "Commands:\n"
            "\tbrowse     List all registered services\n"
            "\tsearch     Search for a service or interface\n"
            "\tadd        Register a service\n"
            "\tremove     Unregister a service\n"
            "\n"
            "Options:\n"
            "\t--system   Use the system-wide services database instead of the\n"
            "\t           user-specific database\n"
            "\n";
}

void CommandProcessor::browse(const QStringList &args)
{
    Q_UNUSED(args);
    showAllEntries();
}

void CommandProcessor::search(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tsearch <service|interface [version]>\n\n"
                "Examples:\n"
                "\tsearch SomeService\n"
                "\tsearch com.nokia.SomeInterface\n"
                "\tsearch com.nokia.SomeInterface 3.5\n"
                "\tsearch com.nokia.SomeInterface 3.5+\n";
        return;
    }

    const QString &name = args[0];
    if (name.contains('.')) {
        QServiceFilter filter;
        if (args.count() > 1) {
            const QString &version = args[1];
            bool minimumMatch = version.endsWith('+');
            filter.setInterface(name,
                    minimumMatch ? (version.mid(0, version.length()-1)) : version,
                    minimumMatch ? QServiceFilter::MinimumVersionMatch : QServiceFilter::ExactVersionMatch);
            if (filter.interfaceName().isEmpty()) { // setInterface() failed
                *stdoutStream << "Error: invalid interface version: " << version << '\n';
                return;
            }
        } else {
            filter.setInterface(name);
        }
        showInterfaceInfo(filter);
    } else {
        showServiceInfo(name);
    }
}

static const char * const errorTable[] = {
    "No error", //0
    "Storage read error",
    "Invalid service location",
    "Invalid service xml",
    "Invalid service interface descriptor",
    "Service already exists",
    "Interface implementation already exists",
    "Loading of plug-in failed",
    "Service or interface not found",
    "Insufficient capabilities to access service",
    "Unknown error"
};

void CommandProcessor::add(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tadd <service-xml-file>\n";
        return;
    }

    const QString &xmlPath = args[0];
    if (!QFile::exists(xmlPath)) {
        *stdoutStream << "Error: cannot find file " << xmlPath << '\n';
        return;
    }

    if (serviceManager->addService(xmlPath)) {
        *stdoutStream << "Registered service at " << xmlPath << '\n';
    } else {
        int error = serviceManager->error();
        if (error > 11) //map anything larger than 11 to 11
            error = 11;
        *stdoutStream << "Error: cannot register service at " << xmlPath
                << " (" << errorTable[error] << ")" << '\n';
    }
}

void CommandProcessor::remove(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tremove <service-name>\n";
        return;
    }

    const QString &service = args[0];
    if (serviceManager->removeService(service))
        *stdoutStream << "Unregistered service " << service << '\n';
    else
        *stdoutStream << "Error: cannot unregister service " << service << '\n';
}

bool CommandProcessor::setOptions(const QStringList &options)
{
    if (serviceManager)
        delete serviceManager;

    QStringList opts = options;
    QMutableListIterator<QString> i(opts);
    while (i.hasNext()) {
        if (i.next() == "--system") {
            serviceManager = new QServiceManager(QService::SystemScope, this);
            i.remove();
        }
    }

    if (!opts.isEmpty()) {
        *stdoutStream << "Bad options: " << opts.join(" ") << "\n\n";
        showUsage();
        return false;
    }

    // other initialization, if not triggered by an option
    if (!serviceManager)
        serviceManager = new QServiceManager(this);

    return true;
}

void CommandProcessor::showAllEntries()
{
    QStringList services = serviceManager->findServices();
    if (services.isEmpty())
        *stdoutStream << "No services found.\n";
    else if (services.count() == 1)
        *stdoutStream << "Found 1 service.\n\n";
    else
        *stdoutStream << "Found " << services.count() << " services.\n\n";

    foreach (const QString &service, services)
        showServiceInfo(service);
}

void CommandProcessor::showInterfaceInfo(const QServiceFilter &filter)
{
    QString interface = filter.interfaceName();
    if (filter.majorVersion() >= 0 && filter.minorVersion() >= 0) {
        interface += QString(" %1.%2").arg(filter.majorVersion()).arg(filter.minorVersion());
        if (filter.versionMatchRule() == QServiceFilter::MinimumVersionMatch)
            interface += '+';
    }

    QList<QServiceInterfaceDescriptor> descriptors = serviceManager->findInterfaces(filter);
    if (descriptors.isEmpty()) {
        *stdoutStream << "Interface " << interface << " not found.\n";
        return;
    }

    *stdoutStream << interface << " is implemented by:\n";
    foreach (const QServiceInterfaceDescriptor &desc, descriptors)
        *stdoutStream << '\t' << desc.serviceName() << '\n';
}

void CommandProcessor::showServiceInfo(const QString &service)
{
    QList<QServiceInterfaceDescriptor> descriptors = serviceManager->findInterfaces(service);
    if (descriptors.isEmpty()) {
        *stdoutStream << "Service " << service << " not found.\n";
        return;
    }

    QString description = descriptors[0].attribute(
            QServiceInterfaceDescriptor::ServiceDescription).toString();
    QStringList capabilities = descriptors[0].attribute(
            QServiceInterfaceDescriptor::Capabilities).toStringList();

    *stdoutStream << service << ":\n";
    if (!description.isEmpty())
        *stdoutStream << '\t' << description << '\n';

    int serviceType = descriptors[0].attribute(QServiceInterfaceDescriptor::ServiceType).toInt();
    if (serviceType == QService::Plugin)
        *stdoutStream << "\tPlugin Library: ";
    else
        *stdoutStream << "\tIPC Address: ";

    *stdoutStream << descriptors[0].attribute(QServiceInterfaceDescriptor::Location).toString() << '\n'
        << "\tCapabilities: " << (capabilities.isEmpty() ? "" : capabilities.join(", ")) << '\n'
        << "\tImplements:\n";

    foreach (const QServiceInterfaceDescriptor &desc, descriptors) {
        *stdoutStream << "\t\t" << desc.interfaceName() << ' '
                << desc.majorVersion() << '.' << desc.minorVersion() << '\n';
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    if (args.count() == 1 || args.value(1) == "--help" || args.value(1) == "-h") {
        QTextStream stream(stdout);
        CommandProcessor::showUsage(&stream);
        return 0;
    }

    QStringList options;
    for (int i=1; i<args.count(); i++) {
        if (args[i].startsWith("--"))
            options += args[i];
    }

    CommandProcessor processor;
    processor.execute(options, args.value(options.count() + 1), args.mid(options.count() + 2));
    return 0;
}

#include "servicefw.moc"
<commit_msg>ServiceFW tool updated for IPC and Scope<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <stdio.h>

#include <QtCore>
#include <QTextStream>
#include <qservicemanager.h>
#include <QString>

QT_USE_NAMESPACE

QTM_USE_NAMESPACE

class CommandProcessor : public QObject
{
    Q_OBJECT

public:
    CommandProcessor(QObject *parent = 0);
    ~CommandProcessor();

    void execute(const QStringList &options, const QString &cmd, const QStringList &args);
    void showUsage();
    static void showUsage(QTextStream *stream);

public slots:
    void browse(const QStringList &args);
    void search(const QStringList &args);
    void add(const QStringList &args);
    void remove(const QStringList &args);

private:
    bool setOptions(const QStringList &options);
    void showAllEntries();
    void showInterfaceInfo(const QServiceFilter &filter);
    void showInterfaceInfo(QList<QServiceInterfaceDescriptor> descriptors);
    void showServiceInfo(const QString &service);

    QServiceManager *serviceManager;
    QTextStream *stdoutStream;
};

CommandProcessor::CommandProcessor(QObject *parent)
    : QObject(parent),
      serviceManager(0),
      stdoutStream(new QTextStream(stdout))
{
}

CommandProcessor::~CommandProcessor()
{
    delete stdoutStream;
}

void CommandProcessor::execute(const QStringList &options, const QString &cmd, const QStringList &args)
{
    if (cmd.isEmpty()) {
        *stdoutStream << "Error: no command given\n\n";
        showUsage();
        return;
    }

    if (!setOptions(options))
        return;

    int methodIndex = metaObject()->indexOfMethod(cmd.toAscii() + "(QStringList)");
    if (methodIndex < 0) {
        *stdoutStream << "Bad command: " << cmd << "\n\n";
        showUsage();
        return;
    }

    if (!metaObject()->method(methodIndex).invoke(this, Q_ARG(QStringList, args)))
        *stdoutStream << "Cannot invoke method for command:" << cmd << '\n';
}

void CommandProcessor::showUsage()
{
    showUsage(stdoutStream);
}

void CommandProcessor::showUsage(QTextStream *stream)
{
    *stream << "Usage: servicefw [options] <command> [command parameters]\n\n"
            "Commands:\n"
            "\tbrowse     List all registered services\n"
            "\tsearch     Search for a service or interface\n"
            "\tadd        Register a service\n"
            "\tremove     Unregister a service\n"
            "\n"
            "Options:\n"
            "\t--system   Use the system-wide services database instead of the\n"
            "\t           user-specific database\n"
            "\t--user     Use the user-specific services database for add/remove.\n"
            "\t           This is the default\n"
            "\n";
}

void CommandProcessor::browse(const QStringList &args)
{
    Q_UNUSED(args);
    showAllEntries();
}

void CommandProcessor::search(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tsearch <service|interface [version]>\n\n"
                "Examples:\n"
                "\tsearch SomeService\n"
                "\tsearch com.nokia.SomeInterface\n"
                "\tsearch com.nokia.SomeInterface 3.5\n"
                "\tsearch com.nokia.SomeInterface 3.5+\n";
        return;
    }

    const QString &name = args[0];
    if (name.contains('.')) {
        QServiceFilter filter;
        if (args.count() > 1) {
            const QString &version = args[1];
            bool minimumMatch = version.endsWith('+');
            filter.setInterface(name,
                    minimumMatch ? (version.mid(0, version.length()-1)) : version,
                    minimumMatch ? QServiceFilter::MinimumVersionMatch : QServiceFilter::ExactVersionMatch);
            if (filter.interfaceName().isEmpty()) { // setInterface() failed
                *stdoutStream << "Error: invalid interface version: " << version << '\n';
                return;
            }
        } else {
            filter.setInterface(name);
        }
        showInterfaceInfo(filter);
    } else {
        showServiceInfo(name);
    }
}

static const char * const errorTable[] = {
    "No error", //0
    "Storage read error",
    "Invalid service location",
    "Invalid service xml",
    "Invalid service interface descriptor",
    "Service already exists",
    "Interface implementation already exists",
    "Loading of plug-in failed",
    "Service or interface not found",
    "Insufficient capabilities to access service",
    "Unknown error"
};

void CommandProcessor::add(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tadd <service-xml-file>\n";
        return;
    }

    const QString &xmlPath = args[0];
    if (!QFile::exists(xmlPath)) {
        *stdoutStream << "Error: cannot find file " << xmlPath << '\n';
        return;
    }

    if (serviceManager->addService(xmlPath)) {
        *stdoutStream << "Registered service at " << xmlPath << '\n';
    } else {
        int error = serviceManager->error();
        if (error > 11) //map anything larger than 11 to 11
            error = 11;
        *stdoutStream << "Error: cannot register service at " << xmlPath
                << " (" << errorTable[error] << ")" << '\n';
    }
}

void CommandProcessor::remove(const QStringList &args)
{
    if (args.isEmpty()) {
        *stdoutStream << "Usage:\n\tremove <service-name>\n";
        return;
    }

    const QString &service = args[0];
    if (serviceManager->removeService(service))
        *stdoutStream << "Unregistered service " << service << '\n';
    else
        *stdoutStream << "Error: cannot unregister service " << service << '\n';
}

bool CommandProcessor::setOptions(const QStringList &options)
{
    if (serviceManager)
        delete serviceManager;

    bool systemScope = false;
    bool userScope = false;

    QStringList opts = options;
    QMutableListIterator<QString> i(opts);
    while (i.hasNext()) {
        QString option = i.next();
        if (option == "--system") {
            systemScope = true;
            i.remove();
        } else if (option == "--user") {
            userScope = true;
            i.remove();
        }
    }

    if (!userScope && systemScope)
        serviceManager = new QServiceManager(QService::SystemScope, this);

    if (!opts.isEmpty()) {
        *stdoutStream << "Bad options: " << opts.join(" ") << "\n\n";
        showUsage();
        return false;
    }

    // other initialization, if not triggered by an option
    if (!serviceManager)
        serviceManager = new QServiceManager(this);

    return true;
}

void CommandProcessor::showAllEntries()
{
    QStringList services = serviceManager->findServices();
    if (services.isEmpty())
        *stdoutStream << "No services found.\n";
    else if (services.count() == 1)
        *stdoutStream << "Found 1 service.\n\n";
    else
        *stdoutStream << "Found " << services.count() << " services.\n\n";

    foreach (const QString &service, services)
        showServiceInfo(service);
}

void CommandProcessor::showInterfaceInfo(const QServiceFilter &filter)
{
    QString interface = filter.interfaceName();
    if (filter.majorVersion() >= 0 && filter.minorVersion() >= 0) {
        interface += QString(" %1.%2").arg(filter.majorVersion()).arg(filter.minorVersion());
        if (filter.versionMatchRule() == QServiceFilter::MinimumVersionMatch)
            interface += '+';
    }

    QList<QServiceInterfaceDescriptor> descriptors = serviceManager->findInterfaces(filter);
    if (descriptors.isEmpty()) {
        *stdoutStream << "Interface " << interface << " not found.\n";
        return;
    }

    *stdoutStream << interface << " is implemented by:\n";
    foreach (const QServiceInterfaceDescriptor &desc, descriptors)
        *stdoutStream << '\t' << desc.serviceName() << '\n';
}

void CommandProcessor::showServiceInfo(const QString &service)
{
    QList<QServiceInterfaceDescriptor> descriptors = serviceManager->findInterfaces(service);
    if (descriptors.isEmpty()) {
        *stdoutStream << "Service " << service << " not found.\n";
        return;
    }

    QList<QServiceInterfaceDescriptor> pluginDesc;
    QList<QServiceInterfaceDescriptor> ipcDesc;
    foreach (const QServiceInterfaceDescriptor &desc, descriptors) {
        int serviceType = desc.attribute(QServiceInterfaceDescriptor::ServiceType).toInt();
        if (serviceType == QService::Plugin)
            pluginDesc.append(desc);
        else
            ipcDesc.append(desc);
    }

    if (pluginDesc.size() > 0) {
        *stdoutStream << service;
        if (ipcDesc.size() > 0)
            *stdoutStream << " (Plugin):\n";
        else
            *stdoutStream << ":\n";

        QString description = pluginDesc[0].attribute(
                QServiceInterfaceDescriptor::ServiceDescription).toString();
        if (!description.isEmpty())
            *stdoutStream << '\t' << description << '\n';

        *stdoutStream << "\tPlugin Library: ";
        showInterfaceInfo(pluginDesc);
    }

    if (ipcDesc.size() > 0) {
        *stdoutStream << service;
        if (pluginDesc.size() > 0)
            *stdoutStream << " (IPC):\n";
        else
            *stdoutStream << ":\n";

        QString description = ipcDesc[0].attribute(
                QServiceInterfaceDescriptor::ServiceDescription).toString();
        if (!description.isEmpty())
            *stdoutStream << '\t' << description << '\n';

        *stdoutStream << "\tIPC Address: ";
        showInterfaceInfo(ipcDesc);
    }
}

void CommandProcessor::showInterfaceInfo(QList<QServiceInterfaceDescriptor> descriptors)
{
    QService::Scope scope = descriptors[0].scope();

    *stdoutStream << descriptors[0].attribute(QServiceInterfaceDescriptor::Location).toString() << '\n'
                  << "\tScope: " << (scope == QService::SystemScope ? "All users" : "Current User") << '\n'
                  << "\tImplements:\n";

    foreach (const QServiceInterfaceDescriptor &desc, descriptors) {
        QStringList capabilities = desc.attribute(
            QServiceInterfaceDescriptor::Capabilities).toStringList();

        *stdoutStream << "\t    " << desc.interfaceName() << ' '
                      << desc.majorVersion() << '.' << desc.minorVersion()
                      << (capabilities.isEmpty() ? "" : "\t{" + capabilities.join(", ") + "}") << "\n";
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    QStringList args = QCoreApplication::arguments();

    // check for at least one non-option argument
    bool exec = false;

    QStringList options;
    for (int i=1; i<args.count(); i++) {
        if (args[i].startsWith("--"))
            options += args[i];
        else
            exec = true;
    }

    if (!exec || args.count() == 1 || args.value(1) == "--help" || args.value(1) == "-h") {
        QTextStream stream(stdout);
        CommandProcessor::showUsage(&stream);
        return 0;
    }

    CommandProcessor processor;
    processor.execute(options, args.value(options.count() + 1), args.mid(options.count() + 2));
    return 0;
}

#include "servicefw.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2019-2021 Morwenn
 * SPDX-License-Identifier: MIT
 */
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <utility>
#include <vector>

#define CPPSORT_ENABLE_ASSERTIONS
//#define CPPSORT_ENABLE_AUDITS

#include <cpp-sort/adapters.h>
#include <cpp-sort/probes.h>
#include <cpp-sort/sorters.h>
#include <cpp-sort/utility/buffer.h>
#include <cpp-sort/utility/functional.h>
#include "../benchmarks/benchmarking-tools/distributions.h"
#include "../testsuite/testing-tools/algorithm.h"
#include "../testsuite/testing-tools/wrapper.h"

struct shuffled_string:
    dist::base_distribution<shuffled_string>
{
    template<typename OutputIterator, typename T=long long int>
    auto operator()(OutputIterator out, long long int size, T start=T(0)) const
        -> void
    {
        // Pseudo-random number generator
        thread_local std::mt19937 engine(15321);

        std::vector<std::string> vec;
        vec.reserve(size);

        T end = start + size;
        for (auto i = start ; i < end ; ++i) {
            auto s = std::to_string(i);
            vec.push_back(std::string(50 - s.size(), '0') + std::move(s));
        }
        std::shuffle(std::begin(vec), std::end(vec), engine);
        std::move(std::begin(vec), std::end(vec), out);
    }
};

template<typename Sorter>
void test(const char* name)
{
    const int size = 412;

    std::vector<std::string> collection;
    auto distribution = shuffled_string{};
    distribution(std::back_inserter(collection), size);

    auto copy = collection;
    cppsort::quick_sort(std::begin(copy), std::end(copy));

    auto sorter = Sorter{};
    sorter(collection);

    // Collect basic data
    auto first_unsorted_it = std::is_sorted_until(std::begin(collection), std::end(collection));
    bool is_collection_sorted = first_unsorted_it == std::end(collection);

    // Display information
    std::cout << std::boolalpha << name << std::endl;
    std::cout << "is the collection sorted? ";
    std::cout << is_collection_sorted << std::endl;
    if (not is_collection_sorted) {
        std::cout << "position of the first unsorted element: "
                  << std::distance(std::begin(collection), first_unsorted_it)
                  << std::endl;
    }
    std::cout << "is it the same as the one sorted with std::sort? ";
    std::cout << (collection == copy) << std::endl;
    std::cout << "were some elements altered? ";
    auto copy2 = collection;
    cppsort::quick_sort(std::begin(collection), std::end(collection));
    std::cout << (collection != copy) << std::endl;

    // Measures of presortedness
    std::cout << '\n'
        << "dis: " << cppsort::probe::dis(copy2) << std::endl
        << "enc: " << cppsort::probe::enc(copy2) << std::endl
        << "exc: " << cppsort::probe::exc(copy2) << std::endl
        << "ham: " << cppsort::probe::ham(copy2) << std::endl
        << "inv: " << cppsort::probe::inv(copy2) << std::endl
        << "max: " << cppsort::probe::max(copy2) << std::endl
        << "mono: " << cppsort::probe::mono(copy2) << std::endl
        << "osc: " << cppsort::probe::osc(copy2) << std::endl
        << "par: " << cppsort::probe::par(copy2) << std::endl
        << "rem: " << cppsort::probe::rem(copy2) << std::endl
        << "runs: " << cppsort::probe::runs(copy2) << std::endl
        << '\n';

    if (size < 40) {
        std::cout << "unsorted collection:\n";
        for (const auto& elem: copy2) {
            std::cout << elem << ' ';
        }
        std::cout << "\n\n" << std::flush;
    }
}

int main()
{
    test<cppsort::poplar_sorter>("poplar_sort");
}
<commit_msg>Slightly improve test_failing_sorter.cpp<commit_after>/*
 * Copyright (c) 2019-2021 Morwenn
 * SPDX-License-Identifier: MIT
 */
#include <algorithm>
#include <iostream>
#include <iterator>
#include <random>
#include <string>
#include <utility>
#include <vector>

#define CPPSORT_ENABLE_ASSERTIONS
//#define CPPSORT_ENABLE_AUDITS

#include <cpp-sort/adapters.h>
#include <cpp-sort/probes.h>
#include <cpp-sort/sorters.h>
#include <cpp-sort/utility/buffer.h>
#include <cpp-sort/utility/functional.h>
#include "../benchmarks/benchmarking-tools/distributions.h"
#include "../testsuite/testing-tools/algorithm.h"
#include "../testsuite/testing-tools/wrapper.h"

struct shuffled_string:
    dist::base_distribution<shuffled_string>
{
    template<typename OutputIterator, typename T=long long int>
    auto operator()(OutputIterator out, long long int size, T start=T(0)) const
        -> void
    {
        // Pseudo-random number generator
        thread_local std::mt19937 engine(15321);

        std::vector<std::string> vec;
        vec.reserve(size);

        T end = start + size;
        for (auto i = start ; i < end ; ++i) {
            auto s = std::to_string(i);
            vec.push_back(std::string(50 - s.size(), '0') + std::move(s));
        }
        std::shuffle(std::begin(vec), std::end(vec), engine);
        std::move(std::begin(vec), std::end(vec), out);
    }
};

template<typename Sorter>
void test(const char* name)
{
    const int size = 412;

    std::vector<std::string> collection;
    auto distribution = shuffled_string{};
    distribution(std::back_inserter(collection), size);

    auto copy = collection;
    cppsort::quick_sort(std::begin(copy), std::end(copy));

    auto sorter = Sorter{};
    sorter(collection);
    auto copy2 = collection;

    // Collect basic data
    auto first_unsorted_it = std::is_sorted_until(std::begin(collection), std::end(collection));
    bool is_collection_sorted = first_unsorted_it == std::end(collection);

    // Display information
    std::cout << std::boolalpha << name << std::endl;
    std::cout << "is the collection sorted? ";
    std::cout << is_collection_sorted << std::endl;
    if (not is_collection_sorted) {
        std::cout << "position of the first unsorted element: "
                  << std::distance(std::begin(collection), first_unsorted_it)
                  << std::endl;
    } else {
        std::cout << "is it the same as the one sorted with quicksort? ";
        std::cout << (collection == copy) << std::endl;
        std::cout << "were some elements altered? ";
        cppsort::quick_sort(std::begin(collection), std::end(collection));
        std::cout << (collection != copy) << std::endl;
    }

    // Measures of presortedness
    std::cout << '\n'
        << "dis: " << cppsort::probe::dis(copy2) << std::endl
        << "enc: " << cppsort::probe::enc(copy2) << std::endl
        << "exc: " << cppsort::probe::exc(copy2) << std::endl
        << "ham: " << cppsort::probe::ham(copy2) << std::endl
        << "inv: " << cppsort::probe::inv(copy2) << std::endl
        << "max: " << cppsort::probe::max(copy2) << std::endl
        << "mono: " << cppsort::probe::mono(copy2) << std::endl
        << "osc: " << cppsort::probe::osc(copy2) << std::endl
        << "par: " << cppsort::probe::par(copy2) << std::endl
        << "rem: " << cppsort::probe::rem(copy2) << std::endl
        << "runs: " << cppsort::probe::runs(copy2) << std::endl
        << '\n';

    if (size < 40) {
        std::cout << "unsorted collection:\n";
        for (const auto& elem: copy2) {
            std::cout << elem << ' ';
        }
        std::cout << "\n\n" << std::flush;
    }
}

int main()
{
    test<cppsort::poplar_sorter>("poplar_sort");
}
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 * Copyright (c) 2016-2018 metaverse core developers (see MVS-AUTHORS)
 *
 * This file is part of metaverse.
 *
 * metaverse is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <metaverse/blockchain/settings.hpp>

#include <boost/filesystem.hpp>
#include <metaverse/consensus/miner.hpp>
#include <metaverse/bitcoin/constants.hpp>

namespace libbitcoin {
namespace blockchain {

using namespace boost::filesystem;

settings::settings()
  : block_pool_capacity(5000),
    transaction_pool_capacity(4096),
    transaction_pool_consistency(false),
    use_testnet_rules(false),
    collect_split_stake(true)
{
}

// Use push_back due to initializer_list bug:
// stackoverflow.com/a/20168627/1172329
settings::settings(bc::settings context)
  : settings()
{
    switch (context)
    {
        case bc::settings::mainnet:
        {
            // FIXEME.p2p-node.cpp, This is for header-first sync, attach_header_sync_session
            basic_checkpoints.reserve(1);
            basic_checkpoints.push_back({ "b81848ef9ae86e84c3da26564bc6ab3a79efc628239d11471ab5cd25c0684c2d", 0 });

            // validate_block, This is for each singel node validate
            checkpoints.reserve(4);
            checkpoints.push_back({ "d4f84eb9acb52cbfb003bd4fb88f4b5cf1f6328f193097d42b9403d7030abb8e", 5000 });
            checkpoints.push_back({ "d4f84eb9acb52cbfb003bd4fb88f4b5cf1f6328f193097d42b9403d7030abb8e", 3800 });
            checkpoints.push_back({ "d120edf7e14d8f426b7390e94ae7bfd746f9fc247b28e336db052295177ac9d3", 410000 });
            checkpoints.push_back({ "ed11a074ce80cbf82b5724bea0d74319dc6f180198fa1bbfb562bcbd50089e63", 1030000 });
            checkpoints.push_back({ "a18a5aa5270835dd720a561c20230435e0508e8339ee30998da6dd79eee83b29", 1270000 });
            // fixme. header sync first has some problem.
            //checkpoints.push_back({ "250a083ddd62ea1d0907e29ff8d64e42c451f93560196f3f693fdc1bc6b84d61", 10000 });
            //checkpoints.push_back({ "e989e4b2d60ae2f8fbaa1cdb69d05afa63e7f1f99cf715589a93e4877c92fa8b", 100000 });
            //checkpoints.push_back({ "58986f8f9848d32aa1a210f3890e82312326657b6b84d2aa4bf00b41403dc191", 200000 });
            //checkpoints.push_back({ "b9ec93b181e5ca3825df23c8100188a503b98d6e7240c7b21cedc980304967ea", 300000 });
            //checkpoints.push_back({ "843411e1194c11cc958abd923498e1a7488ba9b0bccf1a3a5960f3bc213645ce", 400000 });
            //checkpoints.push_back({ "2be656ee2c84684faaefd4e9f21f157d1dcb6ad9d25bf18d037cea37d23437ca", 500000 });
            //checkpoints.push_back({ "265e051b24034d3bb51e99099a98d1d103c703cdac22a0d52e816aeb9cb807b9", 600000 });
            //checkpoints.push_back({ "bd512ef95e5c6c99bf03112be7ac7fc0a6ef1113678dd583a18778ca683908f9", 700000 });
            //checkpoints.push_back({ "9a0efd7b41cfc1cbeb1bfbd2ab3cb7989314611608cc4236b80a540444fbfb36", 800000 });

            bc::wallet::ec_private::mainnet_p2kh = 0x32;
            bc::wallet::ec_public::mainnet_p2kh = 0x32;
            bc::wallet::payment_address::mainnet_p2kh = 0x32;
            break;
        }

        case bc::settings::testnet:
        {
            use_testnet_rules = true;

            basic_checkpoints.reserve(1);
            basic_checkpoints.push_back({ "b1076144f919c8efaf55e5ec267daa6d5dc0a12609c9c6fddf8157270ae6e7ca", 0 });
            //checkpoints.reserve(1);
            //checkpoints.push_back({ "b1076144f919c8efaf55e5ec267daa6d5dc0a12609c9c6fddf8157270ae6e7ca", 0 });

            bc::wallet::ec_private::mainnet_p2kh = 0x7f;
            bc::wallet::ec_public::mainnet_p2kh = 0x7f;
            bc::wallet::payment_address::mainnet_p2kh = 0x7f;

            libbitcoin::consensus::bucket_size  = 50000;
            libbitcoin::consensus::lock_heights = {10, 20, 30, 40, 50};
            libbitcoin::coinbase_maturity       = 1;
            libbitcoin::pos_enabled_height      = 1000000;
            break;
        }

        default:
        case bc::settings::none:
        {
        }
    }
}

} // namespace blockchain
} // namespace libbitcoin
<commit_msg>update settings of blockchain checkpoint<commit_after>/**
 * Copyright (c) 2011-2015 libbitcoin developers (see AUTHORS)
 * Copyright (c) 2016-2018 metaverse core developers (see MVS-AUTHORS)
 *
 * This file is part of metaverse.
 *
 * metaverse is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License with
 * additional permissions to the one published by the Free Software
 * Foundation, either version 3 of the License, or (at your option)
 * any later version. For more information see LICENSE.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <metaverse/blockchain/settings.hpp>

#include <boost/filesystem.hpp>
#include <metaverse/consensus/miner.hpp>
#include <metaverse/bitcoin/constants.hpp>

namespace libbitcoin {
namespace blockchain {

using namespace boost::filesystem;

settings::settings()
  : block_pool_capacity(5000),
    transaction_pool_capacity(4096),
    transaction_pool_consistency(false),
    use_testnet_rules(false),
    collect_split_stake(true)
{
}

// Use push_back due to initializer_list bug:
// stackoverflow.com/a/20168627/1172329
settings::settings(bc::settings context)
  : settings()
{
    switch (context)
    {
        case bc::settings::mainnet:
        {
            // FIXEME.p2p-node.cpp, This is for header-first sync, attach_header_sync_session
            // header sync first has some problem.
            basic_checkpoints.reserve(1);
            basic_checkpoints.push_back({ "b81848ef9ae86e84c3da26564bc6ab3a79efc628239d11471ab5cd25c0684c2d", 0 });

            // validate_block, This is for each singel node validate
            checkpoints.reserve(7);
            checkpoints.push_back({ "b81848ef9ae86e84c3da26564bc6ab3a79efc628239d11471ab5cd25c0684c2d", 0 });
            checkpoints.push_back({ "d4f84eb9acb52cbfb003bd4fb88f4b5cf1f6328f193097d42b9403d7030abb8e", 3800 });
            checkpoints.push_back({ "e989e4b2d60ae2f8fbaa1cdb69d05afa63e7f1f99cf715589a93e4877c92fa8b", 100000 });
            checkpoints.push_back({ "d120edf7e14d8f426b7390e94ae7bfd746f9fc247b28e336db052295177ac9d3", 410000 }); //0.6.9 fix
            checkpoints.push_back({ "9a0efd7b41cfc1cbeb1bfbd2ab3cb7989314611608cc4236b80a540444fbfb36", 800000 });
            checkpoints.push_back({ "ed11a074ce80cbf82b5724bea0d74319dc6f180198fa1bbfb562bcbd50089e63", 1030000 }); //future time attack
            checkpoints.push_back({ "a18a5aa5270835dd720a561c20230435e0508e8339ee30998da6dd79eee83b29", 1270000 }); //super nova

            bc::wallet::ec_private::mainnet_p2kh = 0x32;
            bc::wallet::ec_public::mainnet_p2kh = 0x32;
            bc::wallet::payment_address::mainnet_p2kh = 0x32;
            break;
        }

        case bc::settings::testnet:
        {
            use_testnet_rules = true;

            basic_checkpoints.reserve(1);
            basic_checkpoints.push_back({ "b1076144f919c8efaf55e5ec267daa6d5dc0a12609c9c6fddf8157270ae6e7ca", 0 });
            checkpoints.reserve(1);
            checkpoints.push_back({ "b1076144f919c8efaf55e5ec267daa6d5dc0a12609c9c6fddf8157270ae6e7ca", 0 });

            bc::wallet::ec_private::mainnet_p2kh = 0x7f;
            bc::wallet::ec_public::mainnet_p2kh = 0x7f;
            bc::wallet::payment_address::mainnet_p2kh = 0x7f;

            libbitcoin::consensus::bucket_size  = 50000;
            libbitcoin::consensus::lock_heights = {10, 20, 30, 40, 50};
            libbitcoin::coinbase_maturity       = 1;
            libbitcoin::pos_enabled_height      = 1000000;
            break;
        }

        default:
        case bc::settings::none:
        {
        }
    }
}

} // namespace blockchain
} // namespace libbitcoin
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <string>
#include <map>
#include <vector>

#define SGLF_MERGE_VERSION "0.1.1"

typedef struct sglf_type {
  std::string tileid;
  std::string md5str;
  std::string seq;
} sglf_t;

int parse_tileid(int &tilepath, int &tilever, int &tilestep, int &tilevar, int &tilespan, std::string &tileid_str) {
  int i, state = 0;
  size_t pos=0, n;
  long int li;

  n = tileid_str.size();

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -1; }
  tilepath = (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -2; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -3; }
  tilever= (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -4; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -5; }
  tilestep= (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -6; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -7; }
  tilevar = (int)li;

  for (; (pos<n) && (tileid_str[pos] != '+'); pos++);
  pos++;
  if (pos>=n) { return -8; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -7; }
  tilespan = (int)li;

  return 0;
}

enum SGLF_READSTATE_ENUM {
  SGLF_RS_ERR = -1,
  SGLF_RS_OK = 0,
  SGLF_RS_OK_EOF = 1,
  SGLF_RS_EOF = 2,
};

// Read in an SGLF line and store the tilepath, tile library version, tilestep and tile span into the
// appropriate variables.
// Fill the `m5st` and `seq` variables with the rad in hash and sequence from the file.
//
// Return:
//  -1 - error
//   0 - success
//   1 - EOF (line read in successfully but encountered an EOF at the end)
//   2 - EOF (no data read)
//
int read_sglf_line(FILE *fp,
    int &tilepath, int &tilever, int &tilestep, int &tilevar, int &tilespan,
    std::string &m5str,
    std::string &seq) {
  int ch, state=0, char_count=0;
  std::string buf;

  // skip past whitespace
  //
  while (!feof(fp)) {
    ch = fgetc(fp);
    if ((ch!=' ') && (ch!='\n') && (ch!=EOF)) {
      ungetc(ch, fp);
      break;
    }
  }

  if (ch==EOF) { return SGLF_RS_EOF; }

  buf.clear();
  while (!feof(fp)) {
    ch = fgetc(fp);
    if ((ch=='\n') || (ch==EOF)) { break; }

    char_count++;

    if (ch==',') {

      if      (state == 0) { parse_tileid(tilepath, tilever, tilestep, tilevar, tilespan, buf); }
      else if (state == 1) { m5str = buf; }

      buf.clear();
      state++;
      continue;
    }

    buf += (char)ch;

  }

  seq = buf;

  if (char_count>0) {
    if (state != 2) { return SGLF_RS_ERR; }
    if (ch==EOF) { return SGLF_RS_OK_EOF; }
  }
  else if (char_count==0) {
    if (ch==EOF) { return SGLF_RS_EOF; }
  }

  return SGLF_RS_OK;
}

typedef struct tile_type {
  int path, ver, step, var, span;
} tile_t;

// This does a 'zipper'-like merge of both SGLF streams.
// A whole tilestep is read from the first stream and printed
// and the second stream is read for a whole tilestep, only
// printing the tiles that haven't already been printed.
//
//
int sglf_merge_and_print(FILE *ofp, FILE *src_fp, FILE *add_fp) {
  int r, src_line_no=0, add_line_no=0;
  int varid=-1;

  tile_t src, src_prev, add, add_prev;

  std::string src_buf, add_buf;
  std::string src_m5, src_seq;
  std::string add_m5, add_seq;

  int src_print_prev=0, add_print_prev=0, add_beg=1;

  std::map< std::string, int > src_m5_map;
  std::map< std::string, int >::iterator srch;

  add.path=-1;
  src.path=-1;

  while ( (!feof(src_fp)) && (!feof(add_fp)) ) {

    // reset the variable id and map of seen seqeunce hashes
    // per tilestep block
    //
    varid = -1;
    src_m5_map.clear();

    // print the already read in line of the beginning of the
    // 'tilestep block'.
    // We want to skip on the first pass so we've used a flag.
    //
    if (src_print_prev) {
      src_m5_map[src_m5] = 1;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
        src.path, src.ver, src.step, src.var, src.span,
        src_m5.c_str(),
        src_seq.c_str());
      varid = src.var;
    }

    // Read a tilestep block from the 'src' SGLF stream
    //
    while (!feof(src_fp)) {
      r = read_sglf_line(src_fp,
                         src.path, src.ver, src.step, src.var, src.span,
                         src_m5,
                         src_seq);
      src_line_no++;
      if (r<0) { fprintf(stderr, "ERROR on source sglf line %i\n", src_line_no); continue; }

      // we've read a line but got EOF instead of newline at the end, let the logic outside
      // of this loop print the result.
      //
      else if (r==SGLF_RS_OK_EOF) {
        src_print_prev=1;
        continue;
      }
      else if (r==SGLF_RS_EOF) {
        src_print_prev=0;
        continue;
      }

      if (src_print_prev==0) {
        src_prev.path = src.path;
        src_prev.ver  = src.ver;
        src_prev.step = src.step;
        src_prev.var  = src.var;
      }

      src_print_prev=1;

      // We've encountered the next tilestep block, break
      //
      if ((src.path != src_prev.path) ||
          (src.ver  != src_prev.ver) ||
          (src.step != src_prev.step)) {

        src_prev.path = src.path;
        src_prev.ver  = src.ver;
        src_prev.step = src.step;

        break;
      }

      src_m5_map[src_m5] = 1;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          src.path, src.ver, src.step, src.var, src.span,
          src_m5.c_str(),
          src_seq.c_str());
      src_prev.path = src.path;
      src_prev.ver  = src.ver;
      src_prev.step = src.step;

      varid = src.var;

      src_prev.path = src.path;
      src_prev.ver  = src.ver;
      src_prev.step = src.step;

    }

    // The 'src' SGLF stream tilestep block is catching up
    // to the 'add' SGLF stream, so keep on processing
    // the 'src' SGLF stream.
    //
    if ((add.path == src.path) &&
        (add.step >= src.step)) {
      continue;
    }

    // src.step holds the beginning of the 'queued' tilestep block
    // from the 'src' stream.
    // Print the beginning of the tilestep block if appropriate
    // We want to skip on the first pass so we've used a flag.
    //
    if (add_print_prev) {

      if ( (add.path < src.path) ||
           ((add.path == src.path) && (add.step < src.step)) ) {

        srch = src_m5_map.find(add_m5);
        if (srch == src_m5_map.end()) {

          varid++;

          printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
              add.path, add.ver, add.step, varid, add.span,
              add_m5.c_str(),
              add_seq.c_str());
        }
        else { }

      }

    }

    add_beg=1;
    while (!feof(add_fp)) {
      r = read_sglf_line(add_fp,
                         add.path, add.ver, add.step, add.var, add.span,
                         add_m5,
                         add_seq);

      add_line_no++;
      if (r<0) { fprintf(stderr, "ERROR on other sglf line %i\n", add_line_no); continue; }

      // we've read a line but got EOF instead of newline at the end, let the logic outside
      // of this loop print the result.
      //
      else if (r==SGLF_RS_OK_EOF) {
        add_print_prev=1;
        continue;
      }
      else if (r==SGLF_RS_EOF) {
        add_print_prev=0;
        continue;
      }

      if (add_beg==1) {
        add_prev.path = add.path;
        add_prev.ver  = add.ver;
        add_prev.step = add.step;
      }
      add_beg=0;

      add_print_prev = 1;

      if ( (add.path < src.path) ||
           ((add.path == src.path) && (add.step < src.step)) ) {

        srch = src_m5_map.find(add_m5);
        if (srch == src_m5_map.end()) {

          varid++;
          printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
              add.path, add.ver, add.step, varid, add.span,
              add_m5.c_str(),
              add_seq.c_str());
        }
        else { }

        if (add.step != add_prev.step) { varid=-1; }

      }
      else {
        break;
      }

      add_prev.path = add.path;
      add_prev.ver  = add.ver;
      add_prev.step = add.step;

    }

  }

  // Do a final process of the src sglf
  //
  if (src_print_prev) {
    src_m5_map[src_m5] = 1;
    printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
      src.path, src.ver, src.step, src.var, src.span,
      src_m5.c_str(),
      src_seq.c_str());
  }

  // One of the two streams is at EOF so run through and
  // process and print both with the understadning that only
  // one will actually be processed.
  //

  while (!feof(src_fp)) {
    r = read_sglf_line(src_fp,
                       src.path, src.ver, src.step, src.var, src.span,
                       src_m5,
                       src_seq);
    src_line_no++;
    if (r<0) { fprintf(stderr, "ERROR on source sglf line %i\n", src_line_no); continue; }
    else if (r==SGLF_RS_EOF) { continue; }

    src_m5_map[src_m5] = 1;
    printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
        src.path, src.ver, src.step, src.var, src.span,
        src_m5.c_str(),
        src_seq.c_str());
    src_prev.path = src.path;
    src_prev.ver  = src.ver;
    src_prev.step = src.step;

    varid = src.var;

    src_prev.path = src.path;
    src_prev.ver  = src.ver;
    src_prev.step = src.step;

  }

  // Do a final process on the 'add' sglf
  //
  if (add_print_prev) {

    srch = src_m5_map.find(add_m5);
    if (srch == src_m5_map.end()) {

      varid++;

      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          add.path, add.ver, add.step, varid, add.span,
          add_m5.c_str(),
          add_seq.c_str());
    }
    else { }

  }

  while (!feof(add_fp)) {
    r = read_sglf_line(add_fp,
                       add.path, add.ver, add.step, add.var, add.span,
                       add_m5,
                       add_seq);
    add_line_no++;
    if (r<0) { fprintf(stderr, "ERROR on other sglf line %i\n", add_line_no); continue; }
    else if (r==SGLF_RS_EOF) { continue; }
    //else if (r==1) { continue; }

    add_print_prev = 1;

    srch = src_m5_map.find(add_m5);
    if (srch == src_m5_map.end()) {

      varid++;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          add.path, add.ver, add.step, varid, add.span,
          add_m5.c_str(),
          add_seq.c_str());
    }
    else { }

  }

  return 0;
}

void show_help(void) {
  printf("\n");
  printf("sglf-merge version: %s\n\n", SGLF_MERGE_VERSION);
  printf("usage: merge-sglf <source-sglf> <new-sglf>\n");
  printf("\n");
}

int main(int argc, char **argv) {
  FILE *src_fp, *add_fp;

  if (argc!=3) {
    show_help();
    exit(-1);
  }

  src_fp = fopen(argv[1], "r");
  if (!src_fp) {
    perror(argv[1]);
    exit(-1);
  }

  add_fp = fopen(argv[2], "r");
  if (!add_fp) {
    perror(argv[2]);
    exit(-2);
  }

  sglf_merge_and_print(stdout, src_fp, add_fp);

  fclose(src_fp);
  fclose(add_fp);

}
<commit_msg>no issue #<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include <string>
#include <map>
#include <vector>

#define SGLF_MERGE_VERSION "0.1.1"

typedef struct sglf_type {
  std::string tileid;
  std::string md5str;
  std::string seq;
} sglf_t;

int parse_tileid(int &tilepath, int &tilever, int &tilestep, int &tilevar, int &tilespan, std::string &tileid_str) {
  int i, state = 0;
  size_t pos=0, n;
  long int li;

  n = tileid_str.size();

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -1; }
  tilepath = (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -2; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -3; }
  tilever= (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -4; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -5; }
  tilestep= (int)li;

  for (; (pos<n) && (tileid_str[pos] != '.'); pos++);
  pos++;
  if (pos>=n) { return -6; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -7; }
  tilevar = (int)li;

  for (; (pos<n) && (tileid_str[pos] != '+'); pos++);
  pos++;
  if (pos>=n) { return -8; }

  //--

  li = strtol(tileid_str.c_str() + pos, NULL, 16);
  if ((errno == ERANGE) || (errno == EINVAL)) { return -7; }
  tilespan = (int)li;

  return 0;
}

enum SGLF_READSTATE_ENUM {
  SGLF_RS_ERR = -1,
  SGLF_RS_OK = 0,
  SGLF_RS_OK_EOF = 1,
  SGLF_RS_EOF = 2,
};

// Read in an SGLF line and store the tilepath, tile library version, tilestep and tile span into the
// appropriate variables.
// Fill the `m5st` and `seq` variables with the rad in hash and sequence from the file.
//
// Return:
//  -1 - error
//   0 - success
//   1 - EOF (line read in successfully but encountered an EOF at the end)
//   2 - EOF (no data read)
//
int read_sglf_line(FILE *fp,
    int &tilepath, int &tilever, int &tilestep, int &tilevar, int &tilespan,
    std::string &m5str,
    std::string &seq) {
  int ch, state=0, char_count=0;
  std::string buf;

  // skip past whitespace
  //
  while (!feof(fp)) {
    ch = fgetc(fp);
    if ((ch!=' ') && (ch!='\n') && (ch!=EOF)) {
      ungetc(ch, fp);
      break;
    }
  }

  if (ch==EOF) { return SGLF_RS_EOF; }

  buf.clear();
  while (!feof(fp)) {
    ch = fgetc(fp);
    if ((ch=='\n') || (ch==EOF)) { break; }

    char_count++;

    if (ch==',') {

      if      (state == 0) { parse_tileid(tilepath, tilever, tilestep, tilevar, tilespan, buf); }
      else if (state == 1) { m5str = buf; }

      buf.clear();
      state++;
      continue;
    }

    buf += (char)ch;

  }

  seq = buf;

  if (char_count>0) {
    if (state != 2) { return SGLF_RS_ERR; }
    if (ch==EOF) { return SGLF_RS_OK_EOF; }
  }
  else if (char_count==0) {
    if (ch==EOF) { return SGLF_RS_EOF; }
  }

  return SGLF_RS_OK;
}

typedef struct tile_type {
  int path, ver, step, var, span;
} tile_t;

// This does a 'zipper'-like merge of both SGLF streams.
// A whole tilestep is read from the first stream and printed
// and the second stream is read for a whole tilestep, only
// printing the tiles that haven't already been printed.
//
//
int sglf_merge_and_print(FILE *ofp, FILE *src_fp, FILE *add_fp) {
  int r, src_line_no=0, add_line_no=0;
  int varid=-1;

  tile_t src, src_prev, add, add_prev;

  std::string src_buf, add_buf;
  std::string src_m5, src_seq;
  std::string add_m5, add_seq;

  int src_print_prev=0, add_print_prev=0, add_beg=1;

  std::map< std::string, int > src_m5_map;
  std::map< std::string, int >::iterator srch;

  add.path=-1;
  src.path=-1;

  while ( (!feof(src_fp)) && (!feof(add_fp)) ) {

    // reset the variable id and map of seen seqeunce hashes
    // per tilestep block
    //
    varid = -1;
    src_m5_map.clear();

    // print the already read in line of the beginning of the
    // 'tilestep block'.
    // We want to skip on the first pass so we've used a flag.
    //
    if (src_print_prev) {
      src_m5_map[src_m5] = 1;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
        src.path, src.ver, src.step, src.var, src.span,
        src_m5.c_str(),
        src_seq.c_str());
      varid = src.var;
    }

    // Read a tilestep block from the 'src' SGLF stream
    //
    while (!feof(src_fp)) {
      r = read_sglf_line(src_fp,
                         src.path, src.ver, src.step, src.var, src.span,
                         src_m5,
                         src_seq);
      src_line_no++;
      if (r<0) { fprintf(stderr, "ERROR on source sglf line %i\n", src_line_no); continue; }

      // we've read a line but got EOF instead of newline at the end, let the logic outside
      // of this loop print the result.
      //
      else if (r==SGLF_RS_OK_EOF) {
        src_print_prev=1;
        continue;
      }
      else if (r==SGLF_RS_EOF) {
        src_print_prev=0;
        continue;
      }

      if (src_print_prev==0) {
        src_prev.path = src.path;
        src_prev.ver  = src.ver;
        src_prev.step = src.step;
        src_prev.var  = src.var;
      }

      src_print_prev=1;

      // We've encountered the next tilestep block, break
      //
      if ((src.path != src_prev.path) ||
          (src.ver  != src_prev.ver) ||
          (src.step != src_prev.step)) {

        src_prev.path = src.path;
        src_prev.ver  = src.ver;
        src_prev.step = src.step;

        break;
      }

      src_m5_map[src_m5] = 1;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          src.path, src.ver, src.step, src.var, src.span,
          src_m5.c_str(),
          src_seq.c_str());
      src_prev.path = src.path;
      src_prev.ver  = src.ver;
      src_prev.step = src.step;

      varid = src.var;

      src_prev.path = src.path;
      src_prev.ver  = src.ver;
      src_prev.step = src.step;

    }

    // The 'src' SGLF stream tilestep block is catching up
    // to the 'add' SGLF stream, so keep on processing
    // the 'src' SGLF stream.
    //
    if ((add.path == src.path) &&
        (add.step >= src.step)) {
      continue;
    }

    // src.step holds the beginning of the 'queued' tilestep block
    // from the 'src' stream.
    // Print the beginning of the tilestep block if appropriate
    // We want to skip on the first pass so we've used a flag.
    //
    if (add_print_prev) {

      if ( (add.path < src.path) ||
           ((add.path == src.path) && (add.step < src.step)) ) {

        srch = src_m5_map.find(add_m5);
        if (srch == src_m5_map.end()) {

          varid++;

          printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
              add.path, add.ver, add.step, varid, add.span,
              add_m5.c_str(),
              add_seq.c_str());
        }
        else { }

      }

    }

    add_beg=1;
    while (!feof(add_fp)) {
      r = read_sglf_line(add_fp,
                         add.path, add.ver, add.step, add.var, add.span,
                         add_m5,
                         add_seq);

      add_line_no++;
      if (r<0) { fprintf(stderr, "ERROR on other sglf line %i\n", add_line_no); continue; }

      // we've read a line but got EOF instead of newline at the end, let the logic outside
      // of this loop print the result.
      //
      else if (r==SGLF_RS_OK_EOF) {
        add_print_prev=1;
        continue;
      }
      else if (r==SGLF_RS_EOF) {
        add_print_prev=0;
        continue;
      }

      if (add_beg==1) {
        add_prev.path = add.path;
        add_prev.ver  = add.ver;
        add_prev.step = add.step;
      }
      add_beg=0;

      add_print_prev = 1;

      if ( (add.path < src.path) ||
           ((add.path == src.path) && (add.step < src.step)) ) {

        srch = src_m5_map.find(add_m5);
        if (srch == src_m5_map.end()) {

          // The 'src' stream skipped a tilestep but the 'add' stream
          // hasn't, so reset the varid counter
          //
          if (add.step != add_prev.step) { varid=-1; }

          varid++;
          printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
              add.path, add.ver, add.step, varid, add.span,
              add_m5.c_str(),
              add_seq.c_str());
        }
        else { }

      }
      else { break; }

      add_prev.path = add.path;
      add_prev.ver  = add.ver;
      add_prev.step = add.step;

    }

  }

  // Do a final process of the src sglf
  //
  if (src_print_prev) {
    src_m5_map[src_m5] = 1;
    printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
      src.path, src.ver, src.step, src.var, src.span,
      src_m5.c_str(),
      src_seq.c_str());
  }

  // One of the two streams is at EOF so run through and
  // process and print both with the understadning that only
  // one will actually be processed.
  //

  while (!feof(src_fp)) {
    r = read_sglf_line(src_fp,
                       src.path, src.ver, src.step, src.var, src.span,
                       src_m5,
                       src_seq);
    src_line_no++;
    if (r<0) { fprintf(stderr, "ERROR on source sglf line %i\n", src_line_no); continue; }
    else if (r==SGLF_RS_EOF) { continue; }

    src_m5_map[src_m5] = 1;
    printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
        src.path, src.ver, src.step, src.var, src.span,
        src_m5.c_str(),
        src_seq.c_str());
    src_prev.path = src.path;
    src_prev.ver  = src.ver;
    src_prev.step = src.step;

    varid = src.var;

    src_prev.path = src.path;
    src_prev.ver  = src.ver;
    src_prev.step = src.step;

  }

  // Do a final process on the 'add' sglf
  //
  if (add_print_prev) {

    srch = src_m5_map.find(add_m5);
    if (srch == src_m5_map.end()) {

      varid++;

      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          add.path, add.ver, add.step, varid, add.span,
          add_m5.c_str(),
          add_seq.c_str());
    }
    else { }

  }

  while (!feof(add_fp)) {
    r = read_sglf_line(add_fp,
                       add.path, add.ver, add.step, add.var, add.span,
                       add_m5,
                       add_seq);
    add_line_no++;
    if (r<0) { fprintf(stderr, "ERROR on other sglf line %i\n", add_line_no); continue; }
    else if (r==SGLF_RS_EOF) { continue; }
    //else if (r==1) { continue; }

    add_print_prev = 1;

    srch = src_m5_map.find(add_m5);
    if (srch == src_m5_map.end()) {

      varid++;
      printf("%04x.%02x.%04x.%03x+%x,%s,%s\n",
          add.path, add.ver, add.step, varid, add.span,
          add_m5.c_str(),
          add_seq.c_str());
    }
    else { }

  }

  return 0;
}

void show_help(void) {
  printf("\n");
  printf("sglf-merge version: %s\n\n", SGLF_MERGE_VERSION);
  printf("usage: merge-sglf <source-sglf> <new-sglf>\n");
  printf("\n");
}

int main(int argc, char **argv) {
  FILE *src_fp, *add_fp;

  if (argc!=3) {
    show_help();
    exit(-1);
  }

  src_fp = fopen(argv[1], "r");
  if (!src_fp) {
    perror(argv[1]);
    exit(-1);
  }

  add_fp = fopen(argv[2], "r");
  if (!add_fp) {
    perror(argv[2]);
    exit(-2);
  }

  sglf_merge_and_print(stdout, src_fp, add_fp);

  fclose(src_fp);
  fclose(add_fp);

}
<|endoftext|>