<commit_before>#line 2 "libsxc:Signal/Waiter.cxx"
// LICENSE/*{{{*/
/*
  libsxc
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*}}}*/

// INCLUDE/*{{{*/

#include <map>

#include <pthread.h>
#include <signal.h>
#include <errno.h>

#include <libsxc/Signal/Waiter.hxx>

/*}}}*/

namespace libsxc
{
  namespace Signal
  {
    Waiter::Waiter(bool fill)/*{{{*/
    : _handlers()
    , _set()
    , _threadId()
    , _stopRequested(false)
    , _running(false)
    {
      if (fill) {
        // Fill with all signals.
        if (sigfillset(&_set))
          return;
      } else {
        // Clear the signal selection.
        if (sigemptyset(&_set))
          return;
      }
      // Publish the sigmask.
      int status = pthread_sigmask(SIG_SETMASK, &_set, NULL);
      if (status)
        return;
    }/*}}}*/
    Waiter::~Waiter()/*{{{*/
    {
      if (_running) {
        stop();
        pthread_join(_threadId, NULL);
      }
    }/*}}}*/

    void Waiter::reg(unsigned int signal, Handler &sh)/*{{{*/
    {
      if (_handlers.end() != _handlers.find(signal)) {
        // There already is a signal handler registered for this signal.
        // FIXME: throw appropriate exception
        return;
      }
      if (_running) {
        // Don't register signal handlers while running, as they would be added
        // _after_ the next signal has been received.
        // FIXME: throw appropriate exception
        return;
      }
      if (sigaddset(&_set, signal))
        return;
      _handlers.insert(std::make_pair(signal, &sh));

      int status = pthread_sigmask(SIG_SETMASK, &_set, NULL);
      if (status)
        return;
    }/*}}}*/
    void Waiter::run()/*{{{*/
    {
      if (_stopRequested) {
        // A stop may have been requested even before the waiter is up and
        // running.
        return;
      }

      if (_handlers.empty() && !sigismember(&_set, SIGINT)) {
        // We need at least one signal handler registered, or all signals set
        // to ignore, so we can send it in case we want to stop the thread.
        // FIXME: throw appropriate exception
        return;
      }

      int status;

      status = pthread_create(&_threadId, NULL, _wait, (void *) this);
      if (status) {
        // FIXME: throw exception.
        return;
      }
    }/*}}}*/
    void Waiter::join()/*{{{*/
    {
      if (_running)
        pthread_join(_threadId, NULL);
    }/*}}}*/
    void Waiter::stop()/*{{{*/
    {
      _stopRequested = true;

      if (!_running) {
        // Allow this method without having the thread actually running. This
        // will make the run method return immediately, as the stop is still
        // requested.
        return;
      }

      // Send a signal to the current process that will be caught by the
      // running @ref wait thread and result in the thread to exit. Not using
      // _threadId or raise(), as they are thread specific.
      unsigned int signal;
      if (_handlers.empty()) {
        signal = SIGINT;
      } else {
        signal = _handlers.begin()->first;
      }
      if (-1 == kill(getpid(), signal)) {
        int err = errno;
        return;
      }
    }/*}}}*/

    void *Waiter::_wait(void *rawThat)/*{{{*/
    {
      Waiter *that = reinterpret_cast<Waiter *>(rawThat);
      that->_running = true;
      int number;
      int count = 0;
      Handlers::iterator handler;
      int status;

      while (true) {
        status = sigwait(&(that->_set), &number);
        if (status)
          break;

        if (that->_stopRequested) {
          // Don't call the handler as we have to exit immediately. The
          // received signal is most probably the one sent by the @ref stop
          // method, but this doesn't matter, and does not have to be proven,
          // as we have to exit anyway without handling anything else (even the
          // signals already in queue).
          break;
        }

        handler = that->_handlers.find(number);
        if (that->_handlers.end() != handler)
          handler->second->handle(number);
        // else: ignore.
      }

      that->_running = false;
      return (void *) NULL;
    }/*}}}*/
  }
}

// Use no tabs at all; two spaces indentation; max. eighty chars per line.
// vim: et ts=2 sw=2 sts=2 tw=80 fdm=marker
<commit_msg>Fix: Include neccessary system headers<commit_after>#line 2 "libsxc:Signal/Waiter.cxx"
// LICENSE/*{{{*/
/*
  libsxc
  Copyright (C) 2008 Dennis Felsing, Andreas Waidler

  Permission to use, copy, modify, and/or distribute this software for any
  purpose with or without fee is hereby granted, provided that the above
  copyright notice and this permission notice appear in all copies.

  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
/*}}}*/

// INCLUDE/*{{{*/

#include <map>

#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

#include <libsxc/Signal/Waiter.hxx>

/*}}}*/

namespace libsxc
{
  namespace Signal
  {
    Waiter::Waiter(bool fill)/*{{{*/
    : _handlers()
    , _set()
    , _threadId()
    , _stopRequested(false)
    , _running(false)
    {
      if (fill) {
        // Fill with all signals.
        if (sigfillset(&_set))
          return;
      } else {
        // Clear the signal selection.
        if (sigemptyset(&_set))
          return;
      }
      // Publish the sigmask.
      int status = pthread_sigmask(SIG_SETMASK, &_set, NULL);
      if (status)
        return;
    }/*}}}*/
    Waiter::~Waiter()/*{{{*/
    {
      if (_running) {
        stop();
        pthread_join(_threadId, NULL);
      }
    }/*}}}*/

    void Waiter::reg(unsigned int signal, Handler &sh)/*{{{*/
    {
      if (_handlers.end() != _handlers.find(signal)) {
        // There already is a signal handler registered for this signal.
        // FIXME: throw appropriate exception
        return;
      }
      if (_running) {
        // Don't register signal handlers while running, as they would be added
        // _after_ the next signal has been received.
        // FIXME: throw appropriate exception
        return;
      }
      if (sigaddset(&_set, signal))
        return;
      _handlers.insert(std::make_pair(signal, &sh));

      int status = pthread_sigmask(SIG_SETMASK, &_set, NULL);
      if (status)
        return;
    }/*}}}*/
    void Waiter::run()/*{{{*/
    {
      if (_stopRequested) {
        // A stop may have been requested even before the waiter is up and
        // running.
        return;
      }

      if (_handlers.empty() && !sigismember(&_set, SIGINT)) {
        // We need at least one signal handler registered, or all signals set
        // to ignore, so we can send it in case we want to stop the thread.
        // FIXME: throw appropriate exception
        return;
      }

      int status;

      status = pthread_create(&_threadId, NULL, _wait, (void *) this);
      if (status) {
        // FIXME: throw exception.
        return;
      }
    }/*}}}*/
    void Waiter::join()/*{{{*/
    {
      if (_running)
        pthread_join(_threadId, NULL);
    }/*}}}*/
    void Waiter::stop()/*{{{*/
    {
      _stopRequested = true;

      if (!_running) {
        // Allow this method without having the thread actually running. This
        // will make the run method return immediately, as the stop is still
        // requested.
        return;
      }

      // Send a signal to the current process that will be caught by the
      // running @ref wait thread and result in the thread to exit. Not using
      // _threadId or raise(), as they are thread specific.
      unsigned int signal;
      if (_handlers.empty()) {
        signal = SIGINT;
      } else {
        signal = _handlers.begin()->first;
      }
      if (-1 == kill(getpid(), signal)) {
        int err = errno;
        return;
      }
    }/*}}}*/

    void *Waiter::_wait(void *rawThat)/*{{{*/
    {
      Waiter *that = reinterpret_cast<Waiter *>(rawThat);
      that->_running = true;
      int number;
      int count = 0;
      Handlers::iterator handler;
      int status;

      while (true) {
        status = sigwait(&(that->_set), &number);
        if (status)
          break;

        if (that->_stopRequested) {
          // Don't call the handler as we have to exit immediately. The
          // received signal is most probably the one sent by the @ref stop
          // method, but this doesn't matter, and does not have to be proven,
          // as we have to exit anyway without handling anything else (even the
          // signals already in queue).
          break;
        }

        handler = that->_handlers.find(number);
        if (that->_handlers.end() != handler)
          handler->second->handle(number);
        // else: ignore.
      }

      that->_running = false;
      return (void *) NULL;
    }/*}}}*/
  }
}

// Use no tabs at all; two spaces indentation; max. eighty chars per line.
// vim: et ts=2 sw=2 sts=2 tw=80 fdm=marker
<|endoftext|>


<commit_before>
#include <libclientserver.h>

SignalHandler::SignalHandler(ISignalHandler *handler)
{
	this->handler = handler;
	m_loop = true;

	if (sigemptyset(&m_sigs) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGALRM) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGCHLD) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGHUP) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGTERM) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGUSR1) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGUSR2) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGPIPE) < 0)
		abort();

	if (sigprocmask(SIG_BLOCK, &m_sigs, NULL) < 0)
	{
		abort();
	}

	Thread::Start();
}

SignalHandler::~SignalHandler()
{
	m_loop = false;
	Thread::Signal(SIGUSR1);
	Thread::Stop();

	if (sigprocmask(SIG_UNBLOCK, &m_sigs, NULL) < 0)
	{
		abort();
	}
}

void SignalHandler::Block()
{
	m_mutex.Lock();
}

void SignalHandler::UnBlock()
{
	m_mutex.Unlock();
}

void SignalHandler::Run()
{
	while(1)
	{
		siginfo_t info;
		if (sigwaitinfo(&m_sigs, &info) < 0)
			abort();

		if (m_loop == false)
			break;

		m_mutex.Lock();
		switch(info.si_signo)
		{
			case SIGALRM:
				handler->SigAlarm(&info);
				break;
			case SIGCHLD:
				handler->SigChild(&info);
				break;
			case SIGHUP:
				handler->SigHUP(&info);
				break;
			case SIGTERM:
				handler->SigTerm(&info);
				break;
			case SIGUSR1:
				handler->SigUser1(&info);
				break;
			case SIGUSR2:
				handler->SigUser2(&info);
				break;
			case SIGPIPE:
				handler->SigPipe(&info);
				break;
			default:
				abort(); //Unknown signal
				break;
		}
		m_mutex.Unlock();
	}
}

<commit_msg>Fixed issue when debugger attached<commit_after>
#include <libclientserver.h>

SignalHandler::SignalHandler(ISignalHandler *handler)
{
	this->handler = handler;
	m_loop = true;

	if (sigemptyset(&m_sigs) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGALRM) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGCHLD) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGHUP) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGTERM) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGUSR1) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGUSR2) < 0)
		abort();

	if (sigaddset(&m_sigs, SIGPIPE) < 0)
		abort();

	if (sigprocmask(SIG_BLOCK, &m_sigs, NULL) < 0)
	{
		abort();
	}

	Thread::Start();
}

SignalHandler::~SignalHandler()
{
	m_loop = false;
	Thread::Signal(SIGUSR1);
	Thread::Stop();

	if (sigprocmask(SIG_UNBLOCK, &m_sigs, NULL) < 0)
	{
		abort();
	}
}

void SignalHandler::Block()
{
	m_mutex.Lock();
}

void SignalHandler::UnBlock()
{
	m_mutex.Unlock();
}

void SignalHandler::Run()
{
	while(1)
	{
		siginfo_t info;
		if (sigwaitinfo(&m_sigs, &info) < 0)
		{
			switch(errno)
			{
				case EINTR:
					continue;
					break;
				default:
					abort();
			}
		}

		if (m_loop == false)
			break;

		m_mutex.Lock();
		switch(info.si_signo)
		{
			case SIGALRM:
				handler->SigAlarm(&info);
				break;
			case SIGCHLD:
				handler->SigChild(&info);
				break;
			case SIGHUP:
				handler->SigHUP(&info);
				break;
			case SIGTERM:
				handler->SigTerm(&info);
				break;
			case SIGUSR1:
				handler->SigUser1(&info);
				break;
			case SIGUSR2:
				handler->SigUser2(&info);
				break;
			case SIGPIPE:
				handler->SigPipe(&info);
				break;
			default:
				abort(); //Unknown signal
				break;
		}
		m_mutex.Unlock();
	}
}

<|endoftext|>


<commit_before>#pragma once

#include <atomic>
#include <memory>
#include <thread>
#include <vector>

#include "types.hpp"
#include "utils/assert.hpp"

namespace opossum {

class TaskQueue;

/**
 * To be executed on a separate Thread, fetches and executes tasks until the queue is empty AND the shutdown flag is set
 * Ideally there should be one Worker actively doing work per CPU, but multiple might be active occasionally
 */
class Worker : public std::enable_shared_from_this<Worker>, private Noncopyable {
  friend class CurrentScheduler;

 public:
  static std::shared_ptr<Worker> get_this_thread_worker();

  Worker(const std::shared_ptr<TaskQueue>& queue, WorkerID id, CpuID cpu_id);

  /**
   * Unique ID of a worker. Currently not in use, but really helpful for debugging.
   */
  WorkerID id() const;
  std::shared_ptr<TaskQueue> queue() const;
  CpuID cpu_id() const;

  void start();
  void join();

  uint64_t num_finished_tasks() const;

  void operator=(const Worker&) = delete;
  void operator=(Worker&&) = delete;

 protected:
  void operator()();
  void _work();

  template <typename TaskType>
  void _wait_for_tasks(const std::vector<std::shared_ptr<TaskType>>& tasks) {
    auto tasks_completed = [&tasks]() {
      for (auto& task : tasks) {
        if (!task->is_done()) {
          return false;
        }
      }
      return true;
    };

    while (!tasks_completed()) {
      _work();
    }
  }

 private:
  /**
   * Pin a worker to a particular core.
   * This does not work on non-NUMA systems, and might be addressed in the future.
   */
  void _set_affinity();

  std::shared_ptr<TaskQueue> _queue;
  WorkerID _id;
  CpuID _cpu_id;
  std::thread _thread;
  std::atomic<uint64_t> _num_finished_tasks{0};
};

}  // namespace opossum
<commit_msg>Reverse check if tasks are completed in Worker::_wait_for_tasks(). (#1386)<commit_after>#pragma once

#include <atomic>
#include <memory>
#include <thread>
#include <vector>

#include "types.hpp"
#include "utils/assert.hpp"

namespace opossum {

class TaskQueue;

/**
 * To be executed on a separate Thread, fetches and executes tasks until the queue is empty AND the shutdown flag is set
 * Ideally there should be one Worker actively doing work per CPU, but multiple might be active occasionally
 */
class Worker : public std::enable_shared_from_this<Worker>, private Noncopyable {
  friend class CurrentScheduler;

 public:
  static std::shared_ptr<Worker> get_this_thread_worker();

  Worker(const std::shared_ptr<TaskQueue>& queue, WorkerID id, CpuID cpu_id);

  /**
   * Unique ID of a worker. Currently not in use, but really helpful for debugging.
   */
  WorkerID id() const;
  std::shared_ptr<TaskQueue> queue() const;
  CpuID cpu_id() const;

  void start();
  void join();

  uint64_t num_finished_tasks() const;

  void operator=(const Worker&) = delete;
  void operator=(Worker&&) = delete;

 protected:
  void operator()();
  void _work();

  template <typename TaskType>
  void _wait_for_tasks(const std::vector<std::shared_ptr<TaskType>>& tasks) {
    auto tasks_completed = [&tasks]() {
      // Reversely iterate through the list of tasks, because unfinished tasks are likely at the end of the list.
      for (auto it = tasks.rbegin() ; it != tasks.rend() ; ++it) {
        if (!(*it)->is_done()) {
          return false;
        }
      }
      return true;
    };

    while (!tasks_completed()) {
      _work();
    }
  }

 private:
  /**
   * Pin a worker to a particular core.
   * This does not work on non-NUMA systems, and might be addressed in the future.
   */
  void _set_affinity();

  std::shared_ptr<TaskQueue> _queue;
  WorkerID _id;
  CpuID _cpu_id;
  std::thread _thread;
  std::atomic<uint64_t> _num_finished_tasks{0};
};

}  // namespace opossum
<|endoftext|>


<commit_before>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2020, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

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

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

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

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

#include <lib/support-lean/OSUtil.h>

//*************************** Forward Declarations **************************

using std::endl;

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

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

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

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

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

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("[FileUtil::copy] could not open destination file '"
	       << dst << "' (" << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("could not open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Throw("[FileUtil::copy] could not open source files: " << errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("[FileUtil::move] '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find 'curIdx' such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  //
  // Note: Could make this a binary search, but it would likely have
  // insignificant effects.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("[FileUtil::mkdir] '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret != 0) {
    if (errno == EEXIST) {

      std::vector<string> dirnmVec;

      // qualifier 1: jobid
      const char* jobid_cstr = OSUtil_jobid();
      if (jobid_cstr) {
	string dirnm1 = string(dirnm) + "-" + string(jobid_cstr);
	dirnmVec.push_back(dirnm1);
      }

      // qualifier 2: pid
      uint pid = OSUtil_pid();
      string pid_str = StrUtil::toStr(pid);
      string dirnm2 = string(dirnm) + "-" + pid_str;
      dirnmVec.push_back(dirnm2);

      // attempt to create alternative directories
      for (uint i = 0; i < dirnmVec.size(); ++i) {
	dirnm_new = dirnmVec[i];
	DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying '" << dirnm_new << "'");
	ret = ::mkdir(dirnm_new.c_str(), mkmode);
	if (ret == 0) {
	  is_done = true;
	  break;
	}
      }

      if (is_done) {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
      }
      else {
	DIAG_Die("Could not create an alternative to directory " << dirnm);
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<commit_msg>changed FileUtil::copy fatal error into a warning<commit_after>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2020, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

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

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

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

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

#include <lib/support-lean/OSUtil.h>

//*************************** Forward Declarations **************************

using std::endl;

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

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

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

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

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

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("Unable to write file in hpctoolkit database '"
	       << dst << "' (" << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("unable to open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Msg(1, "Unable to copy file into hpctoolkit database: " <<
	      errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("[FileUtil::move] '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find 'curIdx' such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  //
  // Note: Could make this a binary search, but it would likely have
  // insignificant effects.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("[FileUtil::mkdir] '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret != 0) {
    if (errno == EEXIST) {

      std::vector<string> dirnmVec;

      // qualifier 1: jobid
      const char* jobid_cstr = OSUtil_jobid();
      if (jobid_cstr) {
	string dirnm1 = string(dirnm) + "-" + string(jobid_cstr);
	dirnmVec.push_back(dirnm1);
      }

      // qualifier 2: pid
      uint pid = OSUtil_pid();
      string pid_str = StrUtil::toStr(pid);
      string dirnm2 = string(dirnm) + "-" + pid_str;
      dirnmVec.push_back(dirnm2);

      // attempt to create alternative directories
      for (uint i = 0; i < dirnmVec.size(); ++i) {
	dirnm_new = dirnmVec[i];
	DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying '" << dirnm_new << "'");
	ret = ::mkdir(dirnm_new.c_str(), mkmode);
	if (ret == 0) {
	  is_done = true;
	  break;
	}
      }

      if (is_done) {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
      }
      else {
	DIAG_Die("Could not create an alternative to directory " << dirnm);
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<|endoftext|>


<commit_before>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// -----------------------------------
// Part of HPCToolkit (hpctoolkit.org)
// -----------------------------------
//
// Copyright ((c)) 2002-2010, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

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

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

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

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

//*************************** Forward Declarations **************************

using std::endl;

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

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

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

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

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

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("could not open destination '" << dst << "' ("
	       << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("could not open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Throw("could not open source files: " << errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("moving '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find curIdx such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("While mkdir-ing '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret == -1) {
    if (errno == EEXIST) {
      // attempt to create dirnm+pid;
      pid_t pid = getpid();
      string pid_str = StrUtil::toStr(pid);
      dirnm_new = dirnm_new + "-" + pid_str;
      DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying " << dirnm_new);
      ret = ::mkdir(dirnm_new.c_str(), mkmode);
      if (ret == -1) {
	DIAG_Die("Could not create alternate directory " << dirnm_new);
      }
      else {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
	is_done = true;
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<commit_msg>FileUtil::mkdir(): minor update to comments.<commit_after>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// -----------------------------------
// Part of HPCToolkit (hpctoolkit.org)
// -----------------------------------
//
// Copyright ((c)) 2002-2010, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) nor the names of its
//   contributors may be used to endorse or promote products derived from
//   this software without specific prior written permission.
//
// This software is provided by RICE and contributors "as is" and any
// express or implied warranties, including, but not limited to, the
// implied warranties of merchantability and fitness for a particular
// purpose are disclaimed. In no event shall RICE or contributors be
// liable for any direct, indirect, incidental, special, exemplary, or
// consequential damages (including, but not limited to, procurement of
// substitute goods or services; loss of use, data, or profits; or
// business interruption) however caused and on any theory of liability,
// whether in contract, strict liability, or tort (including negligence
// or otherwise) arising in any way out of the use of this software, even
// if advised of the possibility of such damage.
//
// ******************************************************* EndRiceCopyright *

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

//************************* System Include Files ****************************

#include <sys/param.h>

#include <cstdlib> // for 'mkstemp' (not technically visible in C++)
#include <cstdio>  // for 'tmpnam', 'rename'
#include <cerrno>
#include <cstdarg>
#include <cstring>

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

#include <fnmatch.h>

#include <string>
using std::string;

//*************************** User Include Files ****************************

#include "FileUtil.hpp"

#include "diagnostics.h"
#include "StrUtil.hpp"
#include "Trace.hpp"

//*************************** Forward Declarations **************************

using std::endl;

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

namespace FileUtil {

string
basename(const char* fName)
{
  string baseFileName;

  const char* lastSlash = strrchr(fName, '/');
  if (lastSlash) {
    // valid: "/foo" || ".../foo" AND invalid: "/" || ".../"
    baseFileName = lastSlash + 1;
  }
  else {
    // filename contains no slashes, already in short form
    baseFileName = fName;
  }
  return baseFileName;

#if 0
  // A "more C++" implementation (Gaurav)
  std::string
  PathFindMgr::getFileName(const std::string& path) const
  {
    size_t in = path.find_last_of("/");
    if (in != path.npos && path.length() > 1)
      return path.substr(in + 1);

    return path;
  }
#endif
}

string
rmSuffix(const char* fName)
{
  string baseFileName = fName;

  size_t pos = baseFileName.find_last_of('.');
  if (pos != string::npos) {
    baseFileName = baseFileName.substr(0, pos);
  }
  return baseFileName;
}

string
dirname(const char* fName)
{
  const char* lastSlash = strrchr(fName, '/');
  string pathComponent = ".";
  if (lastSlash) {
    pathComponent = fName;
    pathComponent.resize(lastSlash - fName);
  }
  return pathComponent;
}

bool
fnmatch(const std::vector<std::string>& patternVec,
	const char* string, int flags)
{
  for (uint i = 0; i < patternVec.size(); ++i) {
    const std::string& pat = patternVec[i];
    bool fnd = FileUtil::fnmatch(pat, string, flags);
    if (fnd) {
      return true;
    }
  }

  return false;
}

} // end of FileUtil namespace

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

namespace FileUtil {

bool
isReadable(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return true; // the file is readable
  }
  return false;
}

bool
isDir(const char* path)
{
  struct stat sbuf;
  if (stat(path, &sbuf) == 0) {
    return (S_ISDIR(sbuf.st_mode)
	    /*|| S_ISLNK(sbuf.st_mode) && isDir(readlink(path))*/);
  }
  return false; // unknown
}

int
countChar(const char* path, char c)
{
  int srcFd = open(path, O_RDONLY);
  if (srcFd < 0) {
    return -1;
  }
  int count = 0;
  char buf[256];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, 256)) > 0) {
    for (int i = 0; i < nRead; i++) {
      if (buf[i] == c) count++;
    }
  }
  return count;
}

} // end of FileUtil namespace

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

static void
cpy(int srcFd, int dstFd)
{
  static const int bufSz = 4096;
  char buf[bufSz];
  ssize_t nRead;
  while ((nRead = read(srcFd, buf, bufSz)) > 0) {
    write(dstFd, buf, nRead);
  }
}

namespace FileUtil {

void
copy(const char* dst, ...)
{
  va_list srcFnmList;
  va_start(srcFnmList, dst);

  DIAG_MsgIf(0, "FileUtil::copy: ... -> " << dst);

  int dstFd = open(dst, O_WRONLY | O_CREAT | O_TRUNC,
		   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  if (dstFd < 0) {
    DIAG_Throw("could not open destination '" << dst << "' ("
	       << strerror(errno) << ")");
  }

  string errorMsg;

  char* srcFnm;
  while ( (srcFnm = va_arg(srcFnmList, char*)) ) {
    int srcFd = open(srcFnm, O_RDONLY);
    if ((srcFd < 0) || (dstFd < 0)) {
      errorMsg += (string("could not open '") + srcFnm + "' ("
		   + strerror(errno) + ")");
    }
    else {
      cpy(srcFd, dstFd);
      close(srcFd);
    }
  }

  va_end(srcFnmList);
  close(dstFd);

  if (!errorMsg.empty()) {
    DIAG_Throw("could not open source files: " << errorMsg);
  }
}

void
move(const char* dst, const char* src)
{
  int ret = rename(src, dst);
  if (ret != 0) {
    DIAG_Throw("moving '" << src << "' -> '" << dst << "'");
  }
}

int
remove(const char* file)
{
  return unlink(file);
}

int
mkdir(const char* dir)
{
  if (!dir) {
    DIAG_Throw("Invalid mkdir argument: (NULL)");
  }

  string pathStr = dir;
  bool isAbsPath = (dir[0] == '/');

  // -------------------------------------------------------
  // 1. Convert path string to vector of path components
  //    "/p0/p1/p2/.../pn/px" ==> [p0 p1 p2 ... pn px]
  //    "/p0"                 ==> [p0]
  //    "p0"                  ==> [p0]
  //    "./p0"                ==> [. p0]
  //
  // Note: we could do tokenization in place (string::find_last_of()),
  // but (1) this is more elegant and (2) sytem calls and disk
  // accesses will overwhelm any possible difference in performance.
  // -------------------------------------------------------
  std::vector<string> pathVec;
  StrUtil::tokenize_char(pathStr, "/", pathVec);

  DIAG_Assert(!pathVec.empty(), DIAG_UnexpectedInput);

  // -------------------------------------------------------
  // 2. Find 'curIdx' such that all paths before pathVec[curIdx] have
  // been created.
  //
  // Note: Start search from the last path component, assuming that in
  // the common case, intermediate directories are already created.
  //
  // Note: Could make this a binary search, but it would likely have
  // insignificant effects.
  // -------------------------------------------------------
  size_t begIdx = 0;
  size_t endIdx = pathVec.size() - 1;

  size_t curIdx = endIdx;
  for ( ; curIdx >= begIdx; --curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    if (isDir(x)) {
      break; // FIXME: double check: what if this is a symlink?
    }
  }

  curIdx++;

  // -------------------------------------------------------
  // 3. Build directories from pathVec[curIdx ... endIdx]
  // -------------------------------------------------------
  mode_t mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  for ( ; curIdx <= endIdx; ++curIdx) {
    string x = StrUtil::join(pathVec, "/", 0, curIdx + 1);
    if (isAbsPath) {
      x = "/" + x;
    }

    int ret = ::mkdir(x.c_str(), mode);
    if (ret != 0) {
      DIAG_Throw("While mkdir-ing '" << pathStr << "': Could not mkdir '"
		 << x << "' (" << strerror(errno) << ")");
    }
  }

  return 0;
}

std::pair<string, bool>
mkdirUnique(const char* dirnm)
{
  string dirnm_new = dirnm;
  bool is_done = false;

  mode_t mkmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

  int ret = ::mkdir(dirnm, mkmode);
  if (ret == -1) {
    if (errno == EEXIST) {
      // attempt to create dirnm+pid;
      pid_t pid = getpid();
      string pid_str = StrUtil::toStr(pid);
      dirnm_new = dirnm_new + "-" + pid_str;
      DIAG_Msg(1, "Directory '" << dirnm << "' already exists. Trying " << dirnm_new);
      ret = ::mkdir(dirnm_new.c_str(), mkmode);
      if (ret == -1) {
	DIAG_Die("Could not create alternate directory " << dirnm_new);
      }
      else {
	DIAG_Msg(1, "Created directory: " << dirnm_new);
	is_done = true;
      }
    }
    else {
      DIAG_Die("Could not create database directory " << dirnm);
    }
  }

  return make_pair(dirnm_new, is_done);
}

const char*
tmpname()
{
  // below is a hack to replace the deprecated tmpnam which g++ 3.2.2 will
  // no longer allow. the mkstemp routine, which is touted as the replacement
  // for tmpnam, provides a file descriptor as a return value. there is
  // unfortunately no way to interface this with the ofstream class constructor
  // which requires a filename. thus, a hack is born ...
  // John Mellor-Crummey 5/7/2003

  // eraxxon: GNU is right that 'tmpnam' can be dangerous, but
  // 'mkstemp' is not strictly part of C++! We could create an
  // interface to 'mkstemp' within a C file, but this is getting
  // cumbersome... and 'tmpnam' is not quite a WMD.

#ifdef __GNUC__
  static char tmpfilename[MAXPATHLEN];

  // creating a unique temp name with the new mkstemp interface now
  // requires opening, closing, and deleting a file when all we want
  // is the filename. sigh ...
  strcpy(tmpfilename,"/tmp/hpcviewtmpXXXXXX");
  close(mkstemp(tmpfilename));
  unlink(tmpfilename);

  return tmpfilename;
#else
  return tmpnam(NULL);
#endif
}

} // end of FileUtil namespace

<|endoftext|>


<commit_before>/*
  http://portaudio.com/docs/v19-doxydocs/api_overview.html
*/

/* BEGIN Setup */
#include "portaudio.h"
#include "pa_asio.h"
#include <nan.h>

using namespace Nan;
using String = v8::String;
using Number = v8::Number;
using Object = v8::Object;
using Value = v8::Value;
using Value = v8::Value;
using LocalString = v8::Local<String>;
using LocalNumber = v8::Local<Number>;
using LocalObject = v8::Local<Object>;
using LocalValue = v8::Local<Value>;
using MaybeLocalValue = v8::MaybeLocal<Value>;

/* BEGIN Helpers */
int LocalizeInt (MaybeLocalValue lvIn) {
  return lvIn.ToLocalChecked()->Uint32Value();
}

/* BEGIN Initialization, termination, and utility */
NAN_METHOD(initialize) {
  PaError err = Pa_Initialize();
  if (err != paNoError) {
    ThrowError(Pa_GetErrorText(err));
  }
}

NAN_METHOD(terminate) {
  PaError err = Pa_Terminate();
  if (err != paNoError) {
    ThrowError(Pa_GetErrorText(err));
  }
}

NAN_METHOD(getVersion) {
  info.GetReturnValue().Set(Pa_GetVersion());
}

/* BEGIN Host APIs */
NAN_METHOD(getHostApiCount) {
  info.GetReturnValue().Set(Pa_GetHostApiCount());
}

NAN_METHOD(getDefaultHostApi) {
  info.GetReturnValue().Set(Pa_GetDefaultHostApi());
}

NAN_METHOD(getHostApiInfo) {
  HandleScope scope;
  int api = info[0].IsEmpty() ? Pa_GetDefaultHostApi() : info[0]->Uint32Value();
  const PaHostApiInfo* hai = Pa_GetHostApiInfo(api);
  LocalObject obj = New<Object>();
  LocalString haiIndex = New("apiIndex").ToLocalChecked();
  LocalString haiType = New("type").ToLocalChecked();
  LocalString haiName = New("name").ToLocalChecked();
  LocalString haiDefC = New("deviceCount").ToLocalChecked();
  LocalString haiDefIn = New("defaultInputDevice").ToLocalChecked();
  LocalString haiDefOut = New("defaultOutputDevice").ToLocalChecked();
  obj->Set(haiIndex, New<Number>(api));
  obj->Set(haiType, New<Number>(hai->type));
  obj->Set(haiName, New<String>(hai->name).ToLocalChecked());
  obj->Set(haiDefC, New<Number>(hai->deviceCount));
  obj->Set(haiDefIn, New<Number>(hai->defaultInputDevice));
  obj->Set(haiDefOut, New<Number>(hai->defaultOutputDevice));
  info.GetReturnValue().Set(obj);
}

/* BEGIN Device APIs */
NAN_METHOD(getDeviceCount) {
  info.GetReturnValue().Set(Pa_GetDeviceCount());
}

NAN_METHOD(getDefaultInputDevice) {
  info.GetReturnValue().Set(Pa_GetDefaultInputDevice());
}

NAN_METHOD(getDefaultOutputDevice) {
  info.GetReturnValue().Set(Pa_GetDefaultOutputDevice());
}

NAN_METHOD(getDeviceInfo) {
  HandleScope scope;
  int dvc = info[0].IsEmpty()
    ? Pa_GetDefaultInputDevice()
    : info[0]->Uint32Value();
  const PaDeviceInfo* di = Pa_GetDeviceInfo(dvc);
  LocalObject obj = New<Object>();
  LocalString diIndex = New("deviceIndex").ToLocalChecked();
  LocalString diHost = New("hostApi").ToLocalChecked();
  LocalString diName = New("name").ToLocalChecked();
  LocalString diMaxI = New("maxInputChannels").ToLocalChecked();
  LocalString diMaxO = New("maxOutputChannels").ToLocalChecked();
  LocalString diDefLIL = New("defaultLowInputLatency").ToLocalChecked();
  LocalString diDefLOL = New("defaultLowOutputLatency").ToLocalChecked();
  LocalString diDefHIL = New("defaultHighInputLatency").ToLocalChecked();
  LocalString diDefHOL = New("defaultHighOutputLatency").ToLocalChecked();
  LocalString diDefSR = New("defaultSampleRate").ToLocalChecked();
  obj->Set(diIndex, New<Number>(dvc));
  obj->Set(diHost, New<Number>(di->hostApi));
  obj->Set(diName, New<String>(di->name).ToLocalChecked());
  obj->Set(diMaxI, New<Number>(di->maxInputChannels));
  obj->Set(diMaxO, New<Number>(di->maxOutputChannels));
  obj->Set(diDefLIL, New<Number>(di->defaultLowInputLatency));
  obj->Set(diDefLOL, New<Number>(di->defaultLowOutputLatency));
  obj->Set(diDefHIL, New<Number>(di->defaultHighInputLatency));
  obj->Set(diDefHOL, New<Number>(di->defaultHighOutputLatency));
  obj->Set(diDefSR, New<Number>(di->defaultSampleRate));
  info.GetReturnValue().Set(obj);
}

/* BEGIN Stream APIs */
NAN_METHOD(openStream) {
  HandleScope scope;
  LocalObject obj = info[0]->ToObject();
  LocalString input = New("input").ToLocalChecked();
  LocalString output = New("output").ToLocalChecked();
  LocalObject objInput = Get(obj, input).ToLocalChecked()->ToObject();
  LocalObject objOutput = Get(obj, output).ToLocalChecked()->ToObject();
  LocalString device = New("device").ToLocalChecked();
  LocalString channelCount = New("channelCount").ToLocalChecked();
  LocalString sampleFormat = New("sampleFormat").ToLocalChecked();
  LocalString suggestedLatency = New("suggestedLatency").ToLocalChecked();

  PaStreamParameters paramsIn = {
    static_cast<PaDeviceIndex>(LocalizeInt(Get(objInput, device))),
    static_cast<int>(LocalizeInt(Get(objInput, channelCount))),
    static_cast<PaSampleFormat>(LocalizeInt(Get(objInput, sampleFormat))),
    static_cast<PaTime>(LocalizeInt(Get(objInput, suggestedLatency))),
    NULL
  };

  PaStreamParameters paramsOut = {
    static_cast<PaDeviceIndex>(LocalizeInt(Get(objOutput, device))),
    static_cast<int>(LocalizeInt(Get(objOutput, channelCount))),
    static_cast<PaSampleFormat>(LocalizeInt(Get(objOutput, sampleFormat))),
    static_cast<PaTime>(LocalizeInt(Get(objOutput, suggestedLatency))),
    NULL
  };

  // Testing that params are set right
  info.GetReturnValue().Set(New<Number>(paramsIn.device));
}

/* BEGIN Init & Exports */
NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, initialize);
  NAN_EXPORT(target, terminate);
  NAN_EXPORT(target, getVersion);
  NAN_EXPORT(target, getHostApiCount);
  NAN_EXPORT(target, getDefaultHostApi);
  NAN_EXPORT(target, getHostApiInfo);
  NAN_EXPORT(target, getDeviceCount);
  NAN_EXPORT(target, getDefaultInputDevice);
  NAN_EXPORT(target, getDefaultOutputDevice);
  NAN_EXPORT(target, getDeviceInfo);
  NAN_EXPORT(target, openStream);
}

NODE_MODULE(jsaudio, Init)
<commit_msg>Refactor a bit<commit_after>/*
  http://portaudio.com/docs/v19-doxydocs/api_overview.html
*/

/* BEGIN Setup */
// #include "helpers.cc"
#include "portaudio.h"
#include <nan.h>
#ifdef _WIN32
  #include "pa_asio.h"
#endif

using namespace Nan;
using String = v8::String;
using Number = v8::Number;
using Object = v8::Object;
using Value = v8::Value;
using Value = v8::Value;
using LocalString = v8::Local<String>;
using LocalNumber = v8::Local<Number>;
using LocalObject = v8::Local<Object>;
using LocalValue = v8::Local<Value>;
using MaybeLocalValue = v8::MaybeLocal<Value>;

/* BEGIN Helpers */
int LocalizeInt (MaybeLocalValue lvIn) {
  return lvIn.ToLocalChecked()->Uint32Value();
}

LocalString ToLocString (std::string str) {
  return New(str).ToLocalChecked();
}

LocalObject ToLocObject (MaybeLocalValue lvIn) {
  return lvIn.ToLocalChecked()->ToObject();
}

void HostApiInfoToLocalObject (LocalObject obj, const PaHostApiInfo* hai) {
  obj->Set(
    ToLocString("type"), New<Number>(hai->type));
  obj->Set(
    ToLocString("name"), New<String>(hai->name).ToLocalChecked());
  obj->Set(
    ToLocString("deviceCount"), New<Number>(hai->deviceCount));
  obj->Set(
    ToLocString("defaultInputDevice"), New<Number>(hai->defaultInputDevice));
  obj->Set(
    ToLocString("defaultOutputDevice"), New<Number>(hai->defaultOutputDevice));
  return;
}

void DeviceInfoToLocalObject (LocalObject obj, const PaDeviceInfo* di) {
  obj->Set(
    ToLocString("hostApi"),
    New<Number>(di->hostApi));
  obj->Set(
    ToLocString("name"),
    New<String>(di->name).ToLocalChecked());
  obj->Set(
    ToLocString("maxInputChannels"),
    New<Number>(di->maxInputChannels));
  obj->Set(
    ToLocString("maxOutputChannels"),
    New<Number>(di->maxOutputChannels));
  obj->Set(
    ToLocString("defaultLowInputLatency"),
    New<Number>(di->defaultLowInputLatency));
  obj->Set(
    ToLocString("defaultLowOutputLatency"),
    New<Number>(di->defaultLowOutputLatency));
  obj->Set(
    ToLocString("defaultHighInputLatency"),
    New<Number>(di->defaultHighInputLatency));
  obj->Set(
    ToLocString("defaultHighOutputLatency"),
    New<Number>(di->defaultHighOutputLatency));
  obj->Set(
    ToLocString("defaultSampleRate"),
    New<Number>(di->defaultSampleRate));
  return;
}

PaStreamParameters LocObjToPaStreamParameters (LocalObject obj) {
  PaStreamParameters params = {
    static_cast<PaDeviceIndex>(
      LocalizeInt(Get(obj, ToLocString("device")))),
    static_cast<int>(
      LocalizeInt(Get(obj, ToLocString("channelCount")))),
    static_cast<PaSampleFormat>(
      LocalizeInt(Get(obj, ToLocString("sampleFormat")))),
    static_cast<PaTime>(
      LocalizeInt(Get(obj, ToLocString("suggestedLatency")))),
    NULL
  };
  return params;
}

/* BEGIN Initialization, termination, and utility */
NAN_METHOD(initialize) {
  PaError err = Pa_Initialize();
  if (err != paNoError) {
    ThrowError(Pa_GetErrorText(err));
  }
}

NAN_METHOD(terminate) {
  PaError err = Pa_Terminate();
  if (err != paNoError) {
    ThrowError(Pa_GetErrorText(err));
  }
}

NAN_METHOD(getVersion) {
  info.GetReturnValue().Set(Pa_GetVersion());
}

/* BEGIN Host APIs */
NAN_METHOD(getHostApiCount) {
  info.GetReturnValue().Set(Pa_GetHostApiCount());
}

NAN_METHOD(getDefaultHostApi) {
  info.GetReturnValue().Set(Pa_GetDefaultHostApi());
}

NAN_METHOD(getHostApiInfo) {
  HandleScope scope;
  int api = info[0].IsEmpty() ? Pa_GetDefaultHostApi() : info[0]->Uint32Value();
  const PaHostApiInfo* hai = Pa_GetHostApiInfo(api);
  LocalObject obj = New<Object>();
  obj->Set(ToLocString("apiIndex"), New<Number>(api));
  HostApiInfoToLocalObject(obj, hai);
  info.GetReturnValue().Set(obj);
}

/* BEGIN Device APIs */
NAN_METHOD(getDeviceCount) {
  info.GetReturnValue().Set(Pa_GetDeviceCount());
}

NAN_METHOD(getDefaultInputDevice) {
  info.GetReturnValue().Set(Pa_GetDefaultInputDevice());
}

NAN_METHOD(getDefaultOutputDevice) {
  info.GetReturnValue().Set(Pa_GetDefaultOutputDevice());
}

NAN_METHOD(getDeviceInfo) {
  HandleScope scope;
  int dvc = info[0].IsEmpty()
    ? Pa_GetDefaultInputDevice()
    : info[0]->Uint32Value();
  const PaDeviceInfo* di = Pa_GetDeviceInfo(dvc);
  LocalObject obj = New<Object>();
  obj->Set(ToLocString("deviceIndex"), New<Number>(dvc));
  DeviceInfoToLocalObject(obj, di);
  info.GetReturnValue().Set(obj);
}

/* BEGIN Stream APIs */
NAN_METHOD(openStream) {
  HandleScope scope;
  LocalObject obj = info[0]->ToObject();
  LocalObject objInput = ToLocObject(Get(obj, ToLocString("input")));
  LocalObject objOutput = ToLocObject(Get(obj, ToLocString("output")));
  PaStreamParameters paramsIn = LocObjToPaStreamParameters(objInput);
  PaStreamParameters paramsOut = LocObjToPaStreamParameters(objOutput);
  // Testing that params are set right
  info.GetReturnValue().Set(New<Number>(paramsIn.device));
}

/* BEGIN Init & Exports */
NAN_MODULE_INIT(Init) {
  NAN_EXPORT(target, initialize);
  NAN_EXPORT(target, terminate);
  NAN_EXPORT(target, getVersion);
  NAN_EXPORT(target, getHostApiCount);
  NAN_EXPORT(target, getDefaultHostApi);
  NAN_EXPORT(target, getHostApiInfo);
  NAN_EXPORT(target, getDeviceCount);
  NAN_EXPORT(target, getDefaultInputDevice);
  NAN_EXPORT(target, getDefaultOutputDevice);
  NAN_EXPORT(target, getDeviceInfo);
  NAN_EXPORT(target, openStream);
}

NODE_MODULE(jsaudio, Init)
<|endoftext|>


<commit_before>
#include "ThymioTracker.h"

#include <vector>
#include <stdexcept>
#include <fstream>

#include <opencv2/core.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

namespace thymio_tracker
{

static const std::vector<cv::Scalar> colorPalette = {
    cv::Scalar(76, 114, 176),
    cv::Scalar(85, 168, 104),
    cv::Scalar(196, 78, 82),
    cv::Scalar(129, 114, 178),
    cv::Scalar(204, 185, 116),
    cv::Scalar(100, 181, 205)
};

Timer::Timer()
    : mTicks{0}
    , mIndex(0)
    , mFps(-1.0)
{}

void Timer::tic()
{
    std::clock_t current = std::clock();
    std::clock_t prev = mTicks[mIndex];
    mTicks[mIndex] = current;
    ++mIndex;
    if(mIndex >= N)
        mIndex = 0;

    if(prev != 0)
        mFps = CLOCKS_PER_SEC * N / static_cast<double>(current - prev);
}

void DetectionInfo::clear()
{
    blobs.clear();
    blobPairs.clear();
    blobTriplets.clear();
    blobQuadriplets.clear();
    blobsinTriplets.clear();
    matches.clear();
}

void drawPointsAndIds(cv::Mat& inputImage, const std::vector<DetectionGH>& matches)
{
    //draw Id
    for(unsigned int i = 0; i < matches.size(); ++i)
    {
        char pointIdStr[100];
        sprintf(pointIdStr, "%d", matches[i].id);
        circle(inputImage, matches[i].position, 4, cvScalar(0, 250, 250), -1, 8, 0);
        putText(inputImage, pointIdStr, matches[i].position, cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cvScalar(250,250,250), 1, CV_AA);
    }
}

void drawAxes(cv::Mat& image, const cv::Mat& orientation)
{
    static const cv::Scalar axes_colors[] = {cv::Scalar(255, 0, 0), cv::Scalar(0, 255, 0), cv::Scalar(0, 0, 255)};
    cv::Size::value_type width = image.size().width;
    cv::Point2d center(width * 0.1, width * 0.1);
    double length = width * 0.05;

    for(int i = 0; i < 3; ++i)
    {
        const cv::Point2d direction(orientation.at<float>(i, 1), orientation.at<float>(i, 0));
        const cv::Point2d arrow = center - length * direction;
        const cv::Scalar& color = axes_colors[i];

        cv::line(image, center, arrow, color);
    }
}

ThymioTracker::ThymioTracker(const std::string& calibrationFile,
                             const std::string& geomHashingFile,
                             const std::vector<std::string>& landmarkFiles)
    : mDetectionInfo(landmarkFiles.size())
    , mFeatureExtractor(cv::BRISK::create())
{
    //static const std::string ghfilename = "/sdcard/GH_Arth_Perspective.dat";
    std::ifstream geomHashingStream(geomHashingFile, std::ios::in | std::ios::binary);
    if (!geomHashingStream.is_open())
    {
        std::cerr << "Could not open " << geomHashingFile << std::endl;
        throw std::runtime_error("GHscale::loadFromFile > File not found!");
    }

    // loadCalibration("../data/calibration/embedded_camera_calib.xml", &calibration, &imgSize);
    // loadCalibration("../data/calibration/nexus_camera_calib.xml", &calibration, &imgSize);
    cv::FileStorage calibrationStorage(calibrationFile, cv::FileStorage::READ);
    if(!calibrationStorage.isOpened())
    {
        std::cerr << "Could not open " << calibrationFile << std::endl;
        throw std::runtime_error("Calibration file not found!");
    }

    std::vector<cv::FileStorage> landmarkStorages;
    for(auto& landmarkFile : landmarkFiles)
    {
        cv::FileStorage fs(landmarkFile, cv::FileStorage::READ);
        if(!fs.isOpened())
            throw std::runtime_error("Marker file not found");
        landmarkStorages.push_back(fs);
    }

    init(calibrationStorage, geomHashingStream, landmarkStorages);

}

ThymioTracker::ThymioTracker(cv::FileStorage& calibrationStorage,
                             std::istream& geomHashingStream,
                             std::vector<cv::FileStorage>& landmarkStorages)
    : mDetectionInfo(landmarkStorages.size())
    , mFeatureExtractor(cv::BRISK::create())
{
    init(calibrationStorage, geomHashingStream, landmarkStorages);
}

void ThymioTracker::init(cv::FileStorage& calibrationStorage,
                         std::istream& geomHashingStream,
                         std::vector<cv::FileStorage>& landmarkStorages)
{
    mGH.loadFromStream(geomHashingStream);
    readCalibrationFromFileStorage(calibrationStorage, mCalibration);
    mGH.setCalibration(mCalibration);

    // Load landmarks
    for(auto& landmarkStorage : landmarkStorages)
        mLandmarks.push_back(Landmark::fromFileStorage(landmarkStorage));
}

void ThymioTracker::resizeCalibration(const cv::Size& imgSize)
{
    // loadCalibration(mCalibrationFile, imgSize, &mCalibration);
    rescaleCalibration(mCalibration, imgSize);
    mGH.setCalibration(mCalibration);
}

void ThymioTracker::update(const cv::Mat& input,
                           const cv::Mat* deviceOrientation)
{
    if(input.size() != mCalibration.imageSize)
        resizeCalibration(input.size());

    mDetectionInfo.clear();

    //get the pairs which are likely to belong to group of blobs from model
    mGrouping.getBlobsAndPairs(input,
                               mDetectionInfo.blobs,
                               mDetectionInfo.blobPairs);

    // get triplet by checking homography and inertia
    mGrouping.getTripletsFromPairs(mDetectionInfo.blobs,
                                   mDetectionInfo.blobPairs,
                                   mDetectionInfo.blobTriplets);

    //get only blobs found in triplets
    getBlobsInTriplets(mDetectionInfo.blobs,
                       mDetectionInfo.blobTriplets,
                       mDetectionInfo.blobsinTriplets);

    mGrouping.getQuadripletsFromTriplets(mDetectionInfo.blobTriplets,
                                         mDetectionInfo.blobQuadriplets);

    //extract blobs and identify which one fit model, return set of positions and Id
    mGH.getModelPointsFromImage(mDetectionInfo.blobsinTriplets, mDetectionInfo.matches);

    mDetectionInfo.robotFound = mRobot.getPose(mCalibration,
                                               mDetectionInfo.matches,
                                               mDetectionInfo.robotPose,
                                               mDetectionInfo.robotFound);

    static int counter = 100;

    ++counter;
    cv::Mat prevIm;input.copyTo(prevIm);//just to do some displaying and debugging and print stuff in input

    // Landmark tracking
    std::vector<cv::KeyPoint> detectedKeypoints;
    cv::Mat detectedDescriptors;

    //check if all the landmarks are tracked
    bool allTracked = true;
    auto lmcDetectionsIt = mDetectionInfo.landmarkDetections.cbegin();
    for(; lmcDetectionsIt != mDetectionInfo.landmarkDetections.cend(); ++lmcDetectionsIt)
    {
        const cv::Mat& h = lmcDetectionsIt->getHomography();
        if(h.empty())
            allTracked = false;
    }

    // Extract features only once every 100 frames and only if need to do any detection
    if(!allTracked && counter >= 20)
    {
        cv::Mat gray_input;
        cv::cvtColor(input, gray_input, CV_RGB2GRAY);
        mFeatureExtractor->detectAndCompute(gray_input, cv::noArray(),
                                            detectedKeypoints, detectedDescriptors);
        counter = 0;
    }

    auto landmarksIt = mLandmarks.cbegin();
    auto lmDetectionsIt = mDetectionInfo.landmarkDetections.begin();
    for(; landmarksIt != mLandmarks.cend(); ++landmarksIt, ++lmDetectionsIt)
        landmarksIt->find(input, mDetectionInfo.prevImage, mCalibration, detectedKeypoints, detectedDescriptors, *lmDetectionsIt);

    //input.copyTo(mDetectionInfo.prevImage);
    prevIm.copyTo(mDetectionInfo.prevImage);

    mTimer.tic();
}

void ThymioTracker::drawLastDetection(cv::Mat* output) const
{
    // mDetectionInfo.image.copyTo(*output);

    if(mDetectionInfo.robotFound)
        mRobot.draw(*output, mCalibration, mDetectionInfo.robotPose);
    else
        putText(*output, "Lost",
                cv::Point2i(10,10),
                cv::FONT_HERSHEY_COMPLEX_SMALL,
                0.8, cvScalar(0,0,250), 1, CV_AA);

    drawBlobPairs(*output, mDetectionInfo.blobs, mDetectionInfo.blobPairs);
    drawBlobTriplets(*output, mDetectionInfo.blobs, mDetectionInfo.blobTriplets);
    drawBlobQuadruplets(*output, mDetectionInfo.blobs, mDetectionInfo.blobQuadriplets);
    // drawPointsAndIds(output, mDetectionInfo.matches);

    // if(deviceOrientation)
    //     drawAxes(*output, *deviceOrientation);

    // Draw landmark detections
    std::vector<cv::Point2f> corners(4);

    auto lmDetectionsIt = mDetectionInfo.landmarkDetections.cbegin();
    auto landmarksIt = mLandmarks.cbegin();
    auto colorIt = colorPalette.cbegin();
    for(; landmarksIt != mLandmarks.cend(); ++landmarksIt, ++lmDetectionsIt, ++colorIt)
    {
        const Landmark& landmark = *landmarksIt;
        const cv::Mat& h = lmDetectionsIt->getHomography();

        // Reset the color iterator if needed
        if(colorIt == colorPalette.cend())
            colorIt = colorPalette.cbegin();

        if(h.empty())
            continue;

        cv::perspectiveTransform(landmark.getCorners(), corners, h);
        cv::line(*output, corners[0], corners[1], *colorIt, 2);
        cv::line(*output, corners[1], corners[2], *colorIt, 2);
        cv::line(*output, corners[2], corners[3], *colorIt, 2);
        cv::line(*output, corners[3], corners[0], *colorIt, 2);

        for(auto c : lmDetectionsIt->getCorrespondences())
        {
            cv::Point2f p = c.second;
            cv::circle(*output, p, 2, cv::Scalar(0, 255, 255));
        }

        //draw pose
        //draw object frame (axis XYZ)
        std::vector<cv::Point3f> framePoints;
        framePoints.push_back(cv::Point3f(0,0,0));
        framePoints.push_back(cv::Point3f(0.03,0,0));
        framePoints.push_back(cv::Point3f(0,0.03,0));
        framePoints.push_back(cv::Point3f(0,0,0.03));

        //cv::Affine3d pose = lmDetectionsIt->getPose().inv();
        cv::Affine3d pose = lmDetectionsIt->getPose();
        std::vector<cv::Point2f> vprojVertices;
        cv::projectPoints(framePoints, pose.rvec(), pose.translation(), mCalibration.cameraMatrix, mCalibration.distCoeffs, vprojVertices);
        cv::line(*output, vprojVertices[0], vprojVertices[1], cv::Scalar(0,0,255), 2);
        cv::line(*output, vprojVertices[0], vprojVertices[2], cv::Scalar(0,255,0), 2);
        cv::line(*output, vprojVertices[0], vprojVertices[3], cv::Scalar(255,0,0), 2);

    }
}

}
<commit_msg>receive grayscale images as input<commit_after>
#include "ThymioTracker.h"

#include <vector>
#include <stdexcept>
#include <fstream>

#include <opencv2/core.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/imgproc.hpp>

namespace thymio_tracker
{

static const std::vector<cv::Scalar> colorPalette = {
    cv::Scalar(76, 114, 176),
    cv::Scalar(85, 168, 104),
    cv::Scalar(196, 78, 82),
    cv::Scalar(129, 114, 178),
    cv::Scalar(204, 185, 116),
    cv::Scalar(100, 181, 205)
};

Timer::Timer()
    : mTicks{0}
    , mIndex(0)
    , mFps(-1.0)
{}

void Timer::tic()
{
    std::clock_t current = std::clock();
    std::clock_t prev = mTicks[mIndex];
    mTicks[mIndex] = current;
    ++mIndex;
    if(mIndex >= N)
        mIndex = 0;

    if(prev != 0)
        mFps = CLOCKS_PER_SEC * N / static_cast<double>(current - prev);
}

void DetectionInfo::clear()
{
    blobs.clear();
    blobPairs.clear();
    blobTriplets.clear();
    blobQuadriplets.clear();
    blobsinTriplets.clear();
    matches.clear();
}

void drawPointsAndIds(cv::Mat& inputImage, const std::vector<DetectionGH>& matches)
{
    //draw Id
    for(unsigned int i = 0; i < matches.size(); ++i)
    {
        char pointIdStr[100];
        sprintf(pointIdStr, "%d", matches[i].id);
        circle(inputImage, matches[i].position, 4, cvScalar(0, 250, 250), -1, 8, 0);
        putText(inputImage, pointIdStr, matches[i].position, cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, cvScalar(250,250,250), 1, CV_AA);
    }
}

void drawAxes(cv::Mat& image, const cv::Mat& orientation)
{
    static const cv::Scalar axes_colors[] = {cv::Scalar(255, 0, 0), cv::Scalar(0, 255, 0), cv::Scalar(0, 0, 255)};
    cv::Size::value_type width = image.size().width;
    cv::Point2d center(width * 0.1, width * 0.1);
    double length = width * 0.05;

    for(int i = 0; i < 3; ++i)
    {
        const cv::Point2d direction(orientation.at<float>(i, 1), orientation.at<float>(i, 0));
        const cv::Point2d arrow = center - length * direction;
        const cv::Scalar& color = axes_colors[i];

        cv::line(image, center, arrow, color);
    }
}

ThymioTracker::ThymioTracker(const std::string& calibrationFile,
                             const std::string& geomHashingFile,
                             const std::vector<std::string>& landmarkFiles)
    : mDetectionInfo(landmarkFiles.size())
    , mFeatureExtractor(cv::BRISK::create())
{
    //static const std::string ghfilename = "/sdcard/GH_Arth_Perspective.dat";
    std::ifstream geomHashingStream(geomHashingFile, std::ios::in | std::ios::binary);
    if (!geomHashingStream.is_open())
    {
        std::cerr << "Could not open " << geomHashingFile << std::endl;
        throw std::runtime_error("GHscale::loadFromFile > File not found!");
    }

    // loadCalibration("../data/calibration/embedded_camera_calib.xml", &calibration, &imgSize);
    // loadCalibration("../data/calibration/nexus_camera_calib.xml", &calibration, &imgSize);
    cv::FileStorage calibrationStorage(calibrationFile, cv::FileStorage::READ);
    if(!calibrationStorage.isOpened())
    {
        std::cerr << "Could not open " << calibrationFile << std::endl;
        throw std::runtime_error("Calibration file not found!");
    }

    std::vector<cv::FileStorage> landmarkStorages;
    for(auto& landmarkFile : landmarkFiles)
    {
        cv::FileStorage fs(landmarkFile, cv::FileStorage::READ);
        if(!fs.isOpened())
            throw std::runtime_error("Marker file not found");
        landmarkStorages.push_back(fs);
    }

    init(calibrationStorage, geomHashingStream, landmarkStorages);

}

ThymioTracker::ThymioTracker(cv::FileStorage& calibrationStorage,
                             std::istream& geomHashingStream,
                             std::vector<cv::FileStorage>& landmarkStorages)
    : mDetectionInfo(landmarkStorages.size())
    , mFeatureExtractor(cv::BRISK::create())
{
    init(calibrationStorage, geomHashingStream, landmarkStorages);
}

void ThymioTracker::init(cv::FileStorage& calibrationStorage,
                         std::istream& geomHashingStream,
                         std::vector<cv::FileStorage>& landmarkStorages)
{
    mGH.loadFromStream(geomHashingStream);
    readCalibrationFromFileStorage(calibrationStorage, mCalibration);
    mGH.setCalibration(mCalibration);

    // Load landmarks
    for(auto& landmarkStorage : landmarkStorages)
        mLandmarks.push_back(Landmark::fromFileStorage(landmarkStorage));
}

void ThymioTracker::resizeCalibration(const cv::Size& imgSize)
{
    // loadCalibration(mCalibrationFile, imgSize, &mCalibration);
    rescaleCalibration(mCalibration, imgSize);
    mGH.setCalibration(mCalibration);
}

void ThymioTracker::update(const cv::Mat& input,
                           const cv::Mat* deviceOrientation)
{
    if(input.size() != mCalibration.imageSize)
        resizeCalibration(input.size());

    mDetectionInfo.clear();

    //get the pairs which are likely to belong to group of blobs from model
    mGrouping.getBlobsAndPairs(input,
                               mDetectionInfo.blobs,
                               mDetectionInfo.blobPairs);

    // get triplet by checking homography and inertia
    mGrouping.getTripletsFromPairs(mDetectionInfo.blobs,
                                   mDetectionInfo.blobPairs,
                                   mDetectionInfo.blobTriplets);

    //get only blobs found in triplets
    getBlobsInTriplets(mDetectionInfo.blobs,
                       mDetectionInfo.blobTriplets,
                       mDetectionInfo.blobsinTriplets);

    mGrouping.getQuadripletsFromTriplets(mDetectionInfo.blobTriplets,
                                         mDetectionInfo.blobQuadriplets);

    //extract blobs and identify which one fit model, return set of positions and Id
    mGH.getModelPointsFromImage(mDetectionInfo.blobsinTriplets, mDetectionInfo.matches);

    mDetectionInfo.robotFound = mRobot.getPose(mCalibration,
                                               mDetectionInfo.matches,
                                               mDetectionInfo.robotPose,
                                               mDetectionInfo.robotFound);

    static int counter = 100;

    ++counter;
    cv::Mat prevIm;input.copyTo(prevIm);//just to do some displaying and debugging and print stuff in input

    // Landmark tracking
    std::vector<cv::KeyPoint> detectedKeypoints;
    cv::Mat detectedDescriptors;

    //check if all the landmarks are tracked
    bool allTracked = true;
    auto lmcDetectionsIt = mDetectionInfo.landmarkDetections.cbegin();
    for(; lmcDetectionsIt != mDetectionInfo.landmarkDetections.cend(); ++lmcDetectionsIt)
    {
        const cv::Mat& h = lmcDetectionsIt->getHomography();
        if(h.empty())
            allTracked = false;
    }

    // Extract features only once every 100 frames and only if need to do any detection
    if(!allTracked && counter >= 20)
    {
        mFeatureExtractor->detectAndCompute(input, cv::noArray(),
                                            detectedKeypoints, detectedDescriptors);
        counter = 0;
    }

    auto landmarksIt = mLandmarks.cbegin();
    auto lmDetectionsIt = mDetectionInfo.landmarkDetections.begin();
    for(; landmarksIt != mLandmarks.cend(); ++landmarksIt, ++lmDetectionsIt)
        landmarksIt->find(input, mDetectionInfo.prevImage, mCalibration, detectedKeypoints, detectedDescriptors, *lmDetectionsIt);

    //input.copyTo(mDetectionInfo.prevImage);
    prevIm.copyTo(mDetectionInfo.prevImage);

    mTimer.tic();
}

void ThymioTracker::drawLastDetection(cv::Mat* output) const
{
    // mDetectionInfo.image.copyTo(*output);

    if(mDetectionInfo.robotFound)
        mRobot.draw(*output, mCalibration, mDetectionInfo.robotPose);
    else
        putText(*output, "Lost",
                cv::Point2i(10,10),
                cv::FONT_HERSHEY_COMPLEX_SMALL,
                0.8, cvScalar(0,0,250), 1, CV_AA);

    drawBlobPairs(*output, mDetectionInfo.blobs, mDetectionInfo.blobPairs);
    drawBlobTriplets(*output, mDetectionInfo.blobs, mDetectionInfo.blobTriplets);
    drawBlobQuadruplets(*output, mDetectionInfo.blobs, mDetectionInfo.blobQuadriplets);
    // drawPointsAndIds(output, mDetectionInfo.matches);

    // if(deviceOrientation)
    //     drawAxes(*output, *deviceOrientation);

    // Draw landmark detections
    std::vector<cv::Point2f> corners(4);

    auto lmDetectionsIt = mDetectionInfo.landmarkDetections.cbegin();
    auto landmarksIt = mLandmarks.cbegin();
    auto colorIt = colorPalette.cbegin();
    for(; landmarksIt != mLandmarks.cend(); ++landmarksIt, ++lmDetectionsIt, ++colorIt)
    {
        const Landmark& landmark = *landmarksIt;
        const cv::Mat& h = lmDetectionsIt->getHomography();

        // Reset the color iterator if needed
        if(colorIt == colorPalette.cend())
            colorIt = colorPalette.cbegin();

        if(h.empty())
            continue;

        cv::perspectiveTransform(landmark.getCorners(), corners, h);
        cv::line(*output, corners[0], corners[1], *colorIt, 2);
        cv::line(*output, corners[1], corners[2], *colorIt, 2);
        cv::line(*output, corners[2], corners[3], *colorIt, 2);
        cv::line(*output, corners[3], corners[0], *colorIt, 2);

        for(auto c : lmDetectionsIt->getCorrespondences())
        {
            cv::Point2f p = c.second;
            cv::circle(*output, p, 2, cv::Scalar(0, 255, 255));
        }

        //draw pose
        //draw object frame (axis XYZ)
        std::vector<cv::Point3f> framePoints;
        framePoints.push_back(cv::Point3f(0,0,0));
        framePoints.push_back(cv::Point3f(0.03,0,0));
        framePoints.push_back(cv::Point3f(0,0.03,0));
        framePoints.push_back(cv::Point3f(0,0,0.03));

        //cv::Affine3d pose = lmDetectionsIt->getPose().inv();
        cv::Affine3d pose = lmDetectionsIt->getPose();
        std::vector<cv::Point2f> vprojVertices;
        cv::projectPoints(framePoints, pose.rvec(), pose.translation(), mCalibration.cameraMatrix, mCalibration.distCoeffs, vprojVertices);
        cv::line(*output, vprojVertices[0], vprojVertices[1], cv::Scalar(0,0,255), 2);
        cv::line(*output, vprojVertices[0], vprojVertices[2], cv::Scalar(0,255,0), 2);
        cv::line(*output, vprojVertices[0], vprojVertices[3], cv::Scalar(255,0,0), 2);

    }
}

}
<|endoftext|>