<commit_before>/*
 * Copyright 2012-2013 Falltergeist Developers.
 *
 * This file is part of Falltergeist.
 *
 * Falltergeist is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Falltergeist is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Falltergeist.  If not, see <http://www.gnu.org/licenses/>.
 */

// C++ standard includes
#include <algorithm>

// libfalltergeist includes
#include "../src/FrmFileType.h"
#include "../src/PalFileType.h"
#include "../src/PalColor.h"

// Third party includes

namespace libfalltergeist
{

FrmFileType::FrmFileType(DatFileEntry * datFileEntry) : DatFileItem(datFileEntry)
{
}

FrmFileType::FrmFileType(std::ifstream * stream) : DatFileItem(stream)
{
}

FrmFileType::~FrmFileType()
{
    delete [] _rgba;
}

void FrmFileType::_initialize()
{
    if (_initialized) return;
    DatFileItem::_initialize();
    DatFileItem::setPosition(0);

    *this >> _version >> _framesPerSecond >> _actionFrame >> _framesPerDirection;

    for (unsigned int i = 0; i != 6; ++i) *this >> _shiftX[i];
    for (unsigned int i = 0; i != 6; ++i) *this >> _shiftY[i];
    for (unsigned int i = 0; i != 6; ++i)
    {
        *this >> _dataOffset[i];
        if (i > 0 && _dataOffset[i-1] == _dataOffset[i]) continue;
        _directions++;
    }

    // for each direction
    for (unsigned int i = 0; i!= _directions; ++i)
    {
        // jump to frames data at frames area
        DatFileItem::setPosition(_dataOffset[i] + 62);

        // read all frames
        for (unsigned int j = 0; j != _framesPerDirection; ++j)
        {
            unsigned short width, height;
            short offsetX, offsetY;

            *this >> width >> height;
            _width[i].push_back(width);
            _height[i].push_back(height);

            // Number of pixels for this frame
            // We don't need this, because we already have width*height
            this->skipBytes(4);

            *this >> offsetX >> offsetY;
            _offsetX[i].push_back(offsetX);
            _offsetY[i].push_back(offsetY);

            // will be used later
            this->skipBytes(width*height);
        }
    }
}

unsigned int FrmFileType::version()
{
    _initialize();
    return _version;
}

unsigned short FrmFileType::framesPerSecond()
{
    _initialize();
    return _framesPerSecond;
}

unsigned short FrmFileType::framesPerDirection()
{
    _initialize();
    return _framesPerDirection;
}

unsigned short FrmFileType::actionFrame()
{
    _initialize();
    return _actionFrame;
}

unsigned int FrmFileType::directions()
{
    _initialize();
    return _directions;
}

unsigned int FrmFileType::width()
{
    _initialize();

    std::vector<unsigned int> width;

    for (unsigned int i = 0; i != _directions; ++i)
    {
        width.push_back(*std::max_element(_width[i].begin(), _width[i].end()));
    };
    return *std::max_element(width.begin(), width.end());
}

unsigned int FrmFileType::height()
{
    _initialize();

    std::vector<unsigned int> height;

    for (unsigned int i = 0; i != _directions; ++i)
    {
        height.push_back(*std::max_element(_height[i].begin(), _height[i].end()));
    };
    return *std::max_element(height.begin(), height.end());
}

unsigned int FrmFileType::width(unsigned int direction, unsigned int frame)
{
    return _width[direction].at(frame);
}

unsigned int FrmFileType::height(unsigned int direction)
{
    _initialize();
    return *std::max_element(_height[direction].begin(), _height[direction].end());
}

unsigned int FrmFileType::height(unsigned int direction, unsigned int frame)
{
    return _height[direction].at(frame);
}

unsigned int* FrmFileType::rgba(PalFileType* palFile)
{
    if (_rgba) return _rgba;
    _initialize();
    unsigned int w = width();
    unsigned int h = height();
    _rgba = new unsigned int[w*h]();

    unsigned int positionY = 0;
    for (unsigned int d = 0; d != _directions; ++d)
    {
        unsigned int positionX = 0;
        DatFileItem::setPosition(_dataOffset[d] + 62);
        for (unsigned int f = 0; f != _framesPerDirection; ++f)
        {
            this->skipBytes(4*3);
            // read frame data and add to _rgba
            for (unsigned int y = 0; y != height(d, f); ++y)
            {
                for (unsigned int x = 0; x != width(d, f); ++x)
                {
                    unsigned char index;
                    *this >> index;
                    _rgba[((y + positionY)*w) + x + positionX] = *palFile->color(index);
                }
            }
            positionX += width(d, f);
        }
        positionY += height(d);
    }
    return _rgba;
}

}
<commit_msg>frm file type update<commit_after>/*
 * Copyright 2012-2013 Falltergeist Developers.
 *
 * This file is part of Falltergeist.
 *
 * Falltergeist is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Falltergeist is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Falltergeist.  If not, see <http://www.gnu.org/licenses/>.
 */

// C++ standard includes
#include <algorithm>
#include <iostream>

// libfalltergeist includes
#include "../src/FrmFileType.h"
#include "../src/PalFileType.h"
#include "../src/PalColor.h"

// Third party includes

namespace libfalltergeist
{

FrmFileType::FrmFileType(DatFileEntry * datFileEntry) : DatFileItem(datFileEntry)
{
}

FrmFileType::FrmFileType(std::ifstream * stream) : DatFileItem(stream)
{
}

FrmFileType::~FrmFileType()
{
    delete [] _rgba;
}

void FrmFileType::_initialize()
{
    if (_initialized) return;
    DatFileItem::_initialize();
    DatFileItem::setPosition(0);

    *this >> _version >> _framesPerSecond >> _actionFrame >> _framesPerDirection;

    for (unsigned int i = 0; i != 6; ++i) *this >> _shiftX[i];
    for (unsigned int i = 0; i != 6; ++i) *this >> _shiftY[i];
    for (unsigned int i = 0; i != 6; ++i)
    {
        *this >> _dataOffset[i];
        if (i > 0 && _dataOffset[i-1] == _dataOffset[i]) continue;
        _directions++;
    }

    // for each direction
    for (unsigned int i = 0; i!= _directions; ++i)
    {
        // jump to frames data at frames area
        DatFileItem::setPosition(_dataOffset[i] + 62);

        // read all frames
        for (unsigned int j = 0; j != _framesPerDirection; ++j)
        {
            unsigned short width, height;
            short offsetX, offsetY;

            *this >> width >> height;
            _width[i].push_back(width);
            _height[i].push_back(height);

            // Number of pixels for this frame
            // We don't need this, because we already have width*height
            this->skipBytes(4);

            *this >> offsetX >> offsetY;
            _offsetX[i].push_back(offsetX);
            _offsetY[i].push_back(offsetY);

            // will be used later
            this->skipBytes(width*height);
        }
    }
}

unsigned int FrmFileType::version()
{
    _initialize();
    return _version;
}

unsigned short FrmFileType::framesPerSecond()
{
    _initialize();
    return _framesPerSecond;
}

unsigned short FrmFileType::framesPerDirection()
{
    _initialize();
    return _framesPerDirection;
}

unsigned short FrmFileType::actionFrame()
{
    _initialize();
    return _actionFrame;
}

unsigned int FrmFileType::directions()
{
    _initialize();
    return _directions;
}

unsigned int FrmFileType::width()
{
    _initialize();

    unsigned int width = 0;

    for (unsigned int f = 0; f != _framesPerDirection; ++f)
    {
        width += _width[0].at(f);
    };
    return width;
}

unsigned int FrmFileType::height()
{
    _initialize();

    unsigned int height = 0;

    for (unsigned int i = 0; i != _directions; ++i)
    {
        height += this->height(i);
    };
    return height;
}

unsigned int FrmFileType::width(unsigned int direction, unsigned int frame)
{
    return _width[direction].at(frame);
}

unsigned int FrmFileType::height(unsigned int direction)
{
    _initialize();
    return *std::max_element(_height[direction].begin(), _height[direction].end());
}

unsigned int FrmFileType::height(unsigned int direction, unsigned int frame)
{
    return _height[direction].at(frame);
}

unsigned int* FrmFileType::rgba(PalFileType* palFile)
{
    if (_rgba) return _rgba;
    _initialize();
    unsigned int w = width();
    unsigned int h = height();
    _rgba = new unsigned int[w*h]();

    unsigned int positionY = 0;
    for (unsigned int d = 0; d != _directions; ++d)
    {
        unsigned int positionX = 0;
        DatFileItem::setPosition(_dataOffset[d] + 62);
        for (unsigned int f = 0; f != _framesPerDirection; ++f)
        {
            this->skipBytes(4*3);
            // read frame data and add to _rgba
            for (unsigned int y = 0; y != height(d, f); ++y)
            {
                for (unsigned int x = 0; x != width(d, f); ++x)
                {
                    unsigned char index;
                    *this >> index;
                    _rgba[((y + positionY)*w) + x + positionX] = *palFile->color(index);
                }
            }
            positionX += width(d, f);
        }
        positionY += height(d);
    }
    return _rgba;
}

}
<|endoftext|>


<commit_before>/*
 OpenLieroX

 hide and seek gamemode

 created 2009-02-09
 code under LGPL
 */

#include <iostream>
#include <math.h>
#include "CHideAndSeek.h"
#include "CWorm.h"
#include "Options.h"
#include "Consts.h"
#include "CServer.h"
#include "CClient.h"
#include "CServerConnection.h"
#include "CServerNetEngine.h"

CHideAndSeek::CHideAndSeek(GameServer* server, CWorm* worms)
{
	cServer = server;
	cWorms = worms;
}

CHideAndSeek::~CHideAndSeek()
{
}

void CHideAndSeek::PrepareGame()
{
}

void CHideAndSeek::PrepareWorm(CWorm* worm)
{
	worm->setLives(0);
}

bool CHideAndSeek::Spawn(CWorm* worm, CVec pos)
{
	worm->Spawn(pos);
	// Hiders only spawn on their own client
	if(worm->getTeam() == HIDER) {
		worm->getClient()->getNetEngine()->SendSpawnWorm(worm, pos);
		return false;
	}
	// Seekers spawn for everyone
	return true;
}

void CHideAndSeek::Kill(CWorm* victim, CWorm* killer)
{
	cServer->SendGlobalText(killer->getName() + " caught " + victim->getName(), TXT_NORMAL);
	killer->AddKill();
	victim->Kill();
}

bool CHideAndSeek::Shoot(CWorm* worm)
{
	return false;
}

void CHideAndSeek::Drop(CWorm* worm)
{
}

void CHideAndSeek::Simulate()
{
	// Check if any of the seekers are in range of the hiders
	int i, j;
	CVec dist;
	for(i = 0; i < MAX_WORMS; i++) {
		if(!cWorms[i].isUsed() || cWorms[i].getLives() == WRM_OUT || cWorms[i].getTeam() == HIDER)
			continue;
		for(j = 0; j < MAX_WORMS; j++) {
			if(!cWorms[j].isUsed() || cWorms[j].getLives() == WRM_OUT || cWorms[j].getTeam() == SEEKER)
				continue;
			dist = cWorms[i].getPos() - cWorms[j].getPos();
			// Catch worms within 100 pixels of the seeker
			if(dist.GetLength() < 100)
				cServer->killWorm(j, i, 0);
		}
	}
}

bool CHideAndSeek::CheckGame()
{
	// Empty games, no need to check anything?
	if(tLXOptions->tGameInfo.features[FT_AllowEmptyGames])
		return false;

	int worms = 0;
	int wormid = 0;
	for(int i = 0; i < MAX_WORMS; i++)
		if(cWorms[i].isUsed() && cWorms[i].getLives() != WRM_OUT && cWorms[i].getTeam() == HIDER) {
			worms++;
			wormid = i;
		}
	if(worms == 0) {
		if (networkTexts->sPlayerHasWon != "<none>")
			cServer->SendGlobalText((replacemax(networkTexts->sPlayerHasWon, "<player>",
				cWorms[wormid].getName(), 1)), TXT_NORMAL);
		iWinner = wormid;
		return true;
	}
	return false;
}

int CHideAndSeek::GameType()
{
	return GMT_TEAMS;
}

int CHideAndSeek::GameTeams()
{
	return 2;
}

int CHideAndSeek::Winner()
{
	return iWinner;
}

<commit_msg>wrong include<commit_after>/*
 OpenLieroX

 hide and seek gamemode

 created 2009-02-09
 code under LGPL
 */

#include <iostream>
#include <cmath>
#include "CHideAndSeek.h"
#include "CWorm.h"
#include "Options.h"
#include "Consts.h"
#include "CServer.h"
#include "CClient.h"
#include "CServerConnection.h"
#include "CServerNetEngine.h"

CHideAndSeek::CHideAndSeek(GameServer* server, CWorm* worms)
{
	cServer = server;
	cWorms = worms;
}

CHideAndSeek::~CHideAndSeek()
{
}

void CHideAndSeek::PrepareGame()
{
}

void CHideAndSeek::PrepareWorm(CWorm* worm)
{
	worm->setLives(0);
}

bool CHideAndSeek::Spawn(CWorm* worm, CVec pos)
{
	worm->Spawn(pos);
	// Hiders only spawn on their own client
	if(worm->getTeam() == HIDER) {
		worm->getClient()->getNetEngine()->SendSpawnWorm(worm, pos);
		return false;
	}
	// Seekers spawn for everyone
	return true;
}

void CHideAndSeek::Kill(CWorm* victim, CWorm* killer)
{
	cServer->SendGlobalText(killer->getName() + " caught " + victim->getName(), TXT_NORMAL);
	killer->AddKill();
	victim->Kill();
}

bool CHideAndSeek::Shoot(CWorm* worm)
{
	return false;
}

void CHideAndSeek::Drop(CWorm* worm)
{
}

void CHideAndSeek::Simulate()
{
	// Check if any of the seekers are in range of the hiders
	int i, j;
	CVec dist;
	for(i = 0; i < MAX_WORMS; i++) {
		if(!cWorms[i].isUsed() || cWorms[i].getLives() == WRM_OUT || cWorms[i].getTeam() == HIDER)
			continue;
		for(j = 0; j < MAX_WORMS; j++) {
			if(!cWorms[j].isUsed() || cWorms[j].getLives() == WRM_OUT || cWorms[j].getTeam() == SEEKER)
				continue;
			dist = cWorms[i].getPos() - cWorms[j].getPos();
			// Catch worms within 100 pixels of the seeker
			if(dist.GetLength() < 100)
				cServer->killWorm(j, i, 0);
		}
	}
}

bool CHideAndSeek::CheckGame()
{
	// Empty games, no need to check anything?
	if(tLXOptions->tGameInfo.features[FT_AllowEmptyGames])
		return false;

	int worms = 0;
	int wormid = 0;
	for(int i = 0; i < MAX_WORMS; i++)
		if(cWorms[i].isUsed() && cWorms[i].getLives() != WRM_OUT && cWorms[i].getTeam() == HIDER) {
			worms++;
			wormid = i;
		}
	if(worms == 0) {
		if (networkTexts->sPlayerHasWon != "<none>")
			cServer->SendGlobalText((replacemax(networkTexts->sPlayerHasWon, "<player>",
				cWorms[wormid].getName(), 1)), TXT_NORMAL);
		iWinner = wormid;
		return true;
	}
	return false;
}

int CHideAndSeek::GameType()
{
	return GMT_TEAMS;
}

int CHideAndSeek::GameTeams()
{
	return 2;
}

int CHideAndSeek::Winner()
{
	return iWinner;
}

<|endoftext|>


<commit_before>#if 1

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/AnimationPathManipulator>
#include <iostream>

class ThreadingHandler : public osgGA::GUIEventHandler
{
public:

    ThreadingHandler() {}

    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
        if (!viewer) return false;

        switch(ea.getEventType())
        {
            case(osgGA::GUIEventAdapter::KEYUP):
            {
                if (ea.getKey()=='m')
                {
                    switch(viewer->getThreadingModel())
                    {
                        case(osgViewer::Viewer::SingleThreaded):
                            viewer->setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
                            osg::notify(osg::NOTICE)<<"Threading model 'CullDrawThreadPerContext' selected."<<std::endl;
                            break;
                        case(osgViewer::Viewer::CullDrawThreadPerContext):
                            viewer->setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
                            osg::notify(osg::NOTICE)<<"Threading model 'DrawThreadPerContext' selected."<<std::endl;
                            break;
                        case(osgViewer::Viewer::DrawThreadPerContext):
                            viewer->setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
                            osg::notify(osg::NOTICE)<<"Threading model 'CullThreadPerCameraDrawThreadPerContext' selected."<<std::endl;
                            break;
                        case(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext):
                            viewer->setThreadingModel(osgViewer::Viewer::SingleThreaded);
                            osg::notify(osg::NOTICE)<<"Threading model 'SingleThreaded' selected."<<std::endl;
                            break;
                        case(osgViewer::Viewer::AutomaticSelection):
                            viewer->setThreadingModel(viewer->suggestBestThreadingModel());
                            osg::notify(osg::NOTICE)<<"Threading model 'AutomaticSelection' selected."<<std::endl;
                            break;
                    }
                    return true;
                }
                if (ea.getKey()=='e')
                {
                    switch(viewer->getEndBarrierPosition())
                    {
                        case(osgViewer::Viewer::BeforeSwapBuffers):
                            viewer->setEndBarrierPosition(osgViewer::Viewer::AfterSwapBuffers);
                            osg::notify(osg::NOTICE)<<"Threading model 'AfterSwapBuffers' selected."<<std::endl;
                            break;
                        case(osgViewer::Viewer::AfterSwapBuffers):
                            viewer->setEndBarrierPosition(osgViewer::Viewer::BeforeSwapBuffers);
                            osg::notify(osg::NOTICE)<<"Threading model 'BeforeSwapBuffers' selected."<<std::endl;
                            break;
                    }
                    return true;
                }
            }
            default: break;
        }

        return false;
    }

    bool _done;
};

class ModelHandler : public osgGA::GUIEventHandler
{
public:

    ModelHandler():
        _position(0) {}

    typedef std::vector<std::string> Filenames;
    Filenames _filenames;
    unsigned int _position;

    void add(const std::string& filename) { _filenames.push_back(filename); }

    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
        if (!viewer) return false;

        if (_filenames.empty()) return false;

        switch(ea.getEventType())
        {
            case(osgGA::GUIEventAdapter::KEYUP):
            {
                if (ea.getKey()=='l')
                {
                    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile( _filenames[_position] );
                    ++_position;
                    if (_position>=_filenames.size()) _position = 0;

                    if (model.valid())
                    {
                        viewer->setSceneData(model.get());
                    }

                    return true;
                }
            }
            default: break;
        }

        return false;
    }

    bool _done;
};

void singleWindowMultipleCameras(osgViewer::Viewer& viewer)
{
    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
    if (!wsi)
    {
        osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        return;
    }

    unsigned int width, height;
    wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->x = 0;
    traits->y = 0;
    traits->width = width;
    traits->height = height;
    traits->windowDecoration = true;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
    if (gc.valid())
    {
        osg::notify(osg::INFO)<<"  GraphicsWindow has been created successfully."<<std::endl;

        // need to ensure that the window is cleared make sure that the complete window is set the correct colour
        // rather than just the parts of the window that are under the camera's viewports
        gc->setClearColor(osg::Vec4f(0.2f,0.2f,0.6f,1.0f));
        gc->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
    else
    {
        osg::notify(osg::NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
    }

    unsigned int numCameras = 2;
    double aspectRatioScale = 1.0;///(double)numCameras;
    for(unsigned int i=0; i<numCameras;++i)
    {
        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport((i*width)/numCameras,(i*height)/numCameras, width/numCameras, height/numCameras));
        GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
        camera->setDrawBuffer(buffer);
        camera->setReadBuffer(buffer);

        viewer.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::scale(aspectRatioScale,1.0,1.0));
    }
}

void multipleWindowMultipleCameras(osgViewer::Viewer& viewer)
{
    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
    if (!wsi)
    {
        osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        return;
    }

    unsigned int width, height;
    wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

    unsigned int numCameras = 6;
    double aspectRatioScale = (double)numCameras;
    double translate_x = double(numCameras)-1;
    for(unsigned int i=0; i<numCameras;++i, translate_x -= 2.0)
    {
        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
        traits->screenNum = i / 3;
        traits->x = (i*width)/numCameras;
        traits->y = 0;
        traits->width = width/numCameras-1;
        traits->height = height;
        traits->windowDecoration = true;
        traits->doubleBuffer = true;
        traits->sharedContext = 0;

        osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
        if (gc.valid())
        {
            osg::notify(osg::INFO)<<"  GraphicsWindow has been created successfully."<<std::endl;
        }
        else
        {
            osg::notify(osg::NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
        }

        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport(0,0, width/numCameras, height));
        GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
        camera->setDrawBuffer(buffer);
        camera->setReadBuffer(buffer);

        viewer.addSlave(camera.get(), osg::Matrix::scale(aspectRatioScale, 1.0, 1.0)*osg::Matrix::translate(translate_x, 0.0, 0.0), osg::Matrix() );
    }
}

int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    if (argc<2)
    {
        std::cout << argv[0] <<": requires filename argument." << std::endl;
        return 1;
    }

    std::string pathfile;
    osg::ref_ptr<osgGA::AnimationPathManipulator> apm = 0;
    while (arguments.read("-p",pathfile))
    {
        apm = new osgGA::AnimationPathManipulator(pathfile);
        if (!apm.valid() || !(apm->valid()) )
        {
            apm = 0;
        }
    }

    osgViewer::Viewer viewer;

    while (arguments.read("-s")) { viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); }
    while (arguments.read("-g")) { viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext); }
    while (arguments.read("-d")) { viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext); }
    while (arguments.read("-c")) { viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext); }

    bool limitNumberOfFrames = false;
    unsigned int maxFrames = 10;
    while (arguments.read("--run-till-frame-number",maxFrames)) { limitNumberOfFrames = true; }

    // alternative viewer window setups.
    while (arguments.read("-1")) { singleWindowMultipleCameras(viewer); }
    while (arguments.read("-2")) { multipleWindowMultipleCameras(viewer); }

    if (apm.valid()) viewer.setCameraManipulator(apm.get());
    else viewer.setCameraManipulator( new osgGA::TrackballManipulator() );

    std::string configfile;
    while (arguments.read("--config", configfile))
    {
        osg::notify(osg::NOTICE)<<"Trying to read config file "<<configfile<<std::endl;
        osg::ref_ptr<osg::Object> object = osgDB::readObjectFile(configfile);
        osgViewer::View* view = dynamic_cast<osgViewer::View*>(object.get());
        if (view)
        {
            osg::notify(osg::NOTICE)<<"Read config file succesfully"<<std::endl;
        }
        else
        {
            osg::notify(osg::NOTICE)<<"Failed to read config file : "<<configfile<<std::endl;
            return 1;
        }
    }

    while (arguments.read("--write-config", configfile)) { osgDB::writeObjectFile(viewer, configfile); }

#if 0

    ModelHandler* modelHandler = new ModelHandler;
    for(int i=1; i<arguments.argc();++i)
    {
        modelHandler->add(arguments[i]);
    }

    viewer.addEventHandler(modelHandler);

#else

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
    if (!loadedModel)
    {
        std::cout << argv[0] <<": No data loaded." << std::endl;
        return 1;
    }

    viewer.setSceneData(loadedModel.get());
#endif

    viewer.realize();

    unsigned int numFrames = 0;
    while(!viewer.done() && !(limitNumberOfFrames && numFrames>=maxFrames))
    {
        viewer.frame();
        ++numFrames;
    }

    return 0;
}
#else

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

int main( int, char **)
{
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cow.osg");

    for(unsigned int i=0; i<5; ++i)
    {
        osg::notify(osg::NOTICE)<<"New frame *******************************"<<std::endl;

        osgViewer::Viewer viewer;
        viewer.setSceneData(model.get());
        viewer.run();
        osg::notify(osg::NOTICE)<<std::endl<<std::endl;
    }
    return 0;
}

#endif
<commit_msg>Added default file in case no file arguments are provided.  Changed to use  standard ThreadingHandler by default.<commit_after>#if 1

#include <osgDB/ReadFile>
#include <osgDB/WriteFile>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/AnimationPathManipulator>
#include <iostream>

class ModelHandler : public osgGA::GUIEventHandler
{
public:

    ModelHandler():
        _position(0) {}

    typedef std::vector<std::string> Filenames;
    Filenames _filenames;
    unsigned int _position;

    void add(const std::string& filename) { _filenames.push_back(filename); }

    bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
    {
        osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
        if (!viewer) return false;

        if (_filenames.empty()) return false;

        switch(ea.getEventType())
        {
            case(osgGA::GUIEventAdapter::KEYUP):
            {
                if (ea.getKey()=='l')
                {
                    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile( _filenames[_position] );
                    ++_position;
                    if (_position>=_filenames.size()) _position = 0;

                    if (model.valid())
                    {
                        viewer->setSceneData(model.get());
                    }

                    return true;
                }
            }
            default: break;
        }

        return false;
    }

    bool _done;
};

void singleWindowMultipleCameras(osgViewer::Viewer& viewer)
{
    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
    if (!wsi)
    {
        osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        return;
    }

    unsigned int width, height;
    wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

    osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
    traits->x = 0;
    traits->y = 0;
    traits->width = width;
    traits->height = height;
    traits->windowDecoration = true;
    traits->doubleBuffer = true;
    traits->sharedContext = 0;

    osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
    if (gc.valid())
    {
        osg::notify(osg::INFO)<<"  GraphicsWindow has been created successfully."<<std::endl;

        // need to ensure that the window is cleared make sure that the complete window is set the correct colour
        // rather than just the parts of the window that are under the camera's viewports
        gc->setClearColor(osg::Vec4f(0.2f,0.2f,0.6f,1.0f));
        gc->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
    else
    {
        osg::notify(osg::NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
    }

    unsigned int numCameras = 2;
    double aspectRatioScale = 1.0;///(double)numCameras;
    for(unsigned int i=0; i<numCameras;++i)
    {
        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport((i*width)/numCameras,(i*height)/numCameras, width/numCameras, height/numCameras));
        GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
        camera->setDrawBuffer(buffer);
        camera->setReadBuffer(buffer);

        viewer.addSlave(camera.get(), osg::Matrixd(), osg::Matrixd::scale(aspectRatioScale,1.0,1.0));
    }
}

void multipleWindowMultipleCameras(osgViewer::Viewer& viewer, bool multipleScreens)
{
    osg::GraphicsContext::WindowingSystemInterface* wsi = osg::GraphicsContext::getWindowingSystemInterface();
    if (!wsi)
    {
        osg::notify(osg::NOTICE)<<"Error, no WindowSystemInterface available, cannot create windows."<<std::endl;
        return;
    }

    unsigned int width, height;
    wsi->getScreenResolution(osg::GraphicsContext::ScreenIdentifier(0), width, height);

    unsigned int numCameras = 6;
    double aspectRatioScale = (double)numCameras;
    double translate_x = double(numCameras)-1;
    for(unsigned int i=0; i<numCameras;++i, translate_x -= 2.0)
    {
        osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
        traits->screenNum = multipleScreens ? i / 3 : 0;
        traits->x = (i*width)/numCameras;
        traits->y = 0;
        traits->width = width/numCameras-1;
        traits->height = height;
        traits->windowDecoration = true;
        traits->doubleBuffer = true;
        traits->sharedContext = 0;

        osg::ref_ptr<osg::GraphicsContext> gc = osg::GraphicsContext::createGraphicsContext(traits.get());
        if (gc.valid())
        {
            osg::notify(osg::INFO)<<"  GraphicsWindow has been created successfully."<<std::endl;
        }
        else
        {
            osg::notify(osg::NOTICE)<<"  GraphicsWindow has not been created successfully."<<std::endl;
        }

        osg::ref_ptr<osg::Camera> camera = new osg::Camera;
        camera->setGraphicsContext(gc.get());
        camera->setViewport(new osg::Viewport(0,0, width/numCameras, height));
        GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;
        camera->setDrawBuffer(buffer);
        camera->setReadBuffer(buffer);

        viewer.addSlave(camera.get(), osg::Matrix::scale(aspectRatioScale, 1.0, 1.0)*osg::Matrix::translate(translate_x, 0.0, 0.0), osg::Matrix() );
    }
}

int main( int argc, char **argv )
{
    // use an ArgumentParser object to manage the program arguments.
    osg::ArgumentParser arguments(&argc,argv);

    if (argc<2)
    {
        std::cout << argv[0] <<": requires filename argument." << std::endl;
        return 1;
    }

    std::string pathfile;
    osg::ref_ptr<osgGA::AnimationPathManipulator> apm = 0;
    while (arguments.read("-p",pathfile))
    {
        apm = new osgGA::AnimationPathManipulator(pathfile);
        if (!apm.valid() || !(apm->valid()) )
        {
            apm = 0;
        }
    }

    osgViewer::Viewer viewer(arguments);

    while (arguments.read("-s")) { viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded); }
    while (arguments.read("-g")) { viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext); }
    while (arguments.read("-d")) { viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext); }
    while (arguments.read("-c")) { viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext); }

    bool limitNumberOfFrames = false;
    unsigned int maxFrames = 10;
    while (arguments.read("--run-till-frame-number",maxFrames)) { limitNumberOfFrames = true; }

    // alternative viewer window setups.
    while (arguments.read("-1")) { singleWindowMultipleCameras(viewer); }
    while (arguments.read("-2")) { multipleWindowMultipleCameras(viewer, false); }
    while (arguments.read("-3")) { multipleWindowMultipleCameras(viewer, true); }

    if (apm.valid()) viewer.setCameraManipulator(apm.get());
    else viewer.setCameraManipulator( new osgGA::TrackballManipulator() );

    viewer.addEventHandler(new osgViewer::StatsHandler);
    viewer.addEventHandler(new osgViewer::ThreadingHandler);

    std::string configfile;
    while (arguments.read("--config", configfile))
    {
        osg::notify(osg::NOTICE)<<"Trying to read config file "<<configfile<<std::endl;
        osg::ref_ptr<osg::Object> object = osgDB::readObjectFile(configfile);
        osgViewer::View* view = dynamic_cast<osgViewer::View*>(object.get());
        if (view)
        {
            osg::notify(osg::NOTICE)<<"Read config file succesfully"<<std::endl;
        }
        else
        {
            osg::notify(osg::NOTICE)<<"Failed to read config file : "<<configfile<<std::endl;
            return 1;
        }
    }

    while (arguments.read("--write-config", configfile)) { osgDB::writeObjectFile(viewer, configfile); }

#if 0

    ModelHandler* modelHandler = new ModelHandler;
    for(int i=1; i<arguments.argc();++i)
    {
        modelHandler->add(arguments[i]);
    }

    viewer.addEventHandler(modelHandler);

#else

    // load the scene.
    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);

    if (!loadedModel) loadedModel = osgDB::readNodeFile("cow.osg");

    if (!loadedModel)
    {
        std::cout << argv[0] <<": No data loaded." << std::endl;
        return 1;
    }

    viewer.setSceneData(loadedModel.get());
#endif

    viewer.realize();

    unsigned int numFrames = 0;
    while(!viewer.done() && !(limitNumberOfFrames && numFrames>=maxFrames))
    {
        viewer.frame();
        ++numFrames;
    }

    return 0;
}
#else

#include <osgViewer/Viewer>
#include <osgDB/ReadFile>
#include <osgDB/WriteFile>

int main( int, char **)
{
    osg::ref_ptr<osg::Node> model = osgDB::readNodeFile("cow.osg");

    for(unsigned int i=0; i<5; ++i)
    {
        osg::notify(osg::NOTICE)<<"New frame *******************************"<<std::endl;

        osgViewer::Viewer viewer;
        viewer.setSceneData(model.get());
        viewer.run();
        osg::notify(osg::NOTICE)<<std::endl<<std::endl;
    }
    return 0;
}

#endif
<|endoftext|>


<commit_before>#include <string.h>
#include <sstream>
#include "track.h"
#include "user.h"
#include "number.h"
#include "db.h"
#include "art.h"
#include "repl.h"
#include "path.h"

Repl hitsd;

using namespace std;

Track::Track(int id){
    _id = 0;
    _artistId = 0;
    if(id<=0) return;

    DB::Result r = DB::query(
        "SELECT tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date FROM tracks, users "
        "WHERE tracks.id = " + number(id) + " AND tracks.user_id = users.id");
    if(!r.empty()){
        _id = id;
        _title = r[0][0];
        _artistId = number(r[0][1]);
        _artist = r[0][2];
        _visible = r[0][3] == "t";
        _date = r[0][4];
    }
}

User Track::artist() const{
    return User(_artistId, _artist);
}

void Track::setTitle(const string &nTitle){
    if(_title == nTitle) return;
    DB::query("UPDATE tracks SET title = $1 WHERE id = " + number(_id), nTitle);
    _title = nTitle;
}

string Track::url(int id){
    stringstream s;
    s << "/track/" << id;
    return s.str();
}

void Track::setVisible(bool v){
    DB::query("UPDATE tracks SET visible = '" + (string)(v?"t":"f") + "' WHERE id = " + number(_id));
    _visible = v;
}

string Track::url(Format f) const{
    string format = f==Vorbis? "vorbis" : "mp3";
    return (string) "/track/" + number(_id) + "/" + format;
}

Track Track::create(int nArtistId, const string &nTitle){
    Track t;
    DB::Result r = DB::query(
        "INSERT INTO tracks (user_id, title, date) VALUES "
        "("+number(nArtistId)+", $1, 'now') "
        "RETURNING id, date", nTitle);
    if(r.empty()) return t;
    return Track(number(r[0][0]), nTitle, nArtistId, User(nArtistId).name(), false, r[0][1]);
}

void Track::remove(){
    DB::query("DELETE FROM track_categories WHERE track_id = "+ number(_id));
    DB::query("DELETE FROM contest_submissions WHERE track_id = " + number(_id));
    DB::query("DELETE FROM featured_tracks WHERE track_id = " + number(_id));
    DB::query("DELETE FROM votes WHERE track_id = " + number(_id));
    DB::query("DELETE FROM comments WHERE type = 'track' AND ref = " + number(_id));
    DB::query("DELETE FROM favorites WHERE type = 'track' AND ref = " + number(_id));
    DB::query("DELETE FROM tracks WHERE id = " + number(_id));
    _id = 0;
}

void initHitsd(){
    if(!hitsd){
        string path = eqbeatsDir() + "/hitsd.sock";
        hitsd = Repl(path.c_str());
    }
}

int Track::getHits() const{
    initHitsd();
    return number(hitsd.exec("get " + number(_id)));
}
int Track::hit(){
    initHitsd();
    return number(hitsd.exec("increment " + number(_id)));
}

vector<Track> Track::resultToVector(const DB::Result &r){
    vector<Track> tracks(r.size());
    for(unsigned i=0; i<r.size(); i++)
        tracks[i] = Track(number(r[i][0]), r[i][1], number(r[i][2]), r[i][3], r[i][4]=="t", r[i][5]);
    return tracks;
}

vector<Track> Track::select(const char *tables, const string cond, const char *order, bool all, int limit, int offset){
    string q = "SELECT tracks.id, tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date FROM tracks, users";
    if(tables) q += (string) "," + tables;
    q += " WHERE tracks.user_id = users.id";
    if(!all) q += " AND tracks.visible='t'";
    if(!cond.empty()) q += " AND " + cond;
    q += (string) " ORDER BY " + order;
    if(limit) q += " LIMIT " + number(limit);
    if(offset) q += " OFFSET " + number(offset);
    return resultToVector(DB::query(q));
}

vector<Track> listTracks(const char *order, int limit, int offset=0){
    return Track::select(0, "", order, false, limit, offset);
}

vector<Track> Track::latest(int n, int offset){ return listTracks("date DESC", n, offset); }
vector<Track> Track::random(int n){ return listTracks("random()", n); }

vector<Track> Track::featured(int n){
    return Track::select("featured_tracks", "featured_tracks.track_id = tracks.id", "featured_tracks.date DESC", false, n);
}

vector<Track> Track::favorites(int uid){
    return select("favorites",
        "favorites.type = 'track'"
        " AND favorites.ref = tracks.id "
        " AND favorites.user_id = " + number(uid),
        "users.name ASC");
}

#define SEL (string) ("SELECT tracks.id, tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date " \
                            "FROM tracks, users WHERE tracks.user_id = users.id AND tracks.visible = 't' ")

vector<Track> Track::search(const string &q){
    if(q.empty()) return vector<Track>();
    vector<string> p;
    istringstream in(q);
    string buf;
    string sql;
    while(in){
        in >> buf;
        p.push_back("%"+buf+"%");
        sql += " AND (tracks.title ILIKE $" + number(p.size()) + " OR users.name ILIKE $" + number(p.size()) + ")";
    }
    return resultToVector(DB::query(SEL + sql, p));
}

vector<Track> Track::exactSearch(const string &qartist, const string &qtitle){
    if(qtitle.empty()||qartist.empty()) return vector<Track>();
    return resultToVector(DB::query(SEL + "AND users.name = $1 AND tracks.title = $2", qartist, qtitle));
}

vector<Track> Track::byTag(const std::string &tag){
    return resultToVector(DB::query(SEL + "AND $1 = ANY(tracks.tags) ORDER BY tracks.date DESC", tag));
}

int Track::favoritesCount() const{
    DB::Result r = DB::query("SELECT COUNT(*) FROM favorites "
        "WHERE type = 'track' AND ref = " + number(_id));
    return r.empty() ? -1 : number(r[0][0]);
}

void Track::bump(){
    if(_id<=0) return;
    DB::query("UPDATE tracks SET date = 'now' WHERE id = " + number(_id));
}

ExtendedTrack::ExtendedTrack(int id){
    _id = 0;
    _artistId = 0;
    if(id<=0) return;

    DB::Result r = DB::query(
        "SELECT tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date,"
        " tracks.notes, tracks.downloadable, array_to_string(tracks.tags, ',') FROM tracks, users "
        "WHERE tracks.id = " + number(id) + " AND tracks.user_id = users.id");
    if(!r.empty()){
        _id = id;
        _title = r[0][0];
        _artistId = number(r[0][1]);
        _artist = r[0][2];
        _visible = r[0][3] == "t";
        _date = r[0][4];
        // Ext
        _notes = r[0][5];
        _downloadable = r[0][6][0] == 't';
        // Tags
        string tstr = r[0][7];
        string buf;
        for(string::const_iterator i=tstr.begin(); i!=tstr.end(); i++){
            if(*i == ','){
                if(!buf.empty()){
                    _tags.push_back(buf);
                    buf.clear();
                }
            }
            else buf += *i;
        }
        if(!buf.empty()) _tags.push_back(buf); // last tag
    }
}

void ExtendedTrack::setDownloadable(bool d){
    DB::query("UPDATE tracks SET downloadable = '" + (string)(d?"t":"f") + "' WHERE id = " + number(_id));
    _downloadable = d;
}

void ExtendedTrack::setNotes(const string &nNotes){
    DB::query("UPDATE tracks SET notes = $1 WHERE id = " + number(_id), nNotes);
    _notes = nNotes;
}

void ExtendedTrack::setTags(const string &nTags){
    DB::query("UPDATE tracks SET tags = regexp_split_to_array($1, E' *, *') WHERE id = " + number(_id), nTags);
    // Doesn't update _tags!
}
<commit_msg>lowercase tags<commit_after>#include <string.h>
#include <sstream>
#include "track.h"
#include "user.h"
#include "number.h"
#include "db.h"
#include "art.h"
#include "repl.h"
#include "path.h"

Repl hitsd;

using namespace std;

Track::Track(int id){
    _id = 0;
    _artistId = 0;
    if(id<=0) return;

    DB::Result r = DB::query(
        "SELECT tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date FROM tracks, users "
        "WHERE tracks.id = " + number(id) + " AND tracks.user_id = users.id");
    if(!r.empty()){
        _id = id;
        _title = r[0][0];
        _artistId = number(r[0][1]);
        _artist = r[0][2];
        _visible = r[0][3] == "t";
        _date = r[0][4];
    }
}

User Track::artist() const{
    return User(_artistId, _artist);
}

void Track::setTitle(const string &nTitle){
    if(_title == nTitle) return;
    DB::query("UPDATE tracks SET title = $1 WHERE id = " + number(_id), nTitle);
    _title = nTitle;
}

string Track::url(int id){
    stringstream s;
    s << "/track/" << id;
    return s.str();
}

void Track::setVisible(bool v){
    DB::query("UPDATE tracks SET visible = '" + (string)(v?"t":"f") + "' WHERE id = " + number(_id));
    _visible = v;
}

string Track::url(Format f) const{
    string format = f==Vorbis? "vorbis" : "mp3";
    return (string) "/track/" + number(_id) + "/" + format;
}

Track Track::create(int nArtistId, const string &nTitle){
    Track t;
    DB::Result r = DB::query(
        "INSERT INTO tracks (user_id, title, date) VALUES "
        "("+number(nArtistId)+", $1, 'now') "
        "RETURNING id, date", nTitle);
    if(r.empty()) return t;
    return Track(number(r[0][0]), nTitle, nArtistId, User(nArtistId).name(), false, r[0][1]);
}

void Track::remove(){
    DB::query("DELETE FROM track_categories WHERE track_id = "+ number(_id));
    DB::query("DELETE FROM contest_submissions WHERE track_id = " + number(_id));
    DB::query("DELETE FROM featured_tracks WHERE track_id = " + number(_id));
    DB::query("DELETE FROM votes WHERE track_id = " + number(_id));
    DB::query("DELETE FROM comments WHERE type = 'track' AND ref = " + number(_id));
    DB::query("DELETE FROM favorites WHERE type = 'track' AND ref = " + number(_id));
    DB::query("DELETE FROM tracks WHERE id = " + number(_id));
    _id = 0;
}

void initHitsd(){
    if(!hitsd){
        string path = eqbeatsDir() + "/hitsd.sock";
        hitsd = Repl(path.c_str());
    }
}

int Track::getHits() const{
    initHitsd();
    return number(hitsd.exec("get " + number(_id)));
}
int Track::hit(){
    initHitsd();
    return number(hitsd.exec("increment " + number(_id)));
}

vector<Track> Track::resultToVector(const DB::Result &r){
    vector<Track> tracks(r.size());
    for(unsigned i=0; i<r.size(); i++)
        tracks[i] = Track(number(r[i][0]), r[i][1], number(r[i][2]), r[i][3], r[i][4]=="t", r[i][5]);
    return tracks;
}

vector<Track> Track::select(const char *tables, const string cond, const char *order, bool all, int limit, int offset){
    string q = "SELECT tracks.id, tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date FROM tracks, users";
    if(tables) q += (string) "," + tables;
    q += " WHERE tracks.user_id = users.id";
    if(!all) q += " AND tracks.visible='t'";
    if(!cond.empty()) q += " AND " + cond;
    q += (string) " ORDER BY " + order;
    if(limit) q += " LIMIT " + number(limit);
    if(offset) q += " OFFSET " + number(offset);
    return resultToVector(DB::query(q));
}

vector<Track> listTracks(const char *order, int limit, int offset=0){
    return Track::select(0, "", order, false, limit, offset);
}

vector<Track> Track::latest(int n, int offset){ return listTracks("date DESC", n, offset); }
vector<Track> Track::random(int n){ return listTracks("random()", n); }

vector<Track> Track::featured(int n){
    return Track::select("featured_tracks", "featured_tracks.track_id = tracks.id", "featured_tracks.date DESC", false, n);
}

vector<Track> Track::favorites(int uid){
    return select("favorites",
        "favorites.type = 'track'"
        " AND favorites.ref = tracks.id "
        " AND favorites.user_id = " + number(uid),
        "users.name ASC");
}

#define SEL (string) ("SELECT tracks.id, tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date " \
                            "FROM tracks, users WHERE tracks.user_id = users.id AND tracks.visible = 't' ")

vector<Track> Track::search(const string &q){
    if(q.empty()) return vector<Track>();
    vector<string> p;
    istringstream in(q);
    string buf;
    string sql;
    while(in){
        in >> buf;
        p.push_back("%"+buf+"%");
        sql += " AND (tracks.title ILIKE $" + number(p.size()) + " OR users.name ILIKE $" + number(p.size()) + ")";
    }
    return resultToVector(DB::query(SEL + sql, p));
}

vector<Track> Track::exactSearch(const string &qartist, const string &qtitle){
    if(qtitle.empty()||qartist.empty()) return vector<Track>();
    return resultToVector(DB::query(SEL + "AND users.name = $1 AND tracks.title = $2", qartist, qtitle));
}

vector<Track> Track::byTag(const std::string &tag){
    return resultToVector(DB::query(SEL + "AND $1 = ANY(tracks.tags) ORDER BY tracks.date DESC", tag));
}

int Track::favoritesCount() const{
    DB::Result r = DB::query("SELECT COUNT(*) FROM favorites "
        "WHERE type = 'track' AND ref = " + number(_id));
    return r.empty() ? -1 : number(r[0][0]);
}

void Track::bump(){
    if(_id<=0) return;
    DB::query("UPDATE tracks SET date = 'now' WHERE id = " + number(_id));
}

ExtendedTrack::ExtendedTrack(int id){
    _id = 0;
    _artistId = 0;
    if(id<=0) return;

    DB::Result r = DB::query(
        "SELECT tracks.title, tracks.user_id, users.name, tracks.visible, tracks.date,"
        " tracks.notes, tracks.downloadable, array_to_string(tracks.tags, ',') FROM tracks, users "
        "WHERE tracks.id = " + number(id) + " AND tracks.user_id = users.id");
    if(!r.empty()){
        _id = id;
        _title = r[0][0];
        _artistId = number(r[0][1]);
        _artist = r[0][2];
        _visible = r[0][3] == "t";
        _date = r[0][4];
        // Ext
        _notes = r[0][5];
        _downloadable = r[0][6][0] == 't';
        // Tags
        string tstr = r[0][7];
        string buf;
        for(string::const_iterator i=tstr.begin(); i!=tstr.end(); i++){
            if(*i == ','){
                if(!buf.empty()){
                    _tags.push_back(buf);
                    buf.clear();
                }
            }
            else buf += *i;
        }
        if(!buf.empty()) _tags.push_back(buf); // last tag
    }
}

void ExtendedTrack::setDownloadable(bool d){
    DB::query("UPDATE tracks SET downloadable = '" + (string)(d?"t":"f") + "' WHERE id = " + number(_id));
    _downloadable = d;
}

void ExtendedTrack::setNotes(const string &nNotes){
    DB::query("UPDATE tracks SET notes = $1 WHERE id = " + number(_id), nNotes);
    _notes = nNotes;
}

void ExtendedTrack::setTags(const string &nTags){
    DB::query("UPDATE tracks SET tags = regexp_split_to_array(lower($1), E' *, *') WHERE id = " + number(_id), nTags);
    // Doesn't update _tags!
}
<|endoftext|>


<commit_before>#include "LLVM_Headers.h"
#include "LLVM_Output.h"
#include "CodeGen_LLVM.h"
#include "CodeGen_C.h"
#include "CodeGen_Internal.h"

#include <iostream>
#include <fstream>

namespace Halide {

std::unique_ptr<llvm::raw_fd_ostream> make_raw_fd_ostream(const std::string &filename) {
    std::string error_string;
    #if LLVM_VERSION < 35
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), error_string));
    #elif LLVM_VERSION == 35
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), error_string, llvm::sys::fs::F_None));
    #else // llvm 3.6
    std::error_code err;
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), err, llvm::sys::fs::F_None));
    if (err) error_string = err.message();
    #endif
    internal_assert(error_string.empty())
        << "Error opening output " << filename << ": " << error_string << "\n";

    return raw_out;
}

#if LLVM_VERSION < 37
void emit_file_legacy(llvm::Module &module, const std::string &filename, llvm::TargetMachine::CodeGenFileType file_type) {
    Internal::debug(1) << "emit_file_legacy.Compiling to native code...\n";
    Internal::debug(2) << "Target triple: " << module.getTargetTriple() << "\n";

    // Get the target specific parser.
    auto target_machine = Internal::make_target_machine(module);
    internal_assert(target_machine) << "Could not allocate target machine!\n";

    // Build up all of the passes that we want to do to the module.
    llvm::PassManager pass_manager;

    // Add an appropriate TargetLibraryInfo pass for the module's triple.
    pass_manager.add(new llvm::TargetLibraryInfo(llvm::Triple(module.getTargetTriple())));

    #if LLVM_VERSION < 33
    pass_manager.add(new llvm::TargetTransformInfo(target_machine->getScalarTargetTransformInfo(),
                                                   target_machine->getVectorTargetTransformInfo()));
    #else
    target_machine->addAnalysisPasses(pass_manager);
    #endif

    #if LLVM_VERSION < 35
    llvm::DataLayout *layout = new llvm::DataLayout(module.get());
    Internal::debug(2) << "Data layout: " << layout->getStringRepresentation();
    pass_manager.add(layout);
    #endif

    // Make sure things marked as always-inline get inlined
    pass_manager.add(llvm::createAlwaysInlinerPass());

    // Override default to generate verbose assembly.
    target_machine->setAsmVerbosityDefault(true);

    auto raw_out = make_raw_fd_ostream(filename);
    std::unique_ptr<llvm::formatted_raw_ostream> out(new llvm::formatted_raw_ostream(*raw_out));

    // Ask the target to add backend passes as necessary.
    target_machine->addPassesToEmitFile(pass_manager, *out, file_type);

    pass_manager.run(module);
}
#endif

void emit_file(llvm::Module &module, const std::string &filename, llvm::TargetMachine::CodeGenFileType file_type) {
#if LLVM_VERSION < 37
    emit_file_legacy(module, filename, file_type);
#else
    Internal::debug(1) << "emit_file.Compiling to native code...\n";
    Internal::debug(2) << "Target triple: " << module.getTargetTriple() << "\n";

    // Get the target specific parser.
    auto target_machine = Internal::make_target_machine(module);
    internal_assert(target_machine.get()) << "Could not allocate target machine!\n";

    #if LLVM_VERSION == 37
        llvm::DataLayout target_data_layout(*(target_machine->getDataLayout()));
    #else
        llvm::DataLayout target_data_layout(target_machine->createDataLayout());
    #endif
    if (!(target_data_layout == module.getDataLayout())) {
        internal_error << "Warning: module's data layout does not match target machine's\n"
                       << target_data_layout.getStringRepresentation() << "\n"
                       << module.getDataLayout().getStringRepresentation() << "\n";
    }

    auto out = make_raw_fd_ostream(filename);

    // Build up all of the passes that we want to do to the module.
    llvm::legacy::PassManager pass_manager;

    pass_manager.add(new llvm::TargetLibraryInfoWrapperPass(llvm::Triple(module.getTargetTriple())));

    // Make sure things marked as always-inline get inlined
    pass_manager.add(llvm::createAlwaysInlinerPass());

    // Override default to generate verbose assembly.
    target_machine->Options.MCOptions.AsmVerbose = true;

    // Ask the target to add backend passes as necessary.
    target_machine->addPassesToEmitFile(pass_manager, *out, file_type);

    pass_manager.run(module);
#endif
}

std::unique_ptr<llvm::Module> compile_module_to_llvm_module(const Module &module, llvm::LLVMContext &context) {
    return codegen_llvm(module, context);
}

void compile_llvm_module_to_object(llvm::Module &module, const std::string &filename) {
    emit_file(module, filename, llvm::TargetMachine::CGFT_ObjectFile);
}

void compile_llvm_module_to_assembly(llvm::Module &module, const std::string &filename) {
    emit_file(module, filename, llvm::TargetMachine::CGFT_AssemblyFile);
}

void compile_llvm_module_to_llvm_bitcode(llvm::Module &module, const std::string &filename) {
    auto file = make_raw_fd_ostream(filename);
    WriteBitcodeToFile(&module, *file);
}

void compile_llvm_module_to_llvm_assembly(llvm::Module &module, const std::string &filename) {
    auto file = make_raw_fd_ostream(filename);
    module.print(*file, nullptr);
}

}  // namespace Halide
<commit_msg>fix LLVM3.5-specific error<commit_after>#include "LLVM_Headers.h"
#include "LLVM_Output.h"
#include "CodeGen_LLVM.h"
#include "CodeGen_C.h"
#include "CodeGen_Internal.h"

#include <iostream>
#include <fstream>

namespace Halide {

std::unique_ptr<llvm::raw_fd_ostream> make_raw_fd_ostream(const std::string &filename) {
    std::string error_string;
    #if LLVM_VERSION < 35
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), error_string));
    #elif LLVM_VERSION == 35
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), error_string, llvm::sys::fs::F_None));
    #else // llvm 3.6
    std::error_code err;
    std::unique_ptr<llvm::raw_fd_ostream> raw_out(new llvm::raw_fd_ostream(filename.c_str(), err, llvm::sys::fs::F_None));
    if (err) error_string = err.message();
    #endif
    internal_assert(error_string.empty())
        << "Error opening output " << filename << ": " << error_string << "\n";

    return raw_out;
}

#if LLVM_VERSION < 37
void emit_file_legacy(llvm::Module &module, const std::string &filename, llvm::TargetMachine::CodeGenFileType file_type) {
    Internal::debug(1) << "emit_file_legacy.Compiling to native code...\n";
    Internal::debug(2) << "Target triple: " << module.getTargetTriple() << "\n";

    // Get the target specific parser.
    auto target_machine = Internal::make_target_machine(module);
    internal_assert(target_machine.get()) << "Could not allocate target machine!\n";

    // Build up all of the passes that we want to do to the module.
    llvm::PassManager pass_manager;

    // Add an appropriate TargetLibraryInfo pass for the module's triple.
    pass_manager.add(new llvm::TargetLibraryInfo(llvm::Triple(module.getTargetTriple())));

    #if LLVM_VERSION < 33
    pass_manager.add(new llvm::TargetTransformInfo(target_machine->getScalarTargetTransformInfo(),
                                                   target_machine->getVectorTargetTransformInfo()));
    #else
    target_machine->addAnalysisPasses(pass_manager);
    #endif

    #if LLVM_VERSION < 35
    llvm::DataLayout *layout = new llvm::DataLayout(module.get());
    Internal::debug(2) << "Data layout: " << layout->getStringRepresentation();
    pass_manager.add(layout);
    #endif

    // Make sure things marked as always-inline get inlined
    pass_manager.add(llvm::createAlwaysInlinerPass());

    // Override default to generate verbose assembly.
    target_machine->setAsmVerbosityDefault(true);

    auto raw_out = make_raw_fd_ostream(filename);
    std::unique_ptr<llvm::formatted_raw_ostream> out(new llvm::formatted_raw_ostream(*raw_out));

    // Ask the target to add backend passes as necessary.
    target_machine->addPassesToEmitFile(pass_manager, *out, file_type);

    pass_manager.run(module);
}
#endif

void emit_file(llvm::Module &module, const std::string &filename, llvm::TargetMachine::CodeGenFileType file_type) {
#if LLVM_VERSION < 37
    emit_file_legacy(module, filename, file_type);
#else
    Internal::debug(1) << "emit_file.Compiling to native code...\n";
    Internal::debug(2) << "Target triple: " << module.getTargetTriple() << "\n";

    // Get the target specific parser.
    auto target_machine = Internal::make_target_machine(module);
    internal_assert(target_machine.get()) << "Could not allocate target machine!\n";

    #if LLVM_VERSION == 37
        llvm::DataLayout target_data_layout(*(target_machine->getDataLayout()));
    #else
        llvm::DataLayout target_data_layout(target_machine->createDataLayout());
    #endif
    if (!(target_data_layout == module.getDataLayout())) {
        internal_error << "Warning: module's data layout does not match target machine's\n"
                       << target_data_layout.getStringRepresentation() << "\n"
                       << module.getDataLayout().getStringRepresentation() << "\n";
    }

    auto out = make_raw_fd_ostream(filename);

    // Build up all of the passes that we want to do to the module.
    llvm::legacy::PassManager pass_manager;

    pass_manager.add(new llvm::TargetLibraryInfoWrapperPass(llvm::Triple(module.getTargetTriple())));

    // Make sure things marked as always-inline get inlined
    pass_manager.add(llvm::createAlwaysInlinerPass());

    // Override default to generate verbose assembly.
    target_machine->Options.MCOptions.AsmVerbose = true;

    // Ask the target to add backend passes as necessary.
    target_machine->addPassesToEmitFile(pass_manager, *out, file_type);

    pass_manager.run(module);
#endif
}

std::unique_ptr<llvm::Module> compile_module_to_llvm_module(const Module &module, llvm::LLVMContext &context) {
    return codegen_llvm(module, context);
}

void compile_llvm_module_to_object(llvm::Module &module, const std::string &filename) {
    emit_file(module, filename, llvm::TargetMachine::CGFT_ObjectFile);
}

void compile_llvm_module_to_assembly(llvm::Module &module, const std::string &filename) {
    emit_file(module, filename, llvm::TargetMachine::CGFT_AssemblyFile);
}

void compile_llvm_module_to_llvm_bitcode(llvm::Module &module, const std::string &filename) {
    auto file = make_raw_fd_ostream(filename);
    WriteBitcodeToFile(&module, *file);
}

void compile_llvm_module_to_llvm_assembly(llvm::Module &module, const std::string &filename) {
    auto file = make_raw_fd_ostream(filename);
    module.print(*file, nullptr);
}

}  // namespace Halide
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexProgress.cxx
 **  Lexer for Progress 4GL.
 ** Based on LexCPP.cxx of Neil Hodgson <neilh@scintilla.org>
  **/
// Copyright 2006-2007 by Yuval Papish <Yuval@YuvCom.com>
// The License.txt file describes the conditions under which this software may be distributed.

/** TODO:
WebSpeed support in html lexer
Support "end triggers" expression of the triggers phrase
change lmPS to lmProgress
Support more than 6 comments levels
**/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static inline bool IsAWordChar(int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsAWordStart(int ch) {
	return (ch < 0x80) && (isalpha(ch) || ch == '_');
}

enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0

static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

    WordList &keywords1 = *keywordlists[0];
    WordList &keywords2 = *keywordlists[1];
    WordList &keywords3 = *keywordlists[2];
    //WordList &keywords4 = *keywordlists[3];
    //WordList &keywords5 = *keywordlists[4];

	int visibleChars = 0;
	int mask;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			visibleChars = 0;
		}

		// Handle line continuation generically.
		if (sc.ch == '~') {
			// Skip whitespace between ~ and EOL
	/*		do {
				sc.Forward();
			} */
			while ((sc.chNext == ' ' || sc.chNext == '\t') ) {
				sc.Forward();
				sc.More();
			}
			if (sc.chNext == '\n' || sc.chNext == '\r') {
				sc.Forward();
				if (sc.ch == '\r' && sc.chNext == '\n') {
					sc.Forward();
				}
				sc.Forward();
				continue;
			}
		}
		// Determine if a new state should be terminated.
		mask = sc.state & 0x10;
		switch (sc.state & 0xf) {
			case SCE_4GL_OPERATOR:
				sc.SetState(SCE_4GL_DEFAULT | mask);
				break;
			case SCE_4GL_NUMBER:
				if (!(IsADigit(sc.ch))) {
					sc.SetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_IDENTIFIER:
				if (!IsAWordChar(sc.ch) && sc.ch != '-') {
					char s[1000];
					sc.GetCurrentLowered(s, sizeof(s));
					if (((sc.state & 0x10) == 0) && keywords2.InList(s) || keywords3.InList(s)) {
						sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart);
					}
					else if (keywords1.InList(s)) {
						if ((s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !isalnum(s[3]) && s[3] != '-') ||
							(s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !isalnum(s[7]))) {
							sc.ChangeState(SCE_4GL_END | ResetSentenceStart);
						}
						else if	((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||
								 (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {
							sc.ChangeState(SCE_4GL_WORD & SetSentenceStart);
						}
						else {
							sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);
						}
					}
					sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));
				}
				break;
			case SCE_4GL_PREPROCESSOR:
				if (sc.atLineStart) {
					sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart);
				} else if (sc.ch == '*' && sc.chNext == '/') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_STRING:
				if (sc.ch == '\"') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_CHARACTER:
				if (sc.ch == '\'') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			default:
				if ((sc.state & 0xf) >= SCE_4GL_COMMENT1) {
					if (sc.ch == '*' && sc.chNext == '/') {
						sc.Forward();
						if ((sc.state & 0xf) == SCE_4GL_COMMENT1) {
							sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
						}
						else
							sc.SetState((sc.state & 0x1f) - 1);
					} else if (sc.ch == '/' && sc.chNext == '*') {
						sc.Forward();
						sc.SetState((sc.state & 0x1f) + 1);
					}
				}
		}

		// Determine if a new state should be entered.
		mask = sc.state & 0x10;
		if ((sc.state & 0xf) == SCE_4GL_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_4GL_NUMBER | ResetSentenceStart);
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				sc.SetState(SCE_4GL_IDENTIFIER | mask);
			} else if (sc.ch == '/' && sc.chNext == '*') {
				sc.SetState(SCE_4GL_COMMENT1 | mask);
				sc.Forward();
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_4GL_STRING | ResetSentenceStart);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_4GL_CHARACTER | ResetSentenceStart);
			} else if (sc.ch == '&' && visibleChars == 0 && ((sc.state & 0x10) == 0)) {
				sc.SetState(SCE_4GL_PREPROCESSOR | ResetSentenceStart);
				// Skip whitespace between & and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
			// Handle syntactical line termination
			} else if ((sc.ch == '.' || sc.ch == ':' || sc.ch == '}') && (sc.chNext == ' ' || sc.chNext == '\t' || sc.chNext == '\n' || sc.chNext == '\r')) {
				sc.SetState(sc.state & SetSentenceStart);
			} else if (isoperator(static_cast<char>(sc.ch))) {
				if (sc.ch == ':')
					sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);
				else
					sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);
			}
		}

		if (!IsASpace(sc.ch)) {
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return (style & 0xf) >= SCE_4GL_COMMENT1 ;
}

// Store both the current line's fold level and the next lines in the
// level store to make it easy to pick up with each increment
// and to make it possible to fiddle the current level for "} else {".
static void FoldNoBox4glDoc(unsigned int startPos, int length, int initStyle,
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelCurrent = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
	int levelMinCurrent = levelCurrent;
	int levelNext = levelCurrent;
	char chNext = static_cast<char>(tolower(styler[startPos]));
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelNext++;
			} else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelNext--;
			}
		}
		else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {
			levelNext++;
		}
		else if ((style & 0xf) == SCE_4GL_END  && (ch == 'e' || ch == 'f')) {
			levelNext--;
		}
		if (atEOL) {
			int levelUse = levelCurrent;
			if (foldAtElse) {
				levelUse = levelMinCurrent;
			}
			int lev = levelUse | levelNext << 16;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if (levelUse < levelNext)
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelCurrent = levelNext;
			levelMinCurrent = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
}

static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                       Accessor &styler) {
	FoldNoBox4glDoc(startPos, length, initStyle, styler);
}

static const char * const FglWordLists[] = {
            "Primary keywords and identifiers",
            "Secondary keywords and identifiers",
            "Documentation comment keywords",
            "Unused",
            "Global classes and typedefs",
            0,
        };

LexerModule lmProgress(SCLEX_PS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);
<commit_msg>Update from Yuval Papish in Feature Request #2023217 Improved handling of the ~ sign. It recognizes special character handling using ~, e.g.: ~" Also a better support for line continuation.<commit_after>// Scintilla source code edit control
/** @file LexProgress.cxx
 **  Lexer for Progress 4GL.
 ** Based on LexCPP.cxx of Neil Hodgson <neilh@scintilla.org>
  **/
// Copyright 2006-2007 by Yuval Papish <Yuval@YuvCom.com>
// The License.txt file describes the conditions under which this software may be distributed.

/** TODO:
WebSpeed support in html lexer
Support "end triggers" expression of the triggers phrase
change lmPS to lmProgress
Support more than 6 comments levels
**/
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

#ifdef SCI_NAMESPACE
using namespace Scintilla;
#endif

static inline bool IsAWordChar(int ch) {
	return (ch < 0x80) && (isalnum(ch) || ch == '_');
}

static inline bool IsAWordStart(int ch) {
	return (ch < 0x80) && (isalpha(ch) || ch == '_');
}

enum SentenceStart { SetSentenceStart = 0xf, ResetSentenceStart = 0x10}; // true -> bit = 0

static void Colourise4glDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
                            Accessor &styler) {

    WordList &keywords1 = *keywordlists[0];
    WordList &keywords2 = *keywordlists[1];
    WordList &keywords3 = *keywordlists[2];
    //WordList &keywords4 = *keywordlists[3];
    //WordList &keywords5 = *keywordlists[4];

	int visibleChars = 0;
	int mask;

	StyleContext sc(startPos, length, initStyle, styler);

	for (; sc.More(); sc.Forward()) {

		if (sc.atLineStart) {
			// Reset states to begining of colourise so no surprises
			// if different sets of lines lexed.
			visibleChars = 0;
		}

		// Handle line continuation generically.
		if (sc.ch == '~') {
			if (sc.chNext > ' ') {
				// skip special char after ~
				sc.Forward();
				continue;
			}
			else {
				// Skip whitespace between ~ and EOL
				while (sc.More() && (sc.chNext == ' ' || sc.chNext == '\t') ) {
					sc.Forward();
				}
				if (sc.chNext == '\n' || sc.chNext == '\r') {
					sc.Forward();
					if (sc.ch == '\r' && sc.chNext == '\n') {
						sc.Forward();
					}
					sc.Forward();
					continue;
				}
			}
		}
		// Determine if a new state should be terminated.
		mask = sc.state & 0x10;
		switch (sc.state & 0xf) {
			case SCE_4GL_OPERATOR:
				sc.SetState(SCE_4GL_DEFAULT | mask);
				break;
			case SCE_4GL_NUMBER:
				if (!(IsADigit(sc.ch))) {
					sc.SetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_IDENTIFIER:
				if (!IsAWordChar(sc.ch) && sc.ch != '-') {
					char s[1000];
					sc.GetCurrentLowered(s, sizeof(s));
					if (((sc.state & 0x10) == 0) && keywords2.InList(s) || keywords3.InList(s)) {
						sc.ChangeState(SCE_4GL_BLOCK | ResetSentenceStart);
					}
					else if (keywords1.InList(s)) {
						if ((s[0] == 'e' && s[1] =='n' && s[2] == 'd' && !isalnum(s[3]) && s[3] != '-') ||
							(s[0] == 'f' && s[1] =='o' && s[2] == 'r' && s[3] == 'w' && s[4] =='a' && s[5] == 'r' && s[6] == 'd'&& !isalnum(s[7]))) {
							sc.ChangeState(SCE_4GL_END | ResetSentenceStart);
						}
						else if	((s[0] == 'e' && s[1] =='l' && s[2] == 's' && s[3] == 'e') ||
								 (s[0] == 't' && s[1] =='h' && s[2] == 'e' && s[3] == 'n')) {
							sc.ChangeState(SCE_4GL_WORD & SetSentenceStart);
						}
						else {
							sc.ChangeState(SCE_4GL_WORD | ResetSentenceStart);
						}
					}
					sc.SetState(SCE_4GL_DEFAULT | (sc.state & 0x10));
				}
				break;
			case SCE_4GL_PREPROCESSOR:
				if (sc.atLineStart) {
					sc.SetState(SCE_4GL_DEFAULT & SetSentenceStart);
				} else if (sc.ch == '*' && sc.chNext == '/') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_STRING:
				if (sc.ch == '\"') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			case SCE_4GL_CHARACTER:
				if (sc.ch == '\'') {
					sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
				}
				break;
			default:
				if ((sc.state & 0xf) >= SCE_4GL_COMMENT1) {
					if (sc.ch == '*' && sc.chNext == '/') {
						sc.Forward();
						if ((sc.state & 0xf) == SCE_4GL_COMMENT1) {
							sc.ForwardSetState(SCE_4GL_DEFAULT | mask);
						}
						else
							sc.SetState((sc.state & 0x1f) - 1);
					} else if (sc.ch == '/' && sc.chNext == '*') {
						sc.Forward();
						sc.SetState((sc.state & 0x1f) + 1);
					}
				}
		}

		// Determine if a new state should be entered.
		mask = sc.state & 0x10;
		if ((sc.state & 0xf) == SCE_4GL_DEFAULT) {
			if (IsADigit(sc.ch) || (sc.ch == '.' && IsADigit(sc.chNext))) {
				sc.SetState(SCE_4GL_NUMBER | ResetSentenceStart);
			} else if (IsAWordStart(sc.ch) || (sc.ch == '@')) {
				sc.SetState(SCE_4GL_IDENTIFIER | mask);
			} else if (sc.ch == '/' && sc.chNext == '*') {
				sc.SetState(SCE_4GL_COMMENT1 | mask);
				sc.Forward();
			} else if (sc.ch == '\"') {
				sc.SetState(SCE_4GL_STRING | ResetSentenceStart);
			} else if (sc.ch == '\'') {
				sc.SetState(SCE_4GL_CHARACTER | ResetSentenceStart);
			} else if (sc.ch == '&' && visibleChars == 0 && ((sc.state & 0x10) == 0)) {
				sc.SetState(SCE_4GL_PREPROCESSOR | ResetSentenceStart);
				// Skip whitespace between & and preprocessor word
				do {
					sc.Forward();
				} while ((sc.ch == ' ' || sc.ch == '\t') && sc.More());
			// Handle syntactical line termination
			} else if ((sc.ch == '.' || sc.ch == ':' || sc.ch == '}') && (sc.chNext == ' ' || sc.chNext == '\t' || sc.chNext == '\n' || sc.chNext == '\r')) {
				sc.SetState(sc.state & SetSentenceStart);
			} else if (isoperator(static_cast<char>(sc.ch))) {
				if (sc.ch == ':')
					sc.SetState(SCE_4GL_OPERATOR & SetSentenceStart);
				else
					sc.SetState(SCE_4GL_OPERATOR | ResetSentenceStart);
			}
		}

		if (!IsASpace(sc.ch)) {
			visibleChars++;
		}
	}
	sc.Complete();
}

static bool IsStreamCommentStyle(int style) {
	return (style & 0xf) >= SCE_4GL_COMMENT1 ;
}

// Store both the current line's fold level and the next lines in the
// level store to make it easy to pick up with each increment
// and to make it possible to fiddle the current level for "} else {".
static void FoldNoBox4glDoc(unsigned int startPos, int length, int initStyle,
                            Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	bool foldAtElse = styler.GetPropertyInt("fold.at.else", 0) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelCurrent = SC_FOLDLEVELBASE;
	if (lineCurrent > 0)
		levelCurrent = styler.LevelAt(lineCurrent-1) >> 16;
	int levelMinCurrent = levelCurrent;
	int levelNext = levelCurrent;
	char chNext = static_cast<char>(tolower(styler[startPos]));
	int styleNext = styler.StyleAt(startPos);
	int style = initStyle;
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = static_cast<char>(tolower(styler.SafeGetCharAt(i + 1)));
		int stylePrev = style;
		style = styleNext;
		styleNext = styler.StyleAt(i + 1);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment && IsStreamCommentStyle(style)) {
			if (!IsStreamCommentStyle(stylePrev)) {
				levelNext++;
			} else if (!IsStreamCommentStyle(styleNext)) { // && !atEOL) {
				// Comments don't end at end of line and the next character may be unstyled.
				levelNext--;
			}
		}
		else if ((style & 0xf) == SCE_4GL_BLOCK && !isalnum(chNext)) {
			levelNext++;
		}
		else if ((style & 0xf) == SCE_4GL_END  && (ch == 'e' || ch == 'f')) {
			levelNext--;
		}
		if (atEOL) {
			int levelUse = levelCurrent;
			if (foldAtElse) {
				levelUse = levelMinCurrent;
			}
			int lev = levelUse | levelNext << 16;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if (levelUse < levelNext)
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelCurrent = levelNext;
			levelMinCurrent = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
}

static void Fold4glDoc(unsigned int startPos, int length, int initStyle, WordList *[],
                       Accessor &styler) {
	FoldNoBox4glDoc(startPos, length, initStyle, styler);
}

static const char * const FglWordLists[] = {
            "Primary keywords and identifiers",
            "Secondary keywords and identifiers",
            "Documentation comment keywords",
            "Unused",
            "Global classes and typedefs",
            0,
        };

LexerModule lmProgress(SCLEX_PS, Colourise4glDoc, "progress", Fold4glDoc, FglWordLists);

<|endoftext|>


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

#include <iterator>
#include <iostream>

namespace libwallet {

// Serialization stuff:
constexpr uint32_t old_serial_magic = 0x3eab61c3; // From the watcher
constexpr uint32_t serial_magic = 0xfecdb760;
constexpr uint8_t serial_tx = 0x42;

BC_API tx_db::~tx_db()
{
}

BC_API tx_db::tx_db(add_handler&& on_add, height_handler&& on_height)
  : on_add_(std::move(on_add)),
    on_height_(std::move(on_height))
{
}

size_t tx_db::last_height()
{
    std::lock_guard<std::mutex> lock(mutex_);

    return last_height_;
}

bool tx_db::has_tx(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    return rows_.find(tx_hash) != rows_.end();
}

bc::transaction_type tx_db::get_tx(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return bc::transaction_type();
    return i->second.tx;
}

size_t tx_db::get_tx_height(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return 0;
    if (i->second.state != tx_state::confirmed)
        return 0;
    return i->second.block_height;
}

bc::output_info_list tx_db::get_utxos(const bc::payment_address& address)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // This is an O(n^2) algorithm!
    bc::output_info_list out;
    for (auto& row: rows_)
    {
        // TODO: Return all outputs, and let downstream filter confirmations
        if (row.second.state != tx_state::confirmed)
            continue;

        // Check each output:
        for (uint32_t i = 0; i < row.second.tx.outputs.size(); ++i)
        {
            auto& output = row.second.tx.outputs[i];
            bc::output_point point = {row.first, i};
            bc::payment_address to_address;
            if (bc::extract(to_address, output.script) &&
                address == to_address && is_unspent(point))
            {
                bc::output_info_type info = {point, output.value};
                out.push_back(info);
            }
        }
    }
    return out;
}

size_t tx_db::count_unconfirmed()
{
    std::lock_guard<std::mutex> lock(mutex_);

    size_t out = 0;
    for (auto row: rows_)
        if (row.second.state == tx_state::unconfirmed)
            ++out;
    return out;
}

void tx_db::send(const bc::transaction_type& tx)
{
    insert(tx, tx_state::unsent);
}

bc::data_chunk tx_db::serialize()
{
    std::lock_guard<std::mutex> lock(mutex_);

    std::basic_ostringstream<uint8_t> stream;
    auto serial = bc::make_serializer(std::ostreambuf_iterator<uint8_t>(stream));

    // Magic version bytes:
    serial.write_4_bytes(serial_magic);

    // Last block height:
    serial.write_8_bytes(last_height_);

    // Tx table:
    for (const auto& row: rows_)
    {
        serial.write_byte(serial_tx);
        serial.write_hash(row.first);
        serial.set_iterator(satoshi_save(row.second.tx, serial.iterator()));
        serial.write_byte(static_cast<uint8_t>(row.second.state));
        serial.write_8_bytes(row.second.block_height);
        serial.write_byte(row.second.need_check);
    }

    // The copy is not very elegant:
    auto str = stream.str();
    return bc::data_chunk(str.begin(), str.end());
}

bool tx_db::load(const bc::data_chunk& data)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto serial = bc::make_deserializer(data.begin(), data.end());
    size_t last_height;
    std::map<bc::hash_digest, tx_row> rows;

    try
    {
        // Header bytes:
        auto magic = serial.read_4_bytes();
        if (old_serial_magic == magic)
            return true;
        if (serial_magic != magic)
            return false;

        // Last block height:
        last_height = serial.read_8_bytes();

        while (serial.iterator() != data.end())
        {
            if (serial.read_byte() != serial_tx)
                return false;

            bc::hash_digest hash = serial.read_hash();
            tx_row row;
            bc::satoshi_load(serial.iterator(), data.end(), row.tx);
            auto step = serial.iterator() + satoshi_raw_size(row.tx);
            serial.set_iterator(step);
            row.state = static_cast<tx_state>(serial.read_byte());
            row.block_height = serial.read_8_bytes();
            row.need_check = serial.read_byte();
            rows[hash] = std::move(row);
        }
    }
    catch (bc::end_of_stream)
    {
        return false;
    }
    last_height_ = last_height;
    rows_ = rows;
    return true;
}

void tx_db::dump()
{
    std::lock_guard<std::mutex> lock(mutex_);

    std::cout << "height: " << last_height_ << std::endl;
    for (const auto& row: rows_)
    {
        std::cout << "================" << std::endl;
        std::cout << "hash: " << bc::encode_hex(row.first) << std::endl;
        std::string state;
        switch (row.second.state)
        {
        case tx_state::unsent:
            std::cout << "state: unsent" << std::endl;
            break;
        case tx_state::unconfirmed:
            std::cout << "state: unconfirmed" << std::endl;
            break;
        case tx_state::confirmed:
            std::cout << "state: confirmed" << std::endl;
            std::cout << "height: " << row.second.block_height << std::endl;
            if (row.second.need_check)
                std::cout << "needs check." << std::endl;
            break;
        }
    }
}

void tx_db::at_height(size_t height)
{
    std::lock_guard<std::mutex> lock(mutex_);

    last_height_ = height;
    on_height_(last_height_);

    // Check for blockchain forks:
    check_fork(height);
}

bc::hash_digest tx_db::insert(const bc::transaction_type& tx, tx_state state)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // Calculate the hash:
    bc::data_chunk data(satoshi_raw_size(tx));
    auto it = satoshi_save(tx, data.begin());
    BITCOIN_ASSERT(it == data.end());
    bc::hash_digest tx_hash = bc::bitcoin_hash(data);

    // Do not stomp existing tx's:
    if (rows_.find(tx_hash) == rows_.end()) {
        rows_[tx_hash] = tx_row{tx, state, 0, false};
        on_add_(tx);
    }

    return tx_hash;
}

void tx_db::confirmed(bc::hash_digest tx_hash, size_t block_height)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    BITCOIN_ASSERT(i != rows_.end());
    auto& row = i->second;

    // If the transaction was already confirmed in another block,
    // that means the chain has forked:
    if (row.state == tx_state::confirmed && row.block_height != block_height)
    {
        //on_fork_();
        check_fork(row.block_height);
    }

    row.state = tx_state::confirmed;
    row.block_height = block_height;
}

void tx_db::unconfirmed(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return;
    auto row = i->second;

    if (row.state == tx_state::confirmed)
    {
        //on_fork_();
        check_fork(row.block_height);
    }

    row.need_check = true;
}

void tx_db::forget(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    rows_.erase(tx_hash);
}

void tx_db::foreach_unsent(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::unsent)
            f(row.first);
}

void tx_db::foreach_unconfirmed(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::unconfirmed)
            f(row.first);
}

void tx_db::foreach_forked(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed && row.second.need_check)
            f(row.first);
}

/**
 * It is possible that the blockchain has forked. Therefore, mark all
 * transactions just below the given height as needing to be checked.
 */
void tx_db::check_fork(size_t height)
{
    // Find the height of next-lower block that has transactions in it:
    size_t prev_height = 0;
    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed &&
            row.second.block_height < height &&
            prev_height < row.second.block_height)
            prev_height = row.second.block_height;

    // Mark all transactions at that level as needing checked:
    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed &&
            row.second.block_height == prev_height)
            row.second.need_check = true;
}

/**
 * Returns true if no other transaction in the database references this
 * output.
 */
bool tx_db::is_unspent(bc::output_point point)
{
    for (auto& row: rows_)
        for (auto& input: row.second.tx.inputs)
            if (point == input.previous_output)
                return false;
    return true;
}

} // libwallet

<commit_msg>Release mutexes before calling callbacks<commit_after>/*
 * Copyright (c) 2011-2014 libbitcoin developers (see AUTHORS)
 *
 * This file is part of libbitcoin-watcher.
 *
 * libbitcoin-watcher is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
#include <bitcoin/watcher/tx_db.hpp>

#include <iterator>
#include <iostream>

namespace libwallet {

// Serialization stuff:
constexpr uint32_t old_serial_magic = 0x3eab61c3; // From the watcher
constexpr uint32_t serial_magic = 0xfecdb760;
constexpr uint8_t serial_tx = 0x42;

BC_API tx_db::~tx_db()
{
}

BC_API tx_db::tx_db(add_handler&& on_add, height_handler&& on_height)
  : on_add_(std::move(on_add)),
    on_height_(std::move(on_height))
{
}

size_t tx_db::last_height()
{
    std::lock_guard<std::mutex> lock(mutex_);

    return last_height_;
}

bool tx_db::has_tx(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    return rows_.find(tx_hash) != rows_.end();
}

bc::transaction_type tx_db::get_tx(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return bc::transaction_type();
    return i->second.tx;
}

size_t tx_db::get_tx_height(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return 0;
    if (i->second.state != tx_state::confirmed)
        return 0;
    return i->second.block_height;
}

bc::output_info_list tx_db::get_utxos(const bc::payment_address& address)
{
    std::lock_guard<std::mutex> lock(mutex_);

    // This is an O(n^2) algorithm!
    bc::output_info_list out;
    for (auto& row: rows_)
    {
        // TODO: Return all outputs, and let downstream filter confirmations
        if (row.second.state != tx_state::confirmed)
            continue;

        // Check each output:
        for (uint32_t i = 0; i < row.second.tx.outputs.size(); ++i)
        {
            auto& output = row.second.tx.outputs[i];
            bc::output_point point = {row.first, i};
            bc::payment_address to_address;
            if (bc::extract(to_address, output.script) &&
                address == to_address && is_unspent(point))
            {
                bc::output_info_type info = {point, output.value};
                out.push_back(info);
            }
        }
    }
    return out;
}

size_t tx_db::count_unconfirmed()
{
    std::lock_guard<std::mutex> lock(mutex_);

    size_t out = 0;
    for (auto row: rows_)
        if (row.second.state == tx_state::unconfirmed)
            ++out;
    return out;
}

void tx_db::send(const bc::transaction_type& tx)
{
    insert(tx, tx_state::unsent);
}

bc::data_chunk tx_db::serialize()
{
    std::lock_guard<std::mutex> lock(mutex_);

    std::basic_ostringstream<uint8_t> stream;
    auto serial = bc::make_serializer(std::ostreambuf_iterator<uint8_t>(stream));

    // Magic version bytes:
    serial.write_4_bytes(serial_magic);

    // Last block height:
    serial.write_8_bytes(last_height_);

    // Tx table:
    for (const auto& row: rows_)
    {
        serial.write_byte(serial_tx);
        serial.write_hash(row.first);
        serial.set_iterator(satoshi_save(row.second.tx, serial.iterator()));
        serial.write_byte(static_cast<uint8_t>(row.second.state));
        serial.write_8_bytes(row.second.block_height);
        serial.write_byte(row.second.need_check);
    }

    // The copy is not very elegant:
    auto str = stream.str();
    return bc::data_chunk(str.begin(), str.end());
}

bool tx_db::load(const bc::data_chunk& data)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto serial = bc::make_deserializer(data.begin(), data.end());
    size_t last_height;
    std::map<bc::hash_digest, tx_row> rows;

    try
    {
        // Header bytes:
        auto magic = serial.read_4_bytes();
        if (old_serial_magic == magic)
            return true;
        if (serial_magic != magic)
            return false;

        // Last block height:
        last_height = serial.read_8_bytes();

        while (serial.iterator() != data.end())
        {
            if (serial.read_byte() != serial_tx)
                return false;

            bc::hash_digest hash = serial.read_hash();
            tx_row row;
            bc::satoshi_load(serial.iterator(), data.end(), row.tx);
            auto step = serial.iterator() + satoshi_raw_size(row.tx);
            serial.set_iterator(step);
            row.state = static_cast<tx_state>(serial.read_byte());
            row.block_height = serial.read_8_bytes();
            row.need_check = serial.read_byte();
            rows[hash] = std::move(row);
        }
    }
    catch (bc::end_of_stream)
    {
        return false;
    }
    last_height_ = last_height;
    rows_ = rows;
    return true;
}

void tx_db::dump()
{
    std::lock_guard<std::mutex> lock(mutex_);

    std::cout << "height: " << last_height_ << std::endl;
    for (const auto& row: rows_)
    {
        std::cout << "================" << std::endl;
        std::cout << "hash: " << bc::encode_hex(row.first) << std::endl;
        std::string state;
        switch (row.second.state)
        {
        case tx_state::unsent:
            std::cout << "state: unsent" << std::endl;
            break;
        case tx_state::unconfirmed:
            std::cout << "state: unconfirmed" << std::endl;
            break;
        case tx_state::confirmed:
            std::cout << "state: confirmed" << std::endl;
            std::cout << "height: " << row.second.block_height << std::endl;
            if (row.second.need_check)
                std::cout << "needs check." << std::endl;
            break;
        }
    }
}

void tx_db::at_height(size_t height)
{
    {
        std::lock_guard<std::mutex> lock(mutex_);
        last_height_ = height;

        // Check for blockchain forks:
        check_fork(height);
    }
    on_height_(last_height_);
}

bc::hash_digest tx_db::insert(const bc::transaction_type& tx, tx_state state)
{
    // Calculate the hash:
    bc::data_chunk data(satoshi_raw_size(tx));
    auto it = satoshi_save(tx, data.begin());
    BITCOIN_ASSERT(it == data.end());
    bc::hash_digest tx_hash = bc::bitcoin_hash(data);

    bool need_callback = false;
    {
        std::lock_guard<std::mutex> lock(mutex_);

        // Do not stomp existing tx's:
        if (rows_.find(tx_hash) == rows_.end()) {
            rows_[tx_hash] = tx_row{tx, state, 0, false};
            need_callback = true;
        }
    }
    if (need_callback)
        on_add_(tx);

    return tx_hash;
}

void tx_db::confirmed(bc::hash_digest tx_hash, size_t block_height)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    BITCOIN_ASSERT(i != rows_.end());
    auto& row = i->second;

    // If the transaction was already confirmed in another block,
    // that means the chain has forked:
    if (row.state == tx_state::confirmed && row.block_height != block_height)
    {
        //on_fork_();
        check_fork(row.block_height);
    }

    row.state = tx_state::confirmed;
    row.block_height = block_height;
}

void tx_db::unconfirmed(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    auto i = rows_.find(tx_hash);
    if (i == rows_.end())
        return;
    auto row = i->second;

    if (row.state == tx_state::confirmed)
    {
        //on_fork_();
        check_fork(row.block_height);
    }

    row.need_check = true;
}

void tx_db::forget(bc::hash_digest tx_hash)
{
    std::lock_guard<std::mutex> lock(mutex_);

    rows_.erase(tx_hash);
}

void tx_db::foreach_unsent(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::unsent)
            f(row.first);
}

void tx_db::foreach_unconfirmed(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::unconfirmed)
            f(row.first);
}

void tx_db::foreach_forked(hash_fn&& f)
{
    std::lock_guard<std::mutex> lock(mutex_);

    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed && row.second.need_check)
            f(row.first);
}

/**
 * It is possible that the blockchain has forked. Therefore, mark all
 * transactions just below the given height as needing to be checked.
 */
void tx_db::check_fork(size_t height)
{
    // Find the height of next-lower block that has transactions in it:
    size_t prev_height = 0;
    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed &&
            row.second.block_height < height &&
            prev_height < row.second.block_height)
            prev_height = row.second.block_height;

    // Mark all transactions at that level as needing checked:
    for (auto row: rows_)
        if (row.second.state == tx_state::confirmed &&
            row.second.block_height == prev_height)
            row.second.need_check = true;
}

/**
 * Returns true if no other transaction in the database references this
 * output.
 */
bool tx_db::is_unspent(bc::output_point point)
{
    for (auto& row: rows_)
        for (auto& input: row.second.tx.inputs)
            if (point == input.previous_output)
                return false;
    return true;
}

} // libwallet

<|endoftext|>