<commit_before>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <exception>
#include <vector>
#include <string>

#include "itkImage.h"
#include "itkImageFileReader.h"

namespace py = pybind11;

using namespace py::literals;

py::dict antsImageHeaderInfo( std::string fname )
{

  itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(
          fname.c_str(), itk::ImageIOFactory::ReadMode);

  imageIO->SetFileName(fname);
  imageIO->ReadImageInformation();

  const size_t numDimensions =  imageIO->GetNumberOfDimensions();
  const size_t numComponents = imageIO->GetNumberOfComponents();
  const std::string pixelClass( imageIO->GetPixelTypeAsString(imageIO->GetPixelType()) );
  const unsigned int pixelCode = imageIO->GetComponentType();

  std::vector<float> dimensions( numDimensions );
  std::vector<float> spacing( numDimensions );
  std::vector<float> origin( numDimensions );
  std::vector<std::vector<float> > direction( numDimensions, std::vector<float>(numDimensions) );

  for (unsigned int i=0; i<numDimensions; i++)
    {
    dimensions[i] = imageIO->GetDimensions(i);
    spacing[i] = imageIO->GetSpacing(i);
    origin[i] = imageIO->GetOrigin(i);
    for (unsigned int j=0; j<numDimensions; j++)
      {
      direction[i][j] = imageIO->GetDirection(i)[j];
      }
    }

  std::string pixeltype = "unknown";

  switch( pixelCode )
    {
    case itk::ImageIOBase::IOComponentType::UNKNOWNCOMPONENTTYPE: // UNKNOWNCOMPONENTTYPE - exception here?
      pixeltype = "unknown";
      break;
    case itk::ImageIOBase::IOComponentType::UCHAR: // UCHAR
      pixeltype = "unsigned char";
      break;
    case itk::ImageIOBase::IOComponentType::CHAR: // CHAR
      pixeltype = "char";
      break;
    case itk::ImageIOBase::IOComponentType::USHORT: // USHORT
      pixeltype = "unsigned short";
      break;
    case itk::ImageIOBase::IOComponentType::SHORT: // SHORT
      pixeltype = "short";
      break;
    case itk::ImageIOBase::IOComponentType::UINT: // UINT
      pixeltype = "unsigned int";
      break;
    case itk::ImageIOBase::IOComponentType::INT: // INT
      pixeltype = "int";
      break;
    case itk::ImageIOBase::IOComponentType::ULONG: // ULONG
      pixeltype = "unsigned long";
      break;
    case itk::ImageIOBase::IOComponentType::LONG: // LONG
      pixeltype = "long";
      break;
    case itk::ImageIOBase::IOComponentType::ULONGLONG: // LONGLONG
      pixeltype = "ulonglong";
      break;
    case itk::ImageIOBase::IOComponentType::LONGLONG: // LONGLONG
      pixeltype = "longlong";
      break;
    case itk::ImageIOBase::IOComponentType::FLOAT: // FLOAT
      pixeltype = "float";
      break;
    case itk::ImageIOBase::IOComponentType::DOUBLE: // DOUBLE
      pixeltype = "double";
      break;
    default:
      pixeltype = "invalid";
    }

  return py::dict("pixelclass"_a=pixelClass,
                  "pixeltype"_a=pixeltype,
                  "nDimensions"_a=numDimensions,
                  "nComponents"_a=numComponents,
                  "dimensions"_a=dimensions,
                  "spacing"_a=spacing,
                  "origin"_a=origin,
                  "direction"_a=direction);
}

PYBIND11_MODULE(antsImageHeaderInfo, m)
{
  m.def("antsImageHeaderInfo", &antsImageHeaderInfo);
}
<commit_msg>COMP: type for enum<commit_after>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include <exception>
#include <vector>
#include <string>

#include "itkImage.h"
#include "itkImageFileReader.h"

namespace py = pybind11;

using namespace py::literals;

py::dict antsImageHeaderInfo( std::string fname )
{

  itk::ImageIOBase::Pointer imageIO =
      itk::ImageIOFactory::CreateImageIO(
          fname.c_str(), itk::ImageIOFactory::ReadMode);

  imageIO->SetFileName(fname);
  imageIO->ReadImageInformation();

  const size_t numDimensions =  imageIO->GetNumberOfDimensions();
  const size_t numComponents = imageIO->GetNumberOfComponents();
  const std::string pixelClass( imageIO->GetPixelTypeAsString(imageIO->GetPixelType()) );
  itk::ImageIOBase::IOComponentEnum pixelCode = imageIO->GetComponentType();

  std::vector<float> dimensions( numDimensions );
  std::vector<float> spacing( numDimensions );
  std::vector<float> origin( numDimensions );
  std::vector<std::vector<float> > direction( numDimensions, std::vector<float>(numDimensions) );

  for (unsigned int i=0; i<numDimensions; i++)
    {
    dimensions[i] = imageIO->GetDimensions(i);
    spacing[i] = imageIO->GetSpacing(i);
    origin[i] = imageIO->GetOrigin(i);
    for (unsigned int j=0; j<numDimensions; j++)
      {
      direction[i][j] = imageIO->GetDirection(i)[j];
      }
    }

  std::string pixeltype = "unknown";

  switch( pixelCode )
    {
    case itk::ImageIOBase::IOComponentType::UNKNOWNCOMPONENTTYPE: // UNKNOWNCOMPONENTTYPE - exception here?
      pixeltype = "unknown";
      break;
    case itk::ImageIOBase::IOComponentType::UCHAR: // UCHAR
      pixeltype = "unsigned char";
      break;
    case itk::ImageIOBase::IOComponentType::CHAR: // CHAR
      pixeltype = "char";
      break;
    case itk::ImageIOBase::IOComponentType::USHORT: // USHORT
      pixeltype = "unsigned short";
      break;
    case itk::ImageIOBase::IOComponentType::SHORT: // SHORT
      pixeltype = "short";
      break;
    case itk::ImageIOBase::IOComponentType::UINT: // UINT
      pixeltype = "unsigned int";
      break;
    case itk::ImageIOBase::IOComponentType::INT: // INT
      pixeltype = "int";
      break;
    case itk::ImageIOBase::IOComponentType::ULONG: // ULONG
      pixeltype = "unsigned long";
      break;
    case itk::ImageIOBase::IOComponentType::LONG: // LONG
      pixeltype = "long";
      break;
    case itk::ImageIOBase::IOComponentType::ULONGLONG: // LONGLONG
      pixeltype = "ulonglong";
      break;
    case itk::ImageIOBase::IOComponentType::LONGLONG: // LONGLONG
      pixeltype = "longlong";
      break;
    case itk::ImageIOBase::IOComponentType::FLOAT: // FLOAT
      pixeltype = "float";
      break;
    case itk::ImageIOBase::IOComponentType::DOUBLE: // DOUBLE
      pixeltype = "double";
      break;
    default:
      pixeltype = "invalid";
    }

  return py::dict("pixelclass"_a=pixelClass,
                  "pixeltype"_a=pixeltype,
                  "nDimensions"_a=numDimensions,
                  "nComponents"_a=numComponents,
                  "dimensions"_a=dimensions,
                  "spacing"_a=spacing,
                  "origin"_a=origin,
                  "direction"_a=direction);
}

PYBIND11_MODULE(antsImageHeaderInfo, m)
{
  m.def("antsImageHeaderInfo", &antsImageHeaderInfo);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2009 Steven Noonan <steven@uplinklabs.net>
 *                and Miah Clayton <miah@ferrousmoon.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "universal_include.h"

#if defined ( TARGET_COMPILER_VC ) || defined ( TARGET_COMPILER_ICC )
#   pragma comment (lib, "unrar.lib")
#endif

#include "App/app.h"
#include "App/file_utils.h"
#include "App/resource.h"

#ifndef TARGET_OS_WINDOWS
inline static void strlwr ( char *_string )
{
    for ( char *p = _string; p && *p != '\0'; p++ )
        *p = tolower(*p);
}
#endif

Resource::Resource()
{
}

Resource::~Resource()
{
    Data::DArray<MemMappedFile *> *files = m_resourceFiles.ConvertToDArray();
    for ( size_t i = 0; i < files->size(); i++ )
    {
        if ( !files->valid ( i ) ) continue;
        delete files->get ( i );
    }
    delete files;
}

void Resource::ParseArchive ( const char *_dataFile, const char *_password )
{
    if (!FileExists( _dataFile))
        return;

    UncompressedArchive    *mainData = NULL;

    try
    {
        mainData = new UncompressedArchive(_dataFile, _password);
    }
    catch( ... )
    {
        return;
    }

    for (size_t i = 0; i < mainData->m_numFiles; ++i)
    {
        MemMappedFile *file = mainData->m_files[i];
        if (file->m_size > 0)
        {
            strlwr(file->m_filename);

            // Subsequent archives may override existing resources

            MemMappedFile *oldFile = m_resourceFiles.find(file->m_filename, NULL);
            if (oldFile) {
                m_resourceFiles.erase(file->m_filename);
                delete oldFile;
            }

            m_resourceFiles.insert(file->m_filename, file);
        }
    }

    delete mainData;
}

BinaryReader *Resource::GetBinaryReader ( char const *_filename )
{
    BinaryReader *reader = NULL;
    char fullFilename[256];

    // TODO: Implement moddability and themes, etc.
#if 0
    if ( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }
#endif

    if ( !reader )
    {
        sprintf( fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }

    if ( !reader )
    {
        if ( FileExists ( _filename ) ) reader = new BinaryFileReader(_filename);
    }

    if ( !reader )
    {
        MemMappedFile *mmfile = GetUncompressedFile(_filename);
        if (mmfile) reader = new BinaryDataReader(mmfile->m_data, mmfile->m_size, _filename);
    }

    return reader;
}

SDL_Surface *Resource::GetImage ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    SDL_Surface *surf = NULL;

    if ( !surf )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        surf = IMG_Load ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !surf && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        surf = IMG_Load_RW ( data, 0 );
        CrbReleaseAssert ( surf );
    }

    return surf;
}

