<commit_before>#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>

#include <osgTerrain/Locator>

#include "ESRIType.h"

#include "ESRIShape.h"
#include "ESRIShapeParser.h"

#include "XBaseParser.h"

class ESRIShapeReaderWriter : public osgDB::ReaderWriter
{
    public:
        ESRIShapeReaderWriter() {}

        virtual const char* className() { return "ESRI Shape ReaderWriter"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"shp");
        }

        virtual ReadResult readObject(const std::string& fileName, const Options* opt) const
        { return readNode(fileName,opt); }

        virtual ReadResult readNode(const std::string& file, const Options* options) const
        {
            std::string ext = osgDB::getFileExtension(file);
            if (!acceptsExtension(ext))
                return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile(file, options);
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            bool useDouble = false;
            if (options && options->getOptionString().find("double")!=std::string::npos)
            {
                useDouble = true;
            }

            ESRIShape::ESRIShapeParser sp(fileName, useDouble);

            std::string xbaseFileName(osgDB::getNameLessExtension(fileName) + ".dbf");
            ESRIShape::XBaseParser xbp(xbaseFileName);

            if (sp.getGeode() && (xbp.getAttributeList().empty() == false))
            {
                if (sp.getGeode()->getNumDrawables() != xbp.getAttributeList().size())
                {
                    osg::notify(osg::WARN) << "ESRIShape loader : .dbf file containe different record number that .shp file." << std::endl
                                           << "                   .dbf record skipped." << std::endl;
                }
                else
                {
                    osg::Geode * geode = sp.getGeode();
                    unsigned int i = 0;

                    ESRIShape::XBaseParser::ShapeAttributeListList::iterator it, end = xbp.getAttributeList().end();
                    for (it = xbp.getAttributeList().begin(); it != end; ++it, ++i)
                    {
                        geode->getDrawable(i)->setUserData(it->get());
                    }
                }
            }

            if (sp.getGeode())
            {

                std::string projFileName(osgDB::getNameLessExtension(fileName) + ".prj");
                if (osgDB::fileExists(projFileName))
                {
                    std::ifstream fin(projFileName.c_str());
                    if (fin)
                    {
                        std::string projstring;
                        while(!fin.eof())
                        {
                            char readline[4096];
                            *readline = 0;
                            fin.getline(readline, sizeof(readline));
                            if (!projstring.empty() && !fin.eof())
                            {
                                projstring += '\n';
                            }
                            projstring += readline;

                        }

                        if (!projstring.empty())
                        {
                            osgTerrain::Locator* locator = new osgTerrain::Locator;
                            sp.getGeode()->setUserData(locator);

                            locator->setFormat("WKT");
                            locator->setCoordinateSystem(projstring);
                            locator->setDefinedInFile(false);
                        }
                    }

                }

            }
            return sp.getGeode();
        }
};

REGISTER_OSGPLUGIN(shp, ESRIShapeReaderWriter)
<commit_msg>Added option docs<commit_after>#include <osgDB/FileNameUtils>
#include <osgDB/FileUtils>
#include <osgDB/Registry>

#include <osgTerrain/Locator>

#include "ESRIType.h"

#include "ESRIShape.h"
#include "ESRIShapeParser.h"

#include "XBaseParser.h"

class ESRIShapeReaderWriter : public osgDB::ReaderWriter
{
    public:
        ESRIShapeReaderWriter()
        {
            supportsExtension("shp","Geospatial Shape file format");
            supportsOption("double","Read x,y,z data as double an stored as geometry in osg::Vec3dArray's.");
        }

        virtual const char* className() { return "ESRI Shape ReaderWriter"; }

        virtual bool acceptsExtension(const std::string& extension) const
        {
            return osgDB::equalCaseInsensitive(extension,"shp");
        }

        virtual ReadResult readObject(const std::string& fileName, const Options* opt) const
        { return readNode(fileName,opt); }

        virtual ReadResult readNode(const std::string& file, const Options* options) const
        {
            std::string ext = osgDB::getFileExtension(file);
            if (!acceptsExtension(ext))
                return ReadResult::FILE_NOT_HANDLED;

            std::string fileName = osgDB::findDataFile(file, options);
            if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;

            bool useDouble = false;
            if (options && options->getOptionString().find("double")!=std::string::npos)
            {
                useDouble = true;
            }

            ESRIShape::ESRIShapeParser sp(fileName, useDouble);

            std::string xbaseFileName(osgDB::getNameLessExtension(fileName) + ".dbf");
            ESRIShape::XBaseParser xbp(xbaseFileName);

            if (sp.getGeode() && (xbp.getAttributeList().empty() == false))
            {
                if (sp.getGeode()->getNumDrawables() != xbp.getAttributeList().size())
                {
                    osg::notify(osg::WARN) << "ESRIShape loader : .dbf file containe different record number that .shp file." << std::endl
                                           << "                   .dbf record skipped." << std::endl;
                }
                else
                {
                    osg::Geode * geode = sp.getGeode();
                    unsigned int i = 0;

                    ESRIShape::XBaseParser::ShapeAttributeListList::iterator it, end = xbp.getAttributeList().end();
                    for (it = xbp.getAttributeList().begin(); it != end; ++it, ++i)
                    {
                        geode->getDrawable(i)->setUserData(it->get());
                    }
                }
            }

            if (sp.getGeode())
            {

                std::string projFileName(osgDB::getNameLessExtension(fileName) + ".prj");
                if (osgDB::fileExists(projFileName))
                {
                    std::ifstream fin(projFileName.c_str());
                    if (fin)
                    {
                        std::string projstring;
                        while(!fin.eof())
                        {
                            char readline[4096];
                            *readline = 0;
                            fin.getline(readline, sizeof(readline));
                            if (!projstring.empty() && !fin.eof())
                            {
                                projstring += '\n';
                            }
                            projstring += readline;

                        }

                        if (!projstring.empty())
                        {
                            osgTerrain::Locator* locator = new osgTerrain::Locator;
                            sp.getGeode()->setUserData(locator);

                            locator->setFormat("WKT");
                            locator->setCoordinateSystem(projstring);
                            locator->setDefinedInFile(false);
                        }
                    }

                }

            }
            return sp.getGeode();
        }
};

REGISTER_OSGPLUGIN(shp, ESRIShapeReaderWriter)
<|endoftext|>


<commit_before>/**************************************************************************
***
*** Copyright (c) 1995-2000 Regents of the University of California,
***               Andrew E. Caldwell, Andrew B. Kahng and Igor L. Markov
*** Copyright (c) 2000-2007 Regents of the University of Michigan,
***               Saurabh N. Adya, Jarrod A. Roy, David A. Papa and
***               Igor L. Markov
***
***  Contact author(s): abk@cs.ucsd.edu, imarkov@umich.edu
***  Original Affiliation:   UCLA, Computer Science Department,
***                          Los Angeles, CA 90095-1596 USA
***
***  Permission is hereby granted, free of charge, to any person obtaining
***  a copy of this software and associated documentation files (the
***  "Software"), to deal in the Software without restriction, including
***  without limitation
***  the rights to use, copy, modify, merge, publish, distribute, sublicense,
***  and/or sell copies of the Software, and to permit persons to whom the
***  Software is furnished to do so, subject to the following conditions:
***
***  The above copyright notice and this permission notice shall be included
***  in all copies or substantial portions of the Software.
***
*** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
*** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
*** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
*** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
***
***
***************************************************************************/

//  Created : November 1997, Mike Oliver, VLSI CAD ABKGROUP UCLA
//  020811  ilm   ported to g++ 3.0

#ifdef _MSC_VER
#pragma warning(disable : 4786)
#endif

#include "abkrand.h"
#include "abkMD5.h"
#include <fstream>
#include <cstdio>

#ifdef _MSC_VER
#define _X86_
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#endif

using std::ios;
using std::ofstream;
using std::ifstream;
using std::cout;
using std::cerr;
using std::endl;

ofstream *SeedHandler::_PseedOutFile = NULL;
ifstream *SeedHandler::_PseedInFile = NULL;
unsigned SeedHandler::_nextSeed = UINT_MAX;
bool SeedHandler::_loggingOff = false;
bool SeedHandler::_haveRandObj = false;
bool SeedHandler::_cleaned = false;
unsigned SeedHandler::_externalSeed = UINT_MAX;
unsigned SeedHandler::_progOverrideExternalSeed = UINT_MAX;

std::map<std::string, unsigned, SeedHandlerCompareStrings> SeedHandler::_counters;

SeedCleaner cleaner;  // when this object goes out of scope at the end of
// execution, it will make sure that SeedHandler::clean()
// gets called

//: Maintains all random seeds used by a process.
// Idea:  First time you create a random object, an initial nondeterministic
//       seed (also called the "external seed" is created from system
//       information and logged to seeds.out.
//       Any random object created with a seed of UINT_MAX ("nondeterministic"),
//       and that does not use the snazzy new "local independence" feature,
//       then uses seeds from a sequence starting with the initial value
//       and increasing by 1 with each new nondeterministic random object
//       created.
//
//       If the seed is overridden with a value other than UINT_MAX it is used,
//       and logged to seeds.out .
//
//       However if seeds.in exists, the initial nondeterministic value
//       is taken from the second line of seeds.in rather than the system
//       clock, and subsequent *deterministic* values are taken from successive
//       lines of seeds.in rather than from the value passed.
//
//       If seeds.out is in use or other errors occur trying to create it,
//       a warning is generated that the seeds will not be logged, and
//       the initial nondeterministic seed is printed (which should be
//       sufficient to recreate the run provided that all "deterministic"
//       seeds truly *are* deterministic (e.g. don't depend on external
//       devices).
//
//       You can disable the logging function by calling the static
//       function SeedHandler::turnOffLogging().  This will not disable
//       the ability to override seeding with seeds.in .
// NEW ULTRA-COOL FEATURE: (17 June 1999)
//       You now have the option, which I (Mike) highly recommend,
//       of specifying, instead of a seed, a "local identifier", which
//       is a string that should identify uniquely the random variable
//       (not necessarily the random object) being used.  The suggested
//       format of this string is as follows: If your
//       RNG is called _rng and is a member of MyClass, pass
//       the string "MyClass::_rng".  If it's a local variable
//       called rng in the method MyClass::myMethod(), pass
//       the string "MyClass::myMethod(),_rng".
//
//       SeedHandler will maintain a collection of counters associated
//       with each of these strings.  The sequence of random numbers
//       from a random object will be determined by three things:
//            1) the "external seed" (same as "initial nondeterm seed").
//            2) the "local identifier" (the string described above).
//            3) the counter saying how many RNG objects have previously
//                 been created with the same local identifier.
//       When any one of these changes, the output should be effectively
//       independent of the previous RNG.  Moreover you don't have
//       to worry about your regressions changing simply because someone
//       else's code which you call has changed the number of RNG objects
//       it uses.
// ANOTHER NEW FEATURE (21 February 2001)
//       At times you may wish to control the external seed yourself, e.g.
//       by specifying the seed on the command line, rather than
//       using either seeds.in or the nondeterministic chooser.
//       To enable this, a static method SeedHandler::overrideExternalSeed()
//       has been added.  If you call this method before any random
//       object has been created, you can set the external seed.
//       The file seeds.out will still be created unless you call
//       SeedHandler::turnOffLogging().  If seeds.in exists, it
//       will control -- your call to overrideExternalSeed() will
//       print a warning message and otherwise be ignored.

//****************************************************************************
//****************************************************************************
//****************************************************************************

void SeedHandler::_init() {
        abkfatal(!_cleaned,
                 "Can't create random object"
                 " after calling SeedHandler::clean()");

        if (!_haveRandObj) {
                _chooseInitNondetSeed();

                if (!_loggingOff) {
                        _initializeOutFile();
                }
        }

        _haveRandObj = true;
}

//****************************************************************************
//****************************************************************************

SeedHandler::SeedHandler(unsigned seed) : _locIdent(NULL), _counter(UINT_MAX), _isSeedMultipartite(false) {
        _init();
        if (seed == UINT_MAX)
                _seed = _nextSeed++;
        else  // deterministic seed, take value given unless
              // seeds.in exists with valid value
        {
                if (_PseedInFile) {
                        *_PseedInFile >> _seed;
                        // cerr << "Seed read was " << _seed << endl;

                        if (_PseedInFile->fail())  // if we've run out, go back
                                                   // to accepting
                                                   // seeds given
                        {
                                _PseedInFile->close();
                                delete _PseedInFile;
                                _PseedInFile = NULL;
                                _seed = seed;
                                // cerr << "But read failed, substituting seed "
                                // << _seed;
                        }

                } else
                        _seed = seed;

                if (!_loggingOff) {
                        abkfatal(_PseedOutFile,
                                 "Internal error: unable to log "
                                 "random seed to file");
                        *_PseedOutFile << _seed << endl;
                }
        }
}

//****************************************************************************
//****************************************************************************
SeedHandler::SeedHandler(const char *locIdent, unsigned counterOverride) : _isSeedMultipartite(true) {
        _init();
        _locIdent = strdup(locIdent);

        if (counterOverride != UINT_MAX)
                _counter = counterOverride;
        else {
                std::map<std::string, unsigned, SeedHandlerCompareStrings>::iterator iC;
                iC = _counters.find(_locIdent);
                if (iC == _counters.end())
                        _counters[_locIdent] = _counter = 0;
                else {
                        iC->second++;
                        _counter = iC->second;
                }
        }
}

//****************************************************************************
//****************************************************************************
SeedHandler::~SeedHandler() {
        if (!_isSeedMultipartite) {
                abkassert(_locIdent == NULL, "Non-null _locIdent with old-style seed");
        } else {
                free(_locIdent);
                _locIdent = NULL;
        }
}
//****************************************************************************
//****************************************************************************

void SeedHandler::turnOffLogging() { _loggingOff = true; }

//****************************************************************************
//****************************************************************************

void SeedHandler::overrideExternalSeed(unsigned extseed) {
        abkfatal(!_haveRandObj,
                 "Can't call SeedHandler::overrideExternalSeed() "
                 "after creating a random object");
        abkfatal(extseed != UINT_MAX, "Can't pass UINT_MAX to SeedHandler::overrideExternalSeed()");
        _progOverrideExternalSeed = extseed;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::clean() {
        _cleaned = true;

        if (_PseedOutFile) {
                _PseedOutFile->seekp(0, ios::beg);  // rewind file
                _PseedOutFile->put('0');            // mark not in use
                _PseedOutFile->close();
        }

        if (_PseedInFile) _PseedInFile->close();

        delete _PseedOutFile;
        delete _PseedInFile;
        _PseedOutFile = NULL;
        _PseedInFile = NULL;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::_chooseInitNondetSeed() {
        _PseedInFile = new ifstream("seeds.in", ios::in);

        if (!*_PseedInFile) {
                delete _PseedInFile;
                _PseedInFile = NULL;
        }

        if (_PseedInFile) {
                unsigned DummyInUseLine;
                cerr << "File seeds.in exists and will override all seeds, "
                        "including "
                        "hardcoded ones " << endl;
                *_PseedInFile >> DummyInUseLine;
                abkwarn(!DummyInUseLine,
                        "File seeds.in appears to come from a process "
                        "that never completed\n");
                *_PseedInFile >> _nextSeed;
                // cerr << "Init nondet seed read was "<<_nextSeed << endl;
                abkfatal(!(_PseedInFile->fail()),
                         "File seeds.in exists but program "
                         "was unable to read initial seed "
                         "therefrom.");
                abkwarn(_progOverrideExternalSeed == UINT_MAX,
                        "\nThere is a programmatic override of the external seed,"
                        " which will be ignored because seeds.in exists");
        } else if (_progOverrideExternalSeed == UINT_MAX) {
                // Timer tm;

                time_t utime, zero = 0;
                abkfatal(time(&utime) != -1, "Can't get time\n");
                double tm = difftime(utime, zero);

                char buf[255];
                unsigned procID = getpid();
                unsigned rndbuf;
                FILE *rnd = fopen("/dev/urandom", "r");
                if (rnd) {
                  (void) fread(&rndbuf, sizeof(rndbuf), 1, rnd);
                        fclose(rnd);
                        sprintf(buf, "%g %d %d", tm, procID, rndbuf);
                } else
                        sprintf(buf, "%g %d", tm, procID);

                MD5 hash(buf);
                _nextSeed = hash;
        } else {
                _nextSeed = _progOverrideExternalSeed;
        }
        _externalSeed = _nextSeed;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::_initializeOutFile() {
        unsigned inUse;

        ifstream outFileAsInFile("seeds.out", ios::in);

        if (!!outFileAsInFile) {

                outFileAsInFile >> inUse;
                if (outFileAsInFile.fail()) {
                        char errtxt[1023];

                        sprintf(errtxt,
                                "Unable to determine whether file seeds.out is"
                                " in use; random seeds from "
                                "this process will not be logged.\n  Initial non-"
                                "deterministic seed is %u",
                                _nextSeed);

                        abkwarn(0, errtxt);
                        _loggingOff = true;
                } else {
                        if (inUse) {
                                char errtxt[1023];

                                sprintf(errtxt,
                                        "File seeds.out is in use; random seeds "
                                        "from "
                                        "this process will not be logged.\nInitial "
                                        "non-"
                                        "deterministic seed is %u.\nIf there is no "
                                        "other process running in this directory, "
                                        "then "
                                        "an earlier\nprocess may have terminated\n"
                                        "abnormally. "
                                        "You should remove or rename seeds.out\n",
                                        _nextSeed);

                                abkwarn(0, errtxt);
                                _loggingOff = true;
                        }
                }
        }
        outFileAsInFile.close();

        if (!_loggingOff) {
                _PseedOutFile = new ofstream("seeds.out", ios::out);  // overwrite file

                if (!_PseedOutFile) {
                        char errtxt[1023];

                        sprintf(errtxt,
                                "Unable to create file seeds.out; random seeds "
                                "from "
                                "this process will not be logged.\n  Initial non-"
                                "deterministic seed is %u",
                                _nextSeed);

                        abkwarn(0, errtxt);
                        _loggingOff = true;
                        delete _PseedOutFile;
                        _PseedOutFile = NULL;
                }

                *_PseedOutFile << "1" << endl;  // mark as in use

                *_PseedOutFile << _nextSeed << endl;  // initial nondet seed
        }
}

//****************************************************************************
//****************************************************************************
//****************************************************************************
//****************************************************************************
<commit_msg>par: quiet unused result warning again<commit_after>/**************************************************************************
***
*** Copyright (c) 1995-2000 Regents of the University of California,
***               Andrew E. Caldwell, Andrew B. Kahng and Igor L. Markov
*** Copyright (c) 2000-2007 Regents of the University of Michigan,
***               Saurabh N. Adya, Jarrod A. Roy, David A. Papa and
***               Igor L. Markov
***
***  Contact author(s): abk@cs.ucsd.edu, imarkov@umich.edu
***  Original Affiliation:   UCLA, Computer Science Department,
***                          Los Angeles, CA 90095-1596 USA
***
***  Permission is hereby granted, free of charge, to any person obtaining
***  a copy of this software and associated documentation files (the
***  "Software"), to deal in the Software without restriction, including
***  without limitation
***  the rights to use, copy, modify, merge, publish, distribute, sublicense,
***  and/or sell copies of the Software, and to permit persons to whom the
***  Software is furnished to do so, subject to the following conditions:
***
***  The above copyright notice and this permission notice shall be included
***  in all copies or substantial portions of the Software.
***
*** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
*** OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
*** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
*** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
*** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
***
***
***************************************************************************/

//  Created : November 1997, Mike Oliver, VLSI CAD ABKGROUP UCLA
//  020811  ilm   ported to g++ 3.0

#ifdef _MSC_VER
#pragma warning(disable : 4786)
#endif

#include "abkrand.h"
#include "abkMD5.h"
#include <fstream>
#include <cstdio>

#ifdef _MSC_VER
#define _X86_
#include <windows.h>
#include <process.h>
#else
#include <unistd.h>
#endif

using std::ios;
using std::ofstream;
using std::ifstream;
using std::cout;
using std::cerr;
using std::endl;

ofstream *SeedHandler::_PseedOutFile = NULL;
ifstream *SeedHandler::_PseedInFile = NULL;
unsigned SeedHandler::_nextSeed = UINT_MAX;
bool SeedHandler::_loggingOff = false;
bool SeedHandler::_haveRandObj = false;
bool SeedHandler::_cleaned = false;
unsigned SeedHandler::_externalSeed = UINT_MAX;
unsigned SeedHandler::_progOverrideExternalSeed = UINT_MAX;

std::map<std::string, unsigned, SeedHandlerCompareStrings> SeedHandler::_counters;

SeedCleaner cleaner;  // when this object goes out of scope at the end of
// execution, it will make sure that SeedHandler::clean()
// gets called

//: Maintains all random seeds used by a process.
// Idea:  First time you create a random object, an initial nondeterministic
//       seed (also called the "external seed" is created from system
//       information and logged to seeds.out.
//       Any random object created with a seed of UINT_MAX ("nondeterministic"),
//       and that does not use the snazzy new "local independence" feature,
//       then uses seeds from a sequence starting with the initial value
//       and increasing by 1 with each new nondeterministic random object
//       created.
//
//       If the seed is overridden with a value other than UINT_MAX it is used,
//       and logged to seeds.out .
//
//       However if seeds.in exists, the initial nondeterministic value
//       is taken from the second line of seeds.in rather than the system
//       clock, and subsequent *deterministic* values are taken from successive
//       lines of seeds.in rather than from the value passed.
//
//       If seeds.out is in use or other errors occur trying to create it,
//       a warning is generated that the seeds will not be logged, and
//       the initial nondeterministic seed is printed (which should be
//       sufficient to recreate the run provided that all "deterministic"
//       seeds truly *are* deterministic (e.g. don't depend on external
//       devices).
//
//       You can disable the logging function by calling the static
//       function SeedHandler::turnOffLogging().  This will not disable
//       the ability to override seeding with seeds.in .
// NEW ULTRA-COOL FEATURE: (17 June 1999)
//       You now have the option, which I (Mike) highly recommend,
//       of specifying, instead of a seed, a "local identifier", which
//       is a string that should identify uniquely the random variable
//       (not necessarily the random object) being used.  The suggested
//       format of this string is as follows: If your
//       RNG is called _rng and is a member of MyClass, pass
//       the string "MyClass::_rng".  If it's a local variable
//       called rng in the method MyClass::myMethod(), pass
//       the string "MyClass::myMethod(),_rng".
//
//       SeedHandler will maintain a collection of counters associated
//       with each of these strings.  The sequence of random numbers
//       from a random object will be determined by three things:
//            1) the "external seed" (same as "initial nondeterm seed").
//            2) the "local identifier" (the string described above).
//            3) the counter saying how many RNG objects have previously
//                 been created with the same local identifier.
//       When any one of these changes, the output should be effectively
//       independent of the previous RNG.  Moreover you don't have
//       to worry about your regressions changing simply because someone
//       else's code which you call has changed the number of RNG objects
//       it uses.
// ANOTHER NEW FEATURE (21 February 2001)
//       At times you may wish to control the external seed yourself, e.g.
//       by specifying the seed on the command line, rather than
//       using either seeds.in or the nondeterministic chooser.
//       To enable this, a static method SeedHandler::overrideExternalSeed()
//       has been added.  If you call this method before any random
//       object has been created, you can set the external seed.
//       The file seeds.out will still be created unless you call
//       SeedHandler::turnOffLogging().  If seeds.in exists, it
//       will control -- your call to overrideExternalSeed() will
//       print a warning message and otherwise be ignored.

//****************************************************************************
//****************************************************************************
//****************************************************************************

void SeedHandler::_init() {
        abkfatal(!_cleaned,
                 "Can't create random object"
                 " after calling SeedHandler::clean()");

        if (!_haveRandObj) {
                _chooseInitNondetSeed();

                if (!_loggingOff) {
                        _initializeOutFile();
                }
        }

        _haveRandObj = true;
}

//****************************************************************************
//****************************************************************************

SeedHandler::SeedHandler(unsigned seed) : _locIdent(NULL), _counter(UINT_MAX), _isSeedMultipartite(false) {
        _init();
        if (seed == UINT_MAX)
                _seed = _nextSeed++;
        else  // deterministic seed, take value given unless
              // seeds.in exists with valid value
        {
                if (_PseedInFile) {
                        *_PseedInFile >> _seed;
                        // cerr << "Seed read was " << _seed << endl;

                        if (_PseedInFile->fail())  // if we've run out, go back
                                                   // to accepting
                                                   // seeds given
                        {
                                _PseedInFile->close();
                                delete _PseedInFile;
                                _PseedInFile = NULL;
                                _seed = seed;
                                // cerr << "But read failed, substituting seed "
                                // << _seed;
                        }

                } else
                        _seed = seed;

                if (!_loggingOff) {
                        abkfatal(_PseedOutFile,
                                 "Internal error: unable to log "
                                 "random seed to file");
                        *_PseedOutFile << _seed << endl;
                }
        }
}

//****************************************************************************
//****************************************************************************
SeedHandler::SeedHandler(const char *locIdent, unsigned counterOverride) : _isSeedMultipartite(true) {
        _init();
        _locIdent = strdup(locIdent);

        if (counterOverride != UINT_MAX)
                _counter = counterOverride;
        else {
                std::map<std::string, unsigned, SeedHandlerCompareStrings>::iterator iC;
                iC = _counters.find(_locIdent);
                if (iC == _counters.end())
                        _counters[_locIdent] = _counter = 0;
                else {
                        iC->second++;
                        _counter = iC->second;
                }
        }
}

//****************************************************************************
//****************************************************************************
SeedHandler::~SeedHandler() {
        if (!_isSeedMultipartite) {
                abkassert(_locIdent == NULL, "Non-null _locIdent with old-style seed");
        } else {
                free(_locIdent);
                _locIdent = NULL;
        }
}
//****************************************************************************
//****************************************************************************

void SeedHandler::turnOffLogging() { _loggingOff = true; }

//****************************************************************************
//****************************************************************************

void SeedHandler::overrideExternalSeed(unsigned extseed) {
        abkfatal(!_haveRandObj,
                 "Can't call SeedHandler::overrideExternalSeed() "
                 "after creating a random object");
        abkfatal(extseed != UINT_MAX, "Can't pass UINT_MAX to SeedHandler::overrideExternalSeed()");
        _progOverrideExternalSeed = extseed;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::clean() {
        _cleaned = true;

        if (_PseedOutFile) {
                _PseedOutFile->seekp(0, ios::beg);  // rewind file
                _PseedOutFile->put('0');            // mark not in use
                _PseedOutFile->close();
        }

        if (_PseedInFile) _PseedInFile->close();

        delete _PseedOutFile;
        delete _PseedInFile;
        _PseedOutFile = NULL;
        _PseedInFile = NULL;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::_chooseInitNondetSeed() {
        _PseedInFile = new ifstream("seeds.in", ios::in);

        if (!*_PseedInFile) {
                delete _PseedInFile;
                _PseedInFile = NULL;
        }

        if (_PseedInFile) {
                unsigned DummyInUseLine;
                cerr << "File seeds.in exists and will override all seeds, "
                        "including "
                        "hardcoded ones " << endl;
                *_PseedInFile >> DummyInUseLine;
                abkwarn(!DummyInUseLine,
                        "File seeds.in appears to come from a process "
                        "that never completed\n");
                *_PseedInFile >> _nextSeed;
                // cerr << "Init nondet seed read was "<<_nextSeed << endl;
                abkfatal(!(_PseedInFile->fail()),
                         "File seeds.in exists but program "
                         "was unable to read initial seed "
                         "therefrom.");
                abkwarn(_progOverrideExternalSeed == UINT_MAX,
                        "\nThere is a programmatic override of the external seed,"
                        " which will be ignored because seeds.in exists");
        } else if (_progOverrideExternalSeed == UINT_MAX) {
                // Timer tm;

                time_t utime, zero = 0;
                abkfatal(time(&utime) != -1, "Can't get time\n");
                double tm = difftime(utime, zero);

                char buf[255];
                unsigned procID = getpid();
                unsigned rndbuf;
                FILE *rnd = fopen("/dev/urandom", "r");
                if (rnd) {
                        size_t x = fread(&rndbuf, sizeof(rndbuf), 1, rnd);
                        (void) x; // unused
                        fclose(rnd);
                        sprintf(buf, "%g %d %d", tm, procID, rndbuf);
                } else
                        sprintf(buf, "%g %d", tm, procID);

                MD5 hash(buf);
                _nextSeed = hash;
        } else {
                _nextSeed = _progOverrideExternalSeed;
        }
        _externalSeed = _nextSeed;
}

//****************************************************************************
//****************************************************************************

void SeedHandler::_initializeOutFile() {
        unsigned inUse;

        ifstream outFileAsInFile("seeds.out", ios::in);

        if (!!outFileAsInFile) {

                outFileAsInFile >> inUse;
                if (outFileAsInFile.fail()) {
                        char errtxt[1023];

                        sprintf(errtxt,
                                "Unable to determine whether file seeds.out is"
                                " in use; random seeds from "
                                "this process will not be logged.\n  Initial non-"
                                "deterministic seed is %u",
                                _nextSeed);

                        abkwarn(0, errtxt);
                        _loggingOff = true;
                } else {
                        if (inUse) {
                                char errtxt[1023];

                                sprintf(errtxt,
                                        "File seeds.out is in use; random seeds "
                                        "from "
                                        "this process will not be logged.\nInitial "
                                        "non-"
                                        "deterministic seed is %u.\nIf there is no "
                                        "other process running in this directory, "
                                        "then "
                                        "an earlier\nprocess may have terminated\n"
                                        "abnormally. "
                                        "You should remove or rename seeds.out\n",
                                        _nextSeed);

                                abkwarn(0, errtxt);
                                _loggingOff = true;
                        }
                }
        }
        outFileAsInFile.close();

        if (!_loggingOff) {
                _PseedOutFile = new ofstream("seeds.out", ios::out);  // overwrite file

                if (!_PseedOutFile) {
                        char errtxt[1023];

                        sprintf(errtxt,
                                "Unable to create file seeds.out; random seeds "
                                "from "
                                "this process will not be logged.\n  Initial non-"
                                "deterministic seed is %u",
                                _nextSeed);

                        abkwarn(0, errtxt);
                        _loggingOff = true;
                        delete _PseedOutFile;
                        _PseedOutFile = NULL;
                }

                *_PseedOutFile << "1" << endl;  // mark as in use

                *_PseedOutFile << _nextSeed << endl;  // initial nondet seed
        }
}

//****************************************************************************
//****************************************************************************
//****************************************************************************
//****************************************************************************
<|endoftext|>


<commit_before>/*
** Copyright 2015 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QMutexLocker>
#include <QFileInfo>
#include <QFile>
#include <QDirIterator>
#include <QDateTime>
#include <set>
#include <fstream>
#include <sstream>
#include "com/centreon/broker/dumper/directory_dumper.hh"
#include "com/centreon/broker/dumper/internal.hh"
#include "com/centreon/broker/dumper/dump.hh"
#include "com/centreon/broker/dumper/remove.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::dumper;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Constructor.
 *
 *  @param[in] path    Dumper path.
 *  @param[in] tagname Dumper tagname.
 *  @param[in] cache   Persistent cache.
 */
directory_dumper::directory_dumper(
          std::string const& path,
          std::string const& tagname,
          misc::shared_ptr<persistent_cache> cache)
  try :
    _path(path),
    _tagname(tagname),
    _cache(cache) {
  // Set watcher timeout.
  _watcher.set_timeout(3000);

  // Get all the last modified timestamps from the cache.
  _get_last_timestamps_from_cache();

  // Set the watch and the initial events.
  std::set<std::string> files_found = _set_watch_over_directory(path);

  // Remove deleted files.
  _remove_deleted_files(files_found);
}
catch (std::exception const& e) {
  throw (exceptions::msg()
         << "dumper: directory dumper couldn't initialize: " << e.what());
}

/**
 *  Destructor.
 */
directory_dumper::~directory_dumper() {
  try {
    // Save the last modified timestamps to the cache.
    _save_last_timestamps_to_cache();
  } catch (std::exception const& e) {
    logging::error(logging::medium)
    << "dump: directory dumper error while trying to save the cache: "
    << e.what();
  }
}

/**
 *  Read data from the dumper.
 *
 *  @param[out] d         Next available event.
 *  @param[in]  deadline  Timeout.
 *
 *  @return Respect io::stream::read()'s return value.
 */
bool directory_dumper::read(
                         misc::shared_ptr<io::data>& d,
                         time_t deadline) {
  d.clear();

  // Get an event already in the event list.
  if (!_event_list.empty()) {
    unsigned int type = _event_list.front().second->type();
    if (type == dump::static_type())
      _last_modified_timestamps[
         _event_list.front().second.ref_as<dump>().filename.toStdString()]
         = _event_list.front().first;
    else if (type == dumper::remove::static_type())
      _last_modified_timestamps.erase(
        _event_list.front().second.ref_as<dumper::remove>().filename.toStdString());
    d = _event_list.front().second;
    _event_list.pop_front();
    return (true);
  }

  // If no events, watch the directory for new events.
  std::vector<file::directory_event> events = _watcher.get_events();
  for (std::vector<file::directory_event>::const_iterator
         it(events.begin()),
         end(events.end());
       it != end;
       ++it) {
    if (it->get_type() == file::directory_event::directory_deleted
          && it->get_path() == _path)
      throw (exceptions::msg()
             << "dumper: directory '" << _path << "' deleted");
    else if (it->get_type() == file::directory_event::deleted) {
      misc::shared_ptr<dumper::remove> d(new dumper::remove);
      d->filename = QString::fromStdString(
                      _get_relative_filename(it->get_path()));
      d->tag = QString::fromStdString(_tagname);
      _event_list.push_back(std::make_pair(timestamp(), d));
    }
    else if (it->get_type() == file::directory_event::created
               && it->get_file_type() == file::directory_event::directory) {
      _set_watch_over_directory(it->get_path());
    }
    else if (it->get_file_type() == file::directory_event::file)
      _event_list.push_back(_dump_a_file(it->get_path()));
  }
}

/**
 *  Write data to the dumper.
 *
 *  @param[in] d Data to write.
 *
 *  @return Always return 1, or throw exceptions.
 */
unsigned int directory_dumper::write(misc::shared_ptr<io::data> const& d) {
  (void)d;
  throw (exceptions::msg()
         << "dumper: attempt to write from a directory dumper stream");
  return (1);
}

/**
 *  Get the list of last modified timestamps from the persistent cache.
 */
void directory_dumper::_get_last_timestamps_from_cache() {
  // No cache, nothing to do.
  if (_cache.isNull())
    return ;

  misc::shared_ptr<io::data> d;
  while (true) {
    _cache->get(d);
    if (d.isNull())
      return;
    if (d->type() == timestamp_cache::static_type()) {
      timestamp_cache const& ts = d.ref_as<timestamp_cache const>();
      _last_modified_timestamps[ts.filename.toStdString()] = ts.last_modified;
    }
  }
}

/**
 *  Save the list of last modified timestamps to the persistent cache.
 */
void directory_dumper::_save_last_timestamps_to_cache() {
  // No cache, nothing to do.
  if (_cache.isNull())
    return ;

  _cache->transaction();
  for (std::map<std::string, timestamp>::const_iterator
         it(_last_modified_timestamps.begin()),
         end(_last_modified_timestamps.end());
       it != end;
       ++it) {
    misc::shared_ptr<timestamp_cache> d(new timestamp_cache);
    d->filename = QString::fromStdString(it->first);
    d->last_modified = it->second;
    _cache->add(d);
  }
  _cache->commit();
}

/**
 *  Set the watch over the directory.
 *
 *  @param[in] path  The directory path.
 *
 *  @return  All the files which were found and dumper.
 */
std::set<std::string> directory_dumper::_set_watch_over_directory(std::string const& path) {
  // Basic checks.
  QFileInfo directory_info(QString::fromStdString(path));
  if (!directory_info.exists())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path << "' doesn't exist");
  if (!directory_info.isDir())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path
           << "' is not a directory");
  if (!directory_info.isReadable())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path
           << "' can not be accessed");

  // Add the directory to the directory watcher.
  try {
    _watcher.add_directory(path);
  } catch (std::exception const& e) {
    throw (exceptions::msg()
           << "dumper: " << e.what());
  }

  // Dump all the files that weren't already dumped at last once
  // using last modified cached timestamp.
  std::set<std::string> found_files;
  {
    QDirIterator dir(
      QDir(QString::fromStdString(path),
      QString(),
      QDir::Name | QDir::IgnoreCase,
      QDir::Files));
    while (dir.hasNext()) {
      QString filepath = dir.next();
      std::map<std::string, timestamp>::const_iterator found_timestamp(
          _last_modified_timestamps.find(filepath.toStdString()));
      if (found_timestamp == _last_modified_timestamps.end()
            || found_timestamp->second < QFileInfo(filepath).lastModified().toTime_t())
        _event_list.push_back(_dump_a_file(filepath.toStdString()));
      found_files.insert(filepath.toStdString());
    }
  }

  // Iterate over directories.
  {
    QDirIterator dir(
      QDir(QString::fromStdString(path),
      QString(),
      QDir::Name | QDir::IgnoreCase,
      QDir::Dirs | QDir::NoDotAndDotDot));
    while (dir.hasNext()) {
      QString filepath = dir.next();
      std::set<std::string> ret = _set_watch_over_directory(
                                    filepath.toStdString());
      found_files.insert(ret.begin(), ret.end());
    }
  }
  return (found_files);
}

/**
 *  Remove all the files which were deleted.
 *
 *  @param[in] found_files  List of files found.
 */
void directory_dumper::_remove_deleted_files(
       std::set<std::string> const& found_files) {
  // Every file that wasn't found has been deleted
  for (std::map<std::string, timestamp>::const_iterator
         it(_last_modified_timestamps.begin()),
         end(_last_modified_timestamps.end());
       it != end;
       ++it)
    if (found_files.find(it->first) == found_files.end()) {
      misc::shared_ptr<dumper::remove> d(new dumper::remove);
      d->filename = QString::fromStdString(it->first);
      d->tag = QString::fromStdString(_tagname);
      _event_list.push_back(std::make_pair(timestamp(), d));
    }
}

/**
 *  Dump a file.
 *
 *  @param[in] path  The path of the file.
 *
 *  @return          A pair of a timestamp containing the time of the dump,
 *                   and an io::data dump containing the file.
 */
std::pair<timestamp, misc::shared_ptr<io::data> > directory_dumper::_dump_a_file(
                             std::string const& path) {
  QFile file(QString::fromStdString(path));

  file.open(QFile::ReadOnly);
  if (!file.isReadable())
    throw (exceptions::msg()
           << "dumper: can't read '" << path << "'");
  timestamp ts(::time(NULL));
  QString content = file.readAll();

  misc::shared_ptr<dumper::dump> dump(new dumper::dump);
  dump->filename = QString::fromStdString(_get_relative_filename(path));
  dump->content = content;
  dump->tag = QString::fromStdString(_tagname);
  return (std::make_pair(ts, dump));
}

/**
 *  Get a filename relative to the path being watched.
 *
 *  @param[in] path  The path being watched.
 *
 *  @return  The filename.
 */
std::string directory_dumper::_get_relative_filename(std::string const& path) {
  std::string ret = path;
  ret.replace(0, _path.size(), "");
  return (ret);
}
<commit_msg>dumper: fix directory_dumper write method.<commit_after>/*
** Copyright 2015 Merethis
**
** This file is part of Centreon Broker.
**
** Centreon Broker is free software: you can redistribute it and/or
** modify it under the terms of the GNU General Public License version 2
** as published by the Free Software Foundation.
**
** Centreon Broker 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 Centreon Broker. If not, see
** <http://www.gnu.org/licenses/>.
*/

#include <QMutexLocker>
#include <QFileInfo>
#include <QFile>
#include <QDirIterator>
#include <QDateTime>
#include <set>
#include <fstream>
#include <sstream>
#include "com/centreon/broker/dumper/directory_dumper.hh"
#include "com/centreon/broker/dumper/internal.hh"
#include "com/centreon/broker/dumper/dump.hh"
#include "com/centreon/broker/dumper/remove.hh"
#include "com/centreon/broker/io/events.hh"
#include "com/centreon/broker/io/exceptions/shutdown.hh"
#include "com/centreon/broker/exceptions/msg.hh"
#include "com/centreon/broker/logging/logging.hh"

using namespace com::centreon::broker;
using namespace com::centreon::broker::dumper;

/**************************************
*                                     *
*           Public Methods            *
*                                     *
**************************************/

/**
 *  Constructor.
 *
 *  @param[in] path    Dumper path.
 *  @param[in] tagname Dumper tagname.
 *  @param[in] cache   Persistent cache.
 */
directory_dumper::directory_dumper(
          std::string const& path,
          std::string const& tagname,
          misc::shared_ptr<persistent_cache> cache)
  try :
    _path(path),
    _tagname(tagname),
    _cache(cache) {
  // Set watcher timeout.
  _watcher.set_timeout(3000);

  // Get all the last modified timestamps from the cache.
  _get_last_timestamps_from_cache();

  // Set the watch and the initial events.
  std::set<std::string> files_found = _set_watch_over_directory(path);

  // Remove deleted files.
  _remove_deleted_files(files_found);
}
catch (std::exception const& e) {
  throw (exceptions::msg()
         << "dumper: directory dumper couldn't initialize: " << e.what());
}

/**
 *  Destructor.
 */
directory_dumper::~directory_dumper() {
  try {
    // Save the last modified timestamps to the cache.
    _save_last_timestamps_to_cache();
  } catch (std::exception const& e) {
    logging::error(logging::medium)
    << "dump: directory dumper error while trying to save the cache: "
    << e.what();
  }
}

/**
 *  Read data from the dumper.
 *
 *  @param[out] d         Next available event.
 *  @param[in]  deadline  Timeout.
 *
 *  @return Respect io::stream::read()'s return value.
 */
bool directory_dumper::read(
                         misc::shared_ptr<io::data>& d,
                         time_t deadline) {
  d.clear();

  // Get an event already in the event list.
  if (!_event_list.empty()) {
    unsigned int type = _event_list.front().second->type();
    if (type == dump::static_type())
      _last_modified_timestamps[
         _event_list.front().second.ref_as<dump>().filename.toStdString()]
         = _event_list.front().first;
    else if (type == dumper::remove::static_type())
      _last_modified_timestamps.erase(
        _event_list.front().second.ref_as<dumper::remove>().filename.toStdString());
    d = _event_list.front().second;
    _event_list.pop_front();
    return (true);
  }

  // If no events, watch the directory for new events.
  std::vector<file::directory_event> events = _watcher.get_events();
  for (std::vector<file::directory_event>::const_iterator
         it(events.begin()),
         end(events.end());
       it != end;
       ++it) {
    if (it->get_type() == file::directory_event::directory_deleted
          && it->get_path() == _path)
      throw (exceptions::msg()
             << "dumper: directory '" << _path << "' deleted");
    else if (it->get_type() == file::directory_event::deleted) {
      misc::shared_ptr<dumper::remove> d(new dumper::remove);
      d->filename = QString::fromStdString(
                      _get_relative_filename(it->get_path()));
      d->tag = QString::fromStdString(_tagname);
      _event_list.push_back(std::make_pair(timestamp(), d));
    }
    else if (it->get_type() == file::directory_event::created
               && it->get_file_type() == file::directory_event::directory) {
      _set_watch_over_directory(it->get_path());
    }
    else if (it->get_file_type() == file::directory_event::file)
      _event_list.push_back(_dump_a_file(it->get_path()));
  }
}

/**
 *  Write data to the dumper.
 *
 *  @param[in] d Data to write.
 *
 *  @return Always return 1, or throw exceptions.
 */
unsigned int directory_dumper::write(misc::shared_ptr<io::data> const& d) {
  (void)d;
  throw (io::exceptions::shutdown(false, true)
         << "cannot write to a dumper directory");
  return (1);
}

/**
 *  Get the list of last modified timestamps from the persistent cache.
 */
void directory_dumper::_get_last_timestamps_from_cache() {
  // No cache, nothing to do.
  if (_cache.isNull())
    return ;

  misc::shared_ptr<io::data> d;
  while (true) {
    _cache->get(d);
    if (d.isNull())
      return;
    if (d->type() == timestamp_cache::static_type()) {
      timestamp_cache const& ts = d.ref_as<timestamp_cache const>();
      _last_modified_timestamps[ts.filename.toStdString()] = ts.last_modified;
    }
  }
}

/**
 *  Save the list of last modified timestamps to the persistent cache.
 */
void directory_dumper::_save_last_timestamps_to_cache() {
  // No cache, nothing to do.
  if (_cache.isNull())
    return ;

  _cache->transaction();
  for (std::map<std::string, timestamp>::const_iterator
         it(_last_modified_timestamps.begin()),
         end(_last_modified_timestamps.end());
       it != end;
       ++it) {
    misc::shared_ptr<timestamp_cache> d(new timestamp_cache);
    d->filename = QString::fromStdString(it->first);
    d->last_modified = it->second;
    _cache->add(d);
  }
  _cache->commit();
}

/**
 *  Set the watch over the directory.
 *
 *  @param[in] path  The directory path.
 *
 *  @return  All the files which were found and dumper.
 */
std::set<std::string> directory_dumper::_set_watch_over_directory(std::string const& path) {
  // Basic checks.
  QFileInfo directory_info(QString::fromStdString(path));
  if (!directory_info.exists())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path << "' doesn't exist");
  if (!directory_info.isDir())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path
           << "' is not a directory");
  if (!directory_info.isReadable())
    throw (exceptions::msg()
           << "dumper: directory dumper path '" << path
           << "' can not be accessed");

  // Add the directory to the directory watcher.
  try {
    _watcher.add_directory(path);
  } catch (std::exception const& e) {
    throw (exceptions::msg()
           << "dumper: " << e.what());
  }

  // Dump all the files that weren't already dumped at last once
  // using last modified cached timestamp.
  std::set<std::string> found_files;
  {
    QDirIterator dir(
      QDir(QString::fromStdString(path),
      QString(),
      QDir::Name | QDir::IgnoreCase,
      QDir::Files));
    while (dir.hasNext()) {
      QString filepath = dir.next();
      std::map<std::string, timestamp>::const_iterator found_timestamp(
          _last_modified_timestamps.find(filepath.toStdString()));
      if (found_timestamp == _last_modified_timestamps.end()
            || found_timestamp->second < QFileInfo(filepath).lastModified().toTime_t())
        _event_list.push_back(_dump_a_file(filepath.toStdString()));
      found_files.insert(filepath.toStdString());
    }
  }

  // Iterate over directories.
  {
    QDirIterator dir(
      QDir(QString::fromStdString(path),
      QString(),
      QDir::Name | QDir::IgnoreCase,
      QDir::Dirs | QDir::NoDotAndDotDot));
    while (dir.hasNext()) {
      QString filepath = dir.next();
      std::set<std::string> ret = _set_watch_over_directory(
                                    filepath.toStdString());
      found_files.insert(ret.begin(), ret.end());
    }
  }
  return (found_files);
}

/**
 *  Remove all the files which were deleted.
 *
 *  @param[in] found_files  List of files found.
 */
void directory_dumper::_remove_deleted_files(
       std::set<std::string> const& found_files) {
  // Every file that wasn't found has been deleted
  for (std::map<std::string, timestamp>::const_iterator
         it(_last_modified_timestamps.begin()),
         end(_last_modified_timestamps.end());
       it != end;
       ++it)
    if (found_files.find(it->first) == found_files.end()) {
      misc::shared_ptr<dumper::remove> d(new dumper::remove);
      d->filename = QString::fromStdString(it->first);
      d->tag = QString::fromStdString(_tagname);
      _event_list.push_back(std::make_pair(timestamp(), d));
    }
}

/**
 *  Dump a file.
 *
 *  @param[in] path  The path of the file.
 *
 *  @return          A pair of a timestamp containing the time of the dump,
 *                   and an io::data dump containing the file.
 */
std::pair<timestamp, misc::shared_ptr<io::data> > directory_dumper::_dump_a_file(
                             std::string const& path) {
  QFile file(QString::fromStdString(path));

  file.open(QFile::ReadOnly);
  if (!file.isReadable())
    throw (exceptions::msg()
           << "dumper: can't read '" << path << "'");
  timestamp ts(::time(NULL));
  QString content = file.readAll();

  misc::shared_ptr<dumper::dump> dump(new dumper::dump);
  dump->filename = QString::fromStdString(_get_relative_filename(path));
  dump->content = content;
  dump->tag = QString::fromStdString(_tagname);
  return (std::make_pair(ts, dump));
}

/**
 *  Get a filename relative to the path being watched.
 *
 *  @param[in] path  The path being watched.
 *
 *  @return  The filename.
 */
std::string directory_dumper::_get_relative_filename(std::string const& path) {
  std::string ret = path;
  ret.replace(0, _path.size(), "");
  return (ret);
}
<|endoftext|>


<commit_before>#include "coord_client.h"

CoordinatorClient::CoordinatorClient(const QString &, QObject *parent)
    : QObject(parent) { }

CoordinatorClient::~CoordinatorClient() { }

void CoordinatorClient::openItem(QUrl item) {
  if (item.scheme() == "file") {
    QFileInfo fileInfo(item.path());
    QString binary;
    if (fileInfo.isDir()) {
      binary = "runcible-dir-list";
    } else {
      binary = "runcible-open-ext-" + fileInfo.suffix();
    }
    QProcess::startDetached(binary, QStringList() << fileInfo.absoluteFilePath());
  } else {
    qDebug() << "Cannot open non-file item " << item;
  }
}

void CoordinatorClient::openItem(QString program, QUrl item) {
  // TODO(cbiffle): this is stubbed out to avoid using COP.
  QProcess::startDetached(program, QStringList() << item.toString());
}
<commit_msg>Switched the coordinator client to use QCOP.<commit_after>#include "coord_client.h"

#include <QCopChannel>

CoordinatorClient::CoordinatorClient(const QString &, QObject *parent)
    : QObject(parent) { }

CoordinatorClient::~CoordinatorClient() { }

void CoordinatorClient::openItem(QUrl item) {
  QByteArray data;
  QDataStream out(&data, QIODevice::WriteOnly);
  out << item;
  qDebug() << "Sending openItem(QUrl)";
  if (!QCopChannel::send("runcible/coordinator", "openItem(QUrl)", data)) {
    qDebug() << "Send failed.";
  }
}

void CoordinatorClient::openItem(QString program, QUrl item) {
  QByteArray data;
  QDataStream out(&data, QIODevice::WriteOnly);
  out << program << item;
  qDebug() << "Sending openItem(QString,QUrl)";
  if (!QCopChannel::send("runcible/coordinator", "openItem(QString,QUrl)", data)) {
    qDebug() << "Send failed.";
  }
}
<|endoftext|>


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

/* Author: Ioan Sucan */

#include "ompl/base/Planner.h"
#include "ompl/util/Exception.h"
#include "ompl/base/GoalSampleableRegion.h"
#include "ompl/base/GoalLazySamples.h"
#include <boost/thread.hpp>

ompl::base::Planner::Planner(const SpaceInformationPtr &si, const std::string &name) :
    si_(si), pis_(this), name_(name), setup_(false), msg_(name)
{
    if (!si_)
        throw Exception(name_, "Invalid space information instance for planner");
}

const ompl::base::PlannerSpecs& ompl::base::Planner::getSpecs(void) const
{
    return specs_;
}

const std::string& ompl::base::Planner::getName(void) const
{
    return name_;
}

void ompl::base::Planner::setName(const std::string &name)
{
    name_ = name;
    msg_.setPrefix(name_);
}

const ompl::base::SpaceInformationPtr&  ompl::base::Planner::getSpaceInformation(void) const
{
    return si_;
}

const ompl::base::ProblemDefinitionPtr& ompl::base::Planner::getProblemDefinition(void) const
{
    return pdef_;
}

void ompl::base::Planner::setProblemDefinition(const ProblemDefinitionPtr &pdef)
{
    pdef_ = pdef;
    pis_.update();
}

const ompl::base::PlannerInputStates& ompl::base::Planner::getPlannerInputStates(void) const
{
    return pis_;
}

void ompl::base::Planner::setup(void)
{
    if (!si_->isSetup())
    {
        msg_.inform("Space information setup was not yet called. Calling now.");
        si_->setup();
    }

    if (setup_)
        msg_.warn("Planner setup called multiple times");
    else
        setup_ = true;
}

void ompl::base::Planner::checkValidity(void)
{
    if (!isSetup())
        setup();
    pis_.checkValidity();
}

bool ompl::base::Planner::isSetup(void) const
{
    return setup_;
}

void ompl::base::Planner::clear(void)
{
    pis_.clear();
    pis_.update();
}

void ompl::base::Planner::getPlannerData(PlannerData &data) const
{
    data.si = si_;
}

bool ompl::base::Planner::solve(const PlannerTerminationConditionFn &ptc, double checkInterval)
{
    return solve(PlannerThreadedTerminationCondition(ptc, checkInterval));
}

bool ompl::base::Planner::solve(double solveTime)
{
    if (solveTime < 1.0)
        return solve(timedPlannerTerminationCondition(solveTime));
    else
        return solve(timedPlannerTerminationCondition(solveTime, std::min(solveTime / 100.0, 0.1)));
}

void ompl::base::Planner::printProperties(std::ostream &out) const
{
    out << "Planner " + getName() + " specs:" << std::endl;
    out << "Multithreaded:                 " << (getSpecs().multithreaded ? "Yes" : "No") << std::endl;
    out << "Reports approximate solutions: " << (getSpecs().approximateSolutions ? "Yes" : "No") << std::endl;
    out << "Can optimize solutions:        " << (getSpecs().optimizingPaths ? "Yes" : "No") << std::endl;
    out << "Aware of the following parameters:";
    std::vector<std::string> params;
    params_.getParamNames(params);
    for (unsigned int i = 0 ; i < params.size() ; ++i)
        out << " " << params[i];
    out << std::endl;
}

void ompl::base::Planner::printSettings(std::ostream &out) const
{
    out << "Declared parameters for planner " << getName() << ":" << std::endl;
    params_.print(out);
}

void ompl::base::PlannerInputStates::clear(void)
{
    if (tempState_)
    {
        si_->freeState(tempState_);
        tempState_ = NULL;
    }
    addedStartStates_ = 0;
    sampledGoalsCount_ = 0;
    pdef_ = NULL;
    si_ = NULL;
}

void ompl::base::PlannerInputStates::restart(void)
{
    addedStartStates_ = 0;
    sampledGoalsCount_ = 0;
}

bool ompl::base::PlannerInputStates::update(void)
{
    if (!planner_)
        throw Exception("No planner set for PlannerInputStates");
    return use(planner_->getSpaceInformation(), planner_->getProblemDefinition());
}

void ompl::base::PlannerInputStates::checkValidity(void) const
{
    std::string error;

    if (!pdef_)
        error = "Problem definition not specified";
    else
    {
        if (pdef_->getStartStateCount() <= 0)
            error = "No start states specified";
        else
            if (!pdef_->getGoal())
                error = "No goal specified";
    }

    if (!error.empty())
    {
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }
}

bool ompl::base::PlannerInputStates::use(const SpaceInformationPtr &si, const ProblemDefinitionPtr &pdef)
{
    if (si && pdef)
        return use(si.get(), pdef.get());
    else
    {
        clear();
        return true;
    }
}

bool ompl::base::PlannerInputStates::use(const SpaceInformation *si, const ProblemDefinition *pdef)
{
    if (pdef_ != pdef || si_ != si)
    {
        clear();
        pdef_ = pdef;
        si_ = si;
        return true;
    }
    return false;
}

const ompl::base::State* ompl::base::PlannerInputStates::nextStart(void)
{
    if (pdef_ == NULL || si_ == NULL)
    {
        std::string error = "Missing space information or problem definition";
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }

    while (addedStartStates_ < pdef_->getStartStateCount())
    {
        const base::State *st = pdef_->getStartState(addedStartStates_);
        addedStartStates_++;
        bool bounds = si_->satisfiesBounds(st);
        bool valid = bounds ? si_->isValid(st) : false;
        if (bounds && valid)
            return st;
        else
        {
            msg::Interface msg(planner_ ? planner_->getName() : "");
            msg.warn("Skipping invalid start state (invalid %s)", bounds ? "state": "bounds");
        }
    }
    return NULL;
}

const ompl::base::State* ompl::base::PlannerInputStates::nextGoal(void)
{
    static PlannerAlwaysTerminatingCondition ptc;
    return nextGoal(ptc);
}

const ompl::base::State* ompl::base::PlannerInputStates::nextGoal(const PlannerTerminationCondition &ptc)
{
    if (pdef_ == NULL || si_ == NULL)
    {
        std::string error = "Missing space information or problem definition";
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }

    const GoalSampleableRegion *goal = dynamic_cast<const GoalSampleableRegion*>(pdef_->getGoal().get());

    if (goal)
    {
        const GoalLazySamples *gls = dynamic_cast<const GoalLazySamples*>(goal);
        bool first = true;
        bool attempt = true;
        while (attempt)
        {
            attempt = false;

            if (sampledGoalsCount_ < goal->maxSampleCount())
            {
                if (tempState_ == NULL)
                    tempState_ = si_->allocState();

                do
                {
                    goal->sampleGoal(tempState_);
                    sampledGoalsCount_++;
                    bool bounds = si_->satisfiesBounds(tempState_);
                    bool valid = bounds ? si_->isValid(tempState_) : false;
                    if (bounds && valid)
                        return tempState_;
                    else
                    {
                        msg::Interface msg(planner_ ? planner_->getName() : "");
                        msg.warn("Skipping invalid goal state (invalid %s)", bounds ? "state": "bounds");
                    }
                }
                while (sampledGoalsCount_ < goal->maxSampleCount() && !ptc());
            }

            if (gls && goal->canSample() && !ptc())
            {
                if (first)
                {
                    first = false;
                    msg::Interface msg(planner_ ? planner_->getName() : "");
                    msg.debug("Waiting for goal region samples ...");
                }
                boost::this_thread::sleep(time::seconds(0.01));
                attempt = !ptc();
            }
        }
    }
    return NULL;
}

bool ompl::base::PlannerInputStates::haveMoreStartStates(void) const
{
    if (pdef_)
        return addedStartStates_ < pdef_->getStartStateCount();
    return false;
}

bool ompl::base::PlannerInputStates::haveMoreGoalStates(void) const
{
    if (pdef_ && pdef_->getGoal())
    {
        const GoalSampleableRegion *goal = dynamic_cast<const GoalSampleableRegion*>(pdef_->getGoal().get());
        if (goal)
            return sampledGoalsCount_ < goal->maxSampleCount();
    }
    return false;
}
<commit_msg>small simplification<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2010, Rice University
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Rice University nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

/* Author: Ioan Sucan */

#include "ompl/base/Planner.h"
#include "ompl/util/Exception.h"
#include "ompl/base/GoalSampleableRegion.h"
#include <boost/thread.hpp>

ompl::base::Planner::Planner(const SpaceInformationPtr &si, const std::string &name) :
    si_(si), pis_(this), name_(name), setup_(false), msg_(name)
{
    if (!si_)
        throw Exception(name_, "Invalid space information instance for planner");
}

const ompl::base::PlannerSpecs& ompl::base::Planner::getSpecs(void) const
{
    return specs_;
}

const std::string& ompl::base::Planner::getName(void) const
{
    return name_;
}

void ompl::base::Planner::setName(const std::string &name)
{
    name_ = name;
    msg_.setPrefix(name_);
}

const ompl::base::SpaceInformationPtr&  ompl::base::Planner::getSpaceInformation(void) const
{
    return si_;
}

const ompl::base::ProblemDefinitionPtr& ompl::base::Planner::getProblemDefinition(void) const
{
    return pdef_;
}

void ompl::base::Planner::setProblemDefinition(const ProblemDefinitionPtr &pdef)
{
    pdef_ = pdef;
    pis_.update();
}

const ompl::base::PlannerInputStates& ompl::base::Planner::getPlannerInputStates(void) const
{
    return pis_;
}

void ompl::base::Planner::setup(void)
{
    if (!si_->isSetup())
    {
        msg_.inform("Space information setup was not yet called. Calling now.");
        si_->setup();
    }

    if (setup_)
        msg_.warn("Planner setup called multiple times");
    else
        setup_ = true;
}

void ompl::base::Planner::checkValidity(void)
{
    if (!isSetup())
        setup();
    pis_.checkValidity();
}

bool ompl::base::Planner::isSetup(void) const
{
    return setup_;
}

void ompl::base::Planner::clear(void)
{
    pis_.clear();
    pis_.update();
}

void ompl::base::Planner::getPlannerData(PlannerData &data) const
{
    data.si = si_;
}

bool ompl::base::Planner::solve(const PlannerTerminationConditionFn &ptc, double checkInterval)
{
    return solve(PlannerThreadedTerminationCondition(ptc, checkInterval));
}

bool ompl::base::Planner::solve(double solveTime)
{
    if (solveTime < 1.0)
        return solve(timedPlannerTerminationCondition(solveTime));
    else
        return solve(timedPlannerTerminationCondition(solveTime, std::min(solveTime / 100.0, 0.1)));
}

void ompl::base::Planner::printProperties(std::ostream &out) const
{
    out << "Planner " + getName() + " specs:" << std::endl;
    out << "Multithreaded:                 " << (getSpecs().multithreaded ? "Yes" : "No") << std::endl;
    out << "Reports approximate solutions: " << (getSpecs().approximateSolutions ? "Yes" : "No") << std::endl;
    out << "Can optimize solutions:        " << (getSpecs().optimizingPaths ? "Yes" : "No") << std::endl;
    out << "Aware of the following parameters:";
    std::vector<std::string> params;
    params_.getParamNames(params);
    for (unsigned int i = 0 ; i < params.size() ; ++i)
        out << " " << params[i];
    out << std::endl;
}

void ompl::base::Planner::printSettings(std::ostream &out) const
{
    out << "Declared parameters for planner " << getName() << ":" << std::endl;
    params_.print(out);
}

void ompl::base::PlannerInputStates::clear(void)
{
    if (tempState_)
    {
        si_->freeState(tempState_);
        tempState_ = NULL;
    }
    addedStartStates_ = 0;
    sampledGoalsCount_ = 0;
    pdef_ = NULL;
    si_ = NULL;
}

void ompl::base::PlannerInputStates::restart(void)
{
    addedStartStates_ = 0;
    sampledGoalsCount_ = 0;
}

bool ompl::base::PlannerInputStates::update(void)
{
    if (!planner_)
        throw Exception("No planner set for PlannerInputStates");
    return use(planner_->getSpaceInformation(), planner_->getProblemDefinition());
}

void ompl::base::PlannerInputStates::checkValidity(void) const
{
    std::string error;

    if (!pdef_)
        error = "Problem definition not specified";
    else
    {
        if (pdef_->getStartStateCount() <= 0)
            error = "No start states specified";
        else
            if (!pdef_->getGoal())
                error = "No goal specified";
    }

    if (!error.empty())
    {
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }
}

bool ompl::base::PlannerInputStates::use(const SpaceInformationPtr &si, const ProblemDefinitionPtr &pdef)
{
    if (si && pdef)
        return use(si.get(), pdef.get());
    else
    {
        clear();
        return true;
    }
}

bool ompl::base::PlannerInputStates::use(const SpaceInformation *si, const ProblemDefinition *pdef)
{
    if (pdef_ != pdef || si_ != si)
    {
        clear();
        pdef_ = pdef;
        si_ = si;
        return true;
    }
    return false;
}

const ompl::base::State* ompl::base::PlannerInputStates::nextStart(void)
{
    if (pdef_ == NULL || si_ == NULL)
    {
        std::string error = "Missing space information or problem definition";
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }

    while (addedStartStates_ < pdef_->getStartStateCount())
    {
        const base::State *st = pdef_->getStartState(addedStartStates_);
        addedStartStates_++;
        bool bounds = si_->satisfiesBounds(st);
        bool valid = bounds ? si_->isValid(st) : false;
        if (bounds && valid)
            return st;
        else
        {
            msg::Interface msg(planner_ ? planner_->getName() : "");
            msg.warn("Skipping invalid start state (invalid %s)", bounds ? "state": "bounds");
        }
    }
    return NULL;
}

const ompl::base::State* ompl::base::PlannerInputStates::nextGoal(void)
{
    static PlannerAlwaysTerminatingCondition ptc;
    return nextGoal(ptc);
}

const ompl::base::State* ompl::base::PlannerInputStates::nextGoal(const PlannerTerminationCondition &ptc)
{
    if (pdef_ == NULL || si_ == NULL)
    {
        std::string error = "Missing space information or problem definition";
        if (planner_)
            throw Exception(planner_->getName(), error);
        else
            throw Exception(error);
    }

    const GoalSampleableRegion *goal = dynamic_cast<const GoalSampleableRegion*>(pdef_->getGoal().get());

    if (goal)
    {
        bool first = true;
        bool attempt = true;
        while (attempt)
        {
            attempt = false;

            if (sampledGoalsCount_ < goal->maxSampleCount())
            {
                if (tempState_ == NULL)
                    tempState_ = si_->allocState();

                do
                {
                    goal->sampleGoal(tempState_);
                    sampledGoalsCount_++;
                    bool bounds = si_->satisfiesBounds(tempState_);
                    bool valid = bounds ? si_->isValid(tempState_) : false;
                    if (bounds && valid)
                        return tempState_;
                    else
                    {
                        msg::Interface msg(planner_ ? planner_->getName() : "");
                        msg.warn("Skipping invalid goal state (invalid %s)", bounds ? "state": "bounds");
                    }
                }
                while (sampledGoalsCount_ < goal->maxSampleCount() && !ptc());
            }

            if (goal->canSample() && !ptc())
            {
                if (first)
                {
                    first = false;
                    msg::Interface msg(planner_ ? planner_->getName() : "");
                    msg.debug("Waiting for goal region samples ...");
                }
                boost::this_thread::sleep(time::seconds(0.01));
                attempt = !ptc();
            }
        }
    }
    return NULL;
}

bool ompl::base::PlannerInputStates::haveMoreStartStates(void) const
{
    if (pdef_)
        return addedStartStates_ < pdef_->getStartStateCount();
    return false;
}

bool ompl::base::PlannerInputStates::haveMoreGoalStates(void) const
{
    if (pdef_ && pdef_->getGoal())
    {
        const GoalSampleableRegion *goal = dynamic_cast<const GoalSampleableRegion*>(pdef_->getGoal().get());
        if (goal)
            return sampledGoalsCount_ < goal->maxSampleCount();
    }
    return false;
}
<|endoftext|>