<commit_before>/*
** Author(s):
**  - Laurent LEC <llec@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <iostream>
#include <iomanip>
#include <istream>
#include <sstream>

#include <qitype/genericobject.hpp>
#include <qi/future.hpp>
#include <qimessaging/session.hpp>

qi::Session session;
std::map<const std::string, qi::ObjectPtr> services;

typedef std::vector<std::string> command;

static int calcOffsetMethod(const qi::MetaObject::MethodMap &mmaps) {
  qi::MetaObject::MethodMap::const_iterator it;
  int max = 0;
  for (it = mmaps.begin(); it != mmaps.end(); ++it) {
    int cur = it->second.sigreturn().size();
    if (cur > max)
      max = cur;
  }
  return max;
}

/****************
*    SERVICE    *
****************/
static void cmd_service(const command           &cmd,
                        command::const_iterator &it)
{
  if (it == cmd.end())
  {
    std::cerr << "service: not enough parameters" << std::endl;
    return;
  }

  std::vector<qi::ServiceInfo> servs = session.services();
  for (unsigned int i = 0; i < servs.size(); ++i)
  {
    if (servs[i].name() != *it)
      continue;
    std::cout << servs[i].name() << std::endl
              << "  id:       " << servs[i].serviceId() << std::endl
              << "  machine:  " << servs[i].machineId() << std::endl
              << "  process:  " << servs[i].processId() << std::endl
              << "  endpoints:" << std::endl;
    for (std::vector<std::string>::const_iterator it2 = servs[i].endpoints().begin();
         it2 != servs[i].endpoints().end();
         ++it2)
    {
      std::cout << "    " << *it2 << std::endl;
    }

    std::cout << "  methods:" << std::endl;
    qi::Future<qi::ObjectPtr> fut = session.service(*it);
    if (fut.hasError()) {
      std::cerr << "service: could not get object: " << fut.error() << std::endl;
      continue;
    }

    qi::ObjectPtr obj = fut.value();
    services[*it] = obj;

    const qi::MetaObject &mobj = obj->metaObject();
    qi::MetaObject::MethodMap methods = mobj.methodMap();
    int offset = calcOffsetMethod(methods);
    qi::MetaObject::MethodMap::const_iterator it2;
    for (it2 = methods.begin(); it2 != methods.end(); ++it2) {
      std::cout << "    " << std::right << std::setfill('0') << std::setw(3) << it2->second.uid() << std::setw(0) << " "
                << std::left << std::setfill(' ') << std::setw(offset) << it2->second.sigreturn() << std::setw(0)
                << " " << it2->second.signature() << std::endl;
    }
    std::cout << "  events:" << std::endl;
    qi::MetaObject::SignalMap events = mobj.signalMap();
    qi::MetaObject::SignalMap::const_iterator it3;
    for (it3 = events.begin(); it3 != events.end(); ++it3) {
      std::cout << "    " << std::right << std::setfill('0') << std::setw(3) << it3->second.uid() << std::setw(0) << " "
                << std::left << std::setfill(' ') << std::setw(offset) << "" << std::setw(0)
                << " " << it3->second.signature() << std::endl;
    }
  }
}

/****************
*    SERVICES   *
****************/
static void cmd_services(const command           &cmd,
                         command::const_iterator &QI_UNUSED(it))
{
  bool enum_all = false;
  if (std::find(cmd.begin(), cmd.end(), "-v") != cmd.end())
    enum_all = true;
  std::vector<qi::ServiceInfo> servs = session.services();
  for (unsigned int i = 0; i < servs.size(); ++i)
  {
    std::cout << "[" << servs[i].serviceId() << "] "
              << servs[i].name() << std::endl;
    if (enum_all) {
      command ncmd;
      command::const_iterator it;

      ncmd.push_back(servs[i].name());
      it = ncmd.begin();
      cmd_service(ncmd, it);
      std::cout << std::endl;
    }
  }
}

/****************
*    SESSION    *
****************/
static void cmd_session(const command           &cmd,
                        command::const_iterator &it)
{
  if (it == cmd.end())
  {
    std::cerr << "session: not enough parameters" << std::endl;
    return;
  }

  if (*it == "connect")
  {
    ++it;
    if (it == cmd.end())
    {
      std::cerr << "session connect: not enough parameters" << std::endl;
      return;
    }
    else
    {
      session.connect(*it);
    }
  }
  else if (*it == "services")
  {
    ++it;
    std::vector<qi::ServiceInfo> servs = session.services();
    for (unsigned int i = 0; i < servs.size(); ++i)
    {
      std::cout << "[" << servs[i].serviceId() << "] "
                << servs[i].name() << std::endl;
    }
  }
  else
  {
    std::cerr << "unexpected token: " << *it << std::endl;
  }
}

static void execute(const command &cmd)
{
  command::const_iterator it = cmd.begin();

  if (it == cmd.end())
  {
    return;
  }

  if (*it == "session")
  {
    cmd_session(cmd, ++it);
  }
  else if (*it == "service")
  {
    cmd_service(cmd, ++it);
  }
  else if (*it == "services")
  {
    cmd_services(cmd, ++it);
  }
  else
  {
    std::cerr << "unexpected token: " << *it << std::endl;
  }
}

static void from_stdin()
{
  char line[8192];

  std::cout << "% ";
  while (std::cin.getline(line, sizeof(line)))
  {
    std::stringstream ssin(line, std::stringstream::in);
    command cmd;
    std::string input;

    while (ssin >> input)
    {
      cmd.push_back(input);
    }

    execute(cmd);

    std::cout << "% ";
  }
}

static void from_argv(int   argc,
                      char *argv[])
{
  command cmd;

  session.connect(argv[1]);

  for (int i = 2;
       i < argc;
       ++i)
  {
    cmd.push_back(argv[i]);
  }

  execute(cmd);
}

static void usage(char *argv0)
{
  std::cout << "Usage: " << argv0 << " [ADDRESS CMD]" << std::endl;
  std::cout << "  connect ADDRESS" << std::endl
            << "  services [-v]" << std::endl
            << "  service SERVICE" << std::endl;
}

int main(int argc, char *argv[])
{
  if (argc == 2 &&
      (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0))
  {
    usage(argv[0]);
    return (0);
  }

  if (argc == 1)
  {
    from_stdin();
  }
  else
  {
    from_argv(argc, argv);
  }

  session.close();
  return (0);
}
<commit_msg>qicli: use qi::details::printMetaObject<commit_after>/*
** Author(s):
**  - Laurent LEC <llec@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <iostream>
#include <iomanip>
#include <istream>
#include <sstream>

#include <qitype/genericobject.hpp>
#include <qi/future.hpp>
#include <qimessaging/session.hpp>

qi::Session session;
std::map<const std::string, qi::ObjectPtr> services;

typedef std::vector<std::string> command;

static int calcOffsetMethod(const qi::MetaObject::MethodMap &mmaps) {
  qi::MetaObject::MethodMap::const_iterator it;
  int max = 0;
  for (it = mmaps.begin(); it != mmaps.end(); ++it) {
    int cur = it->second.sigreturn().size();
    if (cur > max)
      max = cur;
  }
  return max;
}

/****************
*    SERVICE    *
****************/
static void cmd_service(const command           &cmd,
                        command::const_iterator &it)
{
  if (it == cmd.end())
  {
    std::cerr << "service: not enough parameters" << std::endl;
    return;
  }

  std::vector<qi::ServiceInfo> servs = session.services();
  for (unsigned int i = 0; i < servs.size(); ++i)
  {
    if (servs[i].name() != *it)
      continue;
    std::cout << servs[i].name() << std::endl
              << "  id:       " << servs[i].serviceId() << std::endl
              << "  machine:  " << servs[i].machineId() << std::endl
              << "  process:  " << servs[i].processId() << std::endl
              << "  endpoints:" << std::endl;
    for (std::vector<std::string>::const_iterator it2 = servs[i].endpoints().begin();
         it2 != servs[i].endpoints().end();
         ++it2)
    {
      std::cout << "    " << *it2 << std::endl;
    }

    qi::Future<qi::ObjectPtr> fut = session.service(*it);
    if (fut.hasError()) {
      std::cerr << "service: could not get object: " << fut.error() << std::endl;
      continue;
    }

    qi::ObjectPtr obj = fut.value();
    services[*it] = obj;

    qi::details::printMetaObject(std::cout, obj->metaObject());
  }
}

/****************
*    SERVICES   *
****************/
static void cmd_services(const command           &cmd,
                         command::const_iterator &QI_UNUSED(it))
{
  bool enum_all = false;
  if (std::find(cmd.begin(), cmd.end(), "-v") != cmd.end())
    enum_all = true;
  std::vector<qi::ServiceInfo> servs = session.services();
  for (unsigned int i = 0; i < servs.size(); ++i)
  {
    if (enum_all) {
      command ncmd;
      command::const_iterator it;

      ncmd.push_back(servs[i].name());
      it = ncmd.begin();
      cmd_service(ncmd, it);
      std::cout << std::endl;
      continue;
    }
    std::cout << "[" << servs[i].serviceId() << "] "
              << servs[i].name() << std::endl;

  }
}

/****************
*    SESSION    *
****************/
static void cmd_session(const command           &cmd,
                        command::const_iterator &it)
{
  if (it == cmd.end())
  {
    std::cerr << "session: not enough parameters" << std::endl;
    return;
  }

  if (*it == "connect")
  {
    ++it;
    if (it == cmd.end())
    {
      std::cerr << "session connect: not enough parameters" << std::endl;
      return;
    }
    else
    {
      session.connect(*it);
    }
  }
  else if (*it == "services")
  {
    ++it;
    std::vector<qi::ServiceInfo> servs = session.services();
    for (unsigned int i = 0; i < servs.size(); ++i)
    {
      std::cout << "[" << servs[i].serviceId() << "] "
                << servs[i].name() << std::endl;
    }
  }
  else
  {
    std::cerr << "unexpected token: " << *it << std::endl;
  }
}

static void execute(const command &cmd)
{
  command::const_iterator it = cmd.begin();

  if (it == cmd.end())
  {
    return;
  }

  if (*it == "session")
  {
    cmd_session(cmd, ++it);
  }
  else if (*it == "service")
  {
    cmd_service(cmd, ++it);
  }
  else if (*it == "services")
  {
    cmd_services(cmd, ++it);
  }
  else
  {
    std::cerr << "unexpected token: " << *it << std::endl;
  }
}

static void from_stdin()
{
  char line[8192];

  std::cout << "% ";
  while (std::cin.getline(line, sizeof(line)))
  {
    std::stringstream ssin(line, std::stringstream::in);
    command cmd;
    std::string input;

    while (ssin >> input)
    {
      cmd.push_back(input);
    }

    execute(cmd);

    std::cout << "% ";
  }
}

static void from_argv(int   argc,
                      char *argv[])
{
  command cmd;

  session.connect(argv[1]);

  for (int i = 2;
       i < argc;
       ++i)
  {
    cmd.push_back(argv[i]);
  }

  execute(cmd);
}

static void usage(char *argv0)
{
  std::cout << "Usage: " << argv0 << " [ADDRESS CMD]" << std::endl;
  std::cout << "  connect ADDRESS" << std::endl
            << "  services [-v]" << std::endl
            << "  service SERVICE" << std::endl;
}

int main(int argc, char *argv[])
{
  if (argc == 2 &&
      (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0))
  {
    usage(argv[0]);
    return (0);
  }

  if (argc == 1)
  {
    from_stdin();
  }
  else
  {
    from_argv(argc, argv);
  }

  session.close();
  return (0);
}
<|endoftext|>


<commit_before>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Driver.h"
#include "Error.h"
#include "Symbols.h"
#include "llvm/Support/FileOutputBuffer.h"
#include <memory>

using namespace llvm;

const int PageSize = 4096;
const uint8_t Magic[32] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";

void lld::coff::createPDB(StringRef Path) {
  // Create a file.
  size_t FileSize = PageSize * 3;
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufOrErr =
      FileOutputBuffer::create(Path, FileSize);
  error(BufOrErr, Twine("failed to open ") + Path);
  std::unique_ptr<FileOutputBuffer> Buf = std::move(*BufOrErr);

  // Write the file magic.
  uint8_t *P = Buf->getBufferStart();
  memcpy(P, Magic, sizeof(Magic));
}
<commit_msg>COFF: Create an empty but valid PDF file.<commit_after>//===- PDB.cpp ------------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Driver.h"
#include "Error.h"
#include "Symbols.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/FileOutputBuffer.h"
#include <memory>

using namespace llvm;
using namespace llvm::support;
using namespace llvm::support::endian;

const int PageSize = 4096;
const uint8_t Magic[32] = "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0";

namespace {
struct PDBHeader {
  uint8_t Magic[32];
  ulittle32_t PageSize;
  ulittle32_t FpmPage;
  ulittle32_t PageCount;
  ulittle32_t RootSize;
  ulittle32_t Reserved;
  ulittle32_t RootPointer;
};
}

void lld::coff::createPDB(StringRef Path) {
  // Create a file.
  size_t FileSize = PageSize * 3;
  ErrorOr<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
      FileOutputBuffer::create(Path, FileSize);
  error(BufferOrErr, Twine("failed to open ") + Path);
  std::unique_ptr<FileOutputBuffer> Buffer = std::move(*BufferOrErr);

  // Write the file header.
  uint8_t *Buf = Buffer->getBufferStart();
  auto *Hdr = reinterpret_cast<PDBHeader *>(Buf);
  memcpy(Hdr->Magic, Magic, sizeof(Magic));
  Hdr->PageSize = PageSize;
  // I don't know what FpmPage field means, but it must not be 0.
  Hdr->FpmPage = 1;
  Hdr->PageCount = FileSize / PageSize;
  // Root directory is empty, containing only the length field.
  Hdr->RootSize = 4;
  // Root directory is on page 1.
  Hdr->RootPointer = 1;

  // Write the root directory. Root stream is on page 2.
  write32le(Buf + PageSize, 2);
  Buffer->commit();
}
<|endoftext|>


<commit_before>#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <errno.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdlib.h>
#include <cstdlib>

using namespace std;

void stringParse(string usrinput, vector<string> &vec)
{
	char *cstr = new char[usrinput.size()+1];
	strcpy(cstr,usrinput.c_str());
	char *pch = strtok(cstr, " ");
	while(pch != NULL)
	{
		vec.push_back(pch);
		pch = strtok(NULL, " ");
	}
}

void executeCommands(const char *path, char** in, bool ampersand)
{
	int pid;
	if((pid = fork()) == -1)
		perror("fork failed");
	if(pid == 0)
	{
		if(-1 == execv(path, in))
			perror("exevp failed");
	}
	if(!ampersand)
	{
		if(wait(0) == -1)
			perror("wait failed");
	}
}

void parsepath(char *path, vector<string> &p)
{
	string parsedpath;
	int i;
	for(i = 0; path[i] != '\0'; ++i)
	{
		if(path[i] == ':')
		{
			p.push_back(parsedpath);
			parsedpath = "";
		}
		else
			parsedpath += path[i];

	}
	parsedpath += path[i];
	p.push_back(parsedpath);

}

void changec(int i)
{
	signal(SIGINT,SIG_IGN);
	cout << endl;
}

int main()
{
	string input;
	bool amper = false;
	vector<string> strvec;
	vector<string> pathvec;
	vector<string> concatpath;
	char *temp = getenv("PATH");
	if(temp == NULL)
		perror("no path");
//	char *temp2;
//	char *temp3;
	char *concatstrpath;
	string concatstrpath2;
	string correctpath;
	int openInt = 0;
	string cd = "cd";

	while(1)
	{
		cout << "$ ";
		getline(cin, input);
		if(SIG_ERR == signal(SIGINT,changec))
			perror("signal failed");
		if(input == "exit")
			break;
		stringParse(input, strvec);
		for(unsigned int i = 0; i < strvec.size(); ++i)
		{
			if(strvec.at(i) == "&")
				amper = true;
			if(strvec.at(i) == "#")
				strvec.erase(strvec.begin()+i,strvec.end());

		}

		char **usrIn = new char *[strvec.size()+1];
		for(unsigned int i = 0; i < strvec.size(); ++i)
		{
			usrIn[i] = new char[strvec.at(i).size()+1];
			strcpy(usrIn[i], strvec.at(i).c_str());
		}
		usrIn[strvec.size()] = '\0';
		if(strcmp(usrIn[0],cd.c_str()) == 0)
		{
			char *abpath = new char[1024];
			if(usrIn[1] != NULL)
			{
				if(getcwd(abpath,1024) == NULL)
					perror("getcwd failed");
				strcat(abpath,"/");
				strcat(abpath,usrIn[1]);
				cout << abpath << endl;
				if(chdir(abpath) == -1)
					perror("directory change failed");
			}
			else
			{
				char *home = getenv("HOME");
				if(home == NULL)
					perror("getenv failed");
//				cout << home << endl;
				if(chdir(home) == -1)
					perror("directory change failed");
			}
		}
		else
		{

			parsepath(temp,pathvec);

			for(unsigned int i = 0; i < pathvec.size(); ++i)
			{
				char buf[1024];
				strcpy(buf,pathvec.at(i).c_str());
				buf[pathvec.at(i).size()+1] = '\0';
				concatstrpath = strncat(buf,"/",1024);
				concatstrpath2 = strncat(concatstrpath, usrIn[0],1024);
				concatpath.push_back(concatstrpath2);

				if((openInt = open(concatpath.at(i).c_str(), O_RDONLY)) != -1)
				{
					correctpath = concatpath.at(i);
					break;
				}
			}
			if(openInt == -1)
				perror("open failed");
			char **fin = new char *[1024];
			unsigned int j;
			for(j = 0; usrIn[j] != '\0'; ++j)
			{
				fin[j] = new char[1024];
				strcpy(fin[j],usrIn[j]);
			}
			fin[j] = '\0';
			executeCommands(correctpath.c_str(), fin, amper);
			delete [] fin;
		}
		for(unsigned int i = 0; i < strvec.size(); ++i)
			delete usrIn[i];
		strvec.clear();
		delete [] usrIn;
		input = "";
		correctpath = "";
		pathvec.clear();
		concatpath.clear();
	}

}
<commit_msg>everything works<commit_after>#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <errno.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/param.h>
#include <stdlib.h>
#include <cstdlib>

using namespace std;

void stringParse(string usrinput, vector<string> &vec)
{
	char *cstr = new char[usrinput.size()+1];
	strcpy(cstr,usrinput.c_str());
	char *pch = strtok(cstr, " ");
	while(pch != NULL)
	{
		vec.push_back(pch);
		pch = strtok(NULL, " ");
	}
}

void executeCommands(const char *path, char** in, bool ampersand)
{
	int pid;
	if((pid = fork()) == -1)
		perror("fork failed");
	if(pid == 0)
	{
		if(-1 == execv(path, in))
			perror("exevp failed");
	}
	if(!ampersand)
	{
		if(wait(0) == -1)
			perror("wait failed");
	}
}

void parsepath(char *path, vector<string> &p)
{
	string parsedpath;
	int i;
	for(i = 0; path[i] != '\0'; ++i)
	{
		if(path[i] == ':')
		{
			p.push_back(parsedpath);
			parsedpath = "";
		}
		else
			parsedpath += path[i];

	}
	parsedpath += path[i];
	p.push_back(parsedpath);

}

void changec(int i)
{
	signal(SIGINT,SIG_IGN);
	cout << endl;
}

int main()
{
	string input;
	bool amper = false;
	vector<string> strvec;
	vector<string> pathvec;
	vector<string> concatpath;
	char *temp = getenv("PATH");
	if(temp == NULL)
		perror("no path");
//	char *temp2;
//	char *temp3;
	char *concatstrpath;
	string concatstrpath2;
	string correctpath;
	int openInt = 0;
	string cd = "cd";

	while(1)
	{
		cout << "$ ";
		getline(cin, input);
		if(input != "")
		{
			if(SIG_ERR == signal(SIGINT,changec))
				perror("signal failed");

			if(input == "exit")
				exit(1);
			stringParse(input, strvec);
			for(unsigned int i = 0; i < strvec.size(); ++i)
			{
				if(strvec.at(i) == "&")
					amper = true;
				if(strvec.at(i) == "#")
					strvec.erase(strvec.begin()+i,strvec.end());

			}

			char **usrIn = new char *[strvec.size()+1];
			for(unsigned int i = 0; i < strvec.size(); ++i)
			{
				usrIn[i] = new char[strvec.at(i).size()+1];
				strcpy(usrIn[i], strvec.at(i).c_str());
			}
			usrIn[strvec.size()] = '\0';
			if(strcmp(usrIn[0],cd.c_str()) == 0)
			{
				char *abpath = new char[1024];
				if(usrIn[1] != NULL)
				{
					if(getcwd(abpath,1024) == NULL)
						perror("getcwd failed");
					strcat(abpath,"/");
					strcat(abpath,usrIn[1]);
					cout << abpath << endl;
					if(chdir(abpath) == -1)
						perror("directory change failed");
				}
				else
				{
					char *home = getenv("HOME");
					if(home == NULL)
						perror("getenv failed");
//				cout << home << endl;
					if(chdir(home) == -1)
						perror("directory change failed");
				}
			}
			else
			{

				parsepath(temp,pathvec);

				for(unsigned int i = 0; i < pathvec.size(); ++i)
				{
					char buf[1024];
					strcpy(buf,pathvec.at(i).c_str());
					buf[pathvec.at(i).size()+1] = '\0';
					concatstrpath = strncat(buf,"/",1024);
					concatstrpath2 = strncat(concatstrpath, usrIn[0],1024);
					concatpath.push_back(concatstrpath2);

					if((openInt = open(concatpath.at(i).c_str(), O_RDONLY)) != -1)
					{
						correctpath = concatpath.at(i);
						break;
					}
				}
				if(openInt == -1)
					perror("open failed");
				char **fin = new char *[1024];
				unsigned int j;
				for(j = 0; usrIn[j] != '\0'; ++j)
				{
					fin[j] = new char[1024];
					strcpy(fin[j],usrIn[j]);
				}
				fin[j] = '\0';
				executeCommands(correctpath.c_str(), fin, amper);
				delete [] fin;
			}
			for(unsigned int i = 0; i < strvec.size(); ++i)
				delete usrIn[i];
			strvec.clear();
			delete [] usrIn;
			input = "";
			correctpath = "";
			pathvec.clear();
			concatpath.clear();
		}
	}

}
<|endoftext|>


<commit_before>// Copyright Daniel Wallin 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef LUABIND_INSTANCE_HOLDER_081024_HPP
# define LUABIND_INSTANCE_HOLDER_081024_HPP

# include <luabind/detail/inheritance.hpp>
# include <luabind/pointer_traits.hpp>
# include <luabind/typeid.hpp>
# include <stdexcept>

namespace luabind {
	namespace detail {

		class instance_holder
		{
		public:
			instance_holder(bool pointee_const)
			  : m_pointee_const(pointee_const)
			{}

			virtual ~instance_holder()
			{}

			virtual std::pair<void*, int> get(cast_graph const& casts, class_id target) const = 0;
			virtual void release() = 0;

			bool pointee_const() const
			{
				return m_pointee_const;
			}

		private:
			bool m_pointee_const;
		};

		template <class P, class Pointee = void const>
		class pointer_holder : public instance_holder
		{
		public:
			pointer_holder( P p, class_id dynamic_id, void* dynamic_ptr ) :
				instance_holder( detail::is_pointer_to_const<P>() ),
				p(std::move(p)), weak(0), dynamic_id(dynamic_id), dynamic_ptr(dynamic_ptr)
			{
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const
			{
				// if somebody wants the smart-ptr, he can get a reference to it
				if (target == registered_class<P>::id) return std::pair<void*, int>(&this->p, 0);

				void* naked_ptr = const_cast<void*>(static_cast<void const*>(weak ? weak : get_pointer(p)));
				if (!naked_ptr) return std::pair<void*, int>(nullptr, 0);

				typedef typename std::remove_cv<typename std::remove_reference<decltype(*get_pointer(p))>::type>::type pointee_type;

				return casts.cast( naked_ptr,
								  registered_class< pointee_type >::id
								  , target, dynamic_id, dynamic_ptr );
			}

			explicit operator bool() const
			{
				return p ? true : false;
			}

			void release()
			{
				weak = const_cast<void*>(static_cast<void const*>(get_pointer(p)));
				release_ownership(p);
			}

		private:
			mutable P p;
			// weak will hold a possibly stale pointer to the object owned
			// by p once p has released it's owership. This is a workaround
			// to make adopt() work with virtual function wrapper classes.
			void* weak;
			class_id dynamic_id;
			void* dynamic_ptr;
		};

		template <class ValueType>
		class value_holder :
			public instance_holder
		{
		public:
			// No need for dynamic_id / dynamic_ptr, since we always get the most derived type
            value_holder(lua_State* /*L*/, ValueType val)
				: instance_holder(false), val_(std::move(val))
			{}

			explicit operator bool() const
			{
				return true;
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const
			{
				const auto this_id = registered_class<ValueType>::id;
				void* const naked_ptr = const_cast<void*>((const void*)&val_);
				if(target==this_id) return std::pair<void*, int>(naked_ptr, 0);
				return casts.cast(naked_ptr, this_id, target, this_id, naked_ptr);
			}

			void release() override
			{}

		private:
			ValueType val_;
		};

		/*
			Pointer types should automatically convert to reference types
		*/
		template <class ValueType>
		class pointer_like_holder :
			public instance_holder
		{
		public:
			// No need for dynamic_id / dynamic_ptr, since we always get the most derived type
            pointer_like_holder(lua_State* /*L*/, ValueType val, class_id dynamic_id, void* dynamic_ptr)
				:
				instance_holder(std::is_const< decltype(*get_pointer(val)) >::value),
				val_(std::move(val)),
				dynamic_id_(dynamic_id),
				dynamic_ptr_(dynamic_ptr)
			{
			}

			explicit operator bool() const
			{
				return val_ ? true : false;
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const
			{
				const auto value_id = registered_class<ValueType>::id;
				void* const naked_value_ptr = const_cast<void*>((const void*) &val_);
				if(target==value_id) return std::pair<void*, int>(naked_value_ptr, 0);
				// If we were to support automatic pointer conversion, this would be the place

				typedef typename std::remove_cv<typename std::remove_reference<decltype(*get_pointer(val_))>::type >::type pointee_type;
				const auto pointee_id = registered_class< pointee_type >::id;
				void* const naked_pointee_ptr = const_cast<void*>((const void*) get_pointer(val_));
				return casts.cast(naked_pointee_ptr, pointee_id, target, dynamic_id_, dynamic_ptr_);
			}

			void release() override
			{}

		private:
			ValueType val_;
			class_id dynamic_id_;
			void* dynamic_ptr_;
			// weak? must understand what the comment up there really means
		};

	}

} // namespace luabind::detail

#endif // LUABIND_INSTANCE_HOLDER_081024_HPP

<commit_msg>Added missing overrides in instance_holder.hpp<commit_after>// Copyright Daniel Wallin 2008. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef LUABIND_INSTANCE_HOLDER_081024_HPP
# define LUABIND_INSTANCE_HOLDER_081024_HPP

# include <luabind/detail/inheritance.hpp>
# include <luabind/pointer_traits.hpp>
# include <luabind/typeid.hpp>
# include <stdexcept>

namespace luabind {
	namespace detail {

		class instance_holder
		{
		public:
			instance_holder(bool pointee_const)
			  : m_pointee_const(pointee_const)
			{}

			virtual ~instance_holder()
			{}

			virtual std::pair<void*, int> get(cast_graph const& casts, class_id target) const = 0;
			virtual void release() = 0;

			bool pointee_const() const
			{
				return m_pointee_const;
			}

		private:
			bool m_pointee_const;
		};

		template <class P, class Pointee = void const>
		class pointer_holder : public instance_holder
		{
		public:
			pointer_holder( P p, class_id dynamic_id, void* dynamic_ptr ) :
				instance_holder( detail::is_pointer_to_const<P>() ),
				p(std::move(p)), weak(0), dynamic_id(dynamic_id), dynamic_ptr(dynamic_ptr)
			{
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const override
			{
				// if somebody wants the smart-ptr, he can get a reference to it
				if (target == registered_class<P>::id) return std::pair<void*, int>(&this->p, 0);

				void* naked_ptr = const_cast<void*>(static_cast<void const*>(weak ? weak : get_pointer(p)));
				if (!naked_ptr) return std::pair<void*, int>(nullptr, 0);

				typedef typename std::remove_cv<typename std::remove_reference<decltype(*get_pointer(p))>::type>::type pointee_type;

				return casts.cast( naked_ptr,
								  registered_class< pointee_type >::id
								  , target, dynamic_id, dynamic_ptr );
			}

			explicit operator bool() const
			{
				return p ? true : false;
			}

			void release()
			{
				weak = const_cast<void*>(static_cast<void const*>(get_pointer(p)));
				release_ownership(p);
			}

		private:
			mutable P p;
			// weak will hold a possibly stale pointer to the object owned
			// by p once p has released it's owership. This is a workaround
			// to make adopt() work with virtual function wrapper classes.
			void* weak;
			class_id dynamic_id;
			void* dynamic_ptr;
		};

		template <class ValueType>
		class value_holder :
			public instance_holder
		{
		public:
			// No need for dynamic_id / dynamic_ptr, since we always get the most derived type
            value_holder(lua_State* /*L*/, ValueType val)
				: instance_holder(false), val_(std::move(val))
			{}

			explicit operator bool() const
			{
				return true;
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const override
			{
				const auto this_id = registered_class<ValueType>::id;
				void* const naked_ptr = const_cast<void*>((const void*)&val_);
				if(target==this_id) return std::pair<void*, int>(naked_ptr, 0);
				return casts.cast(naked_ptr, this_id, target, this_id, naked_ptr);
			}

			void release() override
			{}

		private:
			ValueType val_;
		};

		/*
			Pointer types should automatically convert to reference types
		*/
		template <class ValueType>
		class pointer_like_holder :
			public instance_holder
		{
		public:
			// No need for dynamic_id / dynamic_ptr, since we always get the most derived type
            pointer_like_holder(lua_State* /*L*/, ValueType val, class_id dynamic_id, void* dynamic_ptr)
				:
				instance_holder(std::is_const< decltype(*get_pointer(val)) >::value),
				val_(std::move(val)),
				dynamic_id_(dynamic_id),
				dynamic_ptr_(dynamic_ptr)
			{
			}

			explicit operator bool() const
			{
				return val_ ? true : false;
			}

			std::pair<void*, int> get(cast_graph const& casts, class_id target) const override
			{
				const auto value_id = registered_class<ValueType>::id;
				void* const naked_value_ptr = const_cast<void*>((const void*) &val_);
				if(target==value_id) return std::pair<void*, int>(naked_value_ptr, 0);
				// If we were to support automatic pointer conversion, this would be the place

				typedef typename std::remove_cv<typename std::remove_reference<decltype(*get_pointer(val_))>::type >::type pointee_type;
				const auto pointee_id = registered_class< pointee_type >::id;
				void* const naked_pointee_ptr = const_cast<void*>((const void*) get_pointer(val_));
				return casts.cast(naked_pointee_ptr, pointee_id, target, dynamic_id_, dynamic_ptr_);
			}

			void release() override
			{}

		private:
			ValueType val_;
			class_id dynamic_id_;
			void* dynamic_ptr_;
			// weak? must understand what the comment up there really means
		};

	}

} // namespace luabind::detail

#endif // LUABIND_INSTANCE_HOLDER_081024_HPP

<|endoftext|>


<commit_before>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of loaddap.

// Copyright (c) 2005 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPYRIGHT URI/MIT 1996
// Please read the full copyright statement in the file COPYRIGH.
//
// Authors:
//      jhrg,jimg       James Gallagher (jgallagher@gso.uri.edu)

// Implementation for ClientStr. See ClientByte.cc
//
// jhrg 9/25/96

#include <assert.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

#include "config_writedap.h"	// was first caused LITTLE_ENDIAN error

#include <iostream>
#include <string>

#include <GNURegex.h>

#include "InternalErr.h"
#include "ClientStr.h"
#include "name_map.h"

// We *should* be using <nan.h> to handle generating NaN. However, many
// machines don't have a function that can be used to generate NaN so I've
// written my own (which uses its own bastardized version of the FP union).
// 2/5/97 jhrg

#include "nan_hack.h"

static double
MakeNaN()
{
    dnan X;
    X.nan.exponent = 0x7ff;
    X.nan.qnan_bit = 0x1;

    return X.d;
}

extern name_map names;
extern bool translate;
extern bool ascii;
extern bool string_to_float;
extern bool verbose;
extern bool warning;

Str *
NewStr(const string &n)
{
    return new ClientStr(n);
}

ClientStr::ClientStr(const string &n) : Str(n)
{
    set_matlab_name(n);
}

BaseType *
ClientStr::ptr_duplicate()
{
    return new ClientStr(*this);
}

bool
ClientStr::read(const string &)
{
  throw InternalErr(__FILE__, __LINE__, "Called unimplemented read method");
}

void
ClientStr::print_val(FILE *os, string, bool print_decl_p)
{
    bool print_as_float = false;
    double val = 0.0;

    // Translate all string variables to Floats. jhrg 1/9/98.
    if (string_to_float) {
	char *ptr = NULL;
	const char *str = _buf.c_str();
	val = strtod(str, &ptr);
	print_as_float = !(val == 0.0 && (ptr == str));

	if (!print_as_float) {
	    val = MakeNaN();
	    print_as_float = true;
	    if (warning) {
		cerr << "Could not translate `" << _buf << "' to a Float64,"
		     << endl;
		cerr << "interning as NaN (not a number: " << val
		     << ")" << endl;
	    }
	}
    }

    if (print_as_float) {
	if (print_decl_p)
            fprintf(os, "Float64\n%s\n", get_matlab_name().c_str());
//	    ss << "Float64" << endl << get_matlab_name() << endl;

	if (ascii)
            fprintf(os, "%lf ", val);
//	    ss << val << " ";
	else
            fwrite((void *)&val, sizeof(double), 1, os);
//	    os.write((char *)&val, sizeof(double));
    }
    else {
	if (print_decl_p)
            fprintf(os, "%s\n%s\n", type_name(), get_matlab_name().c_str());
//	    os << type_name() << endl << get_matlab_name() << endl;

        // There's no special case for ASCII since this is a String.
        fprintf(os, "%s ", _buf.c_str());
//	os << _buf << endl;
    }
}

AttrTable &
ClientStr::getAttrTable()
{
    return _attr;
}

void
ClientStr::setAttrTable(AttrTable &attr)
{
    _attr = attr;
}

void
ClientStr::set_name(const string &n)
{
    BaseType::set_name(n);
    set_matlab_name(n);
}

string
ClientStr::get_matlab_name() const
{
    return _matlabName;
}

void
ClientStr::set_matlab_name(const string &name)
{
    _matlabName = names.lookup(name, translate);
}

// $Log: ClientStr.cc,v $
// Revision 1.3  2003/12/08 17:59:49  edavis
// Merge release-3-4 into trunk
//
// Revision 1.1.1.1  2003/10/22 19:43:19  dan
// Version of the Matlab CommandLine client which uses Matlab Structure
// variables to maintain the shape of the underlying DODS data.
// Revision 1.1.1.1.2.2  2003/10/29 19:03:21  dan
// Removed 'pragma interface' directive from all subclass
// source files.
//
// Revision 1.1.1.1.2.1  2003/10/27 16:41:30  dan
// Changed config include to 'config_writedap.h' to designate
// new version of 'writeval' now called 'writedap'.  The only
// substantive change in 'writedap' is that nested sequence
// variables are now supported.
//
// Revision 1.2  2003/10/23 18:34:02  dan
// Changed config include to config_writedap.h from config_writeval.h
// This is to remain consistent with the renaming used from loaddods
// to loaddap.  To support nested sequences writeval was modified
// to send an end-of-sequence marker to delimit sequence instances.
//
//
// Revision 1.29  2003/05/02 17:16:17  jimg
// I replaced the cast is ostream::write that was (void *) to (char *) to
// get this code to compile with gcc 3.2. This change is also needed for
// VC++, so I was able to remove some of the ifdef WIN32 lines. Also, in
// name_map I added a using namespace std; line.
//
// Revision 1.28  2003/01/29 15:43:52  dan
// Resolved conflict on merge, caused by PWEST's removal
// of the SLLIST includes in a previous update on the trunk.
//
// Revision 1.27  2001/08/27 18:06:57  jimg
// Merged release-3-2-5.
//
// Revision 1.26.2.2  2002/09/05 22:26:49  pwest
// Removed includes to SLList and DLList. These are not necessary and no longer
// supported.
//
// Revision 1.26.2.1  2001/08/21 16:49:18  dan
// Added set/accessor methods for a new local member, matlab_name
// which stores the translated name of the variable so that it does
// not have to be translated during serialization.  This optimizes
// the amount of time spent in variable name translation to a single
// instance.
//
// Added a local method, set_name() which works with the BaseType
// pointer to update both the BaseType name member and local matlab_name
// member.
//
// Revision 1.26  2000/10/03 22:24:17  jimg
// Reorganized the CVS Log entries.
// Changed the read() mfunc definitions to match the 3.2 dap++ library.
//
// Revision 1.25  2000/07/21 10:21:56  rmorris
// Merged with win32-mlclient-branch.
//
// Revision 1.24.2.2  2000/07/09 22:26:32  rmorris
// Mod's to increase portability, minimize ifdef's for win32.
//
// Revision 1.24.2.1  2000/06/26 22:54:26  rmorris
// Mods for port to win32.
//
// Revision 1.24  2000/06/07 00:28:31  jimg
// Merged changes from version 3.1.4
//
// Revision 1.22.2.3  2000/06/02 23:03:32  jimg
// Fixes for AttrTables with no entries.
// Added support for name translation and a DODS_ML_Real_Name attribute.
// Changed the `size' attribtue's name to DODS_ML_Size.
//
// Revision 1.22.2.2  2000/05/26 22:15:54  jimg
// Removed the old DMS time processing code.
//
// Revision 1.23  2000/04/20 23:38:12  jimg
// Merged with release 3.1.3
//
// Revision 1.22.2.1  2000/04/11 21:46:21  jimg
// Removed old code.
//
// Revision 1.22  1999/07/24 00:10:28  jimg
// Merged the release-3-0-2 branch
//
// Revision 1.21  1999/04/30 17:06:55  jimg
// Merged with no-gnu and release-2-24
//
// Revision 1.20  1999/03/24 06:23:43  brent
// convert String.h to std lib <string>, convert to packages regex -- B^2
//
// Revision 1.19  1998/11/25 01:16:19  jimg
// Now processes -w for warnings. This means that verbose (-v) mode is
// information and -w is for warnings only.
//
// Revision 1.18  1998/11/20 08:41:22  jimg
// Fixed the fix for the extra newline separators; it was broken for arrays
//
// Revision 1.17  1998/11/19 20:53:33  jimg
// Fixed the extra newline bug.
//
// Revision 1.16  1998/09/16 23:02:22  jimg
// Removed write_val() and replaced it with print_val() and print_all_vals()
//
// Revision 1.15  1998/08/03 16:39:50  jimg
// Fixed write_val mfunc so that outermost is no longer used
//
// Revision 1.14  1998/06/09 04:09:13  jimg
// Made some of the diagnostic output about interning NaNs part of the verbose
// option. It will only print when writeval is called with the -v option.
//
// Revision 1.13  1998/02/05 20:14:50  jimg
// DODS now compiles with gcc 2.8.x
//
// Revision 1.12  1997/12/02 20:34:37  jimg
// Fixed/Removed the automatic conversion of strings to numbers. This was a
// bad idea.
//
// Revision 1.11  1997/10/04 00:40:06  jimg
// Added changes to support the new deserialize() mfunc and write_val().
//
// Revision 1.10  1997/06/06 04:02:07  jimg
// Added ASCII output option to writeval. Uses a global `flag'.
//
// Revision 1.9  1997/04/19 00:54:58  jimg
// Changed ouput stream to simplify reading (for loaddods).
//
// Revision 1.8  1997/02/06 19:42:39  jimg
// When converting strings to Float64 values, any string that cannot be
// converted is externalized as NaN.
//
// Revision 1.7  1997/01/13 18:01:50  jimg
// Fixed a bug when the degree part of a DDDMMSSH string has only one or two
// digits.
//
// Revision 1.6  1997/01/10 06:49:37  jimg
// Changed call to name_map::lookup() so that non-alphanumerics are mapped to
// underscore.
//
// Revision 1.5  1996/11/23 05:12:13  jimg
// Added support for variable renaming via the name_map object.
//
// Revision 1.4  1996/11/13 18:02:54  jimg
// Fixed bad usage of strtod(). When strtod() returns 0.0, the pointer passed
// as a second argument must be compared to the pointer to the string to be
// converted instead of testing only that it is not null. If the pointer is not
// equal to the string argument then the number *has* converted successfully
// (to 0.0). Otherwise, the string did not convert.
//
// Revision 1.3  1996/10/23 23:46:44  jimg
// Modified so that writeval outputs a `recursive' data stream. Thus any
// data type can be written and later read without being flattened. This
// change was made so that the NSCAT data which is represented as a Sequence
// of Structures.
//
// Revision 1.2  1996/10/07 21:00:29  jimg
// Fixed Headers.
//
// Revision 1.1  1996/09/30 23:59:18  jimg
// Added.
<commit_msg>Fixed print_val(), fprintf in if(print_decl_p) condition requires a EOL character after writing _buf.<commit_after>
// -*- mode: c++; c-basic-offset:4 -*-

// This file is part of loaddap.

// Copyright (c) 2005 OPeNDAP, Inc.
// Author: James Gallagher <jgallagher@opendap.org>
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.

// (c) COPYRIGHT URI/MIT 1996
// Please read the full copyright statement in the file COPYRIGH.
//
// Authors:
//      jhrg,jimg       James Gallagher (jgallagher@gso.uri.edu)

// Implementation for ClientStr. See ClientByte.cc
//
// jhrg 9/25/96

#include <assert.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>

#include "config_writedap.h"	// was first caused LITTLE_ENDIAN error

#include <iostream>
#include <string>

#include <GNURegex.h>

#include "InternalErr.h"
#include "ClientStr.h"
#include "name_map.h"

// We *should* be using <nan.h> to handle generating NaN. However, many
// machines don't have a function that can be used to generate NaN so I've
// written my own (which uses its own bastardized version of the FP union).
// 2/5/97 jhrg

#include "nan_hack.h"

static double
MakeNaN()
{
    dnan X;
    X.nan.exponent = 0x7ff;
    X.nan.qnan_bit = 0x1;

    return X.d;
}

extern name_map names;
extern bool translate;
extern bool ascii;
extern bool string_to_float;
extern bool verbose;
extern bool warning;

Str *
NewStr(const string &n)
{
    return new ClientStr(n);
}

ClientStr::ClientStr(const string &n) : Str(n)
{
    set_matlab_name(n);
}

BaseType *
ClientStr::ptr_duplicate()
{
    return new ClientStr(*this);
}

bool
ClientStr::read(const string &)
{
  throw InternalErr(__FILE__, __LINE__, "Called unimplemented read method");
}

void
ClientStr::print_val(FILE *os, string, bool print_decl_p)
{
    bool print_as_float = false;
    double val = 0.0;

    // Translate all string variables to Floats. jhrg 1/9/98.
    if (string_to_float) {
	char *ptr = NULL;
	const char *str = _buf.c_str();
	val = strtod(str, &ptr);
	print_as_float = !(val == 0.0 && (ptr == str));

	if (!print_as_float) {
	    val = MakeNaN();
	    print_as_float = true;
	    if (warning) {
		cerr << "Could not translate `" << _buf << "' to a Float64,"
		     << endl;
		cerr << "interning as NaN (not a number: " << val
		     << ")" << endl;
	    }
	}
    }

    if (print_as_float) {
	if (print_decl_p)
            fprintf(os, "Float64\n%s\n", get_matlab_name().c_str());
//	    ss << "Float64" << endl << get_matlab_name() << endl;

	if (ascii)
            fprintf(os, "%lf ", val);
//	    ss << val << " ";
	else
	    fwrite((void *)&val, sizeof(double), 1, os);
//	    os.write((char *)&val, sizeof(double));
    }
    else {
	if (print_decl_p)
            fprintf(os, "%s\n%s\n", type_name().c_str(), get_matlab_name().c_str());
//	    os << type_name() << endl << get_matlab_name() << endl;

        // There's no special case for ASCII since this is a String.
        fprintf(os, "%s\n", _buf.c_str());
//	os << _buf << endl;
    }
}

AttrTable &
ClientStr::getAttrTable()
{
    return _attr;
}

void
ClientStr::setAttrTable(AttrTable &attr)
{
    _attr = attr;
}

void
ClientStr::set_name(const string &n)
{
    BaseType::set_name(n);
    set_matlab_name(n);
}

string
ClientStr::get_matlab_name() const
{
    return _matlabName;
}

void
ClientStr::set_matlab_name(const string &name)
{
    _matlabName = names.lookup(name, translate);
}

// $Log: ClientStr.cc,v $
// Revision 1.3  2003/12/08 17:59:49  edavis
// Merge release-3-4 into trunk
//
// Revision 1.1.1.1  2003/10/22 19:43:19  dan
// Version of the Matlab CommandLine client which uses Matlab Structure
// variables to maintain the shape of the underlying DODS data.
// Revision 1.1.1.1.2.2  2003/10/29 19:03:21  dan
// Removed 'pragma interface' directive from all subclass
// source files.
//
// Revision 1.1.1.1.2.1  2003/10/27 16:41:30  dan
// Changed config include to 'config_writedap.h' to designate
// new version of 'writeval' now called 'writedap'.  The only
// substantive change in 'writedap' is that nested sequence
// variables are now supported.
//
// Revision 1.2  2003/10/23 18:34:02  dan
// Changed config include to config_writedap.h from config_writeval.h
// This is to remain consistent with the renaming used from loaddods
// to loaddap.  To support nested sequences writeval was modified
// to send an end-of-sequence marker to delimit sequence instances.
//
//
// Revision 1.29  2003/05/02 17:16:17  jimg
// I replaced the cast is ostream::write that was (void *) to (char *) to
// get this code to compile with gcc 3.2. This change is also needed for
// VC++, so I was able to remove some of the ifdef WIN32 lines. Also, in
// name_map I added a using namespace std; line.
//
// Revision 1.28  2003/01/29 15:43:52  dan
// Resolved conflict on merge, caused by PWEST's removal
// of the SLLIST includes in a previous update on the trunk.
//
// Revision 1.27  2001/08/27 18:06:57  jimg
// Merged release-3-2-5.
//
// Revision 1.26.2.2  2002/09/05 22:26:49  pwest
// Removed includes to SLList and DLList. These are not necessary and no longer
// supported.
//
// Revision 1.26.2.1  2001/08/21 16:49:18  dan
// Added set/accessor methods for a new local member, matlab_name
// which stores the translated name of the variable so that it does
// not have to be translated during serialization.  This optimizes
// the amount of time spent in variable name translation to a single
// instance.
//
// Added a local method, set_name() which works with the BaseType
// pointer to update both the BaseType name member and local matlab_name
// member.
//
// Revision 1.26  2000/10/03 22:24:17  jimg
// Reorganized the CVS Log entries.
// Changed the read() mfunc definitions to match the 3.2 dap++ library.
//
// Revision 1.25  2000/07/21 10:21:56  rmorris
// Merged with win32-mlclient-branch.
//
// Revision 1.24.2.2  2000/07/09 22:26:32  rmorris
// Mod's to increase portability, minimize ifdef's for win32.
//
// Revision 1.24.2.1  2000/06/26 22:54:26  rmorris
// Mods for port to win32.
//
// Revision 1.24  2000/06/07 00:28:31  jimg
// Merged changes from version 3.1.4
//
// Revision 1.22.2.3  2000/06/02 23:03:32  jimg
// Fixes for AttrTables with no entries.
// Added support for name translation and a DODS_ML_Real_Name attribute.
// Changed the `size' attribtue's name to DODS_ML_Size.
//
// Revision 1.22.2.2  2000/05/26 22:15:54  jimg
// Removed the old DMS time processing code.
//
// Revision 1.23  2000/04/20 23:38:12  jimg
// Merged with release 3.1.3
//
// Revision 1.22.2.1  2000/04/11 21:46:21  jimg
// Removed old code.
//
// Revision 1.22  1999/07/24 00:10:28  jimg
// Merged the release-3-0-2 branch
//
// Revision 1.21  1999/04/30 17:06:55  jimg
// Merged with no-gnu and release-2-24
//
// Revision 1.20  1999/03/24 06:23:43  brent
// convert String.h to std lib <string>, convert to packages regex -- B^2
//
// Revision 1.19  1998/11/25 01:16:19  jimg
// Now processes -w for warnings. This means that verbose (-v) mode is
// information and -w is for warnings only.
//
// Revision 1.18  1998/11/20 08:41:22  jimg
// Fixed the fix for the extra newline separators; it was broken for arrays
//
// Revision 1.17  1998/11/19 20:53:33  jimg
// Fixed the extra newline bug.
//
// Revision 1.16  1998/09/16 23:02:22  jimg
// Removed write_val() and replaced it with print_val() and print_all_vals()
//
// Revision 1.15  1998/08/03 16:39:50  jimg
// Fixed write_val mfunc so that outermost is no longer used
//
// Revision 1.14  1998/06/09 04:09:13  jimg
// Made some of the diagnostic output about interning NaNs part of the verbose
// option. It will only print when writeval is called with the -v option.
//
// Revision 1.13  1998/02/05 20:14:50  jimg
// DODS now compiles with gcc 2.8.x
//
// Revision 1.12  1997/12/02 20:34:37  jimg
// Fixed/Removed the automatic conversion of strings to numbers. This was a
// bad idea.
//
// Revision 1.11  1997/10/04 00:40:06  jimg
// Added changes to support the new deserialize() mfunc and write_val().
//
// Revision 1.10  1997/06/06 04:02:07  jimg
// Added ASCII output option to writeval. Uses a global `flag'.
//
// Revision 1.9  1997/04/19 00:54:58  jimg
// Changed ouput stream to simplify reading (for loaddods).
//
// Revision 1.8  1997/02/06 19:42:39  jimg
// When converting strings to Float64 values, any string that cannot be
// converted is externalized as NaN.
//
// Revision 1.7  1997/01/13 18:01:50  jimg
// Fixed a bug when the degree part of a DDDMMSSH string has only one or two
// digits.
//
// Revision 1.6  1997/01/10 06:49:37  jimg
// Changed call to name_map::lookup() so that non-alphanumerics are mapped to
// underscore.
//
// Revision 1.5  1996/11/23 05:12:13  jimg
// Added support for variable renaming via the name_map object.
//
// Revision 1.4  1996/11/13 18:02:54  jimg
// Fixed bad usage of strtod(). When strtod() returns 0.0, the pointer passed
// as a second argument must be compared to the pointer to the string to be
// converted instead of testing only that it is not null. If the pointer is not
// equal to the string argument then the number *has* converted successfully
// (to 0.0). Otherwise, the string did not convert.
//
// Revision 1.3  1996/10/23 23:46:44  jimg
// Modified so that writeval outputs a `recursive' data stream. Thus any
// data type can be written and later read without being flattened. This
// change was made so that the NSCAT data which is represented as a Sequence
// of Structures.
//
// Revision 1.2  1996/10/07 21:00:29  jimg
// Fixed Headers.
//
// Revision 1.1  1996/09/30 23:59:18  jimg
// Added.
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015,2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "log.h"

#include "datetime.h"
#include "utils.h"

#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>

#define BUFFER_SIZE (10 * 1024)
#define STACKED_SEP "<sep>"

const std::regex filter_re("\033\\[[;\\d]*m");
std::mutex Log::stack_mtx;
std::unordered_map<std::thread::id, unsigned> Log::stack_levels;

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

Log::Log(const std::string& str, bool clean_, bool stacked_, std::chrono::time_point<std::chrono::system_clock> wakeup_, int priority_, std::chrono::time_point<std::chrono::system_clock> created_at_)
	: stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  created_at(created_at_),
	  wakeup(wakeup_),
	  str_start(str),
	  priority(priority_),
	  finished(false),
	  cleaned(false) {

	if (stacked) {
		std::lock_guard<std::mutex> lk(stack_mtx);
		thread_id = std::this_thread::get_id();
		try {
			stack_level = ++stack_levels.at(thread_id);
		} catch (const std::out_of_range&) {
			stack_levels[thread_id] = 0;
		}
	}
}

Log::~Log()
{
	cleanup();
}

void
Log::cleanup()
{
	bool f = false;
	finished.compare_exchange_strong(f, clean);

	if (!cleaned.exchange(true)) {
		if (stacked) {
			std::lock_guard<std::mutex> lk(stack_mtx);
			if (stack_levels.at(thread_id)-- == 0) {
				stack_levels.erase(thread_id);
			}
		}
	}
}

long double
Log::age()
{
	return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now() - created_at).count();
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */

LogThread&
Log::_thread()
{
	static LogThread* thread = new LogThread();
	return *thread;
}

int&
Log::_log_level()
{
	static auto* log_level = new int(DEFAULT_LOG_LEVEL);
	return *log_level;
}

DLList<const std::unique_ptr<Logger>>&
Log::_handlers()
{
	static auto* handlers = new DLList<const std::unique_ptr<Logger>>();
	return *handlers;
}

std::string
Log::str_format(bool stacked, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef LOG_OBJ_ADDRESS
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
#endif
#ifdef TRACEBACK
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#else
	result += " ";
	(void)obj;
#endif
	if (stacked) {
		result += STACKED_SEP;
	}
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

LogWrapper
Log::log(bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, clean, stacked, wakeup, priority);
}

bool
Log::clear()
{
	return finished.exchange(true);
}

bool
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (finished.exchange(true)) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(stacked, priority, std::string(), file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, stacked, 0, priority, created_at);

		return true;
	}
	return false;
}

LogWrapper
Log::add(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	auto l_ptr = std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at);

	static LogThread& thread = _thread();
	thread.add(l_ptr);

	return LogWrapper(l_ptr);
}

void
Log::log(int priority, const std::string& str)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	static auto& handlers = _handlers();
	for (auto& handler : handlers) {
		handler->log(priority, str);
	}
}

LogWrapper
Log::print(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	static auto& log_level = _log_level();
	if (priority > log_level) {
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at));
	}

	static auto& handlers = _handlers();
	if (!handlers.size()) {
		handlers.push_back(std::make_unique<StderrLogger>());
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, clean, stacked, wakeup, priority, created_at);
	} else {
		log(priority, str);
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at));
	}
}

void
Log::finish(int wait)
{
	static LogThread& thread = _thread();
	thread.finish(wait);
}

LogThread::LogThread()
	: running(-1),
	  inner_thread(&LogThread::thread_function, this, std::ref(log_list)) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(int wait)
{
	running = wait;
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const std::shared_ptr<Log>& l_ptr)
{
	if (running != 0) {
		log_list.push_back(l_ptr);

		if (std::chrono::system_clock::from_time_t(wakeup) >= l_ptr->wakeup) {
			wakeup_signal.notify_all();
		}
	}
}

void
LogThread::thread_function(DLList<const std::shared_ptr<Log>>& _log_list)
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	auto now = std::chrono::system_clock::now();
	auto next_wakeup = now + 3s;

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		wakeup = std::chrono::system_clock::to_time_t(next_wakeup);
		wakeup_signal.wait_until(lk, next_wakeup);

		now = std::chrono::system_clock::now();
		next_wakeup = now + (running < 0 ? 3s : 100ms);

		for (auto it = _log_list.begin(); it != _log_list.end(); ) {
			auto& l_ptr = *it;
			if (l_ptr->finished) {
				it = _log_list.erase(it);
			} else if (l_ptr->wakeup <= now) {
				l_ptr->finished = true;
				auto msg = l_ptr->str_start;
				auto age = l_ptr->age();
				if (age > 2e8) {
					msg += " ~" + delta_string(age, true);
				}
				if (l_ptr->stacked) {
					msg.replace(msg.find(STACKED_SEP), sizeof(STACKED_SEP) - 1, std::string(l_ptr->stack_level * 2, ' '));
				}
				Log::log(l_ptr->priority, msg);
				it = _log_list.erase(it);
			} else if (next_wakeup > l_ptr->wakeup) {
				next_wakeup = l_ptr->wakeup;
				++it;
			} else {
				++it;
			}
		}

		if (next_wakeup < now + 100ms) {
			next_wakeup = now + 100ms;
		}

		if (running >= 0 && !log_list.size()) {
			break;
		}
	}
}
<commit_msg>Do not print delta time (for the moment)<commit_after>/*
 * Copyright (C) 2015,2016 deipi.com LLC and contributors. All rights reserved.
 *
 * 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.
 */

#include "log.h"

#include "datetime.h"
#include "utils.h"

#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>

#define BUFFER_SIZE (10 * 1024)
#define STACKED_SEP "<sep>"

const std::regex filter_re("\033\\[[;\\d]*m");
std::mutex Log::stack_mtx;
std::unordered_map<std::thread::id, unsigned> Log::stack_levels;

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

Log::Log(const std::string& str, bool clean_, bool stacked_, std::chrono::time_point<std::chrono::system_clock> wakeup_, int priority_, std::chrono::time_point<std::chrono::system_clock> created_at_)
	: stack_level(0),
	  stacked(stacked_),
	  clean(clean_),
	  created_at(created_at_),
	  wakeup(wakeup_),
	  str_start(str),
	  priority(priority_),
	  finished(false),
	  cleaned(false) {

	if (stacked) {
		std::lock_guard<std::mutex> lk(stack_mtx);
		thread_id = std::this_thread::get_id();
		try {
			stack_level = ++stack_levels.at(thread_id);
		} catch (const std::out_of_range&) {
			stack_levels[thread_id] = 0;
		}
	}
}

Log::~Log()
{
	cleanup();
}

void
Log::cleanup()
{
	bool f = false;
	finished.compare_exchange_strong(f, clean);

	if (!cleaned.exchange(true)) {
		if (stacked) {
			std::lock_guard<std::mutex> lk(stack_mtx);
			if (stack_levels.at(thread_id)-- == 0) {
				stack_levels.erase(thread_id);
			}
		}
	}
}

long double
Log::age()
{
	return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::system_clock::now() - created_at).count();
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */

LogThread&
Log::_thread()
{
	static LogThread* thread = new LogThread();
	return *thread;
}

int&
Log::_log_level()
{
	static auto* log_level = new int(DEFAULT_LOG_LEVEL);
	return *log_level;
}

DLList<const std::unique_ptr<Logger>>&
Log::_handlers()
{
	static auto* handlers = new DLList<const std::unique_ptr<Logger>>();
	return *handlers;
}

std::string
Log::str_format(bool stacked, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef LOG_OBJ_ADDRESS
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
#endif
#ifdef TRACEBACK
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#else
	result += " ";
	(void)obj;
#endif
	if (stacked) {
		result += STACKED_SEP;
	}
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

LogWrapper
Log::log(bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(stacked, priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, clean, stacked, wakeup, priority);
}

bool
Log::clear()
{
	return finished.exchange(true);
}

bool
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (finished.exchange(true)) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(stacked, priority, std::string(), file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, stacked, 0, priority, created_at);

		return true;
	}
	return false;
}

LogWrapper
Log::add(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	auto l_ptr = std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at);

	static LogThread& thread = _thread();
	thread.add(l_ptr);

	return LogWrapper(l_ptr);
}

void
Log::log(int priority, const std::string& str)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	static auto& handlers = _handlers();
	for (auto& handler : handlers) {
		handler->log(priority, str);
	}
}

LogWrapper
Log::print(const std::string& str, bool clean, bool stacked, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, std::chrono::time_point<std::chrono::system_clock> created_at)
{
	static auto& log_level = _log_level();
	if (priority > log_level) {
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at));
	}

	static auto& handlers = _handlers();
	if (!handlers.size()) {
		handlers.push_back(std::make_unique<StderrLogger>());
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, clean, stacked, wakeup, priority, created_at);
	} else {
		log(priority, str);
		return LogWrapper(std::make_shared<Log>(str, clean, stacked, wakeup, priority, created_at));
	}
}

void
Log::finish(int wait)
{
	static LogThread& thread = _thread();
	thread.finish(wait);
}

LogThread::LogThread()
	: running(-1),
	  inner_thread(&LogThread::thread_function, this, std::ref(log_list)) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(int wait)
{
	running = wait;
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const std::shared_ptr<Log>& l_ptr)
{
	if (running != 0) {
		log_list.push_back(l_ptr);

		if (std::chrono::system_clock::from_time_t(wakeup) >= l_ptr->wakeup) {
			wakeup_signal.notify_all();
		}
	}
}

void
LogThread::thread_function(DLList<const std::shared_ptr<Log>>& _log_list)
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	auto now = std::chrono::system_clock::now();
	auto next_wakeup = now + 3s;

	while (running != 0) {
		if (--running < 0) {
			running = -1;
		}

		wakeup = std::chrono::system_clock::to_time_t(next_wakeup);
		wakeup_signal.wait_until(lk, next_wakeup);

		now = std::chrono::system_clock::now();
		next_wakeup = now + (running < 0 ? 3s : 100ms);

		for (auto it = _log_list.begin(); it != _log_list.end(); ) {
			auto& l_ptr = *it;
			if (l_ptr->finished) {
				it = _log_list.erase(it);
			} else if (l_ptr->wakeup <= now) {
				l_ptr->finished = true;
				auto msg = l_ptr->str_start;
				if (l_ptr->stacked) {
					msg.replace(msg.find(STACKED_SEP), sizeof(STACKED_SEP) - 1, std::string(l_ptr->stack_level * 2, ' '));
				}
				// auto age = l_ptr->age();
				// if (age > 2e8) {
				// 	msg += " ~" + delta_string(age, true);
				// }
				Log::log(l_ptr->priority, msg);
				it = _log_list.erase(it);
			} else if (next_wakeup > l_ptr->wakeup) {
				next_wakeup = l_ptr->wakeup;
				++it;
			} else {
				++it;
			}
		}

		if (next_wakeup < now + 100ms) {
			next_wakeup = now + 100ms;
		}

		if (running >= 0 && !log_list.size()) {
			break;
		}
	}
}
<|endoftext|>


<commit_before>#include <mpd/client.h>
#include <memory>
#include "consumer.hh"

class connection : public std::unique_ptr<mpd_connection,
                                          void (*)(mpd_connection*)> {
    template <class Fun, class Con, class... Args>
    static auto wrap_error(Fun f, Con con, Args&&... args)
        -> decltype(f(con, std::forward<Args>(args)...)) {
        auto x = f(con, std::forward<Args>(args)...);
        if (!x) {
            throw std::runtime_error(
                mpd_connection_get_error_message(con));
        }
        return x;
    }

    using super = std::unique_ptr<mpd_connection,
                                  void (*)(mpd_connection*)>;

public:
    connection(const char* name, int port, int delay)
        : super(mpd_connection_new(name, port, delay),
                mpd_connection_free) {}
    void run_clear() {
        wrap_error(mpd_run_clear, get());
    }

    void run_update(const char* path = nullptr) {
        wrap_error(mpd_run_update, get(), path);
    }
};
void Consumer::_run_mpd_() {
    connection con("localhost", 6600, 1000);
    con.run_clear();
    con.run_update();
    for (const auto& s : _playlist_lines_) {
        if (!mpd_run_add(con.get(), s.c_str())) {
            fprintf(stderr, "ERROR adding file: %s\n", s.c_str());
        }
    }
}
<commit_msg>Make mpd class local to mpd.cc<commit_after>#include <mpd/client.h>
#include <memory>
#include "consumer.hh"

namespace {
class connection : public std::unique_ptr<mpd_connection,
                                          void (*)(mpd_connection*)> {
    template <class Fun, class Con, class... Args>
    static auto wrap_error(Fun f, Con con, Args&&... args)
        -> decltype(f(con, std::forward<Args>(args)...)) {
        auto x = f(con, std::forward<Args>(args)...);
        if (!x) {
            throw std::runtime_error(
                mpd_connection_get_error_message(con));
        }
        return x;
    }

    using super = std::unique_ptr<mpd_connection,
                                  void (*)(mpd_connection*)>;

public:
    connection(const char* name, int port, int delay)
        : super(mpd_connection_new(name, port, delay),
                mpd_connection_free) {}
    void run_clear() {
        wrap_error(mpd_run_clear, get());
    }

    void run_update(const char* path = nullptr) {
        wrap_error(mpd_run_update, get(), path);
    }
};
}

void Consumer::_run_mpd_() {
    connection con("localhost", 6600, 1000);
    con.run_clear();
    con.run_update();
    for (const auto& s : _playlist_lines_) {
        if (!mpd_run_add(con.get(), s.c_str())) {
            fprintf(stderr, "ERROR adding file: %s\n", s.c_str());
        }
    }
}
<|endoftext|>


<commit_before>/*!
	@file
	@author		Evmenov Georgiy
	@date		01/2008
	@module
*/

#include "RenderBoxScene.h"

namespace wraps
{

	RenderBoxScene::RenderBoxScene() :
		mCameraNode(nullptr),
		mCamera(nullptr),
		mEntity(nullptr),
		mAnimationState(nullptr),
		mRotationSpeed(RENDER_BOX_AUTO_ROTATION_SPEED),
		mMouseRotation(false),
		mLastPointerX(0),
		mLeftPressed(false),
		mAutoRotation(false),
		mFrameAdvise(false),
		mScene(nullptr),
		mNode(nullptr)
	{
	}

	RenderBoxScene::~RenderBoxScene()
	{
	}

	void RenderBoxScene::destroy()
	{
		clearScene();

		if (mCanvas)
		{
			frameAdvise(false);

			mCanvas->eventMouseDrag = nullptr;
			mCanvas->eventMouseButtonPressed = nullptr;
			mCanvas->eventMouseButtonReleased = nullptr;

			Ogre::Root* root = Ogre::Root::getSingletonPtr();
			if (root && mScene)
				root->destroySceneManager(mScene);
			mScene= nullptr;
		}

		RenderBox::destroy();
	}

	void RenderBoxScene::setCanvas(MyGUI::CanvasPtr _value)
	{
		RenderBox::setCanvas(_value);

		mCanvas->eventMouseDrag = newDelegate(this, &RenderBoxScene::notifyMouseDrag);
		mCanvas->eventMouseButtonPressed = newDelegate(this, &RenderBoxScene::notifyMouseButtonPressed);
		mCanvas->eventMouseButtonReleased = newDelegate(this, &RenderBoxScene::notifyMouseButtonReleased);

		createScene();
	}

	//    ,
	void RenderBoxScene::injectObject(const Ogre::String& _meshName, const Ogre::Vector3 & _position, const Ogre::Quaternion & _orientation, const Ogre::Vector3 & _scale)
	{
		clearScene();

		static size_t num = 0;
		mEntity = mScene->createEntity(MyGUI::utility::toString(this, "_RenderBoxMesh_", _meshName, num++), _meshName);
		Ogre::SceneNode * node = mNode->createChildSceneNode(_position, _orientation);
		node->attachObject(mEntity);

		updateViewport();
	}

	void RenderBoxScene::setAnimation(const Ogre::String& _animation)
	{
		if (mEntity == nullptr)
			return;

		try
		{
			mAnimationState = mEntity->getAnimationState(_animation);
			mAnimationState->setEnabled(true);
			mAnimationState->setLoop(true);
			mAnimationState->setWeight(1);
		}
		catch (Ogre::ItemIdentityException&)
		{
		}

		frameAdvise(needFrameUpdate());
	}

	//
	void RenderBoxScene::clearScene()
	{
		setRotationAngle(Ogre::Degree(0));

		if (mScene)
		{
			mScene->destroyAllEntities();
			mNode->removeAndDestroyAllChildren();
		}

		mEntity = nullptr;
		mAnimationState = nullptr;
	}

	void RenderBoxScene::setAutoRotationSpeed(int _value)
	{
		mRotationSpeed = _value;
	}

	void RenderBoxScene::setRotationAngle(const Ogre::Degree& _value)
	{
		if (mNode)
		{
			mNode->resetOrientation();
			mNode->yaw(Ogre::Radian(_value));
		}
	}

	Ogre::Degree RenderBoxScene::getRotationAngle()
	{
		return Ogre::Degree(mNode->getOrientation().getYaw());
	}

	void RenderBoxScene::setMouseRotation(bool _enable)
	{
		mMouseRotation = _enable;
	}

	void RenderBoxScene::frameEntered(float _time)
	{
		if (!mLeftPressed)
		{
			if (mAutoRotation)
				mNode->yaw(Ogre::Radian(Ogre::Degree(_time * mRotationSpeed)));
		}
		if (mAnimationState)
			mAnimationState->addTime(_time);
	}

	void RenderBoxScene::createScene()
	{
		//
		mScene = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC, MyGUI::utility::toString(this, "_SceneManagerRenderBox"));

		//
		mNode = mScene->getRootSceneNode()->createChildSceneNode();

		mScene->setAmbientLight(Ogre::ColourValue(0.8, 0.8, 0.8));

		//
		Ogre::Vector3 dir(-1, -1, 0.5);
		dir.normalise();
		Ogre::Light * light = mScene->createLight(MyGUI::utility::toString(this, "_LightRenderBox"));
		light->setType(Ogre::Light::LT_DIRECTIONAL);
		light->setDirection(dir);

		std::string camera(MyGUI::utility::toString(this, "_CameraRenderBox"));
		mCamera = mScene->createCamera(camera);
		mCamera->setNearClipDistance(1);

		mCameraNode = mScene->getRootSceneNode()->createChildSceneNode(camera);
		mCameraNode->attachObject(mCamera);

		if (mCanvas->getHeight() == 0)
			mCamera->setAspectRatio(1);
		else
			mCamera->setAspectRatio( float(mCanvas->getWidth()) / float(mCanvas->getHeight()) );

		setViewport(mCamera);
	}

	void RenderBoxScene::updateViewport()
	{
		//
		if ((mCanvas->getWidth() <= 1) || (mCanvas->getHeight() <= 1))
			return;

		if ((nullptr != mEntity) && (nullptr != mCamera))
		{
			//  ,    ,
			mCamera->setAspectRatio((float)mCanvas->getWidth() / (float)mCanvas->getHeight());

			//  ,
			Ogre::AxisAlignedBox box;

			box.merge(mEntity->getBoundingBox().getMinimum() + mEntity->getParentSceneNode()->_getDerivedPosition());
			box.merge(mEntity->getBoundingBox().getMaximum() + mEntity->getParentSceneNode()->_getDerivedPosition());

			if (box.isNull()) return;

			Ogre::Vector3 vec = box.getSize();

			float width = sqrt(vec.x*vec.x + vec.z*vec.z); //   -  (  )
			float len2 = width / mCamera->getAspectRatio();
			float height = vec.y;
			float len1 = height;
			if (len1 < len2) len1 = len2;
			len1 /= 0.86; // [sqrt(3)/2] for 60 degrees field of view
			//     +  ,     BoundingBox' +
			Ogre::Vector3 result = box.getCenter() + Ogre::Vector3(0, 0, vec.z/2 + len1) + Ogre::Vector3(0, height*0.1, len1*0.2);
			Ogre::Vector3 look = Ogre::Vector3(0, box.getCenter().y /*+ box.getCenter().y * (1-mCurrentScale)*/, 0);

			mCameraNode->setPosition(result);
			mCameraNode->lookAt(look, Ogre::Node::TS_WORLD);
		}
	}

	void RenderBoxScene::setAutoRotation(bool _auto)
	{
		mAutoRotation = _auto;
		frameAdvise(needFrameUpdate());
	}

	void RenderBoxScene::requestUpdateCanvas(MyGUI::CanvasPtr _canvas, MyGUI::Canvas::Event _event)
	{
		RenderBox::requestUpdateCanvas(_canvas, _event);

		updateViewport();
	}

	void RenderBoxScene::frameAdvise(bool _advise)
	{
		if (_advise && !mFrameAdvise && needFrameUpdate())
		{
			MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &RenderBoxScene::frameEntered);
			mFrameAdvise = true;
		}
		else if (!_advise && mFrameAdvise && !needFrameUpdate())
		{
			MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &RenderBoxScene::frameEntered);
			mFrameAdvise = false;
		}
	}

	void RenderBoxScene::notifyMouseDrag(MyGUI::WidgetPtr _sender, int _left, int _top)
	{
		if (mMouseRotation)
		{
			mNode->yaw(Ogre::Radian(Ogre::Degree(_left - mLastPointerX)));
			mLastPointerX = _left;
		}
	}

	void RenderBoxScene::notifyMouseButtonPressed(MyGUI::WidgetPtr _sender, int _left, int _top, MyGUI::MouseButton _id)
	{
		if (_id == MyGUI::MouseButton::Left)
		{
			if (mMouseRotation)
			{
				const MyGUI::IntPoint & point = MyGUI::InputManager::getInstance().getLastLeftPressed();
				mLastPointerX = point.left;
				mLeftPressed = true;
			}
		}
	}

	void RenderBoxScene::notifyMouseButtonReleased(MyGUI::WidgetPtr _sender, int _left, int _top, MyGUI::MouseButton _id)
	{
		if (MyGUI::MouseButton::Left == _id) mLeftPressed = false;
	}

} // namespace wraps
<commit_msg>fix RenderBoxScene<commit_after>/*!
	@file
	@author		Evmenov Georgiy
	@date		01/2008
	@module
*/

#include "RenderBoxScene.h"

namespace wraps
{

	RenderBoxScene::RenderBoxScene() :
		mCameraNode(nullptr),
		mCamera(nullptr),
		mEntity(nullptr),
		mAnimationState(nullptr),
		mRotationSpeed(RENDER_BOX_AUTO_ROTATION_SPEED),
		mMouseRotation(false),
		mLastPointerX(0),
		mLeftPressed(false),
		mAutoRotation(false),
		mFrameAdvise(false),
		mScene(nullptr),
		mNode(nullptr)
	{
	}

	RenderBoxScene::~RenderBoxScene()
	{
	}

	void RenderBoxScene::destroy()
	{
		clearScene();

		if (mCanvas)
		{
			frameAdvise(false);

			mCanvas->eventMouseDrag = nullptr;
			mCanvas->eventMouseButtonPressed = nullptr;
			mCanvas->eventMouseButtonReleased = nullptr;
			mCanvas = nullptr;

			Ogre::Root* root = Ogre::Root::getSingletonPtr();
			if (root && mScene)
				root->destroySceneManager(mScene);
			mScene = nullptr;
			mNode = nullptr;
		}

		RenderBox::destroy();
	}

	void RenderBoxScene::setCanvas(MyGUI::CanvasPtr _value)
	{
		RenderBox::setCanvas(_value);

		mCanvas->eventMouseDrag = newDelegate(this, &RenderBoxScene::notifyMouseDrag);
		mCanvas->eventMouseButtonPressed = newDelegate(this, &RenderBoxScene::notifyMouseButtonPressed);
		mCanvas->eventMouseButtonReleased = newDelegate(this, &RenderBoxScene::notifyMouseButtonReleased);

		createScene();
	}

	//    ,
	void RenderBoxScene::injectObject(const Ogre::String& _meshName, const Ogre::Vector3 & _position, const Ogre::Quaternion & _orientation, const Ogre::Vector3 & _scale)
	{
		clearScene();

		static size_t num = 0;
		mEntity = mScene->createEntity(MyGUI::utility::toString(this, "_RenderBoxMesh_", _meshName, num++), _meshName);
		Ogre::SceneNode * node = mNode->createChildSceneNode(_position, _orientation);
		node->attachObject(mEntity);

		updateViewport();
	}

	void RenderBoxScene::setAnimation(const Ogre::String& _animation)
	{
		if (mEntity == nullptr)
			return;

		try
		{
			mAnimationState = mEntity->getAnimationState(_animation);
			mAnimationState->setEnabled(true);
			mAnimationState->setLoop(true);
			mAnimationState->setWeight(1);
		}
		catch (Ogre::ItemIdentityException&)
		{
		}

		frameAdvise(needFrameUpdate());
	}

	//
	void RenderBoxScene::clearScene()
	{
		setRotationAngle(Ogre::Degree(0));

		if (mScene)
		{
			mScene->destroyAllEntities();
			mNode->removeAndDestroyAllChildren();
		}

		mEntity = nullptr;
		mAnimationState = nullptr;
	}

	void RenderBoxScene::setAutoRotationSpeed(int _value)
	{
		mRotationSpeed = _value;
	}

	void RenderBoxScene::setRotationAngle(const Ogre::Degree& _value)
	{
		if (mNode)
		{
			mNode->resetOrientation();
			mNode->yaw(Ogre::Radian(_value));
		}
	}

	Ogre::Degree RenderBoxScene::getRotationAngle()
	{
		return Ogre::Degree(mNode->getOrientation().getYaw());
	}

	void RenderBoxScene::setMouseRotation(bool _enable)
	{
		mMouseRotation = _enable;
	}

	void RenderBoxScene::frameEntered(float _time)
	{
		if (!mLeftPressed)
		{
			if (mAutoRotation && mNode)
				mNode->yaw(Ogre::Radian(Ogre::Degree(_time * mRotationSpeed)));
		}
		if (mAnimationState)
			mAnimationState->addTime(_time);
	}

	void RenderBoxScene::createScene()
	{
		//
		mScene = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC, MyGUI::utility::toString(this, "_SceneManagerRenderBox"));

		//
		mNode = mScene->getRootSceneNode()->createChildSceneNode();

		mScene->setAmbientLight(Ogre::ColourValue(0.8, 0.8, 0.8));

		//
		Ogre::Vector3 dir(-1, -1, 0.5);
		dir.normalise();
		Ogre::Light * light = mScene->createLight(MyGUI::utility::toString(this, "_LightRenderBox"));
		light->setType(Ogre::Light::LT_DIRECTIONAL);
		light->setDirection(dir);

		std::string camera(MyGUI::utility::toString(this, "_CameraRenderBox"));
		mCamera = mScene->createCamera(camera);
		mCamera->setNearClipDistance(1);

		mCameraNode = mScene->getRootSceneNode()->createChildSceneNode(camera);
		mCameraNode->attachObject(mCamera);

		if (mCanvas->getHeight() == 0)
			mCamera->setAspectRatio(1);
		else
			mCamera->setAspectRatio( float(mCanvas->getWidth()) / float(mCanvas->getHeight()) );

		setViewport(mCamera);
	}

	void RenderBoxScene::updateViewport()
	{
		//
		if ((mCanvas->getWidth() <= 1) || (mCanvas->getHeight() <= 1))
			return;

		if ((nullptr != mEntity) && (nullptr != mCamera))
		{
			//  ,    ,
			mCamera->setAspectRatio((float)mCanvas->getWidth() / (float)mCanvas->getHeight());

			//  ,
			Ogre::AxisAlignedBox box;

			box.merge(mEntity->getBoundingBox().getMinimum() + mEntity->getParentSceneNode()->_getDerivedPosition());
			box.merge(mEntity->getBoundingBox().getMaximum() + mEntity->getParentSceneNode()->_getDerivedPosition());

			if (box.isNull()) return;

			Ogre::Vector3 vec = box.getSize();

			float width = sqrt(vec.x*vec.x + vec.z*vec.z); //   -  (  )
			float len2 = width / mCamera->getAspectRatio();
			float height = vec.y;
			float len1 = height;
			if (len1 < len2) len1 = len2;
			len1 /= 0.86; // [sqrt(3)/2] for 60 degrees field of view
			//     +  ,     BoundingBox' +
			Ogre::Vector3 result = box.getCenter() + Ogre::Vector3(0, 0, vec.z/2 + len1) + Ogre::Vector3(0, height*0.1, len1*0.2);
			Ogre::Vector3 look = Ogre::Vector3(0, box.getCenter().y /*+ box.getCenter().y * (1-mCurrentScale)*/, 0);

			mCameraNode->setPosition(result);
			mCameraNode->lookAt(look, Ogre::Node::TS_WORLD);
		}
	}

	void RenderBoxScene::setAutoRotation(bool _auto)
	{
		mAutoRotation = _auto;
		frameAdvise(needFrameUpdate());
	}

	void RenderBoxScene::requestUpdateCanvas(MyGUI::CanvasPtr _canvas, MyGUI::Canvas::Event _event)
	{
		RenderBox::requestUpdateCanvas(_canvas, _event);

		updateViewport();
	}

	void RenderBoxScene::frameAdvise(bool _advise)
	{
		if (_advise && !mFrameAdvise && needFrameUpdate())
		{
			MyGUI::Gui::getInstance().eventFrameStart += MyGUI::newDelegate(this, &RenderBoxScene::frameEntered);
			mFrameAdvise = true;
		}
		else if (!_advise && mFrameAdvise && !needFrameUpdate())
		{
			MyGUI::Gui::getInstance().eventFrameStart -= MyGUI::newDelegate(this, &RenderBoxScene::frameEntered);
			mFrameAdvise = false;
		}
	}

	void RenderBoxScene::notifyMouseDrag(MyGUI::WidgetPtr _sender, int _left, int _top)
	{
		if (mMouseRotation)
		{
			if (mNode)
				mNode->yaw(Ogre::Radian(Ogre::Degree(_left - mLastPointerX)));
			mLastPointerX = _left;
		}
	}

	void RenderBoxScene::notifyMouseButtonPressed(MyGUI::WidgetPtr _sender, int _left, int _top, MyGUI::MouseButton _id)
	{
		if (_id == MyGUI::MouseButton::Left)
		{
			if (mMouseRotation)
			{
				const MyGUI::IntPoint & point = MyGUI::InputManager::getInstance().getLastLeftPressed();
				mLastPointerX = point.left;
				mLeftPressed = true;
			}
		}
	}

	void RenderBoxScene::notifyMouseButtonReleased(MyGUI::WidgetPtr _sender, int _left, int _top, MyGUI::MouseButton _id)
	{
		if (MyGUI::MouseButton::Left == _id) mLeftPressed = false;
	}

} // namespace wraps
<|endoftext|>


<commit_before>#include "ride/projectexplorer.h"

#include <vector>

#include <wx/dir.h>
#include <wx/filename.h>

#include "ride/mainwindow.h"

ProjectExplorer::ProjectExplorer(MainWindow* main)
  : wxTreeCtrl(main, wxID_ANY, wxDefaultPosition, wxDefaultSize,
  wxTR_HAS_BUTTONS
  | wxTR_TWIST_BUTTONS
  | wxTR_MULTIPLE
  | wxTR_LINES_AT_ROOT
  ), main_(main) {
  UpdateColors();
}

void ProjectExplorer::UpdateColors() {
  const ride::Style& style = main_->settings().fonts_and_colors().default_style();
  this->SetBackgroundColour(C(style.background()));
  this->SetForegroundColour(C(style.foreground()));
}

void ProjectExplorer::SetFolder(const wxString& folder) {
  folder_ = folder;
  UpdateFolderStructure();
}

bool IsDiretory(const wxFileName& root, const wxString directory) {
  wxFileName temp = root;
  temp.AppendDir(directory);
  const wxString full_path = temp.GetFullPath();
  const bool ret = wxDir::Exists(full_path);
  return ret;
}

void ProjectExplorer::UpdateFolderStructure() {
  this->AppendItem(this->GetRootItem(), "Project");

  const int flags = wxDIR_FILES | wxDIR_DIRS; // walk files and folders
  const wxString filespec = "";

  SubUpdateFolderStructure(folder_, this->GetRootItem(), filespec, flags);

  this->ExpandAll();
}

std::vector<wxString> TraverseFilesAndFolders(const wxFileName& root, const wxString filespec, const int flags) {
  std::vector<wxString> ret;
  const wxString root_full_path = root.GetFullPath();

  wxDir directory(root_full_path);

  directory.Open(root_full_path);

  wxString file_or_directory_name;
  bool cont = directory.GetFirst(&file_or_directory_name, filespec, flags);
  while (cont)
  {
    ret.push_back(file_or_directory_name);
    cont = directory.GetNext(&file_or_directory_name);
  }

  directory.Close();
  return ret;
}

void ProjectExplorer::SubUpdateFolderStructure(const wxFileName& root, wxTreeItemId parent, const wxString filespec, const int flags)
{
  const wxString root_full_path = root.GetFullPath();
  const std::vector<wxString> files_and_folders = TraverseFilesAndFolders(root, filespec, flags);
  for (const wxString file_or_directory_name : files_and_folders)
  {
    wxTreeItemId child = this->AppendItem(parent, file_or_directory_name);
    if (IsDiretory(root, file_or_directory_name)) {
      wxFileName child_name(root);
      child_name.AppendDir(file_or_directory_name);
      SubUpdateFolderStructure(child_name, child, filespec, flags);
    }
  }
}
<commit_msg>Refactored some code<commit_after>#include "ride/projectexplorer.h"

#include <vector>

#include <wx/dir.h>
#include <wx/filename.h>

#include "ride/mainwindow.h"

ProjectExplorer::ProjectExplorer(MainWindow* main)
  : wxTreeCtrl(main, wxID_ANY, wxDefaultPosition, wxDefaultSize,
  wxTR_HAS_BUTTONS
  | wxTR_TWIST_BUTTONS
  | wxTR_MULTIPLE
  | wxTR_LINES_AT_ROOT
  ), main_(main) {
  UpdateColors();
}

void ProjectExplorer::UpdateColors() {
  const ride::Style& style = main_->settings().fonts_and_colors().default_style();
  this->SetBackgroundColour(C(style.background()));
  this->SetForegroundColour(C(style.foreground()));
}

void ProjectExplorer::SetFolder(const wxString& folder) {
  folder_ = folder;
  UpdateFolderStructure();
}

wxFileName SubFolder(const wxFileName& root, const wxString& sub_folder) {
  wxFileName folder(root);
  folder.AppendDir(sub_folder);
  return folder;
}

bool IsDiretory(const wxFileName& root, const wxString directory) {
  const wxFileName temp = SubFolder(root, directory);
  const wxString full_path = temp.GetFullPath();
  const bool ret = wxDir::Exists(full_path);
  return ret;
}

void ProjectExplorer::UpdateFolderStructure() {
  this->AppendItem(this->GetRootItem(), "Project");

  const int flags = wxDIR_FILES | wxDIR_DIRS; // walk files and folders
  const wxString filespec = "";

  SubUpdateFolderStructure(folder_, this->GetRootItem(), filespec, flags);

  this->ExpandAll();
}

std::vector<wxString> TraverseFilesAndFolders(const wxFileName& root, const wxString filespec, const int flags) {
  std::vector<wxString> ret;
  const wxString root_full_path = root.GetFullPath();

  wxDir directory(root_full_path);

  directory.Open(root_full_path);

  wxString file_or_directory_name;
  bool cont = directory.GetFirst(&file_or_directory_name, filespec, flags);
  while (cont)
  {
    ret.push_back(file_or_directory_name);
    cont = directory.GetNext(&file_or_directory_name);
  }

  directory.Close();
  return ret;
}

void ProjectExplorer::SubUpdateFolderStructure(const wxFileName& root, wxTreeItemId parent, const wxString filespec, const int flags)
{
  const wxString root_full_path = root.GetFullPath();
  const std::vector<wxString> files_and_folders = TraverseFilesAndFolders(root, filespec, flags);
  for (const wxString file_or_directory_name : files_and_folders)
  {
    wxTreeItemId child = this->AppendItem(parent, file_or_directory_name);
    if (IsDiretory(root, file_or_directory_name)) {
      const wxFileName child_name = SubFolder(root, file_or_directory_name);
      SubUpdateFolderStructure(child_name, child, filespec, flags);
    }
  }
}
<|endoftext|>