#ifdef USE_SDLMIXER
Mix_Chunk *Resource::GetSound ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    Mix_Chunk *chunk = NULL;

    if ( !chunk )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        chunk = Mix_LoadWAV ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !chunk && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        chunk = Mix_LoadWAV_RW ( data, 0 );
    }

    return chunk;
}
#endif

TextReader *Resource::GetTextReader(char const *_filename)
{
    TextReader *reader = NULL;
    char fullFilename[256];

    fullFilename[0] = 0;

#if 0
    if( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if( DoesFileExist(fullFilename) )
            reader = new TextFileReader(fullFilename);

#ifdef TARGET_OS_VISTA
        // The Oberon build bundles the Perdition mod
        if( !reader )
        {
            sprintf( fullFilename, "mods/%s/%s", m_modName, _filename );
            if( DoesFileExist(fullFilename) )
                reader = new TextFileReader(fullFilename);
        }
#endif
    }
#endif

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        if ( FileExists ( fullFilename ) )
            reader = new TextFileReader(fullFilename);
    }

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        MemMappedFile *mmfile = GetUncompressedFile(fullFilename);
        if ( mmfile )
            reader = new TextDataReader((char*)mmfile->m_data, mmfile->m_size, fullFilename);
    }

    return reader;
}

MemMappedFile *Resource::GetUncompressedFile(char const *_filename)
{
	char           fullFilename[2048];

	MemMappedFile *file = NULL;

	if (!file) {
		file = m_resourceFiles.find(_filename, NULL);
	}

	if (!file) {
		sprintf(fullFilename, "%s", _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	if (!file) {
		sprintf(fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	return file;
}
<commit_msg>Resource: remove obsolete code in GetTextReader<commit_after>/*
 * Copyright (c) 2009 Steven Noonan <steven@uplinklabs.net>
 *                and Miah Clayton <miah@ferrousmoon.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "universal_include.h"

#if defined ( TARGET_COMPILER_VC ) || defined ( TARGET_COMPILER_ICC )
#   pragma comment (lib, "unrar.lib")
#endif

#include "App/app.h"
#include "App/file_utils.h"
#include "App/resource.h"

#ifndef TARGET_OS_WINDOWS
inline static void strlwr ( char *_string )
{
    for ( char *p = _string; p && *p != '\0'; p++ )
        *p = tolower(*p);
}
#endif

Resource::Resource()
{
}

Resource::~Resource()
{
    Data::DArray<MemMappedFile *> *files = m_resourceFiles.ConvertToDArray();
    for ( size_t i = 0; i < files->size(); i++ )
    {
        if ( !files->valid ( i ) ) continue;
        delete files->get ( i );
    }
    delete files;
}

void Resource::ParseArchive ( const char *_dataFile, const char *_password )
{
    if (!FileExists( _dataFile))
        return;

    UncompressedArchive    *mainData = NULL;

    try
    {
        mainData = new UncompressedArchive(_dataFile, _password);
    }
    catch( ... )
    {
        return;
    }

    for (size_t i = 0; i < mainData->m_numFiles; ++i)
    {
        MemMappedFile *file = mainData->m_files[i];
        if (file->m_size > 0)
        {
            strlwr(file->m_filename);

            // Subsequent archives may override existing resources

            MemMappedFile *oldFile = m_resourceFiles.find(file->m_filename, NULL);
            if (oldFile) {
                m_resourceFiles.erase(file->m_filename);
                delete oldFile;
            }

            m_resourceFiles.insert(file->m_filename, file);
        }
    }

    delete mainData;
}

BinaryReader *Resource::GetBinaryReader ( char const *_filename )
{
    BinaryReader *reader = NULL;
    char fullFilename[256];

    // TODO: Implement moddability and themes, etc.
#if 0
    if ( m_modName )
    {
        sprintf( fullFilename, "%smods/%s/%s", g_app->GetProfileDirectory(), m_modName, _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }
#endif

    if ( !reader )
    {
        sprintf( fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename );
        if ( FileExists ( fullFilename) ) reader = new BinaryFileReader(fullFilename);
    }

    if ( !reader )
    {
        if ( FileExists ( _filename ) ) reader = new BinaryFileReader(_filename);
    }

    if ( !reader )
    {
        MemMappedFile *mmfile = GetUncompressedFile(_filename);
        if (mmfile) reader = new BinaryDataReader(mmfile->m_data, mmfile->m_size, _filename);
    }

    return reader;
}

SDL_Surface *Resource::GetImage ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    SDL_Surface *surf = NULL;

    if ( !surf )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        surf = IMG_Load ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !surf && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        surf = IMG_Load_RW ( data, 0 );
        CrbReleaseAssert ( surf );
    }

    return surf;
}

#ifdef USE_SDLMIXER
Mix_Chunk *Resource::GetSound ( char const *_filename )
{
    char buffer[2048];
    MemMappedFile *memmap = NULL;
    Mix_Chunk *chunk = NULL;

    if ( !chunk )
    {
        sprintf ( buffer, "%s%s", g_app->GetResourcePath(), _filename );
        chunk = Mix_LoadWAV ( buffer );
    }

    memmap = GetUncompressedFile ( _filename );
    if ( !chunk && memmap )
    {
        SDL_RWops *data = SDL_RWFromMem ( memmap->m_data, memmap->m_size );
        chunk = Mix_LoadWAV_RW ( data, 0 );
    }

    return chunk;
}
#endif

TextReader *Resource::GetTextReader(char const *_filename)
{
    TextReader *reader = NULL;
    char fullFilename[256];

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        if ( FileExists ( fullFilename ) )
            reader = new TextFileReader(fullFilename);
    }

    if( !reader )
    {
        sprintf( fullFilename, "data/%s", _filename );
        MemMappedFile *mmfile = GetUncompressedFile(fullFilename);
        if ( mmfile )
            reader = new TextDataReader((char*)mmfile->m_data, mmfile->m_size, fullFilename);
    }

    return reader;
}

MemMappedFile *Resource::GetUncompressedFile(char const *_filename)
{
	char           fullFilename[2048];

	MemMappedFile *file = NULL;

	if (!file) {
		file = m_resourceFiles.find(_filename, NULL);
	}

	if (!file) {
		sprintf(fullFilename, "%s", _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	if (!file) {
		sprintf(fullFilename, "%s%s", g_app->GetApplicationSupportPath(), _filename);
		if (FileExists(fullFilename)) {
			IO::FileReader *fr = new IO::FileReader();
			fr->Open(fullFilename);
			size_t          len = fr->Length();

			file = new MemMappedFile(fullFilename, len);
			m_resourceFiles.insert(_filename, file);
			fr->ReadBlock((char *)file->m_data, len);
			fr->Close();
			delete fr;
		}
	}

	return file;
}
<|endoftext|>


<commit_before>#include <vector>
#include <deque>

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>

// Ros
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <lps/LPSRange.h>

#include <math.h>
#include <loligo/core/Options.h>
#include <loligo/core/Log.h>
#include <loligo/serial_cobs/Serial.h>
#include <loligo/core/StringUtils.h>
#include <loligo/serial_cobs/RangePacket.h>

static struct Option options[] =
{
    { "device",              OpType(OP_REQ),    "/dev/ttyUSB.tag*",
      "tty interface for lps, generally /dev/ttyUSBx"
    },
    { "device-speed",        OpType(OP_REQ),    "115200",
      "serial speed"
    },
    { "log-files",           OpType(OP_REQ),    "stdout",
      "comma separated list of files to send logging output"
    },
    { "log-level",           OpType(OP_REQ),    "verbose",
      "output messages up to this level"
    },
    { "map=<filename>",       OpType(OP_REQ),   "",
      "svg file to load map from"
    },
    { "help",                OpType(OP_NON),    "",
      "-show help message"},
    { "", 0, "", ""}
};

std::vector<Serial*> _s;

bool addSerialDevice(const string device, const string speed)
{
    if (!Serial::checkDeviceFile(device.c_str())) return false;
    Serial *s = new Serial('\0');
    if (!s->openDevice(device.c_str(), speed.c_str()))
    {
        delete s;
        return false;
    }
    _s.push_back(s);
    return true;
}

int main(int argc, char *argv[])
{
    Options opts(argc, argv, options);

    // initialize logging
    Log::init(&opts);

    if (opts("help"))
    {
        std::cerr << "lpsmonitor - monitor lps tags." << std::endl;
        std::cerr << "Options:" << std::endl;

        opts.printHelp(0);
        return 0;
    }

    ros::init(argc, argv, "lps_talker");

    ros::NodeHandle n;
    ros::Publisher lps_pub = n.advertise<lps::LPSRange>("lpsranges", 100);
    ros::Rate loop_rate(10);

    // Open serial ports
    std::vector<std::string> device = opts.getStrings("device");
    std::string speed = opts.getString("device-speed");
    for (unsigned i=0;i<device.size();i++)
    {
        string dev = device[i];

        // check for wildcards
        size_t wc_pos = dev.find("*");
        if (wc_pos != string::npos)
        {
            for (unsigned i=0;i<100;i++)
            {
                string devn = dev.substr(0, wc_pos) + StringUtils::stringf("%d", i);
                addSerialDevice(devn,speed);
            }
            continue;
        }

        addSerialDevice(dev,speed);
    }

    // Sleep to allow arduinos to exit bootloader
    ros::Duration(2.0).sleep();

    // If there are no serial devices, there's no point in running
    if (_s.size() == 0)
    {
        ROS_ERROR("No Serial devices to listen to, exiting");
        exit(2);
    }

    vector<int> stimeouts(_s.size(),0);
    char result[512];
    uint32_t count=0;
    while (ros::ok() && _s.size()>0)
    {
        Log::print(LOG_INFO, "Loop start\n");
        bool didsomething = false;
        for (unsigned i=0;i<_s.size();i++)
        {
            if (stimeouts[i]>10) continue;
            // Trigger transmission
            _s[i]->clearBuffers();
            ROS_INFO("Trigger %d",i);
            uint8_t d=0;_s[i]->write_bytes(&d,1);usleep(10000);

            if (!_s[i]->read_available())
            {
                ROS_INFO("Waiting for %d",i);
                if (_s[i]->wait_for_data(100) < 1)
                {
                    ROS_INFO("%d no data?\n",i);
                    //stimeouts[i]++;
                    continue;
                }
            }

            int n=30;
            while (n-->0)
            {
                result[0]=0xff;
                size_t plen = _s[i]->read_packet(result, sizeof(result)-1);
                if (plen == 0)
                {
                    _s[i]->wait_for_data(50);
                    continue;
                }
                if (plen < 0)
                {
                    ROS_INFO("plen<0");
                    continue;
                }
                ros::Time t = ros::Time::now();

                Packet p;
                bool preadok = p.readFrom((uint8_t*)result, plen);
                if (!preadok) continue;
                if (p.type() != PACKET_TYPE_RANGE) continue;

                RangePacket rp(p);
                ROS_INFO("%.2x->%.2x %6dmm %.1fdbm",rp.from(),rp.anchorid(),rp.dist(),rp.power());
                if (rp.anchorid() == 0xeeee) break;
                if (rp.anchorid() > 0xff) continue;

                lps::LPSRange rangemsg;
                rangemsg.header.stamp=t;
                rangemsg.header.seq=count++;
                rangemsg.tag_id=rp.from();
                rangemsg.dist_mm=rp.dist();
                rangemsg.anchor_id=rp.anchorid();
                rangemsg.power=rp.power();

                lps_pub.publish(rangemsg);
                didsomething = true;
            }
        }
        if (!didsomething)
            for (unsigned i=0;i<stimeouts.size();i++) stimeouts[i]--;

        ros::spinOnce();
        loop_rate.sleep();
    }

	return 0;
}

<commit_msg>tag->lps<commit_after>#include <vector>
#include <deque>

#include <stdio.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>

// Ros
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <lps/LPSRange.h>

#include <math.h>
#include <loligo/core/Options.h>
#include <loligo/core/Log.h>
#include <loligo/serial_cobs/Serial.h>
#include <loligo/core/StringUtils.h>
#include <loligo/serial_cobs/RangePacket.h>

static struct Option options[] =
{
    { "device",              OpType(OP_REQ),    "/dev/ttyUSB.lps*",
      "tty interface for lps, generally /dev/ttyUSBx"
    },
    { "device-speed",        OpType(OP_REQ),    "115200",
      "serial speed"
    },
    { "log-files",           OpType(OP_REQ),    "stdout",
      "comma separated list of files to send logging output"
    },
    { "log-level",           OpType(OP_REQ),    "verbose",
      "output messages up to this level"
    },
    { "map=<filename>",       OpType(OP_REQ),   "",
      "svg file to load map from"
    },
    { "help",                OpType(OP_NON),    "",
      "-show help message"},
    { "", 0, "", ""}
};

std::vector<Serial*> _s;

bool addSerialDevice(const string device, const string speed)
{
    if (!Serial::checkDeviceFile(device.c_str())) return false;
    Serial *s = new Serial('\0');
    if (!s->openDevice(device.c_str(), speed.c_str()))
    {
        delete s;
        return false;
    }
    _s.push_back(s);
    return true;
}

int main(int argc, char *argv[])
{
    Options opts(argc, argv, options);

    // initialize logging
    Log::init(&opts);

    if (opts("help"))
    {
        std::cerr << "lpsmonitor - monitor lps tags." << std::endl;
        std::cerr << "Options:" << std::endl;

        opts.printHelp(0);
        return 0;
    }

    ros::init(argc, argv, "lps_talker");

    ros::NodeHandle n;
    ros::Publisher lps_pub = n.advertise<lps::LPSRange>("lpsranges", 100);
    ros::Rate loop_rate(10);

    // Open serial ports
    std::vector<std::string> device = opts.getStrings("device");
    std::string speed = opts.getString("device-speed");
    for (unsigned i=0;i<device.size();i++)
    {
        string dev = device[i];

        // check for wildcards
        size_t wc_pos = dev.find("*");
        if (wc_pos != string::npos)
        {
            for (unsigned i=0;i<100;i++)
            {
                string devn = dev.substr(0, wc_pos) + StringUtils::stringf("%d", i);
                addSerialDevice(devn,speed);
            }
            continue;
        }

        addSerialDevice(dev,speed);
    }

    // Sleep to allow arduinos to exit bootloader
    ros::Duration(2.0).sleep();

    // If there are no serial devices, there's no point in running
    if (_s.size() == 0)
    {
        ROS_ERROR("No Serial devices to listen to, exiting");
        exit(2);
    }

    vector<int> stimeouts(_s.size(),0);
    char result[512];
    uint32_t count=0;
    while (ros::ok() && _s.size()>0)
    {
        Log::print(LOG_INFO, "Loop start\n");
        bool didsomething = false;
        for (unsigned i=0;i<_s.size();i++)
        {
            if (stimeouts[i]>10) continue;
            // Trigger transmission
            _s[i]->clearBuffers();
            ROS_INFO("Trigger %d",i);
            uint8_t d=0;_s[i]->write_bytes(&d,1);usleep(10000);

            if (!_s[i]->read_available())
            {
                ROS_INFO("Waiting for %d",i);
                if (_s[i]->wait_for_data(100) < 1)
                {
                    ROS_INFO("%d no data?\n",i);
                    //stimeouts[i]++;
                    continue;
                }
            }

            int n=30;
            while (n-->0)
            {
                result[0]=0xff;
                size_t plen = _s[i]->read_packet(result, sizeof(result)-1);
                if (plen == 0)
                {
                    _s[i]->wait_for_data(50);
                    continue;
                }
                if (plen < 0)
                {
                    ROS_INFO("plen<0");
                    continue;
                }
                ros::Time t = ros::Time::now();

                Packet p;
                bool preadok = p.readFrom((uint8_t*)result, plen);
                if (!preadok) continue;
                if (p.type() != PACKET_TYPE_RANGE) continue;

                RangePacket rp(p);
                ROS_INFO("%.2x->%.2x %6dmm %.1fdbm",rp.from(),rp.anchorid(),rp.dist(),rp.power());
                if (rp.anchorid() == 0xeeee) break;
                if (rp.anchorid() > 0xff) continue;

                lps::LPSRange rangemsg;
                rangemsg.header.stamp=t;
                rangemsg.header.seq=count++;
                rangemsg.tag_id=rp.from();
                rangemsg.dist_mm=rp.dist();
                rangemsg.anchor_id=rp.anchorid();
                rangemsg.power=rp.power();

                lps_pub.publish(rangemsg);
                didsomething = true;
            }
        }
        if (!didsomething)
            for (unsigned i=0;i<stimeouts.size();i++) stimeouts[i]--;

        ros::spinOnce();
        loop_rate.sleep();
    }

	return 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <stdint.h>

/* Comment out this line for a non-test network */
#define BTS_TEST_NETWORK
#define BTS_TEST_NETWORK_VERSION                            6 // autogenerated

/** @file bts/blockchain/config.hpp
 *  @brief Defines global constants that determine blockchain behavior
 */
#define BTS_BLOCKCHAIN_VERSION                              2
#define BTS_BLOCKCHAIN_DATABASE_VERSION                     6

/**
 *  The address prepended to string representation of
 *  addresses.
 *
 *  Changing these parameters will result in a hard fork.
 */
#define BTS_ADDRESS_PREFIX                                  "XTS"
#define BTS_BLOCKCHAIN_SYMBOL                               "XTS"
#define BTS_BLOCKCHAIN_NAME                                 "BitShares PLAY XTS"
#define BTS_BLOCKCHAIN_DESCRIPTION                          "BitShares PLAY Test Network"

#define BTS_BLOCKCHAIN_PRECISION                            100000
#define BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC       (60*60*24*2)
#define BTS_BLOCKCHAIN_MIN_YIELD_PERIOD_SEC                 (60*60*24) // 24 hours

#define BTS_BLOCKCHAIN_MIN_BURN_FEE                         BTS_BLOCKCHAIN_PRECISION * 1 // 1 XTS
#define BTS_BLOCKCHAIN_DEFAULT_RELAY_FEE                    10000 // XTS
#define BTS_BLOCKCHAIN_MINIMUM_SHORT_ORDER_SIZE             (BTS_BLOCKCHAIN_PRECISION*100)

#ifdef BTS_TEST_NETWORK
#define BTS_BLOCKCHAIN_MAX_SHORT_PERIOD_SEC                 (2*60*60) // 2 hours
#else
#define BTS_BLOCKCHAIN_MAX_SHORT_PERIOD_SEC                 (30*24*60*60) // 1 month
#endif

#ifdef BTS_TEST_NETWORK
#define BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC               10
#else
#define BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC               (60*60) // 1 hour
#endif

/**
 * The number of delegates that the blockchain is designed to support
 */
#define BTS_BLOCKCHAIN_HOUSE_EDGE                           (1) // 1% house edge
#define BTS_BLOCKCHAIN_NUM_DELEGATES                        uint32_t(101)
#define BTS_BLOCKCHAIN_MAX_SLATE_SIZE                       (BTS_BLOCKCHAIN_NUM_DELEGATES + (BTS_BLOCKCHAIN_NUM_DELEGATES/10))
#define BTS_BLOCKCHAIN_MIN_FEEDS                            ((BTS_BLOCKCHAIN_NUM_DELEGATES/2) + 1)
#define BTS_BLOCKCHAIN_MAX_UNDO_HISTORY                     (BTS_BLOCKCHAIN_NUM_DELEGATES*4)

#define BTS_BLOCKCHAIN_ENABLE_NEGATIVE_VOTES                false

#define BTS_MAX_DELEGATE_PAY_PER_BLOCK                      int64_t( 50 * BTS_BLOCKCHAIN_PRECISION ) // 50 XTS

/**
 * To prevent a delegate from producing blocks on split network,
 * we check the connection count.  This means no blocks get produced
 * until at least a minimum number of clients are on line.
 */
#define BTS_MIN_DELEGATE_CONNECTION_COUNT                   1

/**
 * Defines the number of seconds that should elapse between blocks
 */
#define BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC                   int64_t(10)

/**
 *  The maximum size of the raw data contained in the blockchain, this size is
 *  notional based upon the serilized size of all user-generated transactions in
 *  all blocks for one year.
 *
 *  Actual size on disk will likely be 2 or 3x this size due to indexes and other
 *  storeage overhead.
 *
 *  Adjusting this value will change the effective fee charged on transactions
 */
#define BTS_BLOCKCHAIN_MAX_SIZE                             (1024*1024*1024*int64_t(100)) // 100 GB
#define BTS_BLOCKCHAIN_MIN_NAME_SIZE                        1
#define BTS_BLOCKCHAIN_MAX_NAME_SIZE                        63
#define BTS_BLOCKCHAIN_MAX_NAME_DATA_SIZE                   (1024*64)
#define BTS_BLOCKCHAIN_MAX_MEMO_SIZE                        19 // bytes
#define BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE                      8 // characters
#define BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE                      3 // characters

/**
 *  The maximum amount that can be issued for user assets.
 *
 *  10^18 / 2^63 < 1  however, to support representing all share values as a double in
 *  languages like java script, we must stay within the epsilon so
 *
 *  10^15 / 2^53 < 1 allows all values to be represented as a double or an int64
 */
#define BTS_BLOCKCHAIN_MAX_SHARES                           (1000*1000*int64_t(1000)*1000*int64_t(1000))

/**
 * Initial shares read from the genesis block are scaled to this number. It is divided
 * by 100 so that new shares may be issued without exceeding BTS_BLOCKCHAIN_MAX_SHARES
 */
#define BTS_BLOCKCHAIN_INITIAL_SHARES                       (BTS_BLOCKCHAIN_MAX_SHARES/5)

/**
 *  The number of blocks expected per hour based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_HOUR                      ((60*60)/BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/**
 *  The number of blocks expected per day based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_DAY                       (BTS_BLOCKCHAIN_BLOCKS_PER_HOUR*int64_t(24))

/**
 * The number of blocks expected per year based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_YEAR                      (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*int64_t(365))

#define BTS_BLOCKCHAIN_AVERAGE_TRX_SIZE                     512 // just a random assumption used to calibrate TRX per SEC
#define BTS_BLOCKCHAIN_MAX_TRX_PER_SECOND                   1  // (10)
#define BTS_BLOCKCHAIN_MAX_PENDING_QUEUE_SIZE               10 // (BTS_BLOCKCHAIN_MAX_TRX_PER_SECOND * BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/** defines the maximum block size allowed, 2 MB per hour */
#define BTS_BLOCKCHAIN_MAX_BLOCK_SIZE                       (10 * BTS_BLOCKCHAIN_AVERAGE_TRX_SIZE * BTS_BLOCKCHAIN_MAX_PENDING_QUEUE_SIZE )

/**
    This constant defines the number of blocks a delegate must produce before
    they are expected to break even on registration costs with their earned income.

 *   Currently set to 2 hours of active block production to break even.
 */
#define BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE            (BTS_BLOCKCHAIN_BLOCKS_PER_DAY/12)

/**
    If you are going to create an asset, you expect that it will be used in transactions.  We would
    like to limit the issuance of assets that have no demand for transactions, so we charge a fee
    proportional to average transaction fees included in a block (AKA delegate pay).  This constant
    defines the number of blocks worth of transactions that justify the creation of a new asset.

    The fee is set such that the transactions of this asset alone could justify filling up 2 full weeks of
    block production.
 */
#define BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE               (BTS_BLOCKCHAIN_BLOCKS_PER_DAY * 14)
<commit_msg>change config for test branch the same with XTS<commit_after>#pragma once

#include <stdint.h>

/* Comment out this line for a non-test network */
#define BTS_TEST_NETWORK
#define BTS_TEST_NETWORK_VERSION                            6 // autogenerated

/** @file bts/blockchain/config.hpp
 *  @brief Defines global constants that determine blockchain behavior
 */
#define BTS_BLOCKCHAIN_VERSION                              109
#define BTS_BLOCKCHAIN_DATABASE_VERSION                     6

/**
 *  The address prepended to string representation of
 *  addresses.
 *
 *  Changing these parameters will result in a hard fork.
 */
#define BTS_ADDRESS_PREFIX                                  "XTS"
#define BTS_BLOCKCHAIN_SYMBOL                               "XTS"
#define BTS_BLOCKCHAIN_NAME                                 "BitShares XTS"
#define BTS_BLOCKCHAIN_DESCRIPTION                          "BitShares PLAY Test Network"

#define BTS_BLOCKCHAIN_PRECISION                            100000
#define BTS_BLOCKCHAIN_MAX_TRANSACTION_EXPIRATION_SEC       (60*60*24*2)
#define BTS_BLOCKCHAIN_MIN_YIELD_PERIOD_SEC                 (60*60*24) // 24 hours

#define BTS_BLOCKCHAIN_MIN_BURN_FEE                         BTS_BLOCKCHAIN_PRECISION * 1 // 1 XTS
#define BTS_BLOCKCHAIN_DEFAULT_RELAY_FEE                    10000 // XTS
#define BTS_BLOCKCHAIN_MINIMUM_SHORT_ORDER_SIZE             (BTS_BLOCKCHAIN_PRECISION*100)

#ifdef BTS_TEST_NETWORK
#define BTS_BLOCKCHAIN_MAX_SHORT_PERIOD_SEC                 (2*60*60) // 2 hours
#else
#define BTS_BLOCKCHAIN_MAX_SHORT_PERIOD_SEC                 (30*24*60*60) // 1 month
#endif

#ifdef BTS_TEST_NETWORK
#define BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC               10
#else
#define BTS_BLOCKCHAIN_VOTE_UPDATE_PERIOD_SEC               (60*60) // 1 hour
#endif

/**
 * The number of delegates that the blockchain is designed to support
 */
#define BTS_BLOCKCHAIN_HOUSE_EDGE                           (1) // 1% house edge
#define BTS_BLOCKCHAIN_NUM_DELEGATES                        uint32_t(101)
#define BTS_BLOCKCHAIN_MAX_SLATE_SIZE                       (BTS_BLOCKCHAIN_NUM_DELEGATES + (BTS_BLOCKCHAIN_NUM_DELEGATES/10))
#define BTS_BLOCKCHAIN_MIN_FEEDS                            ((BTS_BLOCKCHAIN_NUM_DELEGATES/2) + 1)
#define BTS_BLOCKCHAIN_MAX_UNDO_HISTORY                     (BTS_BLOCKCHAIN_NUM_DELEGATES*4)

#define BTS_BLOCKCHAIN_ENABLE_NEGATIVE_VOTES                false

#define BTS_MAX_DELEGATE_PAY_PER_BLOCK                      int64_t( 50 * BTS_BLOCKCHAIN_PRECISION ) // 50 XTS

/**
 * To prevent a delegate from producing blocks on split network,
 * we check the connection count.  This means no blocks get produced
 * until at least a minimum number of clients are on line.
 */
#define BTS_MIN_DELEGATE_CONNECTION_COUNT                   1

/**
 * Defines the number of seconds that should elapse between blocks
 */
#define BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC                   int64_t(10)

/**
 *  The maximum size of the raw data contained in the blockchain, this size is
 *  notional based upon the serilized size of all user-generated transactions in
 *  all blocks for one year.
 *
 *  Actual size on disk will likely be 2 or 3x this size due to indexes and other
 *  storeage overhead.
 *
 *  Adjusting this value will change the effective fee charged on transactions
 */
#define BTS_BLOCKCHAIN_MAX_SIZE                             (1024*1024*1024*int64_t(100)) // 100 GB
#define BTS_BLOCKCHAIN_MIN_NAME_SIZE                        1
#define BTS_BLOCKCHAIN_MAX_NAME_SIZE                        63
#define BTS_BLOCKCHAIN_MAX_NAME_DATA_SIZE                   (1024*64)
#define BTS_BLOCKCHAIN_MAX_MEMO_SIZE                        19 // bytes
#define BTS_BLOCKCHAIN_MAX_SYMBOL_SIZE                      8 // characters
#define BTS_BLOCKCHAIN_MIN_SYMBOL_SIZE                      3 // characters

/**
 *  The maximum amount that can be issued for user assets.
 *
 *  10^18 / 2^63 < 1  however, to support representing all share values as a double in
 *  languages like java script, we must stay within the epsilon so
 *
 *  10^15 / 2^53 < 1 allows all values to be represented as a double or an int64
 */
#define BTS_BLOCKCHAIN_MAX_SHARES                           (1000*1000*int64_t(1000)*1000*int64_t(1000))

/**
 * Initial shares read from the genesis block are scaled to this number. It is divided
 * by 100 so that new shares may be issued without exceeding BTS_BLOCKCHAIN_MAX_SHARES
 */
#define BTS_BLOCKCHAIN_INITIAL_SHARES                       (BTS_BLOCKCHAIN_MAX_SHARES/5)

/**
 *  The number of blocks expected per hour based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_HOUR                      ((60*60)/BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/**
 *  The number of blocks expected per day based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_DAY                       (BTS_BLOCKCHAIN_BLOCKS_PER_HOUR*int64_t(24))

/**
 * The number of blocks expected per year based upon the BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC
 */
#define BTS_BLOCKCHAIN_BLOCKS_PER_YEAR                      (BTS_BLOCKCHAIN_BLOCKS_PER_DAY*int64_t(365))

#define BTS_BLOCKCHAIN_AVERAGE_TRX_SIZE                     512 // just a random assumption used to calibrate TRX per SEC
#define BTS_BLOCKCHAIN_MAX_TRX_PER_SECOND                   1  // (10)
#define BTS_BLOCKCHAIN_MAX_PENDING_QUEUE_SIZE               10 // (BTS_BLOCKCHAIN_MAX_TRX_PER_SECOND * BTS_BLOCKCHAIN_BLOCK_INTERVAL_SEC)

/** defines the maximum block size allowed, 2 MB per hour */
#define BTS_BLOCKCHAIN_MAX_BLOCK_SIZE                       (10 * BTS_BLOCKCHAIN_AVERAGE_TRX_SIZE * BTS_BLOCKCHAIN_MAX_PENDING_QUEUE_SIZE )

/**
    This constant defines the number of blocks a delegate must produce before
    they are expected to break even on registration costs with their earned income.

 *   Currently set to 2 hours of active block production to break even.
 */
#define BTS_BLOCKCHAIN_DELEGATE_REGISTRATION_FEE            (BTS_BLOCKCHAIN_BLOCKS_PER_DAY/12)

/**
    If you are going to create an asset, you expect that it will be used in transactions.  We would
    like to limit the issuance of assets that have no demand for transactions, so we charge a fee
    proportional to average transaction fees included in a block (AKA delegate pay).  This constant
    defines the number of blocks worth of transactions that justify the creation of a new asset.

    The fee is set such that the transactions of this asset alone could justify filling up 2 full weeks of
    block production.
 */
#define BTS_BLOCKCHAIN_ASSET_REGISTRATION_FEE               (BTS_BLOCKCHAIN_BLOCKS_PER_DAY * 14)
<|endoftext|>


<commit_before>#include <fstream>
#include <sstream>

#include <glog/logging.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#define VISUAL

// Name of the main program window
static const std::string W_NAME = "WINDOW";

// Frequency in seconds to write frame to disk
size_t WRITE_FREQUENCY = 5;

std::string getUsage() {
    std::stringstream ss;
    ss << "Usage: <image> <min_area> <max_area>";
    return ss.str();
}

std::string getDesc() {
    std::stringstream ss;
    ss << "Description: All inputs should be normalized: [0, 1]";
    return ss.str();
}

int main(int argc, char** argv) {
    // Log to stderr instead of to the tmp directory
    FLAGS_logtostderr = 1;
    // Initiate Google Logging
    google::InitGoogleLogging(argv[0]);

    if (argc < 4) {
        LOG(ERROR) << "Not enough arguments:";
        LOG(ERROR) << getUsage();
        LOG(ERROR) << getDesc();
        exit(1);
    }

    // Read input values
    std::string img_filename = argv[1];
    double min_area = atoi(argv[2]);
    double max_area = atoi(argv[3]);

    // Blob Detection Params
    cv::SimpleBlobDetector::Params params;
    params.minDistBetweenBlobs = 100.0f;
    params.filterByInertia = false;
    params.filterByConvexity = false;
    params.filterByColor = true;
    params.blobColor = 255;
    params.filterByCircularity = false;
    params.filterByArea = true;
    params.minArea = min_area; //600
    params.maxArea = max_area; //7200

    cv::Ptr<cv::FeatureDetector> blob_detect = new cv::SimpleBlobDetector(params);
    blob_detect->create("BisonBlob");

    LOG(INFO) << "Checking for blobs in: '" << img_filename << "'";
    cv::Mat image = cv::imread(img_filename, CV_LOAD_IMAGE_COLOR);
    //cv::resize(image, image, cv::Size(2056,1028));

    if (image.empty()) {
        LOG(FATAL) << "Image failed to load...";
    }

#ifdef VISUAL
    cv::namedWindow(W_NAME, cv::WINDOW_NORMAL);
    //cv::imshow(W_NAME, image);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif

    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);

#ifdef VISUAL
    //cv::imshow(W_NAME, hsv);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif

    std::vector<cv::Mat> channels;
    cv::split(hsv, channels);
    cv::Mat hue = channels[0];
    cv::Mat thresh;
    cv::threshold(hue, thresh, 22, 255, cv::THRESH_BINARY_INV);
    std::vector<cv::KeyPoint> keypoints;
    blob_detect->detect(thresh, keypoints);
    LOG(INFO) << "Bison found: " << keypoints.size();

#ifdef VISUAL
    //cv::imshow(W_NAME, thresh);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif

    cv::Mat hsv_keypoints;
    drawKeypoints(thresh, keypoints, hsv_keypoints, cv::Scalar::all(-1), cv::DrawMatchesFlags::DEFAULT);

#ifdef VISUAL
    cv::imshow(W_NAME, hsv_keypoints);
    cv::waitKey(10000); // Wait for 5 seconds
#endif

#ifdef VISUAL
    cv::destroyWindow(W_NAME);
#endif
    return 0;
}
<commit_msg>Added mask to remove roads and dirt patches<commit_after>#include <fstream>
#include <sstream>

#include <glog/logging.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

#define VISUAL

// Name of the main program window
static const std::string W_NAME = "WINDOW";

// Frequency in seconds to write frame to disk
size_t WRITE_FREQUENCY = 5;

std::string getUsage() {
    std::stringstream ss;
    ss << "Usage: <image> <min_area> <max_area>";
    return ss.str();
}

std::string getDesc() {
    std::stringstream ss;
    ss << "Description: All inputs should be normalized: [0, 1]";
    return ss.str();
}

int main(int argc, char** argv) {
    // Log to stderr instead of to the tmp directory
    FLAGS_logtostderr = 1;
    // Initiate Google Logging
    google::InitGoogleLogging(argv[0]);

    if (argc < 4) {
        LOG(ERROR) << "Not enough arguments:";
        LOG(ERROR) << getUsage();
        LOG(ERROR) << getDesc();
        exit(1);
    }

    // Read input values
    std::string img_filename = argv[1];
    double min_area = atoi(argv[2]);
    double max_area = atoi(argv[3]);

    // Blob Detection Params
    cv::SimpleBlobDetector::Params params;
    params.minDistBetweenBlobs = 10.0f;
    params.filterByInertia = false;
    params.filterByConvexity = false;
    params.filterByColor = true;
    params.blobColor = 255;
    params.filterByCircularity = true;
    params.minCircularity = 0.1; //0.1
    params.maxCircularity = 0.9; //0.9
    params.filterByArea = true;
    params.minArea = min_area; //450
    params.maxArea = max_area; //9500

    cv::Ptr<cv::FeatureDetector> blob_detect = new cv::SimpleBlobDetector(params);
    blob_detect->create("BisonBlob");

    LOG(INFO) << "Checking for blobs in: '" << img_filename << "'";
    cv::Mat image = cv::imread(img_filename, CV_LOAD_IMAGE_COLOR);
    //cv::GaussianBlur(image, image, cv::Size(0, 0), 5);

    if (image.empty()) {
        LOG(FATAL) << "Image failed to load...";
    }

#ifdef VISUAL
    cv::namedWindow(W_NAME, cv::WINDOW_NORMAL);
    //cv::namedWindow("Hue", cv::WINDOW_NORMAL);
    //cv::namedWindow("Sat", cv::WINDOW_NORMAL);
    //cv::namedWindow("Val", cv::WINDOW_NORMAL);
    //cv::imshow(W_NAME, image);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif

    cv::Mat hsv;
    cv::cvtColor(image, hsv, CV_BGR2HSV);

#ifdef VISUAL
    //cv::imshow(W_NAME, hsv);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif

    std::vector<cv::Mat> channels;
    cv::split(hsv, channels);
    cv::Mat hue = channels[0];
    cv::Mat sat = channels[1];
    cv::Mat val = channels[2];
#ifdef VISUAL
    //cv::imshow("Hue", hue);
    //cv::imshow("Sat", sat);
    //cv::imshow("Val", val);
    //cv::waitKey(5000); // Wait for 5 seconds
#endif
    cv::Mat mask = cv::Mat::zeros(sat.size(), sat.type());
    mask = sat > 20;
    cv::Mat thresh;
    cv::threshold(hue, thresh, 22, 255, cv::THRESH_BINARY_INV);
    thresh = thresh & mask;
    std::vector<cv::KeyPoint> keypoints;
    blob_detect->detect(thresh, keypoints);
    LOG(INFO) << "Bison found: " << keypoints.size();

#ifdef VISUAL
    cv::imshow(W_NAME, mask);
    //cv::imshow(W_NAME, thresh);
    cv::waitKey(5000); // Wait for 5 seconds
#endif

    cv::Mat hsv_keypoints;
    drawKeypoints(thresh, keypoints, hsv_keypoints, cv::Scalar(255, 0, 0), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);

#ifdef VISUAL
    cv::imshow(W_NAME, hsv_keypoints);
    cv::waitKey(); // Wait for 5 seconds
#endif

#ifdef VISUAL
    cv::destroyWindow(W_NAME);
#endif
    return 0;
}
<|endoftext|>


<commit_before>// Copyright (2015) Gustav

#include "finans/core/commandline.h"

#include <cassert>
#include <algorithm>

namespace argparse {

  ParserError::ParserError(const std::string& error)
    : runtime_error("error: " + error), has_displayed_usage(false)
  {
  }

  void OnParserError(Running& running, const Parser* parser, ParserError& p) {
    if( p.has_displayed_usage == false ) {
      running.o << "Usage:";
      parser->WriteUsage(running);
      p.has_displayed_usage = true;
    }
  }

  Arguments::Arguments(int argc, char* argv[]) : name_(argv[0])
  {
    for (int i = 1; i < argc; ++i)
    {
      args_.push_back(argv[i]);
    }
  }
  Arguments::Arguments(const std::string& name, const std::vector<std::string>& args) : name_(name), args_(args) {
  }

  const std::string Arguments::operator[](int index) const
  {
    return args_[index];
  }
  const bool Arguments::is_empty() const
  {
    return args_.empty();
  }
  const std::string Arguments::name() const
  {
    return name_;
  }
  const size_t Arguments::size() const
  {
    return args_.size();
  }
  const std::string Arguments::ConsumeOne(const std::string& error)
  {
    if (is_empty()) throw ParserError(error);
    const std::string r = args_[0];
    args_.erase(args_.begin());
    return r;
  }

  Count::Count(size_t c)
    : count_(c)
    , type_(Const)
  {
  }

  Count::Count(Count::Type t)
    : count_(0)
    , type_(t)
  {
    assert(t != Const);
  }

  Count::Type Count::type() const
  {
    return type_;
  }
  size_t Count::count() const
  {
    return count_;
  }

  Running::Running(const std::string& aapp, std::ostream& ao, std::ostream& ae)
    : app(aapp)
    , o(ao)
    , e(ae)
    , quit(false)
  {
  }

  Argument::~Argument()
  {
  }

  Argument::Argument(const Count& co)
    : count_(co)
    , has_been_parsed_(false)
    , has_several_(false)
  {
  }

  bool Argument::has_been_parsed() const {
    return has_been_parsed_;
  }

  void Argument::set_has_been_parsed(bool v) {
    if (has_several_) return;
    has_been_parsed_ = v;
  }

  void Argument::ConsumeArguments(Running& r, Arguments& args, const std::string& argname) {
    switch (count_.type())
    {
    case Count::Const:
      for (size_t i = 0; i < count_.count(); ++i)
      {
        std::stringstream ss;
        ss << "argument " << argname << ": expected ";
        if (count_.count() == 1)
        {
          ss << "one argument";
        }
        else
        {
          ss << count_.count() << " argument(s), " << i << " already given";
        }
        OnArgument(r, args.ConsumeOne(ss.str()));

        // abort on optional?
      }
      return;
    case Count::MoreThanOne:
      OnArgument(r, args.ConsumeOne("argument " + argname + ": expected atleast one argument"));
      // fall through
    case Count::ZeroOrMore:
      while (args.is_empty() == false)
      {
        OnArgument(r, args.ConsumeOne("internal error"));
      }
      return;
    case Count::Optional:
      if (args.is_empty()) {
        OnArgument(r, "");
        return;
      }
      if (IsOptional(args[0])) {
        OnArgument(r, "");
        return;
      }
      OnArgument(r, args.ConsumeOne("internal error"));
      return;
    case Count::None:
      OnArgument(r, "");
      return;
    default:
      assert(0 && "internal error, ArgumentT::parse invalid Count");
      throw "internal error, ArgumentT::parse invalid Count";
    }
  }

  void Argument::set_has_several() {
    has_several_ = true;
  }

  bool IsOptional(const std::string& arg)
  {
    if (arg.empty()) return false; // todo: assert this?
    return arg[0] == '-';
  }

  Extra::Extra()
    : count_(1)
    , has_several_(false)
  {
  }

  Extra& Extra::help(const std::string& h)
  {
    help_ = h;
    return *this;
  }
  const std::string& Extra::help() const
  {
    return help_;
  }

  Extra& Extra::count(const Count c)
  {
    count_ = c;
    return *this;
  }
  const Count& Extra::count() const
  {
    return count_;
  }

  Extra& Extra::metavar(const std::string& metavar)
  {
    metaVar_ = metavar;
    return *this;
  }

  const std::string& Extra::metavar() const
  {
    return metaVar_;
  }

  Extra& Extra::several() {
    has_several_ = true;
    return *this;
  }
  bool Extra::has_several() const {
    return has_several_;
  }

  std::string ToUpper(const std::string& s)
  {
    std::string str = s;
    std::transform(str.begin(), str.end(), str.begin(), toupper);
    return str;
  }

  Help::Help(const std::string& name, const Extra& e)
    : name_(name)
    , help_(e.help())
    , metavar_(e.metavar())
    , count_(e.count().type())
    , countcount_(e.count().count())

  {
  }

  const std::string Help::GetUsage() const
  {
    if (IsOptional(name_))
    {
      const auto rep = GetMetavarReprestentation();
      if( rep.empty()) return "[" + name_ + "]";
      return "[" + name_ + " " + rep + "]";
    }
    else
    {
      return GetMetavarReprestentation();
    }
  }

  const std::string Help::GetMetavarReprestentation() const
  {
    switch (count_)
    {
    case Count::None:
      return "";
    case Count::MoreThanOne:
      return GetMetavarName() + " [" + GetMetavarName() + " ...]";
    case Count::Optional:
      return "[" + GetMetavarName() + "]";
    case Count::ZeroOrMore:
      return "[" + GetMetavarName() + " [" + GetMetavarName() + " ...]]";
    case Count::Const:
    {
      std::ostringstream ss;
      ss << "[";
      for (size_t i = 0; i < countcount_; ++i)
      {
        if (i != 0)
        {
          ss << " ";
        }
        ss << GetMetavarName();
      }
      ss << "]";
      return ss.str();
    }
    default:
      assert(false && "missing case");
      throw "invalid count type in " __FUNCTION__;
    }
  }

  const std::string Help::GetMetavarName() const
  {
    if (metavar_.empty() == false)
    {
      return metavar_;
    }
    else
    {
      if (IsOptional(name_))
      {
        return ToUpper(name_.substr(1));
      }
      else
      {
        return name_;
      }
    }
  }

  const std::string Help::GetHelpCommand() const
  {
    if (IsOptional(name_))
    {
      const auto meta = GetMetavarReprestentation();
      if (meta.empty()) {
        return name_;
      }
      else {
        return name_ + " " + meta;
      }
    }
    else
    {
      return GetMetavarName();
    }
  }

  const std::string& Help::help() const
  {
    return help_;
  }

  struct CallHelp : public Argument
  {
    CallHelp(Parser* on)
      : Argument( Count(Count::Optional) )
      , parser(on)
    {
    }

    void OnArgument(Running& r, const std::string& argname) override
    {
      parser->WriteHelp(r);
      r.quit = true;
    }

    Parser* parser;
  };

  class ParserChild : public Parser {
  public:
    ParserChild(const std::string& desc, const Parser* parent) : Parser(desc), parent_(parent) {}

    void WriteUsage(Running& r) const override {
      parent_->WriteUsage(r);
      Parser::WriteUsage(r);
    }

  private:
    const Parser* parent_;
  };

  Parser::Parser(const std::string& d, const std::string aappname)
    : positionalIndex_(0)
    , description_(d)
    , appname_(aappname)
    , sub_parsers_("subparser")
  {
    std::shared_ptr<Argument> arg(new CallHelp(this));
    AddArgument("-h", arg, Extra().count(Count(Count::None)).help("Show this help message and exit."));
  }

  Parser::ParseStatus Parser::ParseArgs(int argc, char* argv[], std::ostream& out, std::ostream& error) const
  {
    Arguments args(argc, argv);
    return ParseArgs(args, out, error);
  }

  void Parser::AddSubParser(const std::string& name, SubParser* parser) {
    sub_parsers_(name, parser);
  }

  Parser::ParseStatus Parser::ParseArgs(const Arguments& arguments, std::ostream& out, std::ostream& error) const {
    Arguments args = arguments;
    Running running(arguments.name(), out, error);

    try {
      return DoParseArgs(args, running);
    }
    catch (ParserError& p) {
      OnParserError(running, this, p);
      running.e << p.what() << "\n";
      running.o << "\n";
      return Parser::ParseStatus::ParseFailed;
    }
  }

  Parser::ParseStatus Parser::DoParseArgs(Arguments& args, Running& running) const {
    try
    {
      while (false == args.is_empty())
      {
        bool isParsed = false;
        const bool isParsingPositionals = positionalIndex_ < positionals_.size();

        if (IsOptional(args[0]))
        {
          // optional
          const std::string arg = args[0];
          Optionals::const_iterator r = optionals_.find(arg);
          if (r == optionals_.end())
          {
            if (isParsingPositionals == false) {
              throw ParserError("Unknown optional argument: " + arg); // todo: implement partial matching of arguments?
            }
          }
          else {
            if (false == r->second->has_been_parsed()) {
              isParsed = true;
              args.ConsumeOne(); // the optional command = arg[0}
              r->second->ConsumeArguments(running, args, arg);
              r->second->set_has_been_parsed(true);
              if (running.quit) return ParseStatus::ParseQuit;
            }
          }
        }

        bool consumed = false;

        if (isParsed == false) {
          if (positionalIndex_ >= positionals_.size())
          {
            if (sub_parsers_.empty()) {
              throw ParserError("All positional arguments have been consumed: " + args[0]);
            }
            else {
              std::string subname;
              SubParser* sub = sub_parsers_.Convert(args[0], &subname);
              sub_parser_used_ = subname;
              ParserChild parser(args[0], this);
              sub->AddParser(parser);
              consumed = true;
              args.ConsumeOne("SUBCOMMAND");
              try {
                return parser.DoParseArgs(args, running);
              }
              catch (ParserError& p) {
                OnParserError(running, &parser, p);
                running.e << "error: Failed to parse " << subname << ":\n";
                throw;
              }
            }
          }
          if (consumed == false) {
            ArgumentPtr p = positionals_[positionalIndex_];
            ++positionalIndex_;
            p->ConsumeArguments(running, args, "POSITIONAL"); // todo: give better name or something
          }
        }
      }

      if (positionalIndex_ != positionals_.size())
      {
        throw ParserError("too few arguments."); // todo: list a few missing arguments...
      }

      return ParseComplete;
    }
    catch (ParserError& p)
    {
      OnParserError(running, this, p);
      throw;
    }
  }

  void Parser::WriteHelp(Running& r) const
  {
    r.o << "Usage:";
    r.o << " " << (appname_.empty() ? r.app : appname_);
    WriteUsage(r);
    r.o << std::endl << description_ << std::endl << std::endl;

    const std::string sep = "\t";
    const std::string ins = "  ";

    if (helpPositional_.empty() == false)
    {
      r.o << "Positional arguments:" << std::endl;
      for (const Help& positional : helpPositional_)
      {
        r.o << ins << positional.GetHelpCommand();
        const auto h = positional.help();
        if (h.empty() == false) {
          r.o << sep << h;
        }
        r.o << std::endl;
      }

      r.o << std::endl;
    }

    if (helpOptional_.empty() == false)
    {
      r.o << "Optional arguments:" << std::endl;
      for (const Help& optional : helpOptional_)
      {
        r.o << ins << optional.GetHelpCommand();
        const auto h = optional.help();
        if( h.empty() == false) {
          r.o << sep << h;
        }
        r.o << std::endl;
      }
    }

    r.o << std::endl;
  }

  void Parser::WriteUsage(Running& r) const
  {
    for (const Help& optional : helpOptional_)
    {
      r.o << " " << optional.GetUsage();
    }

    if (false == sub_parsers_.empty()) {
      // if the sub-parser is set, use it instead of the array
      if (false == sub_parser_used_.empty()) {
        r.o << " " << sub_parser_used_;
      }
      else {
        const auto sp = sub_parsers_.names();
        r.o << " {";
        bool first = true;
        for (const auto& p : sp) {
          if (first == false) {
            r.o << "|";
          }
          first = false;
          r.o << p;
        }
        r.o << "}";
      }
    }

    for (const Help& positional : helpPositional_)
    {
      r.o << " " << positional.GetUsage();
    }
  }

  Parser& Parser::AddArgument(const std::string& commands, ArgumentPtr arg, const Extra& extra)
  {
    if( extra.has_several() ) {
      arg->set_has_several();
    }
    const auto names = Tokenize(commands, ",", true);
    std::string thename = "";
    for(const auto name: names) {
      if (IsOptional(name))
      {
        optionals_.insert(Optionals::value_type(name, arg));
        if (thename.empty()) thename = name.substr(1);
      }
      else
      {
        positionals_.push_back(arg);
        if( thename.empty() ) thename = name;
      }
    }
    Extra e = extra;
    if (e.metavar().empty()) {
      e.metavar(thename);
    }
    helpOptional_.push_back(Help(commands, e));
    return *this;
  }
}
<commit_msg>const isn't optional<commit_after>// Copyright (2015) Gustav

#include "finans/core/commandline.h"

#include <cassert>
#include <algorithm>

namespace argparse {

  ParserError::ParserError(const std::string& error)
    : runtime_error("error: " + error), has_displayed_usage(false)
  {
  }

  void OnParserError(Running& running, const Parser* parser, ParserError& p) {
    if( p.has_displayed_usage == false ) {
      running.o << "Usage:";
      parser->WriteUsage(running);
      p.has_displayed_usage = true;
    }
  }

  Arguments::Arguments(int argc, char* argv[]) : name_(argv[0])
  {
    for (int i = 1; i < argc; ++i)
    {
      args_.push_back(argv[i]);
    }
  }
  Arguments::Arguments(const std::string& name, const std::vector<std::string>& args) : name_(name), args_(args) {
  }

  const std::string Arguments::operator[](int index) const
  {
    return args_[index];
  }
  const bool Arguments::is_empty() const
  {
    return args_.empty();
  }
  const std::string Arguments::name() const
  {
    return name_;
  }
  const size_t Arguments::size() const
  {
    return args_.size();
  }
  const std::string Arguments::ConsumeOne(const std::string& error)
  {
    if (is_empty()) throw ParserError(error);
    const std::string r = args_[0];
    args_.erase(args_.begin());
    return r;
  }

  Count::Count(size_t c)
    : count_(c)
    , type_(Const)
  {
  }

  Count::Count(Count::Type t)
    : count_(0)
    , type_(t)
  {
    assert(t != Const);
  }

  Count::Type Count::type() const
  {
    return type_;
  }
  size_t Count::count() const
  {
    return count_;
  }

  Running::Running(const std::string& aapp, std::ostream& ao, std::ostream& ae)
    : app(aapp)
    , o(ao)
    , e(ae)
    , quit(false)
  {
  }

  Argument::~Argument()
  {
  }

  Argument::Argument(const Count& co)
    : count_(co)
    , has_been_parsed_(false)
    , has_several_(false)
  {
  }

  bool Argument::has_been_parsed() const {
    return has_been_parsed_;
  }

  void Argument::set_has_been_parsed(bool v) {
    if (has_several_) return;
    has_been_parsed_ = v;
  }

  void Argument::ConsumeArguments(Running& r, Arguments& args, const std::string& argname) {
    switch (count_.type())
    {
    case Count::Const:
      for (size_t i = 0; i < count_.count(); ++i)
      {
        std::stringstream ss;
        ss << "argument " << argname << ": expected ";
        if (count_.count() == 1)
        {
          ss << "one argument";
        }
        else
        {
          ss << count_.count() << " argument(s), " << i << " already given";
        }
        OnArgument(r, args.ConsumeOne(ss.str()));

        // abort on optional?
      }
      return;
    case Count::MoreThanOne:
      OnArgument(r, args.ConsumeOne("argument " + argname + ": expected atleast one argument"));
      // fall through
    case Count::ZeroOrMore:
      while (args.is_empty() == false)
      {
        OnArgument(r, args.ConsumeOne("internal error"));
      }
      return;
    case Count::Optional:
      if (args.is_empty()) {
        OnArgument(r, "");
        return;
      }
      if (IsOptional(args[0])) {
        OnArgument(r, "");
        return;
      }
      OnArgument(r, args.ConsumeOne("internal error"));
      return;
    case Count::None:
      OnArgument(r, "");
      return;
    default:
      assert(0 && "internal error, ArgumentT::parse invalid Count");
      throw "internal error, ArgumentT::parse invalid Count";
    }
  }

  void Argument::set_has_several() {
    has_several_ = true;
  }

  bool IsOptional(const std::string& arg)
  {
    if (arg.empty()) return false; // todo: assert this?
    return arg[0] == '-';
  }

  Extra::Extra()
    : count_(1)
    , has_several_(false)
  {
  }

  Extra& Extra::help(const std::string& h)
  {
    help_ = h;
    return *this;
  }
  const std::string& Extra::help() const
  {
    return help_;
  }

  Extra& Extra::count(const Count c)
  {
    count_ = c;
    return *this;
  }
  const Count& Extra::count() const
  {
    return count_;
  }

  Extra& Extra::metavar(const std::string& metavar)
  {
    metaVar_ = metavar;
    return *this;
  }

  const std::string& Extra::metavar() const
  {
    return metaVar_;
  }

  Extra& Extra::several() {
    has_several_ = true;
    return *this;
  }
  bool Extra::has_several() const {
    return has_several_;
  }

  std::string ToUpper(const std::string& s)
  {
    std::string str = s;
    std::transform(str.begin(), str.end(), str.begin(), toupper);
    return str;
  }

  Help::Help(const std::string& name, const Extra& e)
    : name_(name)
    , help_(e.help())
    , metavar_(e.metavar())
    , count_(e.count().type())
    , countcount_(e.count().count())

  {
  }

  const std::string Help::GetUsage() const
  {
    if (IsOptional(name_))
    {
      const auto rep = GetMetavarReprestentation();
      if( rep.empty()) return "[" + name_ + "]";
      return "[" + name_ + " " + rep + "]";
    }
    else
    {
      return GetMetavarReprestentation();
    }
  }

  const std::string Help::GetMetavarReprestentation() const
  {
    switch (count_)
    {
    case Count::None:
      return "";
    case Count::MoreThanOne:
      return GetMetavarName() + " [" + GetMetavarName() + " ...]";
    case Count::Optional:
      return "[" + GetMetavarName() + "]";
    case Count::ZeroOrMore:
      return "[" + GetMetavarName() + " [" + GetMetavarName() + " ...]]";
    case Count::Const:
    {
      std::ostringstream ss;
      for (size_t i = 0; i < countcount_; ++i)
      {
        if (i != 0)
        {
          ss << " ";
        }
        ss << GetMetavarName();
      }
      return ss.str();
    }
    default:
      assert(false && "missing case");
      throw "invalid count type in " __FUNCTION__;
    }
  }

  const std::string Help::GetMetavarName() const
  {
    if (metavar_.empty() == false)
    {
      return metavar_;
    }
    else
    {
      if (IsOptional(name_))
      {
        return ToUpper(name_.substr(1));
      }
      else
      {
        return name_;
      }
    }
  }

  const std::string Help::GetHelpCommand() const
  {
    if (IsOptional(name_))
    {
      const auto meta = GetMetavarReprestentation();
      if (meta.empty()) {
        return name_;
      }
      else {
        return name_ + " " + meta;
      }
    }
    else
    {
      return GetMetavarName();
    }
  }

  const std::string& Help::help() const
  {
    return help_;
  }

  struct CallHelp : public Argument
  {
    CallHelp(Parser* on)
      : Argument( Count(Count::Optional) )
      , parser(on)
    {
    }

    void OnArgument(Running& r, const std::string& argname) override
    {
      parser->WriteHelp(r);
      r.quit = true;
    }

    Parser* parser;
  };

  class ParserChild : public Parser {
  public:
    ParserChild(const std::string& desc, const Parser* parent) : Parser(desc), parent_(parent) {}

    void WriteUsage(Running& r) const override {
      parent_->WriteUsage(r);
      Parser::WriteUsage(r);
    }

  private:
    const Parser* parent_;
  };

  Parser::Parser(const std::string& d, const std::string aappname)
    : positionalIndex_(0)
    , description_(d)
    , appname_(aappname)
    , sub_parsers_("subparser")
  {
    std::shared_ptr<Argument> arg(new CallHelp(this));
    AddArgument("-h", arg, Extra().count(Count(Count::None)).help("Show this help message and exit."));
  }

  Parser::ParseStatus Parser::ParseArgs(int argc, char* argv[], std::ostream& out, std::ostream& error) const
  {
    Arguments args(argc, argv);
    return ParseArgs(args, out, error);
  }

  void Parser::AddSubParser(const std::string& name, SubParser* parser) {
    sub_parsers_(name, parser);
  }

  Parser::ParseStatus Parser::ParseArgs(const Arguments& arguments, std::ostream& out, std::ostream& error) const {
    Arguments args = arguments;
    Running running(arguments.name(), out, error);

    try {
      return DoParseArgs(args, running);
    }
    catch (ParserError& p) {
      OnParserError(running, this, p);
      running.e << p.what() << "\n";
      running.o << "\n";
      return Parser::ParseStatus::ParseFailed;
    }
  }

  Parser::ParseStatus Parser::DoParseArgs(Arguments& args, Running& running) const {
    try
    {
      while (false == args.is_empty())
      {
        bool isParsed = false;
        const bool isParsingPositionals = positionalIndex_ < positionals_.size();

        if (IsOptional(args[0]))
        {
          // optional
          const std::string arg = args[0];
          Optionals::const_iterator r = optionals_.find(arg);
          if (r == optionals_.end())
          {
            if (isParsingPositionals == false) {
              throw ParserError("Unknown optional argument: " + arg); // todo: implement partial matching of arguments?
            }
          }
          else {
            if (false == r->second->has_been_parsed()) {
              isParsed = true;
              args.ConsumeOne(); // the optional command = arg[0}
              r->second->ConsumeArguments(running, args, arg);
              r->second->set_has_been_parsed(true);
              if (running.quit) return ParseStatus::ParseQuit;
            }
          }
        }

        bool consumed = false;

        if (isParsed == false) {
          if (positionalIndex_ >= positionals_.size())
          {
            if (sub_parsers_.empty()) {
              throw ParserError("All positional arguments have been consumed: " + args[0]);
            }
            else {
              std::string subname;
              SubParser* sub = sub_parsers_.Convert(args[0], &subname);
              sub_parser_used_ = subname;
              ParserChild parser(args[0], this);
              sub->AddParser(parser);
              consumed = true;
              args.ConsumeOne("SUBCOMMAND");
              try {
                return parser.DoParseArgs(args, running);
              }
              catch (ParserError& p) {
                OnParserError(running, &parser, p);
                running.e << "error: Failed to parse " << subname << ":\n";
                throw;
              }
            }
          }
          if (consumed == false) {
            ArgumentPtr p = positionals_[positionalIndex_];
            ++positionalIndex_;
            p->ConsumeArguments(running, args, "POSITIONAL"); // todo: give better name or something
          }
        }
      }

      if (positionalIndex_ != positionals_.size())
      {
        throw ParserError("too few arguments."); // todo: list a few missing arguments...
      }

      return ParseComplete;
    }
    catch (ParserError& p)
    {
      OnParserError(running, this, p);
      throw;
    }
  }

  void Parser::WriteHelp(Running& r) const
  {
    r.o << "Usage:";
    r.o << " " << (appname_.empty() ? r.app : appname_);
    WriteUsage(r);
    r.o << std::endl << description_ << std::endl << std::endl;

    const std::string sep = "\t";
    const std::string ins = "  ";

    if (helpPositional_.empty() == false)
    {
      r.o << "Positional arguments:" << std::endl;
      for (const Help& positional : helpPositional_)
      {
        r.o << ins << positional.GetHelpCommand();
        const auto h = positional.help();
        if (h.empty() == false) {
          r.o << sep << h;
        }
        r.o << std::endl;
      }

      r.o << std::endl;
    }

    if (helpOptional_.empty() == false)
    {
      r.o << "Optional arguments:" << std::endl;
      for (const Help& optional : helpOptional_)
      {
        r.o << ins << optional.GetHelpCommand();
        const auto h = optional.help();
        if( h.empty() == false) {
          r.o << sep << h;
        }
        r.o << std::endl;
      }
    }

    r.o << std::endl;
  }

  void Parser::WriteUsage(Running& r) const
  {
    for (const Help& optional : helpOptional_)
    {
      r.o << " " << optional.GetUsage();
    }

    if (false == sub_parsers_.empty()) {
      // if the sub-parser is set, use it instead of the array
      if (false == sub_parser_used_.empty()) {
        r.o << " " << sub_parser_used_;
      }
      else {
        const auto sp = sub_parsers_.names();
        r.o << " {";
        bool first = true;
        for (const auto& p : sp) {
          if (first == false) {
            r.o << "|";
          }
          first = false;
          r.o << p;
        }
        r.o << "}";
      }
    }

    for (const Help& positional : helpPositional_)
    {
      r.o << " " << positional.GetUsage();
    }
  }

  Parser& Parser::AddArgument(const std::string& commands, ArgumentPtr arg, const Extra& extra)
  {
    if( extra.has_several() ) {
      arg->set_has_several();
    }
    const auto names = Tokenize(commands, ",", true);
    std::string thename = "";
    for(const auto name: names) {
      if (IsOptional(name))
      {
        optionals_.insert(Optionals::value_type(name, arg));
        if (thename.empty()) thename = name.substr(1);
      }
      else
      {
        positionals_.push_back(arg);
        if( thename.empty() ) thename = name;
      }
    }
    Extra e = extra;
    if (e.metavar().empty()) {
      e.metavar(thename);
    }
    helpOptional_.push_back(Help(commands, e));
    return *this;
  }
}
<|endoftext|>