<commit_before>/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

#include <signal.h>

#include <glog/logging.h>

#include <gmock/gmock.h>

#include <gtest/gtest.h>

#include <process/gmock.hpp>
#include <process/gtest.hpp>
#include <process/process.hpp>

#include <stout/os/signals.hpp>

int main(int argc, char** argv)
{
  // Initialize Google Mock/Test.
  testing::InitGoogleMock(&argc, argv);

  // Initialize libprocess.
  process::initialize();

  // Install GLOG's signal handler.
  google::InstallFailureSignalHandler();

  // We reset the GLOG's signal handler for SIGTERM because
  // 'SubprocessTest.Status' sends SIGTERM to a subprocess which
  // results in a stack trace otherwise.
  os::signals::reset(SIGTERM);

  // Add the libprocess test event listeners.
  ::testing::TestEventListeners& listeners =
    ::testing::UnitTest::GetInstance()->listeners();

  listeners.Append(process::ClockTestEventListener::instance());
  listeners.Append(process::FilterTestEventListener::instance());

  int result = RUN_ALL_TESTS();

  process::finalize();
  return result;
}
<commit_msg>Added a SIGPIPE handler for the libprocess tests.<commit_after>/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/

#include <signal.h>

#include <glog/logging.h>
#include <glog/raw_logging.h>

#include <gmock/gmock.h>

#include <gtest/gtest.h>

#include <process/gmock.hpp>
#include <process/gtest.hpp>
#include <process/process.hpp>

#include <stout/os/signals.hpp>

// NOTE: We use RAW_LOG instead of LOG because RAW_LOG doesn't
// allocate any memory or grab locks. And according to
// https://code.google.com/p/google-glog/issues/detail?id=161
// it should work in 'most' cases in signal handlers.
inline void handler(int signal)
{
  if (signal == SIGPIPE) {
    RAW_LOG(WARNING, "Received signal SIGPIPE; escalating to SIGABRT");
    raise(SIGABRT);
  } else {
    RAW_LOG(FATAL, "Unexpected signal in signal handler: %d", signal);
  }
}

int main(int argc, char** argv)
{
  // Initialize Google Mock/Test.
  testing::InitGoogleMock(&argc, argv);

  // Initialize libprocess.
  process::initialize();

  // Install GLOG's signal handler.
  google::InstallFailureSignalHandler();

  // We reset the GLOG's signal handler for SIGTERM because
  // 'SubprocessTest.Status' sends SIGTERM to a subprocess which
  // results in a stack trace otherwise.
  os::signals::reset(SIGTERM);

  // Set up the SIGPIPE signal handler to escalate to SIGABRT
  // in order to have the glog handler catch it and print all
  // of its lovely information.
  os::signals::install(SIGPIPE, handler);

  // Add the libprocess test event listeners.
  ::testing::TestEventListeners& listeners =
    ::testing::UnitTest::GetInstance()->listeners();

  listeners.Append(process::ClockTestEventListener::instance());
  listeners.Append(process::FilterTestEventListener::instance());

  int result = RUN_ALL_TESTS();

  process::finalize();
  return result;
}
<|endoftext|>


<commit_before>// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "subprocess.h"

#include <assert.h>
#include <stdio.h>

#include <algorithm>

#include "util.h"

using namespace std;

Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(),
                                           is_reading_(false),
                                           use_console_(use_console) {
}

Subprocess::~Subprocess() {
  if (pipe_) {
    if (!CloseHandle(pipe_))
      Win32Fatal("CloseHandle");
  }
  // Reap child if forgotten.
  if (child_)
    Finish();
}

HANDLE Subprocess::SetupPipe(HANDLE ioport) {
  char pipe_name[100];
  snprintf(pipe_name, sizeof(pipe_name),
           "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);

  pipe_ = ::CreateNamedPipeA(pipe_name,
                             PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
                             PIPE_TYPE_BYTE,
                             PIPE_UNLIMITED_INSTANCES,
                             0, 0, INFINITE, NULL);
  if (pipe_ == INVALID_HANDLE_VALUE)
    Win32Fatal("CreateNamedPipe");

  if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
    Win32Fatal("CreateIoCompletionPort");

  memset(&overlapped_, 0, sizeof(overlapped_));
  if (!ConnectNamedPipe(pipe_, &overlapped_) &&
      GetLastError() != ERROR_IO_PENDING) {
    Win32Fatal("ConnectNamedPipe");
  }

  // Get the write end of the pipe as a handle inheritable across processes.
  HANDLE output_write_handle =
      CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  HANDLE output_write_child;
  if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
                       GetCurrentProcess(), &output_write_child,
                       0, TRUE, DUPLICATE_SAME_ACCESS)) {
    Win32Fatal("DuplicateHandle");
  }
  CloseHandle(output_write_handle);

  return output_write_child;
}

bool Subprocess::Start(SubprocessSet* set, const string& command, const vector<string> & environment, bool useStderr) {
  HANDLE child_pipe = SetupPipe(set->ioport_);

  SECURITY_ATTRIBUTES security_attributes;
  memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES));
  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  security_attributes.bInheritHandle = TRUE;
  // Must be inheritable so subprocesses can dup to children.
  HANDLE nul =
      CreateFileA("NUL", GENERIC_READ,
                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                  &security_attributes, OPEN_EXISTING, 0, NULL);
  if (nul == INVALID_HANDLE_VALUE)
    Fatal("couldn't open nul");

  STARTUPINFOA startup_info;
  memset(&startup_info, 0, sizeof(startup_info));
  startup_info.cb = sizeof(STARTUPINFO);
  if (!use_console_) {
    startup_info.dwFlags = STARTF_USESTDHANDLES;
    startup_info.hStdInput = nul;
    startup_info.hStdOutput = child_pipe;
    startup_info.hStdError = useStderr ? child_pipe : nul;
  }
  // In the console case, child_pipe is still inherited by the child and closed
  // when the subprocess finishes, which then notifies ninja.

  PROCESS_INFORMATION process_info;
  memset(&process_info, 0, sizeof(process_info));

  // Ninja handles ctrl-c, except for subprocesses in console pools.
  DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
  LPVOID lpEnvironment = nullptr;
  std::string envData;
  if (!environment.empty())
  {
	  for (const auto & keyValue : environment)
		  envData += keyValue + std::string("\0", 1);

	  envData += std::string("\0", 1);
	  lpEnvironment = (void*)envData.c_str();
  }

  // Do not prepend 'cmd /c' on Windows, this breaks command
  // lines greater than 8,191 chars.
  if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
                      /* inherit handles */ TRUE, process_flags,
					  lpEnvironment, NULL,
                      &startup_info, &process_info)) {
    DWORD error = GetLastError();
    if (error == ERROR_FILE_NOT_FOUND) {
      // File (program) not found error is treated as a normal build
      // action failure.
      if (child_pipe)
        CloseHandle(child_pipe);
      CloseHandle(pipe_);
      CloseHandle(nul);
      pipe_ = NULL;
      // child_ is already NULL;
      buf_ = "CreateProcess failed: The system cannot find the file "
          "specified.\n";
      return true;
    } else {
      fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n",
              command.c_str());
      const char* hint = NULL;
      // ERROR_INVALID_PARAMETER means the command line was formatted
      // incorrectly. This can be caused by a command line being too long or
      // leading whitespace in the command. Give extra context for this case.
      if (error == ERROR_INVALID_PARAMETER) {
        if (command.length() > 0 && (command[0] == ' ' || command[0] == '\t'))
          hint = "command contains leading whitespace";
        else
          hint = "is the command line too long?";
      }
      Win32Fatal("CreateProcess", hint);
    }
  }

  // Close pipe channel only used by the child.
  if (child_pipe)
    CloseHandle(child_pipe);
  CloseHandle(nul);

  CloseHandle(process_info.hThread);
  child_ = process_info.hProcess;

  return true;
}

void Subprocess::OnPipeReady() {
  DWORD bytes;
  if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
    if (GetLastError() == ERROR_BROKEN_PIPE) {
      CloseHandle(pipe_);
      pipe_ = NULL;
      return;
    }
    Win32Fatal("GetOverlappedResult");
  }

  if (is_reading_ && bytes)
    buf_.append(overlapped_buf_, bytes);

  memset(&overlapped_, 0, sizeof(overlapped_));
  is_reading_ = true;
  if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
                  &bytes, &overlapped_)) {
    if (GetLastError() == ERROR_BROKEN_PIPE) {
      CloseHandle(pipe_);
      pipe_ = NULL;
      return;
    }
    if (GetLastError() != ERROR_IO_PENDING)
      Win32Fatal("ReadFile");
  }

  // Even if we read any bytes in the readfile call, we'll enter this
  // function again later and get them at that point.
}

ExitStatus Subprocess::Finish() {
  if (!child_)
    return ExitFailure;

  // TODO: add error handling for all of these.
  WaitForSingleObject(child_, INFINITE);

  DWORD exit_code = 0;
  GetExitCodeProcess(child_, &exit_code);

  CloseHandle(child_);
  child_ = NULL;

  return exit_code == 0              ? ExitSuccess :
         exit_code == CONTROL_C_EXIT ? ExitInterrupted :
                                       ExitFailure;
}

bool Subprocess::Done() const {
  return pipe_ == NULL;
}

const string& Subprocess::GetOutput() const {
  return buf_;
}

HANDLE SubprocessSet::ioport_;

SubprocessSet::SubprocessSet(bool setupSignalHandlers)
    : setupSignalHandlers_(setupSignalHandlers) {
  ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
  if (!ioport_)
    Win32Fatal("CreateIoCompletionPort");

  if (setupSignalHandlers_ && !SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
    Win32Fatal("SetConsoleCtrlHandler");
}

SubprocessSet::~SubprocessSet() {
  Clear();

  if (setupSignalHandlers_)
    SetConsoleCtrlHandler(NotifyInterrupted, FALSE);

  CloseHandle(ioport_);
}

BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) {
  if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
    if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
      Win32Fatal("PostQueuedCompletionStatus");
    return TRUE;
  }

  return FALSE;
}

Subprocess *SubprocessSet::Add(const string& command, bool use_console, const vector<string> & environment, bool useStderr) {
  Subprocess *subprocess = new Subprocess(use_console);
  if (!subprocess->Start(this, command, environment, useStderr)) {
    delete subprocess;
    return 0;
  }
  if (subprocess->child_)
    running_.push_back(subprocess);
  else
    finished_.push(subprocess);
  return subprocess;
}

bool SubprocessSet::DoWork() {
  DWORD bytes_read;
  Subprocess* subproc;
  OVERLAPPED* overlapped;

  if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
                                 &overlapped, INFINITE)) {
    if (GetLastError() != ERROR_BROKEN_PIPE)
      Win32Fatal("GetQueuedCompletionStatus");
  }

  if (!subproc) // A NULL subproc indicates that we were interrupted and is
                // delivered by NotifyInterrupted above.
    return true;

  subproc->OnPipeReady();

  if (subproc->Done()) {
    vector<Subprocess*>::iterator end =
        remove(running_.begin(), running_.end(), subproc);
    if (running_.end() != end) {
      finished_.push(subproc);
      running_.resize(end - running_.begin());
    }
  }

  return false;
}

Subprocess* SubprocessSet::NextFinished() {
  if (finished_.empty())
    return NULL;
  Subprocess* subproc = finished_.front();
  finished_.pop();
  return subproc;
}

void SubprocessSet::Clear() {
  for (vector<Subprocess*>::iterator i = running_.begin();
       i != running_.end(); ++i) {
    // Since the foreground process is in our process group, it will receive a
    // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us.
    if ((*i)->child_ && !(*i)->use_console_) {
      if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
                                    GetProcessId((*i)->child_))) {
        Win32Fatal("GenerateConsoleCtrlEvent");
      }
    }
  }
  for (vector<Subprocess*>::iterator i = running_.begin();
       i != running_.end(); ++i)
    delete *i;
  running_.clear();
}
<commit_msg>HOTFIX: revert win32 part for useStderr param.<commit_after>// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "subprocess.h"

#include <assert.h>
#include <stdio.h>

#include <algorithm>

#include "util.h"

using namespace std;

Subprocess::Subprocess(bool use_console) : child_(NULL) , overlapped_(),
                                           is_reading_(false),
                                           use_console_(use_console) {
}

Subprocess::~Subprocess() {
  if (pipe_) {
    if (!CloseHandle(pipe_))
      Win32Fatal("CloseHandle");
  }
  // Reap child if forgotten.
  if (child_)
    Finish();
}

HANDLE Subprocess::SetupPipe(HANDLE ioport) {
  char pipe_name[100];
  snprintf(pipe_name, sizeof(pipe_name),
           "\\\\.\\pipe\\ninja_pid%lu_sp%p", GetCurrentProcessId(), this);

  pipe_ = ::CreateNamedPipeA(pipe_name,
                             PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
                             PIPE_TYPE_BYTE,
                             PIPE_UNLIMITED_INSTANCES,
                             0, 0, INFINITE, NULL);
  if (pipe_ == INVALID_HANDLE_VALUE)
    Win32Fatal("CreateNamedPipe");

  if (!CreateIoCompletionPort(pipe_, ioport, (ULONG_PTR)this, 0))
    Win32Fatal("CreateIoCompletionPort");

  memset(&overlapped_, 0, sizeof(overlapped_));
  if (!ConnectNamedPipe(pipe_, &overlapped_) &&
      GetLastError() != ERROR_IO_PENDING) {
    Win32Fatal("ConnectNamedPipe");
  }

  // Get the write end of the pipe as a handle inheritable across processes.
  HANDLE output_write_handle =
      CreateFileA(pipe_name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
  HANDLE output_write_child;
  if (!DuplicateHandle(GetCurrentProcess(), output_write_handle,
                       GetCurrentProcess(), &output_write_child,
                       0, TRUE, DUPLICATE_SAME_ACCESS)) {
    Win32Fatal("DuplicateHandle");
  }
  CloseHandle(output_write_handle);

  return output_write_child;
}

bool Subprocess::Start(SubprocessSet* set, const string& command, const vector<string> & environment, bool useStderr) {
  HANDLE child_pipe = SetupPipe(set->ioport_);

  SECURITY_ATTRIBUTES security_attributes;
  memset(&security_attributes, 0, sizeof(SECURITY_ATTRIBUTES));
  security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
  security_attributes.bInheritHandle = TRUE;
  // Must be inheritable so subprocesses can dup to children.
  HANDLE nul =
      CreateFileA("NUL", GENERIC_READ,
                  FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
                  &security_attributes, OPEN_EXISTING, 0, NULL);
  if (nul == INVALID_HANDLE_VALUE)
    Fatal("couldn't open nul");

  STARTUPINFOA startup_info;
  memset(&startup_info, 0, sizeof(startup_info));
  startup_info.cb = sizeof(STARTUPINFO);
  if (!use_console_) {
    startup_info.dwFlags = STARTF_USESTDHANDLES;
    startup_info.hStdInput = nul;
    startup_info.hStdOutput = child_pipe;
    startup_info.hStdError = child_pipe; // TODO: utilize useStderr.
  }
  // In the console case, child_pipe is still inherited by the child and closed
  // when the subprocess finishes, which then notifies ninja.

  PROCESS_INFORMATION process_info;
  memset(&process_info, 0, sizeof(process_info));

  // Ninja handles ctrl-c, except for subprocesses in console pools.
  DWORD process_flags = use_console_ ? 0 : CREATE_NEW_PROCESS_GROUP;
  LPVOID lpEnvironment = nullptr;
  std::string envData;
  if (!environment.empty())
  {
	  for (const auto & keyValue : environment)
		  envData += keyValue + std::string("\0", 1);

	  envData += std::string("\0", 1);
	  lpEnvironment = (void*)envData.c_str();
  }

  // Do not prepend 'cmd /c' on Windows, this breaks command
  // lines greater than 8,191 chars.
  if (!CreateProcessA(NULL, (char*)command.c_str(), NULL, NULL,
                      /* inherit handles */ TRUE, process_flags,
					  lpEnvironment, NULL,
                      &startup_info, &process_info)) {
    DWORD error = GetLastError();
    if (error == ERROR_FILE_NOT_FOUND) {
      // File (program) not found error is treated as a normal build
      // action failure.
      if (child_pipe)
        CloseHandle(child_pipe);
      CloseHandle(pipe_);
      CloseHandle(nul);
      pipe_ = NULL;
      // child_ is already NULL;
      buf_ = "CreateProcess failed: The system cannot find the file "
          "specified.\n";
      return true;
    } else {
      fprintf(stderr, "\nCreateProcess failed. Command attempted:\n\"%s\"\n",
              command.c_str());
      const char* hint = NULL;
      // ERROR_INVALID_PARAMETER means the command line was formatted
      // incorrectly. This can be caused by a command line being too long or
      // leading whitespace in the command. Give extra context for this case.
      if (error == ERROR_INVALID_PARAMETER) {
        if (command.length() > 0 && (command[0] == ' ' || command[0] == '\t'))
          hint = "command contains leading whitespace";
        else
          hint = "is the command line too long?";
      }
      Win32Fatal("CreateProcess", hint);
    }
  }

  // Close pipe channel only used by the child.
  if (child_pipe)
    CloseHandle(child_pipe);
  CloseHandle(nul);

  CloseHandle(process_info.hThread);
  child_ = process_info.hProcess;

  return true;
}

void Subprocess::OnPipeReady() {
  DWORD bytes;
  if (!GetOverlappedResult(pipe_, &overlapped_, &bytes, TRUE)) {
    if (GetLastError() == ERROR_BROKEN_PIPE) {
      CloseHandle(pipe_);
      pipe_ = NULL;
      return;
    }
    Win32Fatal("GetOverlappedResult");
  }

  if (is_reading_ && bytes)
    buf_.append(overlapped_buf_, bytes);

  memset(&overlapped_, 0, sizeof(overlapped_));
  is_reading_ = true;
  if (!::ReadFile(pipe_, overlapped_buf_, sizeof(overlapped_buf_),
                  &bytes, &overlapped_)) {
    if (GetLastError() == ERROR_BROKEN_PIPE) {
      CloseHandle(pipe_);
      pipe_ = NULL;
      return;
    }
    if (GetLastError() != ERROR_IO_PENDING)
      Win32Fatal("ReadFile");
  }

  // Even if we read any bytes in the readfile call, we'll enter this
  // function again later and get them at that point.
}

ExitStatus Subprocess::Finish() {
  if (!child_)
    return ExitFailure;

  // TODO: add error handling for all of these.
  WaitForSingleObject(child_, INFINITE);

  DWORD exit_code = 0;
  GetExitCodeProcess(child_, &exit_code);

  CloseHandle(child_);
  child_ = NULL;

  return exit_code == 0              ? ExitSuccess :
         exit_code == CONTROL_C_EXIT ? ExitInterrupted :
                                       ExitFailure;
}

bool Subprocess::Done() const {
  return pipe_ == NULL;
}

const string& Subprocess::GetOutput() const {
  return buf_;
}

HANDLE SubprocessSet::ioport_;

SubprocessSet::SubprocessSet(bool setupSignalHandlers)
    : setupSignalHandlers_(setupSignalHandlers) {
  ioport_ = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
  if (!ioport_)
    Win32Fatal("CreateIoCompletionPort");

  if (setupSignalHandlers_ && !SetConsoleCtrlHandler(NotifyInterrupted, TRUE))
    Win32Fatal("SetConsoleCtrlHandler");
}

SubprocessSet::~SubprocessSet() {
  Clear();

  if (setupSignalHandlers_)
    SetConsoleCtrlHandler(NotifyInterrupted, FALSE);

  CloseHandle(ioport_);
}

BOOL WINAPI SubprocessSet::NotifyInterrupted(DWORD dwCtrlType) {
  if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) {
    if (!PostQueuedCompletionStatus(ioport_, 0, 0, NULL))
      Win32Fatal("PostQueuedCompletionStatus");
    return TRUE;
  }

  return FALSE;
}

Subprocess *SubprocessSet::Add(const string& command, bool use_console, const vector<string> & environment, bool useStderr) {
  Subprocess *subprocess = new Subprocess(use_console);
  if (!subprocess->Start(this, command, environment, useStderr)) {
    delete subprocess;
    return 0;
  }
  if (subprocess->child_)
    running_.push_back(subprocess);
  else
    finished_.push(subprocess);
  return subprocess;
}

bool SubprocessSet::DoWork() {
  DWORD bytes_read;
  Subprocess* subproc;
  OVERLAPPED* overlapped;

  if (!GetQueuedCompletionStatus(ioport_, &bytes_read, (PULONG_PTR)&subproc,
                                 &overlapped, INFINITE)) {
    if (GetLastError() != ERROR_BROKEN_PIPE)
      Win32Fatal("GetQueuedCompletionStatus");
  }

  if (!subproc) // A NULL subproc indicates that we were interrupted and is
                // delivered by NotifyInterrupted above.
    return true;

  subproc->OnPipeReady();

  if (subproc->Done()) {
    vector<Subprocess*>::iterator end =
        remove(running_.begin(), running_.end(), subproc);
    if (running_.end() != end) {
      finished_.push(subproc);
      running_.resize(end - running_.begin());
    }
  }

  return false;
}

Subprocess* SubprocessSet::NextFinished() {
  if (finished_.empty())
    return NULL;
  Subprocess* subproc = finished_.front();
  finished_.pop();
  return subproc;
}

void SubprocessSet::Clear() {
  for (vector<Subprocess*>::iterator i = running_.begin();
       i != running_.end(); ++i) {
    // Since the foreground process is in our process group, it will receive a
    // CTRL_C_EVENT or CTRL_BREAK_EVENT at the same time as us.
    if ((*i)->child_ && !(*i)->use_console_) {
      if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,
                                    GetProcessId((*i)->child_))) {
        Win32Fatal("GenerateConsoleCtrlEvent");
      }
    }
  }
  for (vector<Subprocess*>::iterator i = running_.begin();
       i != running_.end(); ++i)
    delete *i;
  running_.clear();
}
<|endoftext|>


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

/**
 * @file FlightTaskSport.hpp
 *
 * Manual controlled position with maximum speed and no smoothing.
 */

#pragma once

#include "FlightTaskManualPosition.hpp"
#include "mathlib/mathlib.h"
#include <float.h>

class FlightTaskSport : public FlightTaskManualPosition
{
public:
	FlightTaskSport(control::SuperBlock *parent, const char *name) :
		FlightTaskManualPosition(parent, name),
		_vel_xy_max(parent, "MPC_XY_VEL_MAX", false)
	{ }

	virtual ~FlightTaskSport() = default;

protected:
	void _scaleSticks() override
	{

		/* Get all stick scaling from FlightTaskManualAltitude */
		FlightTaskManualAltitude::_scaleSticks();

		/* Constrain length of stick inputs to 1 for xy*/
		matrix::Vector2f stick_xy(_sticks_expo(0), _sticks_expo(1));

		float mag = math::constrain(stick_xy.length(), 0.0f, 1.0f);

		if (mag > FLT_EPSILON) {
			stick_xy = stick_xy.normalized() * mag;
		}

		/* Scale to velocity using max velocity */
		_vel_sp_xy = stick_xy * _vel_xy_max.get();

		/* Rotate setpoint into local frame. */
		matrix::Vector3f vel_sp { _vel_sp_xy(0), _vel_sp_xy(1), 0.0f };
		vel_sp = (matrix::Dcmf(matrix::Eulerf(0.0f, 0.0f, _yaw)) * vel_sp);
		_vel_sp_xy = matrix::Vector2f(vel_sp(0), vel_sp(1));
	}

private:
	control::BlockParamFloat _vel_xy_max; /**< maximal allowed horizontal speed, in sport mode full stick input*/

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

/**
 * @file FlightTaskSport.hpp
 *
 * Manual controlled position with maximum speed and no smoothing.
 */

#pragma once

#include "FlightTaskManualPosition.hpp"
#include "mathlib/mathlib.h"
#include <float.h>

using namespace matrix;

class FlightTaskSport : public FlightTaskManualPosition
{
public:
	FlightTaskSport(control::SuperBlock *parent, const char *name) :
		FlightTaskManualPosition(parent, name),
		_vel_xy_max(parent, "MPC_XY_VEL_MAX", false)
	{ }

	virtual ~FlightTaskSport() = default;

protected:
	void _scaleSticks() override
	{

		/* Get all stick scaling from FlightTaskManualAltitude */
		FlightTaskManualAltitude::_scaleSticks();

		/* Constrain length of stick inputs to 1 for xy*/
		matrix::Vector2f stick_xy(_sticks_expo(0), _sticks_expo(1));

		float mag = math::constrain(stick_xy.length(), 0.0f, 1.0f);

		if (mag > FLT_EPSILON) {
			stick_xy = stick_xy.normalized() * mag;
		}

		/* Scale to velocity using max velocity */
		Vector2f vel_sp_xy = stick_xy * _vel_xy_max.get();

		/* Rotate setpoint into local frame. */
		matrix::Quatf q_yaw = matrix::AxisAnglef(matrix::Vector3f(0.0f, 0.0f, 1.0f), _yaw);
		matrix::Vector3f vel_world = q_yaw.conjugate(matrix::Vector3f(vel_sp_xy(0), vel_sp_xy(1), 0.0f));
		_vel_sp(0) = vel_world(0);
		_vel_sp(1) = vel_world(1);
	}

private:
	control::BlockParamFloat _vel_xy_max; /**< maximal allowed horizontal speed, in sport mode full stick input*/

};
<|endoftext|>


<commit_before>// Point.hpp

#ifndef _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_
#define _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_

//│ ▼1 │ Preprocesser Flag Stuff
//└────┴─────────────────────────

#if !defined RATIONAL_GEOMETRY_THIS_IS_THE_TEST_BINARY                         \
    && !defined DOCTEST_CONFIG_DISABLE

#define DOCTEST_CONFIG_DISABLE

#endif

//│ ▼1 │ Includes
//└────┴──────────

#include "doctest/doctest.h"

#include <array>
#include <cstdarg>
#include <cstddef>

#ifndef DOCTEST_CONFIG_DISABLE
#include <string>
#include <typeinfo>
#endif

//┌────┬──────────
//│ ▲1 │ Includes

namespace rational_geometry {

//│ ▼1 │ Class Template Declaration
//└────┴────────────────────────────

//▼
/// A geometric point in n-space with rational number coordinates.
///
/// This class template should actually work with any type that has infinite
/// precision, or with any type in uses where the type is not used outside of
/// its full accuracy. One suggestion might be to throw an exception on a
/// inaccurate operation from your RatT type.
//▲
template <typename RatT, std::size_t kDimension = 3>
class Point
{
 public:
  // INTERNAL STATE
  std::array<RatT, kDimension> values_;

  // CONSTRUCTORS
  Point();
  Point(std::array<RatT, kDimension> values);
  Point(const Point<RatT, kDimension - 1>& smaller_point, RatT last);

  // ACCESSORS
  Point<RatT, kDimension + 1> as_point();
  Point<RatT, kDimension + 1> as_vector();
};

//│ ▼1 │ Convenience typedefs
//└────┴──────────────────────

template <typename RatT>
using Point3D = Point<RatT, 3>;

template <typename RatT>
using Point2D = Point<RatT, 2>;

//│ ▼1 │ Test Conveniences
//└────┴───────────────────

#ifndef DOCTEST_CONFIG_DISABLE
namespace point {
namespace test_helpers {

typedef Point<int, 3> IPoint3D;
typedef Point<int, 2> IPoint2D;

/// \todo  Consider opening use of these to library users.
const IPoint3D origin3{{0, 0, 0}};

const IPoint3D i3{{1, 0, 0}};
const IPoint3D j3{{0, 1, 0}};
const IPoint3D k3{{0, 0, 1}};

const IPoint2D origin2{{0, 0}};

const IPoint2D i2{{1, 0}};
const IPoint2D j2{{0, 1}};

} // namespace test_helpers
} // namespace point
#endif

//│ ▼1 │ Class Template Definitions
//└─┬──┴─┬──────────────────────────
//  │ ▼2 │ Constructors
//  └────┴──────────────

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point() : values_{}
{
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point(std::array<RatT, kDimension> values)
    : values_{values}
{
}
TEST_CASE("Testing Point<>::Point(std::array<>)")
{
  using namespace point::test_helpers;

  IPoint3D val_a{{1, 2, 3}};

  CHECK(val_a.values_.size() == 3);
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point(
    const Point<RatT, kDimension - 1>& smaller_point, RatT last)
{
  using namespace std;

  copy(
      begin(smaller_point.values_), end(smaller_point.values_), begin(values_));
  *rbegin(values_) = last;
}
TEST_CASE(
    "Testing Point<RatT, kDimension>::Point(Point<RatT, kDimension - 1>, RatT)")
{
  using namespace point::test_helpers;

  IPoint3D val_in{{1, 2, 3}};

  for (const auto& arbitrary_val : {-10, -1, 0, 1, 3, 50, 10'000}) {
    Point<int, 4> val_out{val_in, arbitrary_val};

    CHECK(val_out.values_[3] == arbitrary_val);
  }
}

//  │ ▼2 │ Accessors
//  └────┴───────────

template <typename RatT, size_t kDimension>
Point<RatT, kDimension + 1> Point<RatT, kDimension>::as_point()
{
  return {*this, 1};
}
TEST_CASE("Testing Point<>::as_point()")
{
  static const size_t dimension        = 3;
  static const size_t result_dimension = dimension + 1;

  Point<int, dimension> val_a{{1, 2, 3}};

  auto val_b = val_a.as_point();

  CHECK(val_b.values_.size() == result_dimension);
  CHECK(val_b.values_[result_dimension - 1] == 1);

  std::string expected_value{typeid(Point<int, 4>).name()};
  CHECK(expected_value == typeid(val_b).name());
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension + 1> Point<RatT, kDimension>::as_vector()
{
  return {*this, 0};
}
TEST_CASE("Testing Point<>::as_vector()")
{
  static const size_t dimension        = 3;
  static const size_t result_dimension = dimension + 1;

  Point<int, dimension> val_a{{1, 2, 3}};

  auto val_b = val_a.as_vector();

  CHECK(val_b.values_.size() == result_dimension);
  CHECK(val_b.values_[result_dimension - 1] == 0);

  std::string expected_value{typeid(Point<int, 4>).name()};
  CHECK(expected_value == typeid(val_b).name());
}

//│ ▼1 │ Related Operators
//└────┴───────────────────

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
bool operator==(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  return l_op.values_ == r_op.values_;
}
TEST_CASE("Testing Point<> == Point<>")
{
  using namespace point::test_helpers;

  IPoint3D arbitrary_a{{1, 5, 24}};
  IPoint3D arbitrary_b{{1, 5, 24}};

  // To see if it even compiles, I guess.
  CHECK(arbitrary_a == arbitrary_b);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator+(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  using std::declval;
  Point<decltype(declval<RatT_l>() + declval<RatT_r>()), kDimension> ret;

  for (std::size_t i = 0; i < kDimension; ++i) {
    ret.values_[i] = l_op.values_[i] + r_op.values_[i];
  }
  return ret;
}
TEST_CASE("Testing Point<> + Point<>")
{
  using namespace point::test_helpers;

  IPoint3D a{origin3};
  IPoint3D b{{1, 2, 3}};
  IPoint3D c{{10, 20, 30}};
  IPoint3D d{{4, 5, 6}};

  for (const auto& val : {a, b, c, d}) {
    CHECK(val == val + origin3);
  }

  IPoint3D a_b{{1, 2, 3}};
  CHECK(a_b == a + b);

  IPoint3D b_b{{2, 4, 6}};
  CHECK(b_b == b + b);

  IPoint3D b_c{{11, 22, 33}};
  CHECK(b_c == b + c);

  IPoint3D b_d{{5, 7, 9}};
  CHECK(b_d == b + d);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator*(const Point<RatT_l, kDimension>& l_op, const RatT_r& r_op)
{
  using std::declval;
  Point<decltype(declval<RatT_l>() * r_op), kDimension> ret;

  for (std::size_t i = 0; i < kDimension; ++i) {
    ret.values_[i] = l_op.values_[i] * r_op;
  }
  return ret;
}
TEST_CASE("Testing Point<> * RatT")
{
  using namespace point::test_helpers;

  IPoint3D a{{3, 5, 7}};
  static const int factor{2};
  IPoint3D expected{{6, 10, 14}};

  CHECK(expected == a * factor);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator*(RatT_l l_op, const Point<RatT_r, kDimension>& r_op)
{
  // commutative
  return r_op * l_op;
}
TEST_CASE("Testing RatT * Point<>")
{
  using namespace point::test_helpers;

  static const int factor{2};
  IPoint3D a{{3, 5, 7}};
  IPoint3D expected{{6, 10, 14}};

  CHECK(expected == factor * a);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto dot(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  using std::declval;
  // clang-format off
  decltype(declval<RatT_l>() * declval<RatT_r>()
           +
           declval<RatT_l>() * declval<RatT_r>()) sum{0};
  // clang-format on
  for (std::size_t i = 0; i < kDimension; ++i) {
    sum += l_op.values_[i] * r_op.values_[i];
  }

  return sum;
}
TEST_CASE("Testing dot(Point<>, Point<>)")
{
  using namespace point::test_helpers;

  IPoint2D i{i2};
  IPoint2D j{j2};

  auto i_j = dot(i, j);
  CHECK(0 == i_j);

  auto orthogonal = dot(3 * i + 4 * j, -4 * i + 3 * j);
  CHECK(0 == orthogonal);

  auto something_different = dot(3 * i, 2 * i);
  CHECK(6 == something_different);
}

template <typename RatT_l, typename RatT_r>
auto cross(const Point<RatT_l, 3>& l_op, const Point<RatT_r, 3>& r_op)
{
  using std::declval;
  // clang-format off
  Point<decltype(declval<RatT_l>() * declval<RatT_r>()
                 -
                 declval<RatT_l>() * declval<RatT_r>()), 3> ret{};
  // clang-format on

  const auto& l = l_op.values_;
  const auto& r = r_op.values_;

  ret.values_[0] = l[1] * r[2] - l[2] * r[1];
  ret.values_[1] = l[2] * r[0] - l[0] * r[2];
  ret.values_[2] = l[0] * r[1] - l[1] * r[0];

  return ret;
}
TEST_CASE("Testing cross(Point<>, Point<>, bool right_handed = true)")
{
  using namespace point::test_helpers;

  static const IPoint3D i{i3};
  static const IPoint3D j{j3};
  static const IPoint3D k{k3};

  CHECK(i == cross(j, k));
  CHECK(j == cross(k, i));
  CHECK(k == cross(i, j));

  // Non-commutative
  CHECK(-1 * i == cross(k, j));
  CHECK(-1 * j == cross(i, k));
  CHECK(-1 * k == cross(j, i));
}

//┌────┬───────────────────
//│ ▲1 │ Related Operators

} // namespace rational_geometry

#endif // _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_

// vim:set fdm=marker fmr=▼,▲ cms=\ //%s et ts=2 sw=2 sts=2:

<commit_msg>Add initializer list constructor for Point<commit_after>// Point.hpp

#ifndef _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_
#define _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_

//│ ▼1 │ Preprocesser Flag Stuff
//└────┴─────────────────────────

#if !defined RATIONAL_GEOMETRY_THIS_IS_THE_TEST_BINARY                         \
    && !defined DOCTEST_CONFIG_DISABLE

#define DOCTEST_CONFIG_DISABLE

#endif

//│ ▼1 │ Includes
//└────┴──────────

#include "doctest/doctest.h"

#include <array>
#include <cstdarg>
#include <cstddef>
#include <initializer_list>

#ifndef DOCTEST_CONFIG_DISABLE
#include <string>
#include <typeinfo>
#endif

//┌────┬──────────
//│ ▲1 │ Includes

namespace rational_geometry {

//│ ▼1 │ Class Template Declaration
//└────┴────────────────────────────

//▼
/// A geometric point in n-space with rational number coordinates.
///
/// This class template should actually work with any type that has infinite
/// precision, or with any type in uses where the type is not used outside of
/// its full accuracy. One suggestion might be to throw an exception on a
/// inaccurate operation from your RatT type.
//▲
template <typename RatT, std::size_t kDimension = 3>
class Point
{
 public:
  // INTERNAL STATE
  std::array<RatT, kDimension> values_;

  // CONSTRUCTORS
  Point();
  Point(const std::initializer_list<RatT>& values);
  Point(const std::array<RatT, kDimension>& values);
  Point(const Point<RatT, kDimension - 1>& smaller_point, RatT last);

  // ACCESSORS
  Point<RatT, kDimension + 1> as_point();
  Point<RatT, kDimension + 1> as_vector();
};

//│ ▼1 │ Convenience typedefs
//└────┴──────────────────────

template <typename RatT>
using Point3D = Point<RatT, 3>;

template <typename RatT>
using Point2D = Point<RatT, 2>;

//│ ▼1 │ Test Conveniences
//└────┴───────────────────

#ifndef DOCTEST_CONFIG_DISABLE
namespace point {
namespace test_helpers {

typedef Point<int, 3> IPoint3D;
typedef Point<int, 2> IPoint2D;

/// \todo  Consider opening use of these to library users.
const IPoint3D origin3{0, 0, 0};

const IPoint3D i3{1, 0, 0};
const IPoint3D j3{0, 1, 0};
const IPoint3D k3{0, 0, 1};

const IPoint2D origin2{0, 0};

const IPoint2D i2{1, 0};
const IPoint2D j2{0, 1};

} // namespace test_helpers
} // namespace point
#endif

//│ ▼1 │ Class Template Definitions
//└─┬──┴─┬──────────────────────────
//  │ ▼2 │ Constructors
//  └────┴──────────────

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point() : values_{}
{
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point(const std::initializer_list<RatT>& values)
    : values_{} // 0 initialize
{
  using namespace std;
  auto start = begin(values);
  auto stop  = start + min(values.size(), values_.size());
  copy(start, stop, begin(values_));
}
TEST_CASE("Testing Point<>::Point(std::initializer_list)")
{
  using namespace point::test_helpers;

  IPoint3D val_a{1, 2, 3};
  CHECK(val_a.values_.size() == 3);

  IPoint3D val_b{2, 5};
  CHECK(val_b.values_[1] == 5);
  CHECK(val_b.values_[2] == 0);
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point(const std::array<RatT, kDimension>& values)
    : values_{values}
{
}
TEST_CASE("Testing Point<>::Point(std::array<>)")
{
  using namespace point::test_helpers;

  std::array<int, 3> argument{1, 2, 3};

  IPoint3D val_a{argument};

  CHECK(val_a.values_.size() == 3);
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension>::Point(
    const Point<RatT, kDimension - 1>& smaller_point, RatT last)
{
  using namespace std;

  copy(
      begin(smaller_point.values_), end(smaller_point.values_), begin(values_));
  *rbegin(values_) = last;
}
TEST_CASE(
    "Testing Point<RatT, kDimension>::Point(Point<RatT, kDimension - 1>, RatT)")
{
  using namespace point::test_helpers;

  IPoint3D val_in{1, 2, 3};

  for (const auto& arbitrary_val : {-10, -1, 0, 1, 3, 50, 10'000}) {
    Point<int, 4> val_out{val_in, arbitrary_val};

    CHECK(val_out.values_[3] == arbitrary_val);
  }
}

//  │ ▼2 │ Accessors
//  └────┴───────────

template <typename RatT, size_t kDimension>
Point<RatT, kDimension + 1> Point<RatT, kDimension>::as_point()
{
  return {*this, 1};
}
TEST_CASE("Testing Point<>::as_point()")
{
  static const size_t dimension        = 3;
  static const size_t result_dimension = dimension + 1;

  Point<int, dimension> val_a{1, 2, 3};

  auto val_b = val_a.as_point();

  CHECK(val_b.values_.size() == result_dimension);
  CHECK(val_b.values_[result_dimension - 1] == 1);

  std::string expected_value{typeid(Point<int, 4>).name()};
  CHECK(expected_value == typeid(val_b).name());
}

template <typename RatT, size_t kDimension>
Point<RatT, kDimension + 1> Point<RatT, kDimension>::as_vector()
{
  return {*this, 0};
}
TEST_CASE("Testing Point<>::as_vector()")
{
  static const size_t dimension        = 3;
  static const size_t result_dimension = dimension + 1;

  Point<int, dimension> val_a{1, 2, 3};

  auto val_b = val_a.as_vector();

  CHECK(val_b.values_.size() == result_dimension);
  CHECK(val_b.values_[result_dimension - 1] == 0);

  std::string expected_value{typeid(Point<int, 4>).name()};
  CHECK(expected_value == typeid(val_b).name());
}

//│ ▼1 │ Related Operators
//└────┴───────────────────

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
bool operator==(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  return l_op.values_ == r_op.values_;
}
TEST_CASE("Testing Point<> == Point<>")
{
  using namespace point::test_helpers;

  IPoint3D arbitrary_a{1, 5, 24};
  IPoint3D arbitrary_b{1, 5, 24};

  // To see if it even compiles, I guess.
  CHECK(arbitrary_a == arbitrary_b);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator+(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  using std::declval;
  Point<decltype(declval<RatT_l>() + declval<RatT_r>()), kDimension> ret;

  for (std::size_t i = 0; i < kDimension; ++i) {
    ret.values_[i] = l_op.values_[i] + r_op.values_[i];
  }
  return ret;
}
TEST_CASE("Testing Point<> + Point<>")
{
  using namespace point::test_helpers;

  IPoint3D a{origin3};
  IPoint3D b{1, 2, 3};
  IPoint3D c{10, 20, 30};
  IPoint3D d{4, 5, 6};

  for (const auto& val : {a, b, c, d}) {
    CHECK(val == val + origin3);
  }

  IPoint3D a_b{1, 2, 3};
  CHECK(a_b == a + b);

  IPoint3D b_b{2, 4, 6};
  CHECK(b_b == b + b);

  IPoint3D b_c{11, 22, 33};
  CHECK(b_c == b + c);

  IPoint3D b_d{5, 7, 9};
  CHECK(b_d == b + d);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator*(const Point<RatT_l, kDimension>& l_op, const RatT_r& r_op)
{
  using std::declval;
  Point<decltype(declval<RatT_l>() * r_op), kDimension> ret;

  for (std::size_t i = 0; i < kDimension; ++i) {
    ret.values_[i] = l_op.values_[i] * r_op;
  }
  return ret;
}
TEST_CASE("Testing Point<> * RatT")
{
  using namespace point::test_helpers;

  IPoint3D a{3, 5, 7};
  static const int factor{2};
  IPoint3D expected{6, 10, 14};

  CHECK(expected == a * factor);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto operator*(RatT_l l_op, const Point<RatT_r, kDimension>& r_op)
{
  // commutative
  return r_op * l_op;
}
TEST_CASE("Testing RatT * Point<>")
{
  using namespace point::test_helpers;

  static const int factor{2};
  IPoint3D a{3, 5, 7};
  IPoint3D expected{6, 10, 14};

  CHECK(expected == factor * a);
}

template <typename RatT_l, typename RatT_r, std::size_t kDimension>
auto dot(const Point<RatT_l, kDimension>& l_op,
    const Point<RatT_r, kDimension>& r_op)
{
  using std::declval;
  // clang-format off
  decltype(declval<RatT_l>() * declval<RatT_r>()
           +
           declval<RatT_l>() * declval<RatT_r>()) sum{0};
  // clang-format on
  for (std::size_t i = 0; i < kDimension; ++i) {
    sum += l_op.values_[i] * r_op.values_[i];
  }

  return sum;
}
TEST_CASE("Testing dot(Point<>, Point<>)")
{
  using namespace point::test_helpers;

  IPoint2D i{i2};
  IPoint2D j{j2};

  auto i_j = dot(i, j);
  CHECK(0 == i_j);

  auto orthogonal = dot(3 * i + 4 * j, -4 * i + 3 * j);
  CHECK(0 == orthogonal);

  auto something_different = dot(3 * i, 2 * i);
  CHECK(6 == something_different);
}

template <typename RatT_l, typename RatT_r>
auto cross(const Point<RatT_l, 3>& l_op, const Point<RatT_r, 3>& r_op)
{
  using std::declval;
  // clang-format off
  Point<decltype(declval<RatT_l>() * declval<RatT_r>()
                 -
                 declval<RatT_l>() * declval<RatT_r>()), 3> ret{};
  // clang-format on

  const auto& l = l_op.values_;
  const auto& r = r_op.values_;

  ret.values_[0] = l[1] * r[2] - l[2] * r[1];
  ret.values_[1] = l[2] * r[0] - l[0] * r[2];
  ret.values_[2] = l[0] * r[1] - l[1] * r[0];

  return ret;
}
TEST_CASE("Testing cross(Point<>, Point<>, bool right_handed = true)")
{
  using namespace point::test_helpers;

  static const IPoint3D i{i3};
  static const IPoint3D j{j3};
  static const IPoint3D k{k3};

  CHECK(i == cross(j, k));
  CHECK(j == cross(k, i));
  CHECK(k == cross(i, j));

  // Non-commutative
  CHECK(-1 * i == cross(k, j));
  CHECK(-1 * j == cross(i, k));
  CHECK(-1 * k == cross(j, i));
}

//┌────┬───────────────────
//│ ▲1 │ Related Operators

} // namespace rational_geometry

#endif // _RATIONAL_GEOMETRY_POINT_HPP_INCLUDED_

// vim:set fdm=marker fmr=▼,▲ cms=\ //%s et ts=2 sw=2 sts=2:

<|endoftext|>


<commit_before>/// \file util.cpp
/// Contains generic functions for managing processes and configuration.

#include "util.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#ifdef __FreeBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>

std::map<pid_t, std::string> Util::Procs::plist;
bool Util::Procs::handler_set = false;

/// Sets the current process' running user
void Util::setUser(std::string username){
  if (username != "root"){
    struct passwd * user_info = getpwnam(username.c_str());
    if (!user_info){
      #if DEBUG >= 1
      fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
      #endif
      return;
    }else{
      if (setuid(user_info->pw_uid) != 0){
        #if DEBUG >= 1
        fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
        #endif
      }else{
        #if DEBUG >= 3
        fprintf(stderr, "Changed user to %s\n", username.c_str());
        #endif
      }
    }
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){return;}
  pid_t ret = wait(0);
  #if DEBUG >= 1
  std::string pname = plist[ret];
  #endif
  plist.erase(ret);
  #if DEBUG >= 1
  if (isActive(pname)){
    std::cerr << "Process " << pname << " half-terminated." << std::endl;
    Stop(pname);
  }else{
    std::cerr << "Process " << pname << " fully terminated." << std::endl;
  }
  #endif
}

/// Attempts to run the command cmd.
/// Replaces the current process - use after forking first!
/// This function will never return - it will either run the given
/// command or kill itself with return code 42.
void Util::Procs::runCmd(std::string & cmd){
  //split cmd into arguments
  //supports a maximum of 20 arguments
  char * tmp = (char*)cmd.c_str();
  char * tmp2 = 0;
  char * args[21];
  int i = 0;
  tmp2 = strtok(tmp, " ");
  args[0] = tmp2;
  while (tmp2 != 0 && (i < 20)){
    tmp2 = strtok(0, " ");
    ++i;
    args[i] = tmp2;
  }
  if (i == 20){args[20] = 0;}
  //execute the command
  execvp(args[0], args);
  #if DEBUG >= 1
  std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
  #endif
  _exit(42);
}

/// Starts a new process if the name is not already active.
/// \return 0 if process was not started, process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for this process.
pid_t Util::Procs::Start(std::string name, std::string cmd){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  pid_t ret = fork();
  if (ret == 0){
    runCmd(cmd);
  }else{
    if (ret > 0){
      #if DEBUG >= 1
      std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      return 0;
    }
  }
  return ret;
}

/// Starts two piped processes if the name is not already active.
/// \return 0 if process was not started, main (receiving) process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for sub (sending) process.
/// \arg cmd2 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  int pfildes[2];
  if (pipe(pfildes) == -1){
    #if DEBUG >= 1
    std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
    #endif
    return 0;
  }

  pid_t ret = fork();
  if (ret == 0){
    close(pfildes[0]);
    dup2(pfildes[1],1);
    close(pfildes[1]);
    runCmd(cmd);
  }else{
    if (ret > 0){
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }

  pid_t ret2 = fork();
  if (ret2 == 0){
    close(pfildes[1]);
    dup2(pfildes[0],0);
    close(pfildes[0]);
    runCmd(cmd2);
  }else{
    if (ret2 > 0){
      #if DEBUG >= 1
        std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret2, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      Stop(name);
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }
  close(pfildes[1]);
  close(pfildes[0]);
  return ret;
}

/// Stops the named process, if running.
/// \arg name (Internal) name of process to stop
void Util::Procs::Stop(std::string name){
  int max = 5;
  while (isActive(name)){
    Stop(getPid(name));
    max--;
    if (max <= 0){return;}
  }
}

/// Stops the process with this pid, if running.
/// \arg name The PID of the process to stop.
void Util::Procs::Stop(pid_t name){
  if (isActive(name)){
    kill(name, SIGTERM);
  }
}

/// (Attempts to) stop all running child processes.
void Util::Procs::StopAll(){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    Stop((*it).first);
  }
}

/// Returns the number of active child processes.
int Util::Procs::Count(){
   return plist.size();
}

/// Returns true if a process by this name is currently active.
bool Util::Procs::isActive(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return true;}
  }
  return false;
}

/// Returns true if a process with this PID is currently active.
bool Util::Procs::isActive(pid_t name){
  return (plist.count(name) == 1);
}

/// Gets PID for this named process, if active.
/// \return NULL if not active, process PID otherwise.
pid_t Util::Procs::getPid(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return (*it).first;}
  }
  return 0;
}

/// Gets name for this process PID, if active.
/// \return Empty string if not active, name otherwise.
std::string Util::Procs::getName(pid_t name){
  if (plist.count(name) == 1){
    return plist[name];
  }
  return "";
}

/// Creates a new configuration manager.
Util::Config::Config(){
  listen_port = 4242;
  daemon_mode = true;
  interface = "0.0.0.0";
  configfile = "/etc/ddvtech.conf";
  username = "root";
  ignore_daemon = false;
  ignore_interface = false;
  ignore_port = false;
  ignore_user = false;
}

/// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message.
/// Assumes confsection is set.
void Util::Config::parseArgs(int argc, char ** argv){
  int opt = 0;
  static const char *optString = "ndvp:i:u:c:h?";
  static const struct option longOpts[] = {
    {"help",0,0,'h'},
    {"port",1,0,'p'},
    {"interface",1,0,'i'},
    {"username",1,0,'u'},
    {"no-daemon",0,0,'n'},
    {"daemon",0,0,'d'},
    {"configfile",1,0,'c'},
    {"version",0,0,'v'}
  };
  while ((opt = getopt_long(argc, argv, optString, longOpts, 0)) != -1){
    switch (opt){
      case 'p': listen_port = atoi(optarg); ignore_port = true; break;
      case 'i': interface = optarg; ignore_interface = true; break;
      case 'n': daemon_mode = false; ignore_daemon = true; break;
      case 'd': daemon_mode = true; ignore_daemon = true; break;
      case 'c': configfile = optarg; break;
      case 'u': username = optarg; ignore_user = true; break;
      case 'v':
        printf("%s\n", TOSTRING(VERSION));
        exit(1);
        break;
      case 'h':
      case '?':
        printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -c[onfigfile] VAL, -u[sername] VAL\n");
        printf("Defaults:\n  interface: 0.0.0.0\n  port: %i\n  daemon mode: true\n  configfile: /etc/ddvtech.conf\n  username: root\n", listen_port);
        printf("Username root means no change to UID, no matter what the UID is.\n");
        printf("If the configfile exists, it is always loaded first. Commandline settings then overwrite the config file.\n");
        printf("\nThis process takes it directives from the %s section of the configfile.\n", confsection.c_str());
        printf("This is %s version %s\n", argv[0], TOSTRING(VERSION));
        exit(1);
        break;
    }
  }//commandline options parser
}

/// Parses the configuration file at configfile, if it exists.
/// Assumes confsection is set.
void Util::Config::parseFile(){
  std::ifstream conf(configfile.c_str(), std::ifstream::in);
  std::string tmpstr;
  bool acc_comm = false;
  size_t foundeq;
  if (conf.fail()){
    #if DEBUG >= 3
    fprintf(stderr, "Configuration file %s not found - using build-in defaults...\n", configfile.c_str());
    #endif
  }else{
    while (conf.good()){
      getline(conf, tmpstr);
      if (tmpstr[0] == '['){//new section? check if we care.
        if (tmpstr == confsection){acc_comm = true;}else{acc_comm = false;}
      }else{
        if (!acc_comm){break;}//skip all lines in this section if we do not care about it
        foundeq = tmpstr.find('=');
        if (foundeq != std::string::npos){
          if ((tmpstr.substr(0, foundeq) == "port") && !ignore_port){listen_port = atoi(tmpstr.substr(foundeq+1).c_str());}
          if ((tmpstr.substr(0, foundeq) == "interface") && !ignore_interface){interface = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "username") && !ignore_user){username = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "daemon") && !ignore_daemon){daemon_mode = true;}
          if ((tmpstr.substr(0, foundeq) == "nodaemon") && !ignore_daemon){daemon_mode = false;}
        }//found equals sign
      }//section contents
    }//configfile line loop
  }//configuration
}

/// Will turn the current process into a daemon.
/// Works by calling daemon(1,0):
/// Does not change directory to root.
/// Does redirect output to /dev/null
void Util::Daemonize(){
  #if DEBUG >= 3
  fprintf(stderr, "Going into background mode...\n");
  #endif
  daemon(1, 0);
}
<commit_msg>Fixes config util for nonsection applications, attempt to fix DDV_Controller process spawning.<commit_after>/// \file util.cpp
/// Contains generic functions for managing processes and configuration.

#include "util.h"
#include <string.h>
#include <sys/types.h>
#include <signal.h>

#ifdef __FreeBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif
#include <errno.h>
#include <iostream>
#include <sys/types.h>
#include <pwd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>

std::map<pid_t, std::string> Util::Procs::plist;
bool Util::Procs::handler_set = false;

/// Sets the current process' running user
void Util::setUser(std::string username){
  if (username != "root"){
    struct passwd * user_info = getpwnam(username.c_str());
    if (!user_info){
      #if DEBUG >= 1
      fprintf(stderr, "Error: could not setuid %s: could not get PID\n", username.c_str());
      #endif
      return;
    }else{
      if (setuid(user_info->pw_uid) != 0){
        #if DEBUG >= 1
        fprintf(stderr, "Error: could not setuid %s: not allowed\n", username.c_str());
        #endif
      }else{
        #if DEBUG >= 3
        fprintf(stderr, "Changed user to %s\n", username.c_str());
        #endif
      }
    }
  }
}

/// Used internally to capture child signals and update plist.
void Util::Procs::childsig_handler(int signum){
  if (signum != SIGCHLD){return;}
  pid_t ret = wait(0);
  #if DEBUG >= 1
  std::string pname = plist[ret];
  #endif
  plist.erase(ret);
  #if DEBUG >= 1
  if (isActive(pname)){
    std::cerr << "Process " << pname << " half-terminated." << std::endl;
    Stop(pname);
  }else{
    std::cerr << "Process " << pname << " fully terminated." << std::endl;
  }
  #endif
}

/// Attempts to run the command cmd.
/// Replaces the current process - use after forking first!
/// This function will never return - it will either run the given
/// command or kill itself with return code 42.
void Util::Procs::runCmd(std::string & cmd){
  //split cmd into arguments
  //supports a maximum of 20 arguments
  char * tmp = (char*)cmd.c_str();
  char * tmp2 = 0;
  char * args[21];
  int i = 0;
  tmp2 = strtok(tmp, " ");
  args[0] = tmp2;
  while (tmp2 != 0 && (i < 20)){
    tmp2 = strtok(0, " ");
    ++i;
    args[i] = tmp2;
  }
  if (i == 20){args[20] = 0;}
  //execute the command
  execvp(args[0], args);
  #if DEBUG >= 1
  std::cerr << "Error running \"" << cmd << "\": " << strerror(errno) << std::endl;
  #endif
  _exit(42);
}

/// Starts a new process if the name is not already active.
/// \return 0 if process was not started, process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for this process.
pid_t Util::Procs::Start(std::string name, std::string cmd){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  pid_t ret = fork();
  if (ret == 0){
    runCmd(cmd);
  }else{
    if (ret > 0){
      #if DEBUG >= 1
      std::cerr << "Process " << name << " started, PID " << ret << ": " << cmd << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      return 0;
    }
  }
  return ret;
}

/// Starts two piped processes if the name is not already active.
/// \return 0 if process was not started, main (receiving) process PID otherwise.
/// \arg name Name for this process - only used internally.
/// \arg cmd Commandline for sub (sending) process.
/// \arg cmd2 Commandline for main (receiving) process.
pid_t Util::Procs::Start(std::string name, std::string cmd, std::string cmd2){
  if (isActive(name)){return getPid(name);}
  if (!handler_set){
    struct sigaction new_action;
    new_action.sa_handler = Util::Procs::childsig_handler;
    sigemptyset(&new_action.sa_mask);
    new_action.sa_flags = 0;
    sigaction(SIGCHLD, &new_action, NULL);
    handler_set = true;
  }
  int pfildes[2];
  if (pipe(pfildes) == -1){
    #if DEBUG >= 1
    std::cerr << "Process " << name << " could not be started. Pipe creation failed." << std::endl;
    #endif
    return 0;
  }

  pid_t ret = fork();
  if (ret == 0){
    close(pfildes[0]);
    dup2(pfildes[1],1);
    close(pfildes[1]);
    runCmd(cmd);
  }else{
    if (ret > 0){
      plist.insert(std::pair<pid_t, std::string>(ret, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }

  pid_t ret2 = fork();
  if (ret2 == 0){
    close(pfildes[1]);
    dup2(pfildes[0],0);
    close(pfildes[0]);
    runCmd(cmd2);
  }else{
    if (ret2 > 0){
      #if DEBUG >= 1
        std::cerr << "Process " << name << " started, PIDs (" << ret << ", " << ret2 << "): " << cmd << " | " << cmd2 << std::endl;
      #endif
      plist.insert(std::pair<pid_t, std::string>(ret2, name));
    }else{
      #if DEBUG >= 1
      std::cerr << "Process " << name << " could not be started. fork() failed." << std::endl;
      #endif
      Stop(name);
      close(pfildes[1]);
      close(pfildes[0]);
      return 0;
    }
  }
  close(pfildes[1]);
  close(pfildes[0]);
  return ret;
}

/// Stops the named process, if running.
/// \arg name (Internal) name of process to stop
void Util::Procs::Stop(std::string name){
  int max = 5;
  while (isActive(name)){
    Stop(getPid(name));
    max--;
    if (max <= 0){return;}
  }
}

/// Stops the process with this pid, if running.
/// \arg name The PID of the process to stop.
void Util::Procs::Stop(pid_t name){
  if (isActive(name)){
    kill(name, SIGTERM);
  }
}

/// (Attempts to) stop all running child processes.
void Util::Procs::StopAll(){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    Stop((*it).first);
  }
}

/// Returns the number of active child processes.
int Util::Procs::Count(){
   return plist.size();
}

/// Returns true if a process by this name is currently active.
bool Util::Procs::isActive(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return true;}
  }
  return false;
}

/// Returns true if a process with this PID is currently active.
bool Util::Procs::isActive(pid_t name){
  return (plist.count(name) == 1);
}

/// Gets PID for this named process, if active.
/// \return NULL if not active, process PID otherwise.
pid_t Util::Procs::getPid(std::string name){
  std::map<pid_t, std::string>::iterator it;
  for (it = plist.begin(); it != plist.end(); it++){
    if ((*it).second == name){return (*it).first;}
  }
  return 0;
}

/// Gets name for this process PID, if active.
/// \return Empty string if not active, name otherwise.
std::string Util::Procs::getName(pid_t name){
  if (plist.count(name) == 1){
    return plist[name];
  }
  return "";
}

/// Creates a new configuration manager.
Util::Config::Config(){
  listen_port = 4242;
  daemon_mode = true;
  interface = "0.0.0.0";
  configfile = "/etc/ddvtech.conf";
  username = "root";
  ignore_daemon = false;
  ignore_interface = false;
  ignore_port = false;
  ignore_user = false;
}

/// Parses commandline arguments.
/// Calls exit if an unknown option is encountered, printing a help message.
/// confsection must be either already set or never be set at all when this function is called.
/// In other words: do not change confsection after calling this function.
void Util::Config::parseArgs(int argc, char ** argv){
  int opt = 0;
  static const char *optString = "ndvp:i:u:c:h?";
  static const struct option longOpts[] = {
    {"help",0,0,'h'},
    {"port",1,0,'p'},
    {"interface",1,0,'i'},
    {"username",1,0,'u'},
    {"no-daemon",0,0,'n'},
    {"daemon",0,0,'d'},
    {"configfile",1,0,'c'},
    {"version",0,0,'v'}
  };
  while ((opt = getopt_long(argc, argv, optString, longOpts, 0)) != -1){
    switch (opt){
      case 'p': listen_port = atoi(optarg); ignore_port = true; break;
      case 'i': interface = optarg; ignore_interface = true; break;
      case 'n': daemon_mode = false; ignore_daemon = true; break;
      case 'd': daemon_mode = true; ignore_daemon = true; break;
      case 'c': configfile = optarg; break;
      case 'u': username = optarg; ignore_user = true; break;
      case 'v':
        printf("%s\n", TOSTRING(VERSION));
        exit(1);
        break;
      case 'h':
      case '?':
        std::string doingdaemon = "true";
        if (!daemon_mode){doingdaemon = "false";}
        if (confsection == ""){
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), username.c_str());
        }else{
          printf("Options: -h[elp], -?, -v[ersion], -n[odaemon], -d[aemon], -p[ort] VAL, -i[nterface] VAL, -c[onfigfile] VAL, -u[sername] VAL\n");
          printf("Defaults:\n  interface: %s\n  port: %i\n  daemon mode: %s\n  configfile: %s\n  username: %s\n", interface.c_str(), listen_port, doingdaemon.c_str(), configfile.c_str(), username.c_str());
          printf("Username root means no change to UID, no matter what the UID is.\n");
          printf("If the configfile exists, it is always loaded first. Commandline settings then overwrite the config file.\n");
          printf("\nThis process takes it directives from the %s section of the configfile.\n", confsection.c_str());
        }
        printf("This is %s version %s\n", argv[0], TOSTRING(VERSION));
        exit(1);
        break;
    }
  }//commandline options parser
}

/// Parses the configuration file at configfile, if it exists.
/// Assumes confsection is set.
void Util::Config::parseFile(){
  std::ifstream conf(configfile.c_str(), std::ifstream::in);
  std::string tmpstr;
  bool acc_comm = false;
  size_t foundeq;
  if (conf.fail()){
    #if DEBUG >= 3
    fprintf(stderr, "Configuration file %s not found - using build-in defaults...\n", configfile.c_str());
    #endif
  }else{
    while (conf.good()){
      getline(conf, tmpstr);
      if (tmpstr[0] == '['){//new section? check if we care.
        if (tmpstr == confsection){acc_comm = true;}else{acc_comm = false;}
      }else{
        if (!acc_comm){break;}//skip all lines in this section if we do not care about it
        foundeq = tmpstr.find('=');
        if (foundeq != std::string::npos){
          if ((tmpstr.substr(0, foundeq) == "port") && !ignore_port){listen_port = atoi(tmpstr.substr(foundeq+1).c_str());}
          if ((tmpstr.substr(0, foundeq) == "interface") && !ignore_interface){interface = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "username") && !ignore_user){username = tmpstr.substr(foundeq+1);}
          if ((tmpstr.substr(0, foundeq) == "daemon") && !ignore_daemon){daemon_mode = true;}
          if ((tmpstr.substr(0, foundeq) == "nodaemon") && !ignore_daemon){daemon_mode = false;}
        }//found equals sign
      }//section contents
    }//configfile line loop
  }//configuration
}

/// Will turn the current process into a daemon.
/// Works by calling daemon(1,0):
/// Does not change directory to root.
/// Does redirect output to /dev/null
void Util::Daemonize(){
  #if DEBUG >= 3
  fprintf(stderr, "Going into background mode...\n");
  #endif
  daemon(1, 0);
}
<|endoftext|>


<commit_before><commit_msg>Wrap GL loading logs in branches<commit_after><|endoftext|>


<commit_before>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetCmdParser.cpp
 */

#include "JPetCmdParser.h"
#include <iostream>
#include "../JPetCommonTools/JPetCommonTools.h"
#include "../JPetLoggerInclude.h"
#include "../JPetScopeConfigParser/JPetScopeConfigParser.h"
#include <stdexcept>

JPetCmdParser::JPetCmdParser(): fOptionsDescriptions("Allowed options")
{
  fOptionsDescriptions.add_options()
  ("help,h", "Displays this help message.")
  ("type,t", po::value<std::string>()->required()->implicit_value(""), "Type of file: hld, gz, root or scope.")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open.")
  ("outputPath,o", po::value<std::string>(), "Location to which the outputFiles will be saved.")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value({ -1, -1}, ""), "Range of events to process e.g. -r 1 1000 .")
  ("param,p", po::value<std::string>(), "xml file with TRB settings used by the unpacker program.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.")
  ("localDB,l", po::value<std::string>(), "The file to use as the parameter database.")
  ("localDBCreate,L", po::value<std::string>(), "File name to which the parameter database will be saved.");
}

JPetCmdParser::~JPetCmdParser()
{
  /**/
}

std::vector<JPetOptions> JPetCmdParser::parseAndGenerateOptions(int argc, const char** argv)
{
  po::variables_map variablesMap;
  if (argc == 1) {
    ERROR("No options provided.");
    std::cerr << getOptionsDescription() << "\n";
    throw std::invalid_argument("No options provided.");
  }

  po::store(po::parse_command_line(argc, argv, fOptionsDescriptions), variablesMap);

  /* print out help */
  if (variablesMap.count("help")) {
    std::cout << getOptionsDescription() << "\n";
    exit(0);
  }
  po::notify(variablesMap);
  if (!areCorrectOptions(variablesMap)) {
    throw std::invalid_argument("Wrong user options provided! Check the log!");
  }

  return generateOptions(variablesMap);
}

bool JPetCmdParser::areCorrectOptions(const po::variables_map& variablesMap) const
{
  /* Parse range of events */
  if (variablesMap.count("range")) {
    if (variablesMap["range"].as< std::vector<int> >().size() != 2) {
      ERROR("Wrong number of bounds in range.");
      std::cerr << "Wrong number of bounds in range: " << variablesMap["range"].as< std::vector<int> >().size() << std::endl;
      return false;
    }
    if (
      variablesMap["range"].as< std::vector<int> >()[0]
      > variablesMap["range"].as< std::vector<int> >()[1]) {
      ERROR("Wrong range of events.");
      std::cerr << "Wrong range of events." << std::endl;
      return false;
    }
  }

  if (!isCorrectFileType(getFileType(variablesMap))) {
    ERROR("Wrong type of file.");
    std::cerr << "Wrong type of file: " << getFileType(variablesMap) << std::endl;
    std::cerr << "Possible options: hld, zip, root or scope" << std::endl;
    return false;
  }

  if (isRunNumberSet(variablesMap)) {
    int l_runId = variablesMap["runId"].as<int>();

    if (l_runId <= 0) {
      ERROR("Run id must be a number larger than 0.");
      std::cerr << "Run id must be a number larger than 0." << l_runId << std::endl;
      return false;
    }
  }

  if (isProgressBarSet(variablesMap)) {
    int l_progressBar = variablesMap["progressBar"].as<int>();

    if (l_progressBar != 0 && l_progressBar != 1) {
      ERROR("Wrong parameter of progressbar.");
      std::cerr << "Wrong parameter of progressbar: " << l_progressBar << std::endl;
      return false;
    }
  }

  if (isLocalDBSet(variablesMap)) {
    std::string localDBName = getLocalDBName(variablesMap);
    if ( !JPetCommonTools::ifFileExisting(localDBName) ) {
      ERROR("File : " + localDBName + " does not exist.");
      std::cerr << "File : " << localDBName << " does not exist" << std::endl;
      return false;
    }
  }

  std::vector<std::string> fileNames(variablesMap["file"].as< std::vector<std::string> >());
  for (unsigned int i = 0; i < fileNames.size(); i++) {
    if ( ! JPetCommonTools::ifFileExisting(fileNames[i]) ) {
      std::string fileName = fileNames[i];
      ERROR("File : " + fileName + " does not exist.");
      std::cerr << "File : " << fileNames[i] << " does not exist" << std::endl;
      return false;
    }
  }

  /// The run number option is neclegted if the input file is set as "scope"
  if (isRunNumberSet(variablesMap)) {
    if (getFileType(variablesMap) == "scope") {
      WARNING("Run number was specified but the input file type is a scope!\n The run number will be ignored!");
    }
  }

  /// Check if output path exists
  if (isOutputPath(variablesMap)) {
      auto dir = getOutputPath(variablesMap);
      if (!JPetCommonTools::isDirectory(dir)) {
        ERROR("Output directory : " + dir + " does not exist.");
        std::cerr << "Output directory: " << dir << " does not exist" << std::endl;
        return false;
      }
  }
  return true;
}

std::vector<JPetOptions> JPetCmdParser::generateOptions(const po::variables_map& optsMap) const
{
  std::map<std::string, std::string> options = JPetOptions::getDefaultOptions();
  auto fileType = getFileType(optsMap);
  if (isCorrectFileType(fileType)) {
    options.at("inputFileType") = fileType;
  }
  if (isOutputPath(optsMap)) {
    options.at("outputPath") = JPetCommonTools::appendSlashToPathIfAbsent(getOutputPath(optsMap));
  }
  if (isRunNumberSet(optsMap)) {
    options.at("runId") = std::to_string(getRunNumber(optsMap));
  }
  if (isProgressBarSet(optsMap)) {
    options.at("progressBar") = "true";
  }
  if (isLocalDBSet(optsMap)) {
    options["localDB"] = getLocalDBName(optsMap);
  }
  if (isLocalDBCreateSet(optsMap)) {
    options["localDBCreate"] = getLocalDBCreateName(optsMap);
  }
  auto firstEvent  = getLowerEventBound(optsMap);
  auto lastEvent  = getHigherEventBound(optsMap);
  if (firstEvent >= 0) options.at("firstEvent") = std::to_string(firstEvent);
  if (lastEvent >= 0) options.at("lastEvent") = std::to_string(lastEvent);

  auto files = getFileNames(optsMap);
  std::vector<JPetOptions>  optionContainer;
  /// In case of scope there is one special input file
  /// which is a json config file which must be parsed.
  /// Based on its content the set of input directories are generated.
  /// The input directories contain data files.
  /// The config input file name also should be stored in a special option field.
  if (fileType == "scope") {
    assert(files.size() == 1); /// there should be only file which is config.
    auto configFileName = files.front();
    options.at("scopeConfigFile") =  configFileName;
    JPetScopeConfigParser scopeConfigParser;
    /// The scope module must use a fake input file name which will be used to
    /// produce the correct output file names by the following modules.
    /// At the same time, the input directory with true input files must be
    /// also added. The container of pairs <directory, fileName> is generated
    /// based on the content of the configuration file.
    JPetScopeConfigParser::DirFileContainer dirsAndFiles = scopeConfigParser.getInputDirectoriesAndFakeInputFiles(configFileName);
    for (auto dirAndFile : dirsAndFiles) {
      options.at("scopeInputDirectory") = dirAndFile.first;
      options.at("inputFile") = dirAndFile.second;
      optionContainer.push_back(JPetOptions(options));
    }
  } else {
    /// for every single input file we create separate JPetOptions
    for (auto file : files) {
      options.at("inputFile") = file;
      optionContainer.push_back(JPetOptions(options));
    }
  }
  return optionContainer;
}

//#endif /* __CINT__ */
<commit_msg>Fixed small typo in description of files which can be analysed with framework<commit_after>/**
 *  @copyright Copyright 2016 The J-PET Framework Authors. All rights reserved.
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may find a copy of the License in the LICENCE file.
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *  @file JPetCmdParser.cpp
 */

#include "JPetCmdParser.h"
#include <iostream>
#include "../JPetCommonTools/JPetCommonTools.h"
#include "../JPetLoggerInclude.h"
#include "../JPetScopeConfigParser/JPetScopeConfigParser.h"
#include <stdexcept>

JPetCmdParser::JPetCmdParser(): fOptionsDescriptions("Allowed options")
{
  fOptionsDescriptions.add_options()
  ("help,h", "Displays this help message.")
  ("type,t", po::value<std::string>()->required()->implicit_value(""), "Type of file: hld, zip, root or scope.")
  ("file,f", po::value< std::vector<std::string> >()->required()->multitoken(), "File(s) to open.")
  ("outputPath,o", po::value<std::string>(), "Location to which the outputFiles will be saved.")
  ("range,r", po::value< std::vector<int> >()->multitoken()->default_value({ -1, -1}, ""), "Range of events to process e.g. -r 1 1000 .")
  ("param,p", po::value<std::string>(), "xml file with TRB settings used by the unpacker program.")
  ("runId,i", po::value<int>(), "Run id.")
  ("progressBar,b", "Progress bar.")
  ("localDB,l", po::value<std::string>(), "The file to use as the parameter database.")
  ("localDBCreate,L", po::value<std::string>(), "File name to which the parameter database will be saved.");
}

JPetCmdParser::~JPetCmdParser()
{
  /**/
}

std::vector<JPetOptions> JPetCmdParser::parseAndGenerateOptions(int argc, const char** argv)
{
  po::variables_map variablesMap;
  if (argc == 1) {
    ERROR("No options provided.");
    std::cerr << getOptionsDescription() << "\n";
    throw std::invalid_argument("No options provided.");
  }

  po::store(po::parse_command_line(argc, argv, fOptionsDescriptions), variablesMap);

  /* print out help */
  if (variablesMap.count("help")) {
    std::cout << getOptionsDescription() << "\n";
    exit(0);
  }
  po::notify(variablesMap);
  if (!areCorrectOptions(variablesMap)) {
    throw std::invalid_argument("Wrong user options provided! Check the log!");
  }

  return generateOptions(variablesMap);
}

bool JPetCmdParser::areCorrectOptions(const po::variables_map& variablesMap) const
{
  /* Parse range of events */
  if (variablesMap.count("range")) {
    if (variablesMap["range"].as< std::vector<int> >().size() != 2) {
      ERROR("Wrong number of bounds in range.");
      std::cerr << "Wrong number of bounds in range: " << variablesMap["range"].as< std::vector<int> >().size() << std::endl;
      return false;
    }
    if (
      variablesMap["range"].as< std::vector<int> >()[0]
      > variablesMap["range"].as< std::vector<int> >()[1]) {
      ERROR("Wrong range of events.");
      std::cerr << "Wrong range of events." << std::endl;
      return false;
    }
  }

  if (!isCorrectFileType(getFileType(variablesMap))) {
    ERROR("Wrong type of file.");
    std::cerr << "Wrong type of file: " << getFileType(variablesMap) << std::endl;
    std::cerr << "Possible options: hld, zip, root or scope" << std::endl;
    return false;
  }

  if (isRunNumberSet(variablesMap)) {
    int l_runId = variablesMap["runId"].as<int>();

    if (l_runId <= 0) {
      ERROR("Run id must be a number larger than 0.");
      std::cerr << "Run id must be a number larger than 0." << l_runId << std::endl;
      return false;
    }
  }

  if (isProgressBarSet(variablesMap)) {
    int l_progressBar = variablesMap["progressBar"].as<int>();

    if (l_progressBar != 0 && l_progressBar != 1) {
      ERROR("Wrong parameter of progressbar.");
      std::cerr << "Wrong parameter of progressbar: " << l_progressBar << std::endl;
      return false;
    }
  }

  if (isLocalDBSet(variablesMap)) {
    std::string localDBName = getLocalDBName(variablesMap);
    if ( !JPetCommonTools::ifFileExisting(localDBName) ) {
      ERROR("File : " + localDBName + " does not exist.");
      std::cerr << "File : " << localDBName << " does not exist" << std::endl;
      return false;
    }
  }

  std::vector<std::string> fileNames(variablesMap["file"].as< std::vector<std::string> >());
  for (unsigned int i = 0; i < fileNames.size(); i++) {
    if ( ! JPetCommonTools::ifFileExisting(fileNames[i]) ) {
      std::string fileName = fileNames[i];
      ERROR("File : " + fileName + " does not exist.");
      std::cerr << "File : " << fileNames[i] << " does not exist" << std::endl;
      return false;
    }
  }

  /// The run number option is neclegted if the input file is set as "scope"
  if (isRunNumberSet(variablesMap)) {
    if (getFileType(variablesMap) == "scope") {
      WARNING("Run number was specified but the input file type is a scope!\n The run number will be ignored!");
    }
  }

  /// Check if output path exists
  if (isOutputPath(variablesMap)) {
      auto dir = getOutputPath(variablesMap);
      if (!JPetCommonTools::isDirectory(dir)) {
        ERROR("Output directory : " + dir + " does not exist.");
        std::cerr << "Output directory: " << dir << " does not exist" << std::endl;
        return false;
      }
  }
  return true;
}

std::vector<JPetOptions> JPetCmdParser::generateOptions(const po::variables_map& optsMap) const
{
  std::map<std::string, std::string> options = JPetOptions::getDefaultOptions();
  auto fileType = getFileType(optsMap);
  if (isCorrectFileType(fileType)) {
    options.at("inputFileType") = fileType;
  }
  if (isOutputPath(optsMap)) {
    options.at("outputPath") = JPetCommonTools::appendSlashToPathIfAbsent(getOutputPath(optsMap));
  }
  if (isRunNumberSet(optsMap)) {
    options.at("runId") = std::to_string(getRunNumber(optsMap));
  }
  if (isProgressBarSet(optsMap)) {
    options.at("progressBar") = "true";
  }
  if (isLocalDBSet(optsMap)) {
    options["localDB"] = getLocalDBName(optsMap);
  }
  if (isLocalDBCreateSet(optsMap)) {
    options["localDBCreate"] = getLocalDBCreateName(optsMap);
  }
  auto firstEvent  = getLowerEventBound(optsMap);
  auto lastEvent  = getHigherEventBound(optsMap);
  if (firstEvent >= 0) options.at("firstEvent") = std::to_string(firstEvent);
  if (lastEvent >= 0) options.at("lastEvent") = std::to_string(lastEvent);

  auto files = getFileNames(optsMap);
  std::vector<JPetOptions>  optionContainer;
  /// In case of scope there is one special input file
  /// which is a json config file which must be parsed.
  /// Based on its content the set of input directories are generated.
  /// The input directories contain data files.
  /// The config input file name also should be stored in a special option field.
  if (fileType == "scope") {
    assert(files.size() == 1); /// there should be only file which is config.
    auto configFileName = files.front();
    options.at("scopeConfigFile") =  configFileName;
    JPetScopeConfigParser scopeConfigParser;
    /// The scope module must use a fake input file name which will be used to
    /// produce the correct output file names by the following modules.
    /// At the same time, the input directory with true input files must be
    /// also added. The container of pairs <directory, fileName> is generated
    /// based on the content of the configuration file.
    JPetScopeConfigParser::DirFileContainer dirsAndFiles = scopeConfigParser.getInputDirectoriesAndFakeInputFiles(configFileName);
    for (auto dirAndFile : dirsAndFiles) {
      options.at("scopeInputDirectory") = dirAndFile.first;
      options.at("inputFile") = dirAndFile.second;
      optionContainer.push_back(JPetOptions(options));
    }
  } else {
    /// for every single input file we create separate JPetOptions
    for (auto file : files) {
      options.at("inputFile") = file;
      optionContainer.push_back(JPetOptions(options));
    }
  }
  return optionContainer;
}

//#endif /* __CINT__ */
<|endoftext|>


<commit_before>#include "limit_quote.h"

<commit_msg>Update limit_quote.cpp<commit_after>#include <cstddef>
#include "Limit_quote.h"

double Limit_quote::net_price(size_t n) const
{
    if(n<=max_qty)
        return n*price*(1-discount);
    else
        return max_qty*price*(1-discount)+(n-max_qty)*price;
}
<|endoftext|>