<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
** Copyright (C) 2014 Nomovok Ltd. All rights reserved.
** Contact: info@nomovok.com
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QGuiApplication>
#include <QQmlComponent>
#include <QQuickView>
#include <QFile>
#include <QDebug>
#include <QTextStream>

#include "qmcunit.h"
#include "qmcloader.h"

QTextStream &operator<<(QTextStream &stream, const QmcUnit &unit);
QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::Unit &unit);
QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::CompilationUnit &unit);
QTextStream &operator<<(QTextStream &stream, const QQmlTypeData::ScriptReference &script);

int main(int argc, char *argv[])
{
    int ret;

    if (argc != 2 || !QFile::exists(argv[1])){
        qWarning() << argv[0] << "filename";
        return 1;
    }

    QGuiApplication app(argc, argv);

    QQuickView view;

    QQmlEngine *engine = view.engine();

    QmcLoader loader(engine);
    QString file(argv[1]);
    QFile f(file);
    if (!f.open(QFile::ReadOnly)) {
        qWarning() << "Could not open file for reading: " << file;
        return 2;
    }
    QDataStream in(&f);
    QmcUnit *unit = QmcUnit::loadUnit(in, engine, &loader, QUrl(argv[1]));
    f.close();

    if (unit == NULL) {
         qWarning() << "Could not load QmcUnit object: " << file;
         return 3;
    }

    QTextStream out(stdout);
    out << *unit;

    delete unit;
    return 0;
}

QTextStream &operator<<(QTextStream &stream, const QmcUnit &unit)
{
    // QV4::CompiledData::QmlUnit dump.
    stream << "QmlUnit:\n";
    stream << unit.qmlUnit->header;
    stream << " qmlUnitSize " << unit.qmlUnit->qmlUnitSize << "\n";
    stream << " nImports " << unit.qmlUnit->nImports << "\n";
    stream << " offsetToImports " << unit.qmlUnit->offsetToImports << "\n";
    stream << " nObjects " << unit.qmlUnit->nObjects << "\n";
    stream << " offsetToObjects " << unit.qmlUnit->offsetToObjects << "\n";
    stream << " indexOfRootObject " << unit.qmlUnit->indexOfRootObject << "\n";
    stream << *unit.compilationUnit;
    stream << "Strings:\n";
    foreach (const QString &s, unit.strings)
        stream << " " << s << "\n";
    stream << "Imports:\n";
    foreach (const QV4::CompiledData::Import &import, unit.imports)
        stream << unit.strings[import.uriIndex] << " " << unit.strings[import.qualifierIndex] << "\n";
    stream << "Namespaces:\n";
    foreach (const QString &s, unit.namespaces)
        stream << s << "\n";
    stream << "Type references:\n";
    foreach (const QmcUnitTypeReference& r, unit.typeReferences)
        stream << "index: " << r.index
            << " syntheticComponent: " << r.syntheticComponent
            << " composite: " << r.composite << "\n";
    for (int k = 0; k < unit.codeRefData.size(); ++k) {
        stream << "Code ref " << k << "\n";
        stream << "codeRefData:\n";
        int count = 0;
        foreach (char c, unit.codeRefData[k]) {
            if (count % 8 == 0) stream << QString("%1: ").arg(count, 4);
            QString hexVal = QString("%1 ").arg((unsigned char)c, 2, 16);
            stream << hexVal;
            ++count;
            if (count % 8 == 0) stream << "\n";
        }
        if ((count - 1) & 7) stream << "\n";
        stream << "linkCalls:\n";
        foreach (const QmcUnitCodeRefLinkCall &r, unit.linkCalls[k])
            stream << "index: " << r.index
                << " offset: " << r.offset << "\n";
        stream << "constantVectors:\n";
        foreach (const QV4::Primitive &p, unit.constantVectors[k]) {
            QV4::Value v = p.asValue();
            if (v.isEmpty()) stream << "Empty\n";
            else if (v.isNull()) stream << "NULL\n";
            else if (v.isBoolean()) stream << v.booleanValue() << "\n";
            else if (v.isInteger()) stream << v.integerValue() << "\n";
            else if (v.isDouble()) stream << v.doubleValue() << "\n";
            else if (v.isString()) stream << v.stringValue() << "\n";
            else stream << "Object or managed\n";
        }
    }
    stream << "QmcUnitObjectIndexToId:\n";
    foreach (const QmcUnitObjectIndexToId &tmp, unit.objectIndexToIdRoot) {
        stream << "index: " << tmp.index
            << " id: " << tmp.id << "\n";
    }
    stream << "QmcUnitObjectIndexToIdComponent (QmcUnitObjectIndexToId):\n";
    foreach (const QmcUnitObjectIndexToIdComponent &tmp, unit.objectIndexToIdComponent) {
        stream << tmp.componentIndex;
        foreach (const QmcUnitObjectIndexToId &m, tmp.mappings) {
            stream << " (" << m.index << ", " << m.id << ")";
        }
        stream << "\n";
    }
    stream << "QmcUnitAlias:\n";
    foreach (const QmcUnitAlias &tmp, unit.aliases) {
        stream << "objectIndex: " << tmp.objectIndex
            << " propertyIndex: " << tmp.propertyIndex
            << " contextIndex: " << tmp.contextIndex
            << " targetObjectIndex: " << tmp.targetObjectIndex
            << " targetPropertyIndex: " << tmp.targetPropertyIndex
            << " propertyType: " << tmp.propertyType
            << " flags: " << tmp.flags
            << " notifySignal: " << tmp.notifySignal << "\n";
    }
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::Unit &unit)
{
    stream << "Unit:" << "\n";
    stream << " magic[8] " << unit.magic << "\n";
    stream << " architecture " << unit.architecture << "\n";
    stream << " version " << unit.version << "\n";
    stream << " unitSize " << unit.unitSize << "\n";
    stream << " flags " << unit.flags << "\n";
    stream << " stringTableSize " << unit.stringTableSize << "\n";
    stream << " offsetToStringTable " << unit.offsetToStringTable << "\n";
    stream << " functionTableSize " << unit.functionTableSize << "\n";
    stream << " offsetToFunctionTable " << unit.offsetToFunctionTable << "\n";
    stream << " lookupTableSize " << unit.lookupTableSize << "\n";
    stream << " offsetToLookupTable " << unit.offsetToLookupTable << "\n";
    stream << " regexpTableSize " << unit.regexpTableSize << "\n";
    stream << " offsetToRegexpTable " << unit.offsetToRegexpTable << "\n";
    stream << " constantTableSize " << unit.constantTableSize << "\n";
    stream << " offsetToConstantTable " << unit.offsetToConstantTable << "\n";
    stream << " jsClassTableSize " << unit.jsClassTableSize << "\n";
    stream << " offsetToJSClassTable " << unit.offsetToJSClassTable << "\n";
    stream << " indexOfRootFunction " << unit.indexOfRootFunction << "\n";
    stream << " sourceFileIndex " << unit.sourceFileIndex << "\n";
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::CompilationUnit &unit)
{
    stream << "CompilationUnit:\n";
    //stream << *unit.data; Same as previous unit so no need to print.
    stream << " data->functionTableSize: " << unit.data->functionTableSize << "\n";
    for (int k = 0; k < unit.data->functionTableSize; ++k) {
        const QV4::CompiledData::Function *f = unit.data->functionAt(k);
        stream << " index " << f->index << "\n";
        stream << "  nameIndex " << f->nameIndex << "\n";
        stream << "  flags " << f->flags << "\n";
        stream << "  nFormals " << f->nFormals << "\n";
        stream << "  formalsOffset " << f->formalsOffset << "\n";
        stream << "  nLocals " << f->nLocals << "\n";
        stream << "  localsOffset " << f->localsOffset << "\n";
        stream << "  nInnerFunctions " << f->nInnerFunctions << "\n";
        stream << "  innerFunctionsOffset " << f->innerFunctionsOffset << "\n";
        stream << "  location (row, col) " << f->location.line << ", " << f->location.column << "\n";
    }
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QQmlTypeData::ScriptReference &script)
{
    stream << "ScriptReference:\n";
    stream << " location: " << script.location.line << " " << script.location.column << "\n";
    stream << " qualifier: " << script.qualifier << "\n";
    stream << " script: " << script.script << "\n";
    return stream;
}

<commit_msg>Added script reference printing and some leading spaces to output.<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
** Copyright (C) 2014 Nomovok Ltd. All rights reserved.
** Contact: info@nomovok.com
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "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.
**   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
**     of its contributors may 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."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QGuiApplication>
#include <QQmlComponent>
#include <QQuickView>
#include <QFile>
#include <QDebug>
#include <QTextStream>

#include "qmcunit.h"
#include "qmcloader.h"

QTextStream &operator<<(QTextStream &stream, const QmcUnit &unit);
QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::Unit &unit);
QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::CompilationUnit &unit);
QTextStream &operator<<(QTextStream &stream, const QQmlTypeData::ScriptReference &script);

int main(int argc, char *argv[])
{
    int ret;

    if (argc != 2 || !QFile::exists(argv[1])){
        qWarning() << argv[0] << "filename";
        return 1;
    }

    QGuiApplication app(argc, argv);

    QQuickView view;

    QQmlEngine *engine = view.engine();

    QmcLoader loader(engine);
    QString file(argv[1]);
    QFile f(file);
    if (!f.open(QFile::ReadOnly)) {
        qWarning() << "Could not open file for reading: " << file;
        return 2;
    }
    QDataStream in(&f);
    QmcUnit *unit = QmcUnit::loadUnit(in, engine, &loader, QUrl(argv[1]));
    f.close();

    if (unit == NULL) {
         qWarning() << "Could not load QmcUnit object: " << file;
         return 3;
    }

    QTextStream out(stdout);
    out << *unit;

    delete unit;
    return 0;
}

QTextStream &operator<<(QTextStream &stream, const QmcUnit &unit)
{
    // QV4::CompiledData::QmlUnit dump.
    stream << "QmlUnit:\n";
    stream << unit.qmlUnit->header;
    stream << " qmlUnitSize " << unit.qmlUnit->qmlUnitSize << "\n";
    stream << " nImports " << unit.qmlUnit->nImports << "\n";
    stream << " offsetToImports " << unit.qmlUnit->offsetToImports << "\n";
    stream << " nObjects " << unit.qmlUnit->nObjects << "\n";
    stream << " offsetToObjects " << unit.qmlUnit->offsetToObjects << "\n";
    stream << " indexOfRootObject " << unit.qmlUnit->indexOfRootObject << "\n";
    stream << *unit.compilationUnit;
    stream << "Strings:\n";
    foreach (const QString &s, unit.strings)
        stream << " " << s << "\n";
    stream << "Imports:\n";
    foreach (const QV4::CompiledData::Import &import, unit.imports)
        stream << unit.strings[import.uriIndex] << " " << unit.strings[import.qualifierIndex] << "\n";
    stream << "Namespaces:\n";
    foreach (const QString &s, unit.namespaces)
        stream << s << "\n";
    stream << "Script references:\n";
    foreach (const QString &s, unit.scriptReferences)
        stream << " " << s << "\n";
    stream << "Type references:\n";
    foreach (const QmcUnitTypeReference& r, unit.typeReferences)
        stream << " index: " << r.index
            << " syntheticComponent: " << r.syntheticComponent
            << " composite: " << r.composite << "\n";
    for (int k = 0; k < unit.codeRefData.size(); ++k) {
        stream << "Code ref " << k << "\n";
        stream << "codeRefData:\n";
        int count = 0;
        foreach (char c, unit.codeRefData[k]) {
            if (count % 8 == 0) stream << QString("%1: ").arg(count, 4);
            QString hexVal = QString("%1 ").arg((unsigned char)c, 2, 16);
            stream << hexVal;
            ++count;
            if (count % 8 == 0) stream << "\n";
        }
        if ((count - 1) & 7) stream << "\n";
        stream << "linkCalls:\n";
        foreach (const QmcUnitCodeRefLinkCall &r, unit.linkCalls[k])
            stream << " index: " << r.index
                << " offset: " << r.offset << "\n";
        stream << "constantVectors:\n";
        foreach (const QV4::Primitive &p, unit.constantVectors[k]) {
            QV4::Value v = p.asValue();
            if (v.isEmpty()) stream << "Empty\n";
            else if (v.isNull()) stream << "NULL\n";
            else if (v.isBoolean()) stream << v.booleanValue() << "\n";
            else if (v.isInteger()) stream << v.integerValue() << "\n";
            else if (v.isDouble()) stream << v.doubleValue() << "\n";
            else if (v.isString()) stream << v.stringValue() << "\n";
            else stream << "Object or managed\n";
        }
    }
    stream << "QmcUnitObjectIndexToId:\n";
    foreach (const QmcUnitObjectIndexToId &tmp, unit.objectIndexToIdRoot) {
        stream << "index: " << tmp.index
            << " id: " << tmp.id << "\n";
    }
    stream << "QmcUnitObjectIndexToIdComponent (QmcUnitObjectIndexToId):\n";
    foreach (const QmcUnitObjectIndexToIdComponent &tmp, unit.objectIndexToIdComponent) {
        stream << tmp.componentIndex;
        foreach (const QmcUnitObjectIndexToId &m, tmp.mappings) {
            stream << " (" << m.index << ", " << m.id << ")";
        }
        stream << "\n";
    }
    stream << "QmcUnitAlias:\n";
    foreach (const QmcUnitAlias &tmp, unit.aliases) {
        stream << " objectIndex: " << tmp.objectIndex
            << "  propertyIndex: " << tmp.propertyIndex
            << "  contextIndex: " << tmp.contextIndex
            << "  targetObjectIndex: " << tmp.targetObjectIndex
            << "  targetPropertyIndex: " << tmp.targetPropertyIndex
            << "  propertyType: " << tmp.propertyType
            << "  flags: " << tmp.flags
            << "  notifySignal: " << tmp.notifySignal << "\n";
    }
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::Unit &unit)
{
    stream << "Unit:" << "\n";
    stream << " magic[8] " << unit.magic << "\n";
    stream << " architecture " << unit.architecture << "\n";
    stream << " version " << unit.version << "\n";
    stream << " unitSize " << unit.unitSize << "\n";
    stream << " flags " << unit.flags << "\n";
    stream << " stringTableSize " << unit.stringTableSize << "\n";
    stream << " offsetToStringTable " << unit.offsetToStringTable << "\n";
    stream << " functionTableSize " << unit.functionTableSize << "\n";
    stream << " offsetToFunctionTable " << unit.offsetToFunctionTable << "\n";
    stream << " lookupTableSize " << unit.lookupTableSize << "\n";
    stream << " offsetToLookupTable " << unit.offsetToLookupTable << "\n";
    stream << " regexpTableSize " << unit.regexpTableSize << "\n";
    stream << " offsetToRegexpTable " << unit.offsetToRegexpTable << "\n";
    stream << " constantTableSize " << unit.constantTableSize << "\n";
    stream << " offsetToConstantTable " << unit.offsetToConstantTable << "\n";
    stream << " jsClassTableSize " << unit.jsClassTableSize << "\n";
    stream << " offsetToJSClassTable " << unit.offsetToJSClassTable << "\n";
    stream << " indexOfRootFunction " << unit.indexOfRootFunction << "\n";
    stream << " sourceFileIndex " << unit.sourceFileIndex << "\n";
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QV4::CompiledData::CompilationUnit &unit)
{
    stream << "CompilationUnit:\n";
    //stream << *unit.data; Same as previous unit so no need to print.
    stream << " data->functionTableSize: " << unit.data->functionTableSize << "\n";
    for (int k = 0; k < unit.data->functionTableSize; ++k) {
        const QV4::CompiledData::Function *f = unit.data->functionAt(k);
        stream << " index " << f->index << "\n";
        stream << "  nameIndex " << f->nameIndex << "\n";
        stream << "  flags " << f->flags << "\n";
        stream << "  nFormals " << f->nFormals << "\n";
        stream << "  formalsOffset " << f->formalsOffset << "\n";
        stream << "  nLocals " << f->nLocals << "\n";
        stream << "  localsOffset " << f->localsOffset << "\n";
        stream << "  nInnerFunctions " << f->nInnerFunctions << "\n";
        stream << "  innerFunctionsOffset " << f->innerFunctionsOffset << "\n";
        stream << "  location (row, col) " << f->location.line << ", " << f->location.column << "\n";
    }
    return stream;
}

QTextStream &operator<<(QTextStream &stream, const QQmlTypeData::ScriptReference &script)
{
    stream << "ScriptReference:\n";
    stream << " location: " << script.location.line << " " << script.location.column << "\n";
    stream << " qualifier: " << script.qualifier << "\n";
    stream << " script: " << script.script << "\n";
    return stream;
}

<|endoftext|>


<commit_before>/*
	oolib.cpp	WJ112
*/
/*
 * Copyright (c) 2014, Walter de Jong
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 "oolib"

namespace oo {

const unsigned int version_number = 0x000800;
const char *version_string = "0.8.0";
const char *copyright = "oolib Copyright 2014 by Walter de Jong <walter@heiho.net>";

}	// namespace

// EOB
<commit_msg>this warrants version 0.9.0<commit_after>/*
	oolib.cpp	WJ112
*/
/*
 * Copyright (c) 2014, Walter de Jong
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 "oolib"

namespace oo {

const unsigned int version_number = 0x000900;
const char *version_string = "0.9.0";
const char *copyright = "oolib Copyright 2014 by Walter de Jong <walter@heiho.net>";

}	// namespace

// EOB
<|endoftext|>


<commit_before>#include "entry_ctrl.hpp"
#include "account.hpp"
#include "account_ctrl.hpp"
#include "account_reader.hpp"
#include "decimal_text_ctrl.hpp"
#include "entry.hpp"
#include "finformat.hpp"
#include "locale.hpp"
#include "transaction_type.hpp"
#include <boost/scoped_ptr.hpp>
#include <jewel/decimal.hpp>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/string.h>
#include <cassert>
#include <vector>

using boost::scoped_ptr;
using jewel::Decimal;
using std::vector;

#include <jewel/debug_log.hpp>
#include <iostream>
using std::endl;

namespace phatbooks
{
namespace gui
{

BEGIN_EVENT_TABLE(EntryCtrl, wxPanel)
	EVT_BUTTON
	(	s_split_button_id,
		EntryCtrl::on_split_button_click
	)
END_EVENT_TABLE()

EntryCtrl::EntryCtrl
(	wxWindow* p_parent,
	vector<Account> const& p_accounts,
	PhatbooksDatabaseConnection& p_database_connection,
	transaction_type::TransactionType p_transaction_type,
	wxSize const& p_text_ctrl_size,
	bool p_is_source,
	Decimal const& p_primary_amount
):
	wxPanel(p_parent),
	m_database_connection(p_database_connection),
	m_is_source(p_is_source),
	m_primary_amount(p_primary_amount),
	m_transaction_type(p_transaction_type),
	m_account_reader(0),
	m_text_ctrl_size(p_text_ctrl_size),
	m_top_sizer(0),
	m_side_descriptor(0),
	m_next_row(0)
{
	assert (m_account_name_boxes.empty());
	assert (m_comment_boxes.empty());

	assert_transaction_type_validity(m_transaction_type);

	m_top_sizer = new wxGridBagSizer();
	SetSizer(m_top_sizer);

	// Row 0

	assert (m_next_row == 0);

	m_side_descriptor = new wxStaticText(this, wxID_ANY, side_description());
	m_top_sizer->Add(m_side_descriptor, wxGBPosition(m_next_row, 0));

	wxStaticText* const comment_label = new wxStaticText
	(	this,
		wxID_ANY,
		wxString(" Memo:"),
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_LEFT
	);
	m_top_sizer->Add(comment_label, wxGBPosition(m_next_row, 1));

	m_split_button = new wxButton
	(	this,
		s_split_button_id,
		wxString("Split"),
		wxDefaultPosition,
		m_text_ctrl_size
	);
	m_top_sizer->Add(m_split_button, wxGBPosition(m_next_row, 3));

	// Subsequent rows

	++m_next_row;

	if (m_is_source)
	{
		assert (!m_account_reader);
		m_account_reader = create_source_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	else
	{
		assert (!m_account_reader);
		m_account_reader = create_destination_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}

	vector<Account>::const_iterator it = p_accounts.begin();
	vector<Account>::const_iterator const end = p_accounts.end();

	// TODO Factor this out. (Re-used add_row().)
	for (size_t entry_num = 0; it != end; ++it, ++m_next_row, ++entry_num)
	{
		AccountCtrl* account_name_box = new AccountCtrl
		(	this,
			wxID_ANY,
			*it,
			m_text_ctrl_size,
			m_account_reader->begin(),
			m_account_reader->end(),
			m_database_connection
		);
		m_top_sizer->Add(account_name_box, wxGBPosition(m_next_row, 0));
		m_account_name_boxes.push_back(account_name_box);
		wxTextCtrl* comment_ctrl = new wxTextCtrl
		(	this,
			wxID_ANY,
			wxEmptyString,
			wxDefaultPosition,
			wxSize(m_text_ctrl_size.x * 2, m_text_ctrl_size.y),
			wxALIGN_LEFT
		);
		m_top_sizer->
			Add(comment_ctrl, wxGBPosition(m_next_row, 1), wxGBSpan(1, 2));
		m_comment_boxes.push_back(comment_ctrl);

		Decimal::places_type const precision = m_primary_amount.places();
		DecimalTextCtrl* amount_ctrl = new DecimalTextCtrl
		(	this,
			wxID_ANY,
			m_text_ctrl_size,
			precision,
			false
		);
		if (entry_num == 0)
		{
			amount_ctrl->set_amount(m_primary_amount);
		}
		m_top_sizer->Add(amount_ctrl, wxGBPosition(m_next_row, 3));
		m_amount_boxes.push_back(amount_ctrl);
	}

	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	// Fit();
	// Layout();
	GetParent()->Fit();
}

EntryCtrl::~EntryCtrl()
{
	delete m_account_reader;
	m_account_reader = 0;
}

void
EntryCtrl::refresh_for_transaction_type
(	transaction_type::TransactionType p_transaction_type
)
{
	JEWEL_DEBUG_LOG << "Entered EntryCtrl::refresh_for_transaction_type." << endl;
	assert_transaction_type_validity(p_transaction_type);
	if (p_transaction_type == m_transaction_type)
	{
		// Do nothing
		return;
	}
	assert (p_transaction_type != m_transaction_type);
	m_transaction_type = p_transaction_type;

	delete m_account_reader;
	m_account_reader = 0;

	if (m_is_source)
	{
		assert (!m_account_reader);
		m_account_reader = create_source_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	else
	{
		assert (!m_account_reader);
		m_account_reader = create_destination_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	for
	(	vector<AccountCtrl*>::size_type i = 0;
		i != m_account_name_boxes.size();
		++i
	)
	{
		assert (m_account_reader);
		m_account_name_boxes[i]->
			set(m_account_reader->begin(), m_account_reader->end());
	}
	return;
}

void
EntryCtrl::set_primary_amount(Decimal const& p_primary_amount)
{
	m_primary_amount = p_primary_amount;
	typedef vector<DecimalTextCtrl*>::size_type Size;
	Size const sz = m_amount_boxes.size();
	assert (sz > 0);
	m_amount_boxes[0]->set_amount(m_primary_amount);
	for (Size i = 1; i != sz; ++i)
	{
		m_amount_boxes[i]->set_amount(Decimal(0, m_primary_amount.places()));
	}
	return;
}

vector<Entry>
EntryCtrl::make_entries() const
{
	assert (m_account_name_boxes.size() == m_comment_boxes.size());
	assert (m_comment_boxes.size() == m_amount_boxes.size());
	assert (m_amount_boxes.size() == m_account_name_boxes.size());
	typedef std::vector<Entry>::size_type Size;
	Size const sz = m_account_name_boxes.size();

	vector<Entry> ret;
	for (Size i = 0; i != sz; ++i)
	{
		Entry entry(m_database_connection);

		assert (m_account_name_boxes[i]);
		entry.set_account(m_account_name_boxes[i]->account());

		assert (m_comment_boxes[i]);
		entry.set_comment(wx_to_bstring(m_comment_boxes[i]->GetValue()));

		assert (m_amount_boxes[i]);
		Decimal amount = m_amount_boxes[i]->amount();
		if (!transaction_type_is_actual(m_transaction_type))
		{
			amount = -amount;
		}
		if (m_is_source)
		{
			amount = -amount;
		}
		entry.set_amount(amount);

		entry.set_whether_reconciled(false);

		ret.push_back(entry);
		assert (!entry.has_id());
	}

	assert (ret.size() == sz);
	return ret;
}

void
EntryCtrl::on_split_button_click(wxCommandEvent& event)
{
	(void)event;  // Silence compiler warning re. unused parameter.
	add_row();
	return;
}

void
EntryCtrl::add_row()
{
	assert (m_account_name_boxes.size() >= 1);
	AccountCtrl* account_name_box = new AccountCtrl
	(	this,
		wxID_ANY,
		m_account_name_boxes.at(m_account_name_boxes.size() - 1)->account(),
		m_text_ctrl_size,
		m_account_reader->begin(),
		m_account_reader->end(),
		m_database_connection
	);
	m_top_sizer->Add(account_name_box, wxGBPosition(m_next_row, 0));
	m_account_name_boxes.push_back(account_name_box);
	wxTextCtrl* comment_ctrl = new wxTextCtrl
	(	this,
		wxID_ANY,
		wxEmptyString,
		wxDefaultPosition,
		wxSize(m_text_ctrl_size.x * 2, m_text_ctrl_size.y),
		wxALIGN_LEFT
	);
	m_top_sizer->
		Add(comment_ctrl, wxGBPosition(m_next_row, 1), wxGBSpan(1, 2));
	m_comment_boxes.push_back(comment_ctrl);

	DecimalTextCtrl* amount_ctrl = new DecimalTextCtrl
	(	this,
		wxID_ANY,
		m_text_ctrl_size,
		m_primary_amount.places(),
		false
	);
	m_top_sizer->Add(amount_ctrl, wxGBPosition(m_next_row, 3));
	m_amount_boxes.push_back(amount_ctrl);

	++m_next_row;

	Layout();  // Must call this.
	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	// GetParent()->Layout(); // Do not call this.
	// GetParent()->GetSizer()->RecalcSizes();  // Do not call this.
	GetParent()->Fit();

	return;
}

wxString
EntryCtrl::side_description() const
{
	if (m_is_source)
	{
		return " Source:";
	}
	assert (!m_is_source);
	return " Destination:";
}

}  // namespace gui
}  // namespace phatbooks
<commit_msg>In EntryCtrl, when there is only one Entry line, made "Split" button be positioned on that line instead of providing a DecimalTextCtrl for that line. When there is only one Entry then its amount must be determined by m_primary_amount so the DecimalTextCtrl was useless here. Still need to make it so that when further lines are added, the "Split" button will move up and make way for a DecimalTextCtrl on that line as before.<commit_after>#include "entry_ctrl.hpp"
#include "account.hpp"
#include "account_ctrl.hpp"
#include "account_reader.hpp"
#include "decimal_text_ctrl.hpp"
#include "entry.hpp"
#include "finformat.hpp"
#include "locale.hpp"
#include "transaction_type.hpp"
#include <boost/scoped_ptr.hpp>
#include <jewel/decimal.hpp>
#include <wx/button.h>
#include <wx/gbsizer.h>
#include <wx/gdicmn.h>
#include <wx/panel.h>
#include <wx/string.h>
#include <cassert>
#include <vector>

using boost::scoped_ptr;
using jewel::Decimal;
using std::vector;

#include <jewel/debug_log.hpp>
#include <iostream>
using std::endl;

namespace phatbooks
{
namespace gui
{

BEGIN_EVENT_TABLE(EntryCtrl, wxPanel)
	EVT_BUTTON
	(	s_split_button_id,
		EntryCtrl::on_split_button_click
	)
END_EVENT_TABLE()

EntryCtrl::EntryCtrl
(	wxWindow* p_parent,
	vector<Account> const& p_accounts,
	PhatbooksDatabaseConnection& p_database_connection,
	transaction_type::TransactionType p_transaction_type,
	wxSize const& p_text_ctrl_size,
	bool p_is_source,
	Decimal const& p_primary_amount
):
	wxPanel(p_parent),
	m_database_connection(p_database_connection),
	m_is_source(p_is_source),
	m_primary_amount(p_primary_amount),
	m_transaction_type(p_transaction_type),
	m_account_reader(0),
	m_text_ctrl_size(p_text_ctrl_size),
	m_top_sizer(0),
	m_side_descriptor(0),
	m_next_row(0)
{
	assert (m_account_name_boxes.empty());
	assert (m_comment_boxes.empty());
	assert (m_amount_boxes.empty());

	assert_transaction_type_validity(m_transaction_type);

	m_top_sizer = new wxGridBagSizer();
	SetSizer(m_top_sizer);

	// Row 0

	assert (m_next_row == 0);

	m_side_descriptor = new wxStaticText(this, wxID_ANY, side_description());
	m_top_sizer->Add(m_side_descriptor, wxGBPosition(m_next_row, 0));

	wxStaticText* const comment_label = new wxStaticText
	(	this,
		wxID_ANY,
		wxString(" Memo:"),
		wxDefaultPosition,
		wxDefaultSize,
		wxALIGN_LEFT
	);
	m_top_sizer->Add(comment_label, wxGBPosition(m_next_row, 1));

	m_split_button = new wxButton
	(	this,
		s_split_button_id,
		wxString("Split"),
		wxDefaultPosition,
		m_text_ctrl_size
	);

	// Split button is in row 0 if and only if there are multiple
	// Accounts.
	if (p_accounts.size() > 1)
	{
		m_top_sizer->Add(m_split_button, wxGBPosition(m_next_row, 3));
	}

	// Subsequent rows

	++m_next_row;

	if (m_is_source)
	{
		assert (!m_account_reader);
		m_account_reader = create_source_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	else
	{
		assert (!m_account_reader);
		m_account_reader = create_destination_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}

	vector<Account>::const_iterator it = p_accounts.begin();
	vector<Account>::const_iterator const end = p_accounts.end();

	// TODO Factor this out. (Re-used add_row().)
	for (size_t entry_num = 0; it != end; ++it, ++m_next_row, ++entry_num)
	{
		AccountCtrl* account_name_box = new AccountCtrl
		(	this,
			wxID_ANY,
			*it,
			m_text_ctrl_size,
			m_account_reader->begin(),
			m_account_reader->end(),
			m_database_connection
		);
		m_top_sizer->Add(account_name_box, wxGBPosition(m_next_row, 0));
		m_account_name_boxes.push_back(account_name_box);
		wxTextCtrl* comment_ctrl = new wxTextCtrl
		(	this,
			wxID_ANY,
			wxEmptyString,
			wxDefaultPosition,
			wxSize(m_text_ctrl_size.x * 2, m_text_ctrl_size.y),
			wxALIGN_LEFT
		);
		m_top_sizer->
			Add(comment_ctrl, wxGBPosition(m_next_row, 1), wxGBSpan(1, 2));
		m_comment_boxes.push_back(comment_ctrl);

		// If there is only one Account then there is only one "Entry line",
		// and that Entry line will also house the "Split" button. There will
		// then be no need to have an amount_ctrl for just the one
		// Entry. If there are multiple Entries then we must have already
		// placed the Split button at row 0, and in that case we also need
		// an amount_ctrl for each Entry.
		if (p_accounts.size() == 1)
		{
			m_top_sizer->Add(m_split_button, wxGBPosition(m_next_row, 3));
		}
		else
		{
			Decimal::places_type const precision = m_primary_amount.places();
			DecimalTextCtrl* amount_ctrl = new DecimalTextCtrl
			(	this,
				wxID_ANY,
				m_text_ctrl_size,
				precision,
				false
			);
			if (entry_num == 0)
			{
				amount_ctrl->set_amount(m_primary_amount);
			}
			m_top_sizer->Add(amount_ctrl, wxGBPosition(m_next_row, 3));
			m_amount_boxes.push_back(amount_ctrl);
		}
	}

	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	// Fit();
	// Layout();
	GetParent()->Fit();
}

EntryCtrl::~EntryCtrl()
{
	delete m_account_reader;
	m_account_reader = 0;
}

void
EntryCtrl::refresh_for_transaction_type
(	transaction_type::TransactionType p_transaction_type
)
{
	JEWEL_DEBUG_LOG << "Entered EntryCtrl::refresh_for_transaction_type." << endl;
	assert_transaction_type_validity(p_transaction_type);
	if (p_transaction_type == m_transaction_type)
	{
		// Do nothing
		return;
	}
	assert (p_transaction_type != m_transaction_type);
	m_transaction_type = p_transaction_type;

	delete m_account_reader;
	m_account_reader = 0;

	if (m_is_source)
	{
		assert (!m_account_reader);
		m_account_reader = create_source_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	else
	{
		assert (!m_account_reader);
		m_account_reader = create_destination_account_reader
		(	m_database_connection,
			m_transaction_type
		);
	}
	for
	(	vector<AccountCtrl*>::size_type i = 0;
		i != m_account_name_boxes.size();
		++i
	)
	{
		assert (m_account_reader);
		m_account_name_boxes[i]->
			set(m_account_reader->begin(), m_account_reader->end());
	}
	return;
}

void
EntryCtrl::set_primary_amount(Decimal const& p_primary_amount)
{
	m_primary_amount = p_primary_amount;
	typedef vector<DecimalTextCtrl*>::size_type Size;
	Size const sz = m_amount_boxes.size();
	if (sz > 0)
	{
		assert (m_amount_boxes[0]);
		m_amount_boxes[0]->set_amount(m_primary_amount);
		for (Size i = 1; i != sz; ++i)
		{
			assert (m_amount_boxes[i]);
			m_amount_boxes[i]->
				set_amount(Decimal(0, m_primary_amount.places()));
		}
	}
	return;
}

vector<Entry>
EntryCtrl::make_entries() const
{
	assert (m_account_name_boxes.size() == m_comment_boxes.size());
	assert (m_comment_boxes.size() >= m_amount_boxes.size());
	assert (m_amount_boxes.size() <= m_account_name_boxes.size());
	typedef std::vector<Entry>::size_type Size;
	Size const sz = m_account_name_boxes.size();

	vector<Entry> ret;
	for (Size i = 0; i != sz; ++i)
	{
		Entry entry(m_database_connection);

		assert (m_account_name_boxes[i]);
		entry.set_account(m_account_name_boxes[i]->account());

		assert (m_comment_boxes[i]);
		entry.set_comment(wx_to_bstring(m_comment_boxes[i]->GetValue()));

		Decimal amount = m_primary_amount;
		if (!m_amount_boxes.empty())
		{
			assert (m_amount_boxes.size() == sz);
			assert (m_amount_boxes[i]);
			amount = m_amount_boxes[i]->amount();
		}
		if (!transaction_type_is_actual(m_transaction_type))
		{
			amount = -amount;
		}
		if (m_is_source)
		{
			amount = -amount;
		}
		entry.set_amount(amount);

		entry.set_whether_reconciled(false);

		ret.push_back(entry);
		assert (!entry.has_id());
	}
	assert (ret.size() == sz);
	return ret;
}

void
EntryCtrl::on_split_button_click(wxCommandEvent& event)
{
	(void)event;  // Silence compiler warning re. unused parameter.
	add_row();
	return;
}

void
EntryCtrl::add_row()
{
	// TODO HIGH PRIORITY. If there is currently only 1 row then we need
	// to reposition the Split button up to Row 0, and we also need to provide
	// the original Entry row with a DecimalTextCtrl for its amount.
	assert (m_account_name_boxes.size() >= 1);
	AccountCtrl* account_name_box = new AccountCtrl
	(	this,
		wxID_ANY,
		m_account_name_boxes.at(m_account_name_boxes.size() - 1)->account(),
		m_text_ctrl_size,
		m_account_reader->begin(),
		m_account_reader->end(),
		m_database_connection
	);
	m_top_sizer->Add(account_name_box, wxGBPosition(m_next_row, 0));
	m_account_name_boxes.push_back(account_name_box);
	wxTextCtrl* comment_ctrl = new wxTextCtrl
	(	this,
		wxID_ANY,
		wxEmptyString,
		wxDefaultPosition,
		wxSize(m_text_ctrl_size.x * 2, m_text_ctrl_size.y),
		wxALIGN_LEFT
	);
	m_top_sizer->
		Add(comment_ctrl, wxGBPosition(m_next_row, 1), wxGBSpan(1, 2));
	m_comment_boxes.push_back(comment_ctrl);

	DecimalTextCtrl* amount_ctrl = new DecimalTextCtrl
	(	this,
		wxID_ANY,
		m_text_ctrl_size,
		m_primary_amount.places(),
		false
	);
	m_top_sizer->Add(amount_ctrl, wxGBPosition(m_next_row, 3));
	m_amount_boxes.push_back(amount_ctrl);

	++m_next_row;

	Layout();  // Must call this.
	m_top_sizer->Fit(this);
	m_top_sizer->SetSizeHints(this);
	// GetParent()->Layout(); // Do not call this.
	// GetParent()->GetSizer()->RecalcSizes();  // Do not call this.
	GetParent()->Fit();

	return;
}

wxString
EntryCtrl::side_description() const
{
	if (m_is_source)
	{
		return " Source:";
	}
	assert (!m_is_source);
	return " Destination:";
}

}  // namespace gui
}  // namespace phatbooks
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * 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.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may 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 "output.h"

namespace ledger {

format_xacts::format_xacts(report_t& _report, const string& format)
  : report(_report), last_entry(NULL), last_xact(NULL)
{
  TRACE_CTOR(format_xacts, "report&, const string&");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      next_lines_format.parse(string(n, 0, p - n));
      between_format.parse(string(p + 2));
    } else {
      next_lines_format.parse(n);
    }
  } else {
    first_line_format.parse(format);
    next_lines_format.parse(format);
  }
}

void format_xacts::operator()(xact_t& xact)
{
  std::ostream& out(report.output_stream);

  if (! xact.has_xdata() ||
      ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
    if (last_entry != xact.entry) {
      if (last_entry) {
	bind_scope_t bound_scope(report, *last_entry);
	between_format.format(out, bound_scope);
      }
      bind_scope_t bound_scope(report, xact);
      first_line_format.format(out, bound_scope);
      last_entry = xact.entry;
    }
    else if (last_xact && last_xact->date() != xact.date()) {
      bind_scope_t bound_scope(report, xact);
      first_line_format.format(out, bound_scope);
    }
    else {
      bind_scope_t bound_scope(report, xact);
      next_lines_format.format(out, bound_scope);
    }

    xact.xdata().add_flags(XACT_EXT_DISPLAYED);
    last_xact = &xact;
  }
}

void format_entries::format_last_entry()
{
  bool		first = true;
  std::ostream& out(report.output_stream);

  foreach (xact_t * xact, last_entry->xacts) {
    if (xact->has_xdata() &&
	xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
      if (first) {
	bind_scope_t bound_scope(report, *xact);
	first_line_format.format(out, bound_scope);
	first = false;
      } else {
	bind_scope_t bound_scope(report, *xact);
	next_lines_format.format(out, bound_scope);
      }
      xact->xdata().add_flags(XACT_EXT_DISPLAYED);
    }
  }
}

void format_entries::operator()(xact_t& xact)
{
  xact.xdata().add_flags(XACT_EXT_TO_DISPLAY);

  if (last_entry && xact.entry != last_entry)
    format_last_entry();

  last_entry = xact.entry;
}

void print_entry(std::ostream& out, const entry_base_t& entry_base,
		 const string& prefix)
{
  string print_format;

  if (dynamic_cast<const entry_t *>(&entry_base)) {
    print_format = (prefix + "%D %X%C%P\n" +
		    prefix + "    %-34A  %12o\n%/" +
		    prefix + "    %-34A  %12o\n");
  }
  else if (const auto_entry_t * entry =
	   dynamic_cast<const auto_entry_t *>(&entry_base)) {
    out << "= " << entry->predicate.predicate.text() << '\n';
    print_format = prefix + "    %-34A  %12o\n";
  }
  else if (const period_entry_t * entry =
	   dynamic_cast<const period_entry_t *>(&entry_base)) {
    out << "~ " << entry->period_string << '\n';
    print_format = prefix + "    %-34A  %12o\n";
  }
  else {
    assert(false);
  }

#if 0
  format_entries formatter(out, print_format);
  walk_xacts(const_cast<xacts_list&>(entry_base.xacts), formatter);
  formatter.flush();

  clear_xact_xdata cleaner;
  walk_xacts(const_cast<xacts_list&>(entry_base.xacts), cleaner);
#endif
}

void format_accounts::flush()
{
  std::ostream& out(report.output_stream);

  if (print_final_total) {
    assert(out);
    assert(report.session.master->has_xdata());

    account_t::xdata_t& xdata(report.session.master->xdata());

    if (! report.show_collapsed && xdata.total) {
      out << "--------------------\n";
      xdata.value = xdata.total;
      bind_scope_t bound_scope(report, *report.session.master);
      format.format(out, bound_scope);
    }
  }

  out.flush();
}

void format_accounts::operator()(account_t& account)
{
  if (display_account(account)) {
    if (! account.parent) {
      account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
    } else {
      bind_scope_t bound_scope(report, account);
      format.format(report.output_stream, bound_scope);
      account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
    }
  }
}

bool format_accounts::disp_subaccounts_p(account_t&   account,
					 account_t *& to_show)
{
  bool	      display  = false;
  std::size_t counted  = 0;
  bool        matches  = should_display(account);
  bool        computed = false;
  value_t     acct_total;
  value_t     result;

  to_show = NULL;

  foreach (accounts_map::value_type pair, account.accounts) {
    if (! should_display(*pair.second))
      continue;

    call_scope_t args(*pair.second);
    result = report.get_total_expr(args);
    if (! computed) {
      call_scope_t args(account);
      acct_total = report.get_total_expr(args);
      computed = true;
    }

    if ((result != acct_total) || counted > 0) {
      display = matches;
      break;
    }
    to_show = pair.second;
    counted++;
  }

  return display;
}

bool format_accounts::display_account(account_t& account)
{
  // Never display an account that has already been displayed.
  if (account.has_xdata() &&
      account.xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
    return false;

  // At this point, one of two possibilities exists: the account is a
  // leaf which matches the predicate restrictions; or it is a parent
  // and two or more children must be subtotaled; or it is a parent
  // and its child has been hidden by the predicate.  So first,
  // determine if it is a parent that must be displayed regardless of
  // the predicate.

  account_t * account_to_show = NULL;
  if (disp_subaccounts_p(account, account_to_show))
    return true;

  return ! account_to_show && should_display(account);
}

format_equity::format_equity(report_t& _report, const string& _format)
  : format_accounts(_report)
{
  const char * f = _format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    next_lines_format.parse(string(p + 2));
  } else {
    first_line_format.parse(_format);
    next_lines_format.parse(_format);
  }

  entry_t header_entry;
  header_entry.payee = "Opening Balances";
  header_entry._date = CURRENT_DATE();
  bind_scope_t bound_scope(report, header_entry);
  first_line_format.format(report.output_stream, bound_scope);
}

void format_equity::flush()
{
  account_t summary(NULL, "Equity:Opening Balances");

  account_t::xdata_t& xdata(summary.xdata());
  std::ostream&	      out(report.output_stream);

  xdata.value = total.negate();

  if (total.type() >= value_t::BALANCE) {
    const balance_t * bal;
    if (total.is_type(value_t::BALANCE))
      bal = &(total.as_balance());
    else if (total.is_type(value_t::BALANCE_PAIR))
      bal = &(total.as_balance_pair().quantity());
    else
      assert(false);

    foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
      xdata.value = pair.second;
      xdata.value.negate();
      bind_scope_t bound_scope(report, summary);
      next_lines_format.format(out, bound_scope);
    }
  } else {
    bind_scope_t bound_scope(report, summary);
    next_lines_format.format(out, bound_scope);
  }
  out.flush();
}

void format_equity::operator()(account_t& account)
{
  std::ostream& out(report.output_stream);

  if (display_account(account)) {
    if (account.has_xdata()) {
      value_t val = account.xdata().value;

      if (val.type() >= value_t::BALANCE) {
	const balance_t * bal;
	if (val.is_type(value_t::BALANCE))
	  bal = &(val.as_balance());
	else if (val.is_type(value_t::BALANCE_PAIR))
	  bal = &(val.as_balance_pair().quantity());
	else
	  assert(false);

	foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
	  account.xdata().value = pair.second;
	  bind_scope_t bound_scope(report, account);
	  next_lines_format.format(out, bound_scope);
	}
	account.xdata().value = val;
      } else {
	bind_scope_t bound_scope(report, account);
	next_lines_format.format(out, bound_scope);
      }
      total += val;
    }
    account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
  }
}

} // namespace ledger
<commit_msg>Create bound scopes for locating the total expr.<commit_after>/*
 * Copyright (c) 2003-2009, John Wiegley.  All rights reserved.
 *
 * 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.
 *
 * - Neither the name of New Artisans LLC nor the names of its
 *   contributors may 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 "output.h"

namespace ledger {

format_xacts::format_xacts(report_t& _report, const string& format)
  : report(_report), last_entry(NULL), last_xact(NULL)
{
  TRACE_CTOR(format_xacts, "report&, const string&");

  const char * f = format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    const char * n = p + 2;
    if (const char * p = std::strstr(n, "%/")) {
      next_lines_format.parse(string(n, 0, p - n));
      between_format.parse(string(p + 2));
    } else {
      next_lines_format.parse(n);
    }
  } else {
    first_line_format.parse(format);
    next_lines_format.parse(format);
  }
}

void format_xacts::operator()(xact_t& xact)
{
  std::ostream& out(report.output_stream);

  if (! xact.has_xdata() ||
      ! xact.xdata().has_flags(XACT_EXT_DISPLAYED)) {
    if (last_entry != xact.entry) {
      if (last_entry) {
	bind_scope_t bound_scope(report, *last_entry);
	between_format.format(out, bound_scope);
      }
      bind_scope_t bound_scope(report, xact);
      first_line_format.format(out, bound_scope);
      last_entry = xact.entry;
    }
    else if (last_xact && last_xact->date() != xact.date()) {
      bind_scope_t bound_scope(report, xact);
      first_line_format.format(out, bound_scope);
    }
    else {
      bind_scope_t bound_scope(report, xact);
      next_lines_format.format(out, bound_scope);
    }

    xact.xdata().add_flags(XACT_EXT_DISPLAYED);
    last_xact = &xact;
  }
}

void format_entries::format_last_entry()
{
  bool		first = true;
  std::ostream& out(report.output_stream);

  foreach (xact_t * xact, last_entry->xacts) {
    if (xact->has_xdata() &&
	xact->xdata().has_flags(XACT_EXT_TO_DISPLAY)) {
      if (first) {
	bind_scope_t bound_scope(report, *xact);
	first_line_format.format(out, bound_scope);
	first = false;
      } else {
	bind_scope_t bound_scope(report, *xact);
	next_lines_format.format(out, bound_scope);
      }
      xact->xdata().add_flags(XACT_EXT_DISPLAYED);
    }
  }
}

void format_entries::operator()(xact_t& xact)
{
  xact.xdata().add_flags(XACT_EXT_TO_DISPLAY);

  if (last_entry && xact.entry != last_entry)
    format_last_entry();

  last_entry = xact.entry;
}

void print_entry(std::ostream& out, const entry_base_t& entry_base,
		 const string& prefix)
{
  string print_format;

  if (dynamic_cast<const entry_t *>(&entry_base)) {
    print_format = (prefix + "%D %X%C%P\n" +
		    prefix + "    %-34A  %12o\n%/" +
		    prefix + "    %-34A  %12o\n");
  }
  else if (const auto_entry_t * entry =
	   dynamic_cast<const auto_entry_t *>(&entry_base)) {
    out << "= " << entry->predicate.predicate.text() << '\n';
    print_format = prefix + "    %-34A  %12o\n";
  }
  else if (const period_entry_t * entry =
	   dynamic_cast<const period_entry_t *>(&entry_base)) {
    out << "~ " << entry->period_string << '\n';
    print_format = prefix + "    %-34A  %12o\n";
  }
  else {
    assert(false);
  }

#if 0
  format_entries formatter(out, print_format);
  walk_xacts(const_cast<xacts_list&>(entry_base.xacts), formatter);
  formatter.flush();

  clear_xact_xdata cleaner;
  walk_xacts(const_cast<xacts_list&>(entry_base.xacts), cleaner);
#endif
}

void format_accounts::flush()
{
  std::ostream& out(report.output_stream);

  if (print_final_total) {
    assert(out);
    assert(report.session.master->has_xdata());

    account_t::xdata_t& xdata(report.session.master->xdata());

    if (! report.show_collapsed && xdata.total) {
      out << "--------------------\n";
      xdata.value = xdata.total;
      bind_scope_t bound_scope(report, *report.session.master);
      format.format(out, bound_scope);
    }
  }

  out.flush();
}

void format_accounts::operator()(account_t& account)
{
  if (display_account(account)) {
    if (! account.parent) {
      account.xdata().add_flags(ACCOUNT_EXT_TO_DISPLAY);
    } else {
      bind_scope_t bound_scope(report, account);
      format.format(report.output_stream, bound_scope);
      account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
    }
  }
}

bool format_accounts::disp_subaccounts_p(account_t&   account,
					 account_t *& to_show)
{
  bool	      display  = false;
  std::size_t counted  = 0;
  bool        matches  = should_display(account);
  bool        computed = false;
  value_t     acct_total;
  value_t     result;

  to_show = NULL;

  foreach (accounts_map::value_type pair, account.accounts) {
    if (! should_display(*pair.second))
      continue;

    bind_scope_t bound_scope(report, *pair.second);
    call_scope_t args(bound_scope);
    result = report.get_total_expr(args);
    if (! computed) {
      bind_scope_t account_scope(report, account);
      call_scope_t args(account_scope);
      acct_total = report.get_total_expr(args);
      computed = true;
    }

    if ((result != acct_total) || counted > 0) {
      display = matches;
      break;
    }
    to_show = pair.second;
    counted++;
  }

  return display;
}

bool format_accounts::display_account(account_t& account)
{
  // Never display an account that has already been displayed.
  if (account.has_xdata() &&
      account.xdata().has_flags(ACCOUNT_EXT_DISPLAYED))
    return false;

  // At this point, one of two possibilities exists: the account is a
  // leaf which matches the predicate restrictions; or it is a parent
  // and two or more children must be subtotaled; or it is a parent
  // and its child has been hidden by the predicate.  So first,
  // determine if it is a parent that must be displayed regardless of
  // the predicate.

  account_t * account_to_show = NULL;
  if (disp_subaccounts_p(account, account_to_show))
    return true;

  return ! account_to_show && should_display(account);
}

format_equity::format_equity(report_t& _report, const string& _format)
  : format_accounts(_report)
{
  const char * f = _format.c_str();

  if (const char * p = std::strstr(f, "%/")) {
    first_line_format.parse(string(f, 0, p - f));
    next_lines_format.parse(string(p + 2));
  } else {
    first_line_format.parse(_format);
    next_lines_format.parse(_format);
  }

  entry_t header_entry;
  header_entry.payee = "Opening Balances";
  header_entry._date = CURRENT_DATE();
  bind_scope_t bound_scope(report, header_entry);
  first_line_format.format(report.output_stream, bound_scope);
}

void format_equity::flush()
{
  account_t summary(NULL, "Equity:Opening Balances");

  account_t::xdata_t& xdata(summary.xdata());
  std::ostream&	      out(report.output_stream);

  xdata.value = total.negate();

  if (total.type() >= value_t::BALANCE) {
    const balance_t * bal;
    if (total.is_type(value_t::BALANCE))
      bal = &(total.as_balance());
    else if (total.is_type(value_t::BALANCE_PAIR))
      bal = &(total.as_balance_pair().quantity());
    else
      assert(false);

    foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
      xdata.value = pair.second;
      xdata.value.negate();
      bind_scope_t bound_scope(report, summary);
      next_lines_format.format(out, bound_scope);
    }
  } else {
    bind_scope_t bound_scope(report, summary);
    next_lines_format.format(out, bound_scope);
  }
  out.flush();
}

void format_equity::operator()(account_t& account)
{
  std::ostream& out(report.output_stream);

  if (display_account(account)) {
    if (account.has_xdata()) {
      value_t val = account.xdata().value;

      if (val.type() >= value_t::BALANCE) {
	const balance_t * bal;
	if (val.is_type(value_t::BALANCE))
	  bal = &(val.as_balance());
	else if (val.is_type(value_t::BALANCE_PAIR))
	  bal = &(val.as_balance_pair().quantity());
	else
	  assert(false);

	foreach (balance_t::amounts_map::value_type pair, bal->amounts) {
	  account.xdata().value = pair.second;
	  bind_scope_t bound_scope(report, account);
	  next_lines_format.format(out, bound_scope);
	}
	account.xdata().value = val;
      } else {
	bind_scope_t bound_scope(report, account);
	next_lines_format.format(out, bound_scope);
      }
      total += val;
    }
    account.xdata().add_flags(ACCOUNT_EXT_DISPLAYED);
  }
}

} // namespace ledger
<|endoftext|>


<commit_before>#include "file.hpp"
#include "internal.hpp"
#include "logging.hpp"
#include "macros.hpp"
#include "message.hpp"
#include "parse.hpp"
#include "util.hpp"

#include <cstdarg>
#include <cassert>
#include <cctype>
#include <climits>
#include <string>

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Parsing utilities.

int Parser::parse_char () { return file->get (); }

// Return an non zero error string if a parse error occurred.

inline const char *
Parser::parse_string (const char * str, char prev) {
  for (const char * p = str; *p; p++)
    if (parse_char () == *p) prev = *p;
    else PER ("expected '%c' after '%c'", *p, prev);
  return 0;
}

inline const char *
Parser::parse_positive_int (int & ch, int & res, const char * name) {
  assert (isdigit (ch));
  res = ch - '0';
  while (isdigit (ch = parse_char ())) {
    int digit = ch - '0';
    if (INT_MAX/10 < res || INT_MAX - digit < 10*res)
      PER ("too large '%s' in header", name);
    res = 10*res + digit;
  }
  return 0;
}

inline const char *
Parser::parse_lit (int & ch, int & lit, const int vars) {
  int sign = 0;
  if (ch == '-') {
    if (!isdigit (ch = parse_char ())) PER ("expected digit after '-'");
    sign = -1;
  } else if (!isdigit (ch)) PER ("expected digit or '-'");
  else sign = 1;
  lit = ch - '0';
  while (isdigit (ch = parse_char ())) {
    int digit = ch - '0';
    if (INT_MAX/10 < lit || INT_MAX - digit < 10*lit)
      PER ("literal too large");
    lit = 10*lit + digit;
  }
  if (ch == '\r') ch = parse_char ();
  if (ch != 'c' && ch != ' ' && ch != '\t' && ch != '\n')
    PER ("expected white space after '%d'", sign*lit);
  if (lit > vars)
    PER ("literal %d exceeds maximum variable %d", sign*lit, vars);
  lit *= sign;
  return 0;
}

/*------------------------------------------------------------------------*/

// Parsing function for CNF in DIMACS format.

const char * Parser::parse_dimacs_non_profiled () {
  int ch, vars = 0, clauses = 0;
  for (;;) {
    ch = parse_char ();
    if (ch != 'c') break;
    string buf;
    while ((ch = parse_char ()) != '\n')
      if (ch == EOF) PER ("unexpected end-of-file in header comment");
      else if (ch != '\r') buf.push_back (ch);
    const char * o;
    for (o = buf.c_str (); *o && *o != '-'; o++)
      ;
    VRB ("parse-dimacs", "found option '%s'", o);
    if (*o) internal->opts.set (o);
  }
  if (ch != 'p') PER ("expected 'c' or 'p'");
  const char * err = parse_string (" cnf ", 'p');
  if (err) return err;
  if (!isdigit (ch = parse_char ())) PER ("expected digit after 'p cnf '");
  err = parse_positive_int (ch, vars, "<max-var>");
  if (err) return err;
  if (ch != ' ') PER ("expected ' ' after 'p cnf %d'", vars);
  if (!isdigit (ch = parse_char ()))
    PER ("expected digit after 'p cnf %d '", vars);
  err = parse_positive_int (ch, clauses, "<num-clauses>");
  if (err) return err;
  while (ch == ' ' || ch == '\r') ch = parse_char ();
  if (ch != '\n')
    PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
  MSG ("found 'p cnf %d %d' header", vars, clauses);
  internal->resize (vars);
  int lit = 0, parsed = 0;
  while ((ch = parse_char ()) != EOF) {
    if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') continue;
    if (ch == 'c') {
COMMENT:
      while ((ch = parse_char ()) != '\n')
        if (ch == EOF) PER ("unexpected end-of-file in body comment");
      continue;
    }
    err = parse_lit (ch, lit, vars);
    if (err) return err;
    if (ch == 'c') goto COMMENT;
    internal->add_original_lit (lit);
    if (!lit && parsed++ >= clauses) PER ("too many clauses");
  }
  if (lit) PER ("last clause without '0'");
  if (parsed < clauses) PER ("clause missing");
  MSG ("parsed %d clauses in %.2f seconds", parsed, internal->seconds ());
  return 0;
}

/*------------------------------------------------------------------------*/

// Parsing function for a solution in competition output format.

const char * Parser::parse_solution_non_profiled () {
  NEW (internal->solution, signed char, internal->max_var + 1);
  for (int i = 1; i <= internal->max_var; i++) internal->solution[i] = 0;
  int ch;
  for (;;) {
    ch = parse_char ();
    if (ch == EOF) PER ("missing 's' line");
    if (ch == 'c') {
      while ((ch = parse_char ()) != '\n')
        if (ch == EOF) PER ("unexpected end-of-file in comment");
    }
    if (ch == 's') break;
    PER ("expected 'c' or 's'");
  }
  const char * err = parse_string (" SATISFIABLE", 's');
  if (err) return err;
  if ((ch = parse_char ()) == '\r') ch = parse_char ();
  if (ch != '\n') PER ("expected new-line after 's SATISFIABLE'");
  int count = 0;
  for (;;) {
    ch = parse_char ();
    if (ch != 'v') PER ("expected 'v' at start-of-line");
    if ((ch = parse_char ()) != ' ') PER ("expected ' ' after 'v'");
    int lit = 0; ch = parse_char ();
    do {
      if (ch == ' ' || ch == '\t') { ch = parse_char (); continue; }
      err = parse_lit (ch, lit, internal->max_var);
      if (err) return err;
      if (ch == 'c') PER ("unexpected comment");
      if (!lit) break;
      if (internal->solution[abs (lit)])
        PER ("variable %d occurs twice", abs (lit));
      LOG ("solution %d", lit);
      internal->solution [abs (lit)] = sign (lit);
      count++;
      if (ch == '\r') ch = parse_char ();
    } while (ch != '\n');
    if (!lit) break;
  }
  MSG ("parsed %d solutions %.2f%%",
    count, percent (count, internal->max_var));
  return 0;
}

/*------------------------------------------------------------------------*/

// Wrappers to profile parsing and at the same time use the convenient
// implicit 'return' in PER in the non-profiled versions.

const char * Parser::parse_dimacs () {
  START (parse);
  const char * err = parse_dimacs_non_profiled ();
  STOP (parse);
  return err;
}

const char * Parser::parse_solution () {
  START (parse);
  const char * err = parse_solution_non_profiled ();
  STOP (parse);
  return err;
}

};
<commit_msg>fixed solution parser<commit_after>#include "file.hpp"
#include "internal.hpp"
#include "logging.hpp"
#include "macros.hpp"
#include "message.hpp"
#include "parse.hpp"
#include "util.hpp"

#include <cstdarg>
#include <cassert>
#include <cctype>
#include <climits>
#include <string>

namespace CaDiCaL {

/*------------------------------------------------------------------------*/

// Parsing utilities.

int Parser::parse_char () { return file->get (); }

// Return an non zero error string if a parse error occurred.

inline const char *
Parser::parse_string (const char * str, char prev) {
  for (const char * p = str; *p; p++)
    if (parse_char () == *p) prev = *p;
    else PER ("expected '%c' after '%c'", *p, prev);
  return 0;
}

inline const char *
Parser::parse_positive_int (int & ch, int & res, const char * name) {
  assert (isdigit (ch));
  res = ch - '0';
  while (isdigit (ch = parse_char ())) {
    int digit = ch - '0';
    if (INT_MAX/10 < res || INT_MAX - digit < 10*res)
      PER ("too large '%s' in header", name);
    res = 10*res + digit;
  }
  return 0;
}

inline const char *
Parser::parse_lit (int & ch, int & lit, const int vars) {
  int sign = 0;
  if (ch == '-') {
    if (!isdigit (ch = parse_char ())) PER ("expected digit after '-'");
    sign = -1;
  } else if (!isdigit (ch)) PER ("expected digit or '-'");
  else sign = 1;
  lit = ch - '0';
  while (isdigit (ch = parse_char ())) {
    int digit = ch - '0';
    if (INT_MAX/10 < lit || INT_MAX - digit < 10*lit)
      PER ("literal too large");
    lit = 10*lit + digit;
  }
  if (ch == '\r') ch = parse_char ();
  if (ch != 'c' && ch != ' ' && ch != '\t' && ch != '\n')
    PER ("expected white space after '%d'", sign*lit);
  if (lit > vars)
    PER ("literal %d exceeds maximum variable %d", sign*lit, vars);
  lit *= sign;
  return 0;
}

/*------------------------------------------------------------------------*/

// Parsing function for CNF in DIMACS format.

const char * Parser::parse_dimacs_non_profiled () {
  int ch, vars = 0, clauses = 0;
  for (;;) {
    ch = parse_char ();
    if (ch != 'c') break;
    string buf;
    while ((ch = parse_char ()) != '\n')
      if (ch == EOF) PER ("unexpected end-of-file in header comment");
      else if (ch != '\r') buf.push_back (ch);
    const char * o;
    for (o = buf.c_str (); *o && *o != '-'; o++)
      ;
    VRB ("parse-dimacs", "found option '%s'", o);
    if (*o) internal->opts.set (o);
  }
  if (ch != 'p') PER ("expected 'c' or 'p'");
  const char * err = parse_string (" cnf ", 'p');
  if (err) return err;
  if (!isdigit (ch = parse_char ())) PER ("expected digit after 'p cnf '");
  err = parse_positive_int (ch, vars, "<max-var>");
  if (err) return err;
  if (ch != ' ') PER ("expected ' ' after 'p cnf %d'", vars);
  if (!isdigit (ch = parse_char ()))
    PER ("expected digit after 'p cnf %d '", vars);
  err = parse_positive_int (ch, clauses, "<num-clauses>");
  if (err) return err;
  while (ch == ' ' || ch == '\r') ch = parse_char ();
  if (ch != '\n')
    PER ("expected new-line after 'p cnf %d %d'", vars, clauses);
  MSG ("found 'p cnf %d %d' header", vars, clauses);
  internal->resize (vars);
  int lit = 0, parsed = 0;
  while ((ch = parse_char ()) != EOF) {
    if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\r') continue;
    if (ch == 'c') {
COMMENT:
      while ((ch = parse_char ()) != '\n')
        if (ch == EOF) PER ("unexpected end-of-file in body comment");
      continue;
    }
    err = parse_lit (ch, lit, vars);
    if (err) return err;
    if (ch == 'c') goto COMMENT;
    internal->add_original_lit (lit);
    if (!lit && parsed++ >= clauses) PER ("too many clauses");
  }
  if (lit) PER ("last clause without '0'");
  if (parsed < clauses) PER ("clause missing");
  MSG ("parsed %d clauses in %.2f seconds", parsed, internal->seconds ());
  return 0;
}

/*------------------------------------------------------------------------*/

// Parsing function for a solution in competition output format.

const char * Parser::parse_solution_non_profiled () {
  NEW (internal->solution, signed char, internal->max_var + 1);
  for (int i = 1; i <= internal->max_var; i++) internal->solution[i] = 0;
  int ch;
  for (;;) {
    ch = parse_char ();
    if (ch == EOF) PER ("missing 's' line");
    else if (ch == 'c') {
      while ((ch = parse_char ()) != '\n')
        if (ch == EOF) PER ("unexpected end-of-file in comment");
    } else if (ch == 's') break;
    else PER ("expected 'c' or 's'");
  }
  const char * err = parse_string (" SATISFIABLE", 's');
  if (err) return err;
  if ((ch = parse_char ()) == '\r') ch = parse_char ();
  if (ch != '\n') PER ("expected new-line after 's SATISFIABLE'");
  int count = 0;
  for (;;) {
    ch = parse_char ();
    if (ch != 'v') PER ("expected 'v' at start-of-line");
    if ((ch = parse_char ()) != ' ') PER ("expected ' ' after 'v'");
    int lit = 0; ch = parse_char ();
    do {
      if (ch == ' ' || ch == '\t') { ch = parse_char (); continue; }
      err = parse_lit (ch, lit, internal->max_var);
      if (err) return err;
      if (ch == 'c') PER ("unexpected comment");
      if (!lit) break;
      if (internal->solution[abs (lit)])
        PER ("variable %d occurs twice", abs (lit));
      LOG ("solution %d", lit);
      internal->solution [abs (lit)] = sign (lit);
      count++;
      if (ch == '\r') ch = parse_char ();
    } while (ch != '\n');
    if (!lit) break;
  }
  MSG ("parsed %d solutions %.2f%%",
    count, percent (count, internal->max_var));
  return 0;
}

/*------------------------------------------------------------------------*/

// Wrappers to profile parsing and at the same time use the convenient
// implicit 'return' in PER in the non-profiled versions.

const char * Parser::parse_dimacs () {
  START (parse);
  const char * err = parse_dimacs_non_profiled ();
  STOP (parse);
  return err;
}

const char * Parser::parse_solution () {
  START (parse);
  const char * err = parse_solution_non_profiled ();
  STOP (parse);
  return err;
}

};
<|endoftext|>


<commit_before>#include <cstring>

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <node_buffer.h>
#include <mcnet.h>

#include "parser.h"

using namespace v8;
using namespace node;

mcnet::Parser::Parser() {
  settings.on_packet = mcnet::Parser::on_packet;
  settings.on_error = mcnet::Parser::on_error;
}

mcnet::Parser::~Parser() {
}

void mcnet::Parser::Init(Handle< Object > target) {
  Local< FunctionTemplate > tpl = FunctionTemplate::New(New);

  tpl->SetClassName(String::NewSymbol("Parser"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  tpl->PrototypeTemplate()->Set(String::NewSymbol("execute"), FunctionTemplate::New(Execute)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EAGAIN"), Number::New(MCNET_EAGAIN));
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EINVALID"), Number::New(MCNET_EINVALID));

  Persistent< Function > constructor = Persistent< Function >::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Parser"), constructor);
}

Handle< Value > mcnet::Parser::New(const Arguments& args) {
  HandleScope scope;

  Parser* obj = new Parser();
  obj->Wrap(args.This());

  return args.This();
}

Handle< Value > mcnet::Parser::Execute(const Arguments& args) {
  HandleScope scope;

  mcnet::Parser* parser = ObjectWrap::Unwrap< mcnet::Parser >(args.This());

  Local< Object > buffer = Local< Object >::Cast(args[0]);

  Handle< Object > obj = args.This();
  parser->parser.data = (void*)&obj;
  size_t nparsed = mcnet_parser_execute(&(parser->parser), &(parser->settings), reinterpret_cast< uint8_t* >(Buffer::Data(buffer)), Buffer::Length(buffer));
  parser->parser.data = NULL;

  return scope.Close(Number::New(nparsed));
}

void mcnet::Parser::on_packet(mcnet_parser_t* parser, mcnet_packet_t* packet) {
  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Local< Object > object = Object::New();

  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));

#define PACKET(id, code) case 0x##id: { \
  mcnet_packet_##id##_t* pkt = reinterpret_cast< mcnet_packet_##id##_t* >(packet); \
  BYTE(pid) \
  code \
  break; \
}

#define CODE(data)
#define BOOL(name) object->Set(String::New(#name), Boolean::New(pkt->name ? true : false));
#define NUMBER(name) object->Set(String::New(#name), Number::New(pkt->name));
#define BYTE(name) NUMBER(name)
#define UBYTE(name) NUMBER(name)
#define SHORT(name) NUMBER(name)
#define USHORT(name) NUMBER(name)
#define INT(name) NUMBER(name)
#define LONG(name) NUMBER(name)
#define FLOAT(name) NUMBER(name)
#define DOUBLE(name) NUMBER(name)
#define STRING8(name) BLOB(name, name##_len)
#define STRING16(name) BLOB(name, name##_len * 2)
#define BLOB(name, length) \
  Buffer* name##_buffer = Buffer::New(pkt->length); \
  memcpy(Buffer::Data(name##_buffer), pkt->name, pkt->length); \
  Handle< Value > name##_args[3] = { name##_buffer->handle_, Integer::New(pkt->length), Integer::New(0) }; \
  object->Set(String::New(#name), buffer_constructor->NewInstance(3, name##_args));
#define METADATA(name) \
  Local< Object > name##_metadata = Object::New(); \
  mcnet_metadata_parser_t name##_parser; \
  name##_parser.on_entry = mcnet::Parser::on_metadata_entry; \
  name##_parser.data = (void*)(&name##_metadata); \
  mcnet_metadata_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  object->Set(String::New(#name), name##_metadata);
#define SLOT(name) \
  object->Set(String::New(#name), String::New("slot placeholder"));
#define SLOTS(name, count) \
  object->Set(String::New(#name), String::New("slot array placeholder"));

  switch (packet->pid) {
PACKETS
  }

#undef CODE
#undef BOOL
#undef NUMBER
#undef BYTE
#undef UBYTE
#undef SHORT
#undef USHORT
#undef INT
#undef LONG
#undef FLOAT
#undef DOUBLE
#undef STRING8
#undef STRING16
#undef BLOB
#undef METADATA
#undef SLOT
#undef SLOTS

#undef PACKET

  Handle< Value > argv[2] = {
    String::New("packet"),
    object
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_error(mcnet_parser_t* parser, int err) {
  if (err == MCNET_EAGAIN) {
    return;
  }

  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Handle< Value > argv[2] = {
    String::New("error"),
    Number::New(err)
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_metadata_entry(mcnet_metadata_parser_t* parser, mcnet_metadata_entry_t* entry) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  switch (entry->type) {
    case MCNET_METADATA_TYPE_BYTE: {
//      mcnet_metadata_entry_byte_t* ent = reinterpret_cast< mcnet_metadata_entry_byte_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_SHORT: {
//      mcnet_metadata_entry_short_t* ent = reinterpret_cast< mcnet_metadata_entry_short_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_INT: {
//      mcnet_metadata_entry_int_t* ent = reinterpret_cast< mcnet_metadata_entry_int_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_FLOAT: {
//      mcnet_metadata_entry_float_t* ent = reinterpret_cast< mcnet_metadata_entry_float_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_STRING16: {
//      mcnet_metadata_entry_string16_t* ent = reinterpret_cast< mcnet_metadata_entry_string16_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
    case MCNET_METADATA_TYPE_SLOT: {
//      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
    case MCNET_METADATA_TYPE_INTS: {
//      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
  }
}
<commit_msg>oh ok c++, you don't want to initialise stack space. that's cool too i guess.<commit_after>#include <cstring>

#define BUILDING_NODE_EXTENSION
#include <node.h>
#include <node_buffer.h>
#include <mcnet.h>

#include "parser.h"

using namespace v8;
using namespace node;

mcnet::Parser::Parser() {
  settings.on_packet = mcnet::Parser::on_packet;
  settings.on_error = mcnet::Parser::on_error;
}

mcnet::Parser::~Parser() {
}

void mcnet::Parser::Init(Handle< Object > target) {
  Local< FunctionTemplate > tpl = FunctionTemplate::New(New);

  tpl->SetClassName(String::NewSymbol("Parser"));
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  tpl->PrototypeTemplate()->Set(String::NewSymbol("execute"), FunctionTemplate::New(Execute)->GetFunction());
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EAGAIN"), Number::New(MCNET_EAGAIN));
  tpl->PrototypeTemplate()->Set(String::NewSymbol("EINVALID"), Number::New(MCNET_EINVALID));

  Persistent< Function > constructor = Persistent< Function >::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Parser"), constructor);
}

Handle< Value > mcnet::Parser::New(const Arguments& args) {
  HandleScope scope;

  Parser* obj = new Parser();
  obj->Wrap(args.This());

  return args.This();
}

Handle< Value > mcnet::Parser::Execute(const Arguments& args) {
  HandleScope scope;

  mcnet::Parser* parser = ObjectWrap::Unwrap< mcnet::Parser >(args.This());

  Local< Object > buffer = Local< Object >::Cast(args[0]);

  Handle< Object > obj = args.This();
  parser->parser.data = (void*)&obj;
  size_t nparsed = mcnet_parser_execute(&(parser->parser), &(parser->settings), reinterpret_cast< uint8_t* >(Buffer::Data(buffer)), Buffer::Length(buffer));
  parser->parser.data = NULL;

  return scope.Close(Number::New(nparsed));
}

void mcnet::Parser::on_packet(mcnet_parser_t* parser, mcnet_packet_t* packet) {
  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Local< Object > object = Object::New();

  Local< Object > global = Context::GetCurrent()->Global();
  Local< Function > buffer_constructor = Local< Function >::Cast(global->Get(String::New("Buffer")));

#define PACKET(id, code) case 0x##id: { \
  mcnet_packet_##id##_t* pkt = reinterpret_cast< mcnet_packet_##id##_t* >(packet); \
  BYTE(pid) \
  code \
  break; \
}

#define CODE(data)
#define BOOL(name) object->Set(String::New(#name), Boolean::New(pkt->name ? true : false));
#define NUMBER(name) object->Set(String::New(#name), Number::New(pkt->name));
#define BYTE(name) NUMBER(name)
#define UBYTE(name) NUMBER(name)
#define SHORT(name) NUMBER(name)
#define USHORT(name) NUMBER(name)
#define INT(name) NUMBER(name)
#define LONG(name) NUMBER(name)
#define FLOAT(name) NUMBER(name)
#define DOUBLE(name) NUMBER(name)
#define STRING8(name) BLOB(name, name##_len)
#define STRING16(name) BLOB(name, name##_len * 2)
#define BLOB(name, length) \
  Buffer* name##_buffer = Buffer::New(pkt->length); \
  memcpy(Buffer::Data(name##_buffer), pkt->name, pkt->length); \
  Handle< Value > name##_args[3] = { name##_buffer->handle_, Integer::New(pkt->length), Integer::New(0) }; \
  object->Set(String::New(#name), buffer_constructor->NewInstance(3, name##_args));
#define METADATA(name) \
  Local< Object > name##_metadata = Object::New(); \
  mcnet_metadata_parser_t name##_parser; \
  name##_parser.on_error = NULL; \
  name##_parser.on_complete = NULL; \
  name##_parser.on_entry = mcnet::Parser::on_metadata_entry; \
  name##_parser.data = &name##_metadata; \
  mcnet_metadata_parser_parse(&name##_parser, pkt->name, pkt->name##_len); \
  object->Set(String::New(#name), name##_metadata);
#define SLOT(name) \
  object->Set(String::New(#name), String::New("slot placeholder"));
#define SLOTS(name, count) \
  object->Set(String::New(#name), String::New("slot array placeholder"));

  switch (packet->pid) {
PACKETS
  }

#undef CODE
#undef BOOL
#undef NUMBER
#undef BYTE
#undef UBYTE
#undef SHORT
#undef USHORT
#undef INT
#undef LONG
#undef FLOAT
#undef DOUBLE
#undef STRING8
#undef STRING16
#undef BLOB
#undef METADATA
#undef SLOT
#undef SLOTS

#undef PACKET

  Handle< Value > argv[2] = {
    String::New("packet"),
    object
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_error(mcnet_parser_t* parser, int err) {
  if (err == MCNET_EAGAIN) {
    return;
  }

  Handle< Object >* obj = (Handle< Object >*)(parser->data);

  Handle< Value > argv[2] = {
    String::New("error"),
    Number::New(err)
  };

  MakeCallback(*obj, "emit", 2, argv);
}

void mcnet::Parser::on_metadata_entry(mcnet_metadata_parser_t* parser, mcnet_metadata_entry_t* entry) {
  Local< Object >* obj = reinterpret_cast< Local< Object >* >(parser->data);

  switch (entry->type) {
    case MCNET_METADATA_TYPE_BYTE: {
//      mcnet_metadata_entry_byte_t* ent = reinterpret_cast< mcnet_metadata_entry_byte_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_SHORT: {
//      mcnet_metadata_entry_short_t* ent = reinterpret_cast< mcnet_metadata_entry_short_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_INT: {
//      mcnet_metadata_entry_int_t* ent = reinterpret_cast< mcnet_metadata_entry_int_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_FLOAT: {
//      mcnet_metadata_entry_float_t* ent = reinterpret_cast< mcnet_metadata_entry_float_t* >(entry);
//      (*obj)->Set(ent->index, Number::New(ent->data));
      break;
    }
    case MCNET_METADATA_TYPE_STRING16: {
//      mcnet_metadata_entry_string16_t* ent = reinterpret_cast< mcnet_metadata_entry_string16_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
    case MCNET_METADATA_TYPE_SLOT: {
//      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
    case MCNET_METADATA_TYPE_INTS: {
//      mcnet_metadata_entry_sbs_t* ent = reinterpret_cast< mcnet_metadata_entry_sbs_t* >(entry);
//      (*obj)->Set(ent->index, ent->data);
      break;
    }
  }
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may 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 "libtorrent/pch.hpp"

#include <algorithm>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry(dictionary_type const& v)
	{
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
	{
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
	{
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
	{
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		m_type = t;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			m_type = undefined_t;
		}
	}

	void entry::copy(entry const& e)
	{
		m_type = e.m_type;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			m_type = undefined_t;
		}
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<commit_msg>fixed missing include in entry.cpp<commit_after>/*

Copyright (c) 2003, Arvid Norberg
All rights reserved.

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.
    * Neither the name of the author nor the names of its
      contributors may 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 "libtorrent/pch.hpp"

#include <algorithm>
#include <iostream>
#include <iomanip>
#include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp"

#if defined(_MSC_VER)
namespace std
{
	using ::isprint;
}
#define for if (false) {} else for
#endif

namespace
{
	template <class T>
	void call_destructor(T* o)
	{
		TORRENT_ASSERT(o);
		o->~T();
	}

	struct compare_string
	{
		compare_string(char const* s): m_str(s)  {}

		bool operator()(
			std::pair<std::string
			, libtorrent::entry> const& e) const
		{
			return m_str && e.first == m_str;
		}
		char const* m_str;
	};
}

namespace libtorrent
{
	namespace detail
	{
		TORRENT_EXPORT char const* integer_to_str(char* buf, int size, entry::integer_type val)
		{
			int sign = 0;
			if (val < 0)
			{
				sign = 1;
				val = -val;
			}
			buf[--size] = '\0';
			if (val == 0) buf[--size] = '0';
			for (; size > sign && val != 0;)
			{
				buf[--size] = '0' + char(val % 10);
				val /= 10;
			}
			if (sign) buf[--size] = '-';
			return buf + size;
		}
	}

	entry& entry::operator[](char const* key)
	{
		dictionary_type::iterator i = dict().find(key);
		if (i != dict().end()) return i->second;
		dictionary_type::iterator ret = dict().insert(
			dict().begin()
			, std::make_pair(std::string(key), entry()));
		return ret->second;
	}

	entry& entry::operator[](std::string const& key)
	{
		return (*this)[key.c_str()];
	}

	entry* entry::find_key(char const* key)
	{
		dictionary_type::iterator i = std::find_if(
			dict().begin()
			, dict().end()
			, compare_string(key));
		if (i == dict().end()) return 0;
		return &i->second;

	}

	entry const* entry::find_key(char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) return 0;
		return &i->second;
	}

#ifndef BOOST_NO_EXCEPTIONS
	const entry& entry::operator[](char const* key) const
	{
		dictionary_type::const_iterator i = dict().find(key);
		if (i == dict().end()) throw type_error(
			(std::string("key not found: ") + key).c_str());
		return i->second;
	}

	const entry& entry::operator[](std::string const& key) const
	{
		return (*this)[key.c_str()];
	}
#endif

	entry::entry(dictionary_type const& v)
	{
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	entry::entry(string_type const& v)
	{
		new(data) string_type(v);
		m_type = string_t;
	}

	entry::entry(list_type const& v)
	{
		new(data) list_type(v);
		m_type = list_t;
	}

	entry::entry(integer_type const& v)
	{
		new(data) integer_type(v);
		m_type = int_t;
	}

	void entry::operator=(dictionary_type const& v)
	{
		destruct();
		new(data) dictionary_type(v);
		m_type = dictionary_t;
	}

	void entry::operator=(string_type const& v)
	{
		destruct();
		new(data) string_type(v);
		m_type = string_t;
	}

	void entry::operator=(list_type const& v)
	{
		destruct();
		new(data) list_type(v);
		m_type = list_t;
	}

	void entry::operator=(integer_type const& v)
	{
		destruct();
		new(data) integer_type(v);
		m_type = int_t;
	}

	bool entry::operator==(entry const& e) const
	{
		if (m_type != e.m_type) return false;

		switch(m_type)
		{
		case int_t:
			return integer() == e.integer();
		case string_t:
			return string() == e.string();
		case list_t:
			return list() == e.list();
		case dictionary_t:
			return dict() == e.dict();
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			return true;
		}
	}

	void entry::construct(data_type t)
	{
		m_type = t;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type;
			break;
		case string_t:
			new(data) string_type;
			break;
		case list_t:
			new(data) list_type;
			break;
		case dictionary_t:
			new (data) dictionary_type;
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			m_type = undefined_t;
		}
	}

	void entry::copy(entry const& e)
	{
		m_type = e.m_type;
		switch(m_type)
		{
		case int_t:
			new(data) integer_type(e.integer());
			break;
		case string_t:
			new(data) string_type(e.string());
			break;
		case list_t:
			new(data) list_type(e.list());
			break;
		case dictionary_t:
			new (data) dictionary_type(e.dict());
			break;
		default:
			m_type = undefined_t;
		}
	}

	void entry::destruct()
	{
		switch(m_type)
		{
		case int_t:
			call_destructor(reinterpret_cast<integer_type*>(data));
			break;
		case string_t:
			call_destructor(reinterpret_cast<string_type*>(data));
			break;
		case list_t:
			call_destructor(reinterpret_cast<list_type*>(data));
			break;
		case dictionary_t:
			call_destructor(reinterpret_cast<dictionary_type*>(data));
			break;
		default:
			TORRENT_ASSERT(m_type == undefined_t);
			break;
		}
	}

	void entry::swap(entry& e)
	{
		// not implemented
		TORRENT_ASSERT(false);
	}

	void entry::print(std::ostream& os, int indent) const
	{
		TORRENT_ASSERT(indent >= 0);
		for (int i = 0; i < indent; ++i) os << " ";
		switch (m_type)
		{
		case int_t:
			os << integer() << "\n";
			break;
		case string_t:
			{
				bool binary_string = false;
				for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
				{
					if (!std::isprint(static_cast<unsigned char>(*i)))
					{
						binary_string = true;
						break;
					}
				}
				if (binary_string)
				{
					os.unsetf(std::ios_base::dec);
					os.setf(std::ios_base::hex);
					for (std::string::const_iterator i = string().begin(); i != string().end(); ++i)
						os << std::setfill('0') << std::setw(2)
							<< static_cast<unsigned int>((unsigned char)*i);
					os.unsetf(std::ios_base::hex);
					os.setf(std::ios_base::dec);
					os << "\n";
				}
				else
				{
					os << string() << "\n";
				}
			} break;
		case list_t:
			{
				os << "list\n";
				for (list_type::const_iterator i = list().begin(); i != list().end(); ++i)
				{
					i->print(os, indent+1);
				}
			} break;
		case dictionary_t:
			{
				os << "dictionary\n";
				for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i)
				{
					for (int j = 0; j < indent+1; ++j) os << " ";
					os << "[" << i->first << "]";
					if (i->second.type() != entry::string_t
						&& i->second.type() != entry::int_t)
						os << "\n";
					else os << " ";
					i->second.print(os, indent+2);
				}
			} break;
		default:
			os << "<uninitialized>\n";
		}
	}
}

<|endoftext|>