<commit_before>/************************************************************************************
 * Author: Hunter Jones
 * Date: 04/23/2017
 * File Name: ush.cpp
 * Purpose: ush is a lightweight command line shell utility for unix, the entire
 *  program is contained in this source file. It acts as a minimalistic alternative
 *  to shells like bash, zsh, sh and so on.
 * Notes: This C++ file uses features from the C++11 standard, attempting to compile
 *    against the C++98 libraries will certainly fail. On some older systems, the
 *    C++11 standard is referred to as c++0x.
 */
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>

//BSD Libedit
#include <editline/readline.h>
//Different paths on BSD and Linux
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif

using namespace std;

string userPrompt = "ush-> "; //command line prompt, PS1 to use unix terms
void printPrompt();
void setPath(vector<string>& answer);
vector<string> findCommand();
bool fileExists(string filename);

int main(int argc, char** argv) {
  /**
   * Main function consists entirely of an infinite while loop. The loop consists of
   * three distinct subroutines (i could have refactored them into seperate functions
   * but decided that this was more readable). The first subroutine is to search the $PATH
   * for a program that matches the user specified command. The second is to combine this
   * generated path to the executable with the args specified by the user. Lastly, the shell
   * forks off a process which runs the program with the specified args.
   */
  while(1) { //Main loop begin
    //Initializer Area
    string current{}; //holds the string just recieved from user input
    vector<string> tokenized;
    char* userArgs[100] = {NULL}; //array contains the 'argv' of the program to be run

    //Search $PATH for a program matching users selection
    try{
      tokenized = findCommand();
    }
    catch(const char* msg) {
      cerr << msg << endl;
      continue; //so that the user is able to continue using the command line after a bad input.
    }

    for(unsigned int i = 0; i < tokenized.size() && i < 100; i++) {
      userArgs[i] = (char*)tokenized.at(i).c_str();
    }

    //Forking off to run program
    pid_t pid = fork();
    if(pid > 0) { //Parent runs this
      int statusnum;
      waitpid(pid, &statusnum, 0);
    }
    else { //child runs this
      execv(userArgs[0], userArgs); //execute the program
      exit(-1); //if child reached this something is really amiss.
    }
  } //end of main loop
  return 0;
} //End main

void printPrompt() {
  /**
   * Simply prints the command line prompt to console, could have
   * just used a variable, but left open for possible setPrompt
   */
  cout << userPrompt;
}

void setPath(vector<string>& answer) {
  /**
   * Converts PATH from a single string to a tokenized vector via ':' delimeter
   */
  string current{};
  stringstream x{getenv("PATH")}; //User binary path
  while(x) {
    getline(x,current,':');
    answer.push_back(string{current});
  }
}

string getLineRead() {
  //Uses editline lib
  static char *linebuff = (char *)NULL;
  if(linebuff) {
    free(linebuff);
    linebuff = (char*) NULL;
  }
  linebuff = readline(userPrompt.c_str());
  return string{linebuff};
}

vector<string> findCommand() {
  /**
   * Takes users command input, and finds the appropriate executable file to run.
   * Working directory (if program starts with ./), $PATH variable, and missing files
   * are all taken into account
   */
   //Initializers
  string userInput = getLineRead();;
  vector<string> tokenized{};
  vector<string> path;
  unsigned int wordStart{0};

  //Tokenize the line into a vector of args
  for(unsigned int i = 0; i < userInput.length(); i++) {
    if(userInput.at(i) == ' ') {
      tokenized.push_back(userInput.substr(wordStart,i-wordStart));
      wordStart = i+1;
    }
  }
  tokenized.push_back(userInput.substr(wordStart,userInput.length()));

  //Check for builtin commands, should probably be refactored out later
  if(tokenized.at(0) == "exit") //Exit command input by user
    exit(0);
  if((tokenized.at(0).substr(0,2) == "./") && (fileExists(tokenized.at(0)))) //Command is selected from current dir
    return tokenized;
  if(tokenized.at(0) == "cd") { //has to be implemented in shell, no external commands for it.
    if(chdir(tokenized.at(1).c_str()))
      throw "Error: file not found";
    return tokenized;
  }

  //Search the path for the command and retrieve its full path
  setPath(path);
  for(string x : path) { //Iterate through the path looking for matching files
    if(fileExists(x + "/" + tokenized.at(0))) {
      tokenized.at(0) = x + "/" + tokenized.at(0);
      return tokenized;
    }
  }
  throw "Error: File not found"; //No matches found
} //End findCommand

bool fileExists(string filename) {
  /**
   * Checks if the specified file exists, and returns the result of said test
   * as a boolean. Pretty standard really.
   */
  if(fopen(filename.c_str(),"r") == 0)
    return false;
  else
    return true;
}
<commit_msg>command line arg validation<commit_after>/************************************************************************************
 * Author: Hunter Jones
 * Date: 04/23/2017
 * File Name: ush.cpp
 * Purpose: ush is a lightweight command line shell utility for unix, the entire
 *  program is contained in this source file. It acts as a minimalistic alternative
 *  to shells like bash, zsh, sh and so on.
 * Notes: This C++ file uses features from the C++11 standard, attempting to compile
 *    against the C++98 libraries will certainly fail. On some older systems, the
 *    C++11 standard is referred to as c++0x.
 */
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>

//BSD Libedit
#include <editline/readline.h>
//Different paths on BSD and Linux
#if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__
#include <sys/wait.h>
#else
#include <wait.h>
#endif

using namespace std;

string userPrompt = "ush-> "; //command line prompt, PS1 to use unix terms
void printPrompt();
void setPath(vector<string>& answer);
vector<string> findCommand();
bool fileExists(string filename);

int main(int argc, char** argv) {
  /**
   * Main function consists entirely of an infinite while loop. The loop consists of
   * three distinct subroutines (i could have refactored them into seperate functions
   * but decided that this was more readable). The first subroutine is to search the $PATH
   * for a program that matches the user specified command. The second is to combine this
   * generated path to the executable with the args specified by the user. Lastly, the shell
   * forks off a process which runs the program with the specified args.
   */

  if(argc > 1) {
    cerr << "Usage: " << argv[0] << endl;
    return EXIT_FAILURE;
  }
  while(1) { //Main loop begin
    //Initializer Area
    string current{}; //holds the string just recieved from user input
    vector<string> tokenized;
    char* userArgs[100] = {NULL}; //array contains the 'argv' of the program to be run

    //Search $PATH for a program matching users selection
    try{
      tokenized = findCommand();
    }
    catch(const char* msg) {
      cerr << msg << endl;
      continue; //so that the user is able to continue using the command line after a bad input.
    }

    for(unsigned int i = 0; i < tokenized.size() && i < 100; i++) {
      userArgs[i] = (char*)tokenized.at(i).c_str();
    }

    //Forking off to run program
    pid_t pid = fork();
    if(pid > 0) { //Parent runs this
      int statusnum;
      waitpid(pid, &statusnum, 0);
    }
    else { //child runs this
      execv(userArgs[0], userArgs); //execute the program
      exit(-1); //if child reached this something is really amiss.
    }
  } //end of main loop
  return 0;
} //End main

void printPrompt() {
  /**
   * Simply prints the command line prompt to console, could have
   * just used a variable, but left open for possible setPrompt
   */
  cout << userPrompt;
}

void setPath(vector<string>& answer) {
  /**
   * Converts PATH from a single string to a tokenized vector via ':' delimeter
   */
  string current{};
  stringstream x{getenv("PATH")}; //User binary path
  while(x) {
    getline(x,current,':');
    answer.push_back(string{current});
  }
}

string getLineRead() {
  //Uses editline lib
  static char *linebuff = (char *)NULL;
  if(linebuff) {
    free(linebuff);
    linebuff = (char*) NULL;
  }
  linebuff = readline(userPrompt.c_str());
  return string{linebuff};
}

vector<string> findCommand() {
  /**
   * Takes users command input, and finds the appropriate executable file to run.
   * Working directory (if program starts with ./), $PATH variable, and missing files
   * are all taken into account
   */
   //Initializers
  string userInput = getLineRead();;
  vector<string> tokenized{};
  vector<string> path;
  unsigned int wordStart{0};

  //Tokenize the line into a vector of args
  for(unsigned int i = 0; i < userInput.length(); i++) {
    if(userInput.at(i) == ' ') {
      tokenized.push_back(userInput.substr(wordStart,i-wordStart));
      wordStart = i+1;
    }
  }
  tokenized.push_back(userInput.substr(wordStart,userInput.length()));

  //Check for builtin commands, should probably be refactored out later
  if(tokenized.at(0) == "exit") //Exit command input by user
    exit(0);
  if((tokenized.at(0).substr(0,2) == "./") && (fileExists(tokenized.at(0)))) //Command is selected from current dir
    return tokenized;
  if(tokenized.at(0) == "cd") { //has to be implemented in shell, no external commands for it.
    if(chdir(tokenized.at(1).c_str()))
      throw "Error: file not found";
    return tokenized;
  }

  //Search the path for the command and retrieve its full path
  setPath(path);
  for(string x : path) { //Iterate through the path looking for matching files
    if(fileExists(x + "/" + tokenized.at(0))) {
      tokenized.at(0) = x + "/" + tokenized.at(0);
      return tokenized;
    }
  }
  throw "Error: File not found"; //No matches found
} //End findCommand

bool fileExists(string filename) {
  /**
   * Checks if the specified file exists, and returns the result of said test
   * as a boolean. Pretty standard really.
   */
  if(fopen(filename.c_str(),"r") == 0)
    return false;
  else
    return true;
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <caf/all.hpp>
#include <caf/io/all.hpp>

#include "vast/aliases.h"
#include "vast/announce.h"
#include "vast/banner.h"
#include "vast/filesystem.h"
#include "vast/logger.h"
#include "vast/uuid.h"
#include "vast/actor/accountant.h"
#include "vast/actor/atoms.h"
#include "vast/actor/exit.h"
#include "vast/actor/sink/spawn.h"
#include "vast/actor/source/spawn.h"
#include "vast/concept/printable/to_string.h"
#include "vast/concept/printable/vast/error.h"
#include "vast/concept/printable/vast/uuid.h"
#include "vast/detail/adjust_resource_consumption.h"
#include "vast/util/endpoint.h"
#include "vast/util/string.h"

using namespace vast;
using namespace std::string_literals;

int main(int argc, char *argv[])
{
  if (! detail::adjust_resource_consumption())
    return 1;
  caf::set_scheduler<>(2, -1);
  std::vector<std::string> commands = {
    "connect",
    "disconnect",
    "export",
    "import",
    "quit",
    "peer",
    "send",
    "show",
    "spawn",
    "stop"
  };
  std::vector<std::string> command_line(argv + 1, argv + argc);
  auto cmd = std::find_first_of(command_line.begin(), command_line.end(),
                                commands.begin(), commands.end());
  // Parse and validate command line.
  auto log_level = 3;
  auto dir = "."s;
  auto endpoint = ""s;
  auto host = "127.0.0.1"s;
  auto port = uint16_t{42000};
  auto r = caf::message_builder(command_line.begin(), cmd).extract_opts({
    {"dir,d", "directory for logs and client state", dir},
    {"endpoint,e", "node endpoint", endpoint},
    {"log-level,l", "verbosity of console and/or log file", log_level},
    {"version,v", "print version and exit"}
  });
  if (! r.error.empty())
  {
    std::cerr << r.error << std::endl;
    return 1;
  }
  if (r.opts.count("version") > 0)
  {
    std::cout << VAST_VERSION << std::endl;
    return 0;
  }
  if (r.opts.count("help") > 0)
  {
    std::cout << banner() << "\n\n" << r.helptext;
    return 0;
  }
  if (r.opts.count("endpoint") > 0
      && ! util::parse_endpoint(endpoint, host, port))
  {
    std::cout << "invalid endpoint: " << endpoint << std::endl;
    return 1;
  }
  if (! r.remainder.empty())
  {
    auto invalid_cmd = r.remainder.get_as<std::string>(0);
    std::cerr << "invalid command: " << invalid_cmd << std::endl;
    return 1;
  }
  if (cmd == command_line.end())
  {
    std::cerr << "missing command" << std::endl;
    return 1;
  }
  // Initialize logger.
  auto colorized = true;
  auto verbosity = static_cast<logger::level>(log_level);
  if (! logger::console(verbosity, colorized))
  {
    std::cerr << "failed to initialize logger console backend" << std::endl;
    return 1;
  }
  if (! logger::file(logger::quiet))
  {
    std::cerr << "failed to reset logger file backend" << std::endl;
    return 1;
  }
  // Establish connection to remote node.
  auto guard = caf::detail::make_scope_guard(
    [] { caf::shutdown(); logger::destruct(); }
  );
  announce_types();
  caf::actor node;
  try
  {
    VAST_VERBOSE("connecting to", host << ':' << port);
    node = caf::io::remote_actor(host.c_str(), port);
  }
  catch (caf::network_error const& e)
  {
    VAST_ERROR("failed to connect to", host << ':' << port);
    return 1;
  }
  // Process commands.
  caf::scoped_actor self;
  auto accounting_log = path(dir) / "accounting.log";
  if (*cmd == "import")
  {
    // 1. Spawn a SOURCE.
    caf::message_builder mb;
    auto i = cmd + 1;
    while (i != command_line.end())
      mb.append(*i++);
    auto src = source::spawn(mb.to_message());
    if (! src)
    {
      VAST_ERROR("failed to spawn source:", src.error());
      return 1;
    }
    auto source_guard = caf::detail::make_scope_guard(
      [=] { anon_send_exit(*src, exit::kill); }
    );
    auto acc = self->spawn<accountant<uint64_t>>(accounting_log);
    acc->link_to(*src);
    self->send(*src, put_atom::value, accountant_atom::value, acc);
    // 2. Find the next-best IMPORTER.
    caf::actor importer;
    self->sync_send(node, store_atom::value).await(
      [&](caf::actor const& store) {
        self->sync_send(store, list_atom::value, "actors").await(
          [&](std::map<std::string, caf::message>& m) {
            for (auto& p : m)
              // TODO: as opposed to taking the first importer available, it
              // could make sense to take the one which faces the least load.
              if (p.second.get_as<std::string>(1) == "importer")
              {
                importer = p.second.get_as<caf::actor>(0);
                return;
              }
          }
        );
      }
    );
    if (! importer)
    {
      VAST_ERROR("could not obtain importer from node");
      return 1;
    }
    // 3. Connect SOURCE and IMPORTER.
    VAST_DEBUG("connecting source with remote importer");
    auto msg = make_message(put_atom::value, sink_atom::value, importer);
    self->send(*src, std::move(msg));
    // 4. Run the SOURCE.
    VAST_DEBUG("running source");
    self->send(*src, run_atom::value);
    source_guard.disable();
  }
  else if (*cmd == "export")
  {
    if (cmd + 1 == command_line.end())
    {
      VAST_ERROR("missing sink format");
      return 1;
    }
    else if (cmd + 2 == command_line.end())
    {
      VAST_ERROR("missing query arguments");
      return 1;
    }
    // 1. Spawn a SINK.
    auto snk = sink::spawn(caf::make_message(*(cmd + 1)));
    if (! snk)
    {
      VAST_ERROR("failed to spawn sink:", snk.error());
      return 1;
    }
    auto acc = self->spawn<accountant<uint64_t>>(accounting_log);
    acc->link_to(*snk);
    self->send(*snk, put_atom::value, accountant_atom::value, acc);
    auto sink_guard = caf::detail::make_scope_guard(
      [snk=*snk] { anon_send_exit(snk, exit::kill); }
    );
    // 2. Spawn an EXPORTER.
    caf::message_builder mb;
    auto label = "exporter-" + to_string(uuid::random()).substr(0, 7);
    mb.append("spawn");
    mb.append("-l");
    mb.append(label);
    mb.append("exporter");
    auto i = cmd + 2;
    mb.append(*i++);
    while (i != command_line.end())
      mb.append(*i++);
    caf::actor exporter;
    self->sync_send(node, mb.to_message()).await(
      [&](caf::actor const& actor) {
        exporter = actor;
      },
      [&](error const& e) {
        VAST_ERROR("failed to spawn exporter:", e);
      },
      caf::others >> [&] {
        VAST_ERROR("got unexpected message:",
                   caf::to_string(self->current_message()));
      }
    );
    if (! exporter)
      return 1;
    // 3. Connect EXPORTER with ARCHIVEs and INDEXes.
    VAST_DEBUG("retrieving topology to connect exporter with archive/index");
    self->sync_send(node, store_atom::value).await(
      [&](caf::actor const& store) {
        self->sync_send(store, list_atom::value, "actors").await(
          [&](std::map<std::string, caf::message>& m) {
            for (auto& p : m)
              if (p.second.get_as<std::string>(1) == "archive")
                self->send(exporter, put_atom::value, archive_atom::value,
                           p.second.get_as<caf::actor>(0));
              else if (p.second.get_as<std::string>(1) == "index")
                self->send(exporter, put_atom::value, index_atom::value,
                           p.second.get_as<caf::actor>(0));
          }
        );
      }
    );
    // 4. Connect EXPORTER with SINK.
    self->send(exporter, put_atom::value, sink_atom::value, *snk);
    // 5. Run the EXPORTER.
    VAST_DEBUG("running exporter");
    self->send(exporter, stop_atom::value);
    self->send(exporter, run_atom::value);
    sink_guard.disable();
  }
  else
  {
    auto args = std::vector<std::string>(cmd + 1, command_line.end());
    caf::message_builder mb;
    mb.append(*cmd);
    for (auto& a : args)
      mb.append(std::move(a));
    auto cmd_line = *cmd + util::join(args, " ");
    auto exit_code = 0;
    self->sync_send(node, mb.to_message()).await(
      [&](ok_atom)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
      },
      [&](caf::actor const&)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
      },
      [&](std::string const& str)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
        std::cout << str << std::endl;
      },
      [&](error const& e)
      {
        VAST_ERROR("failed to execute command:", cmd_line);
        VAST_ERROR(e);
        exit_code = 1;
      },
      caf::others >> [&]
      {
        auto msg = to_string(self->current_message());
        VAST_ERROR("got unexpected reply:", msg);
        exit_code = 1;
      }
    );
    if (exit_code != 0)
      return exit_code;
  }
  self->await_all_other_actors_done();
  return 0;
}
<commit_msg>Support multiple importers (and exporters)<commit_after>#include <algorithm>
#include <iostream>
#include <string>
#include <vector>

#include <caf/all.hpp>
#include <caf/io/all.hpp>

#include "vast/aliases.h"
#include "vast/announce.h"
#include "vast/banner.h"
#include "vast/filesystem.h"
#include "vast/logger.h"
#include "vast/uuid.h"
#include "vast/actor/accountant.h"
#include "vast/actor/atoms.h"
#include "vast/actor/exit.h"
#include "vast/actor/sink/spawn.h"
#include "vast/actor/source/spawn.h"
#include "vast/concept/printable/to_string.h"
#include "vast/concept/printable/vast/error.h"
#include "vast/concept/printable/vast/uuid.h"
#include "vast/detail/adjust_resource_consumption.h"
#include "vast/util/endpoint.h"
#include "vast/util/string.h"

using namespace vast;
using namespace std::string_literals;

int main(int argc, char *argv[])
{
  if (! detail::adjust_resource_consumption())
    return 1;
  caf::set_scheduler<>(2, -1);
  std::vector<std::string> commands = {
    "connect",
    "disconnect",
    "export",
    "import",
    "quit",
    "peer",
    "send",
    "show",
    "spawn",
    "stop"
  };
  std::vector<std::string> command_line(argv + 1, argv + argc);
  auto cmd = std::find_first_of(command_line.begin(), command_line.end(),
                                commands.begin(), commands.end());
  // Parse and validate command line.
  auto log_level = 3;
  auto dir = "."s;
  auto endpoint = ""s;
  auto host = "127.0.0.1"s;
  auto port = uint16_t{42000};
  auto r = caf::message_builder(command_line.begin(), cmd).extract_opts({
    {"dir,d", "directory for logs and client state", dir},
    {"endpoint,e", "node endpoint", endpoint},
    {"log-level,l", "verbosity of console and/or log file", log_level},
    {"version,v", "print version and exit"}
  });
  if (! r.error.empty())
  {
    std::cerr << r.error << std::endl;
    return 1;
  }
  if (r.opts.count("version") > 0)
  {
    std::cout << VAST_VERSION << std::endl;
    return 0;
  }
  if (r.opts.count("help") > 0)
  {
    std::cout << banner() << "\n\n" << r.helptext;
    return 0;
  }
  if (r.opts.count("endpoint") > 0
      && ! util::parse_endpoint(endpoint, host, port))
  {
    std::cout << "invalid endpoint: " << endpoint << std::endl;
    return 1;
  }
  if (! r.remainder.empty())
  {
    auto invalid_cmd = r.remainder.get_as<std::string>(0);
    std::cerr << "invalid command: " << invalid_cmd << std::endl;
    return 1;
  }
  if (cmd == command_line.end())
  {
    std::cerr << "missing command" << std::endl;
    return 1;
  }
  // Initialize logger.
  auto colorized = true;
  auto verbosity = static_cast<logger::level>(log_level);
  if (! logger::console(verbosity, colorized))
  {
    std::cerr << "failed to initialize logger console backend" << std::endl;
    return 1;
  }
  if (! logger::file(logger::quiet))
  {
    std::cerr << "failed to reset logger file backend" << std::endl;
    return 1;
  }
  // Establish connection to remote node.
  auto guard = caf::detail::make_scope_guard(
    [] { caf::shutdown(); logger::destruct(); }
  );
  announce_types();
  caf::actor node;
  try
  {
    VAST_VERBOSE("connecting to", host << ':' << port);
    node = caf::io::remote_actor(host.c_str(), port);
  }
  catch (caf::network_error const& e)
  {
    VAST_ERROR("failed to connect to", host << ':' << port);
    return 1;
  }
  // Process commands.
  caf::scoped_actor self;
  auto accounting_log = path(dir) / "accounting.log";
  if (*cmd == "import")
  {
    // 1. Spawn a SOURCE.
    caf::message_builder mb;
    auto i = cmd + 1;
    while (i != command_line.end())
      mb.append(*i++);
    auto src = source::spawn(mb.to_message());
    if (! src)
    {
      VAST_ERROR("failed to spawn source:", src.error());
      return 1;
    }
    auto source_guard = caf::detail::make_scope_guard(
      [=] { anon_send_exit(*src, exit::kill); }
    );
    auto acc = self->spawn<accountant<uint64_t>>(accounting_log);
    acc->link_to(*src);
    self->send(*src, put_atom::value, accountant_atom::value, acc);
    // 2. Find all next-best IMPORTERs.
    std::vector<caf::actor> importers;
    self->sync_send(node, store_atom::value).await(
      [&](caf::actor const& store) {
        self->sync_send(store, list_atom::value, "actors/").await(
          [&](std::map<std::string, caf::message>& m) {
            for (auto& p : m)
              if (p.second.get_as<std::string>(1) == "importer") {
                auto imp = p.second.get_as<caf::actor>(0);
                if (imp != caf::invalid_actor)
                  importers.push_back(imp);
              }
          }
        );
      }
    );
    if (importers.empty())
    {
      VAST_ERROR("no importers found");
      return 1;
    }
    // 3. Connect SOURCE and IMPORTERs.
    for (auto& imp : importers)
    {
      //VAST_ASSERT(imp != caf::invalid_actor);
      VAST_DEBUG("connecting source with importer", imp);
      self->send(*src, put_atom::value, sink_atom::value, imp);
    }
    // 4. Run the SOURCE.
    VAST_DEBUG("running source");
    self->send(*src, run_atom::value);
    source_guard.disable();
  }
  else if (*cmd == "export")
  {
    if (cmd + 1 == command_line.end())
    {
      VAST_ERROR("missing sink format");
      return 1;
    }
    else if (cmd + 2 == command_line.end())
    {
      VAST_ERROR("missing query arguments");
      return 1;
    }
    // 1. Spawn a SINK.
    auto snk = sink::spawn(caf::make_message(*(cmd + 1)));
    if (! snk)
    {
      VAST_ERROR("failed to spawn sink:", snk.error());
      return 1;
    }
    auto acc = self->spawn<accountant<uint64_t>>(accounting_log);
    acc->link_to(*snk);
    self->send(*snk, put_atom::value, accountant_atom::value, acc);
    auto sink_guard = caf::detail::make_scope_guard(
      [snk=*snk] { anon_send_exit(snk, exit::kill); }
    );
    // 2. Spawn an EXPORTER.
    caf::message_builder mb;
    auto label = "exporter-" + to_string(uuid::random()).substr(0, 7);
    mb.append("spawn");
    mb.append("-l");
    mb.append(label);
    mb.append("exporter");
    auto i = cmd + 2;
    mb.append(*i++);
    while (i != command_line.end())
      mb.append(*i++);
    caf::actor exporter;
    self->sync_send(node, mb.to_message()).await(
      [&](caf::actor const& actor) {
        exporter = actor;
      },
      [&](error const& e) {
        VAST_ERROR("failed to spawn exporter:", e);
      },
      caf::others >> [&] {
        VAST_ERROR("got unexpected message:",
                   caf::to_string(self->current_message()));
      }
    );
    if (! exporter)
      return 1;
    // 3. Connect EXPORTER with ARCHIVEs and INDEXes.
    std::vector<caf::actor> archives;
    std::vector<caf::actor> indexes;
    VAST_DEBUG("retrieving topology to connect exporter with archive/index");
    self->sync_send(node, store_atom::value).await(
      [&](caf::actor const& store) {
        self->sync_send(store, list_atom::value, "actors").await(
          [&](std::map<std::string, caf::message>& m) {
            for (auto& p : m)
              if (p.second.get_as<std::string>(1) == "archive")
                archives.push_back(p.second.get_as<caf::actor>(0));
              else if (p.second.get_as<std::string>(1) == "index")
                indexes.push_back(p.second.get_as<caf::actor>(0));
          }
        );
      }
    );
    if (archives.empty())
    {
      VAST_ERROR("no archives found");
      return 1;
    }
    if (indexes.empty())
    {
      VAST_ERROR("no indexes found");
      return 1;
    }
    for (auto& archive : archives)
      self->send(exporter, put_atom::value, archive_atom::value, archive);
    for (auto& index : indexes)
      self->send(exporter, put_atom::value, index_atom::value, index);
    // 4. Connect EXPORTER with SINK.
    self->send(exporter, put_atom::value, sink_atom::value, *snk);
    // 5. Run the EXPORTER.
    VAST_DEBUG("running exporter");
    self->send(exporter, stop_atom::value);
    self->send(exporter, run_atom::value);
    sink_guard.disable();
  }
  else
  {
    auto args = std::vector<std::string>(cmd + 1, command_line.end());
    caf::message_builder mb;
    mb.append(*cmd);
    for (auto& a : args)
      mb.append(std::move(a));
    auto cmd_line = *cmd + util::join(args, " ");
    auto exit_code = 0;
    self->sync_send(node, mb.to_message()).await(
      [&](ok_atom)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
      },
      [&](caf::actor const&)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
      },
      [&](std::string const& str)
      {
        VAST_VERBOSE("successfully executed command:", cmd_line);
        std::cout << str << std::endl;
      },
      [&](error const& e)
      {
        VAST_ERROR("failed to execute command:", cmd_line);
        VAST_ERROR(e);
        exit_code = 1;
      },
      caf::others >> [&]
      {
        auto msg = to_string(self->current_message());
        VAST_ERROR("got unexpected reply:", msg);
        exit_code = 1;
      }
    );
    if (exit_code != 0)
      return exit_code;
  }
  self->await_all_other_actors_done();
  return 0;
}
<|endoftext|>


<commit_before>/*
 * IceWM
 *
 * Copyright (C) 1998-2002 Marko Macek
 */
#include "config.h"
#include "yapp.h"

#include "ypoll.h"
#include "ytimer.h"
#include "yprefs.h"

#include "sysdep.h"

#include "intl.h"

extern char const *ApplicationName;
char const *&YApplication::Name = ApplicationName;

YApplication *app = 0;
static int signalPipe[2] = { 0, 0 };
static sigset_t oldSignalMask;
static sigset_t signalMask;

void initSignals() {
    sigemptyset(&signalMask);
    sigaddset(&signalMask, SIGHUP);
    sigprocmask(SIG_BLOCK, &signalMask, &oldSignalMask);
    sigemptyset(&signalMask);
    sigprocmask(SIG_BLOCK, &signalMask, &oldSignalMask);

    if (pipe(signalPipe) != 0)
        die(2, _("Failed to create anonymous pipe (errno=%d)."), errno);
    fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
    fcntl(signalPipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(signalPipe[1], F_SETFD, FD_CLOEXEC);
}

const char *YApplication::getPrivConfDir() {
    static char cfgdir[PATH_MAX] = "";

    if (*cfgdir == '\0') {
    	const char *env = getenv("ICEWM_PRIVCFG");

	if (NULL == env) {
	    env = getenv("HOME");
	    strcpy(cfgdir, env ? env : "");
	    strcat(cfgdir, "/.icewm");
	} else {
	    strcpy(cfgdir, env);
	}

        msg("using %s for private configuration files", cfgdir);
    }

    return cfgdir;
}

char *YApplication::findConfigFile(const char *name) {
    return findConfigFile(name, R_OK);
}

char *YApplication::findConfigFile(const char *name, int mode) {
    char *p;

    if (name[0] == '/')
        return newstr(name);

    p = strJoin(getPrivConfDir(), "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    p = strJoin(configDir, "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    p = strJoin(REDIR_ROOT(libDir), "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    return 0;
}

YApplication::YApplication(int *argc, char ***argv) {
    app = this;
    fLoopLevel = 0;
    fExitApp = 0;
    fFirstTimer = fLastTimer = 0;
    fFirstPoll = fLastPoll = 0;

    {
	char const * cmd(**argv);
	char cwd[PATH_MAX + 1];

	if ('/' == *cmd)
	    fExecutable = newstr(cmd);
	else if (strchr (cmd, '/'))
	    fExecutable = strJoin(getcwd(cwd, sizeof(cwd)), "/", cmd, NULL);
	else
	    fExecutable = findPath(getenv("PATH"), X_OK, cmd);
    }

    initSignals();
#if 0
    struct sigaction sig;
    sig.sa_handler = SIG_IGN;
    sigemptyset(&sig.sa_mask);
    sig.sa_flags = 0;
    sigaction(SIGCHLD, &sig, &oldSignalCHLD);
#endif
}

YApplication::~YApplication() {
    delete[] fExecutable;

    app = NULL;
}

void YApplication::registerTimer(YTimer *t) {
    t->fPrev = 0;
    t->fNext = fFirstTimer;
    if (fFirstTimer)
        fFirstTimer->fPrev = t;
    else
        fLastTimer = t;
    fFirstTimer = t;
}

void YApplication::unregisterTimer(YTimer *t) {
    if (t->fPrev)
        t->fPrev->fNext = t->fNext;
    else
        fFirstTimer = t->fNext;
    if (t->fNext)
        t->fNext->fPrev = t->fPrev;
    else
        fLastTimer = t->fPrev;
    t->fPrev = t->fNext = 0;
}

void YApplication::getTimeout(struct timeval *timeout) {
    YTimer *t;
    struct timeval curtime;
    bool fFirst = true;

    gettimeofday(&curtime, 0);
    timeout->tv_sec += curtime.tv_sec;
    timeout->tv_usec += curtime.tv_usec;
    while (timeout->tv_usec >= 1000000) {
        timeout->tv_usec -= 1000000;
        timeout->tv_sec++;
    }

    t = fFirstTimer;
    while (t) {
        if (t->isRunning() && (fFirst || timercmp(timeout, &t->timeout, >))) {
            *timeout = t->timeout;
            fFirst = false;
        }
        t = t->fNext;
    }
    if ((curtime.tv_sec == timeout->tv_sec &&
         curtime.tv_usec == timeout->tv_usec)
        || timercmp(&curtime, timeout, >))
    {
        timeout->tv_sec = 0;
        timeout->tv_usec = 1;
    } else {
        timeout->tv_sec -= curtime.tv_sec;
        timeout->tv_usec -= curtime.tv_usec;
        while (timeout->tv_usec < 0) {
            timeout->tv_usec += 1000000;
            timeout->tv_sec--;
        }
    }
    //msg("set: %d %d", timeout->tv_sec, timeout->tv_usec);
    PRECONDITION(timeout->tv_sec >= 0);
    PRECONDITION(timeout->tv_usec >= 0);
}

void YApplication::handleTimeouts() {
    YTimer *t, *n;
    struct timeval curtime;
    gettimeofday(&curtime, 0);

    t = fFirstTimer;
    while (t) {
        n = t->fNext;
        if (t->isRunning() && timercmp(&curtime, &t->timeout, >)) {
            YTimerListener *l = t->getTimerListener();
            t->stopTimer();
            if (l && l->handleTimer(t))
                t->startTimer();
        }
        t = n;
    }
}

void YApplication::registerPoll(YPoll *t) {
    PRECONDITION(t->fd != -1);
    t->fPrev = 0;
    t->fNext = fFirstPoll;
    if (fFirstPoll)
        fFirstPoll->fPrev = t;
    else
        fLastPoll = t;
    fFirstPoll = t;
}

void YApplication::unregisterPoll(YPoll *t) {
    if (t->fPrev)
        t->fPrev->fNext = t->fNext;
    else
        fFirstPoll = t->fNext;
    if (t->fNext)
        t->fNext->fPrev = t->fPrev;
    else
        fLastPoll = t->fPrev;
    t->fPrev = t->fNext = 0;
}

struct timeval idletime;

int YApplication::mainLoop() {
    fLoopLevel++;
    if (!fExitApp)
        fExitLoop = 0;

    gettimeofday(&idletime, 0);

    struct timeval timeout, *tp;

    while (!fExitApp && !fExitLoop) {
        if (handleXEvents()) {
        } else {
            int rc;
            fd_set read_fds;
            fd_set write_fds;

            handleIdle();
            gettimeofday(&idletime, 0);

            FD_ZERO(&read_fds);
            FD_ZERO(&write_fds);
            if (readFDCheckX() != -1)
                FD_SET(readFDCheckX(), &read_fds);
            if (signalPipe[0] != -1)
                FD_SET(signalPipe[0], &read_fds);

#warning "make this more general"
            int IceSMfd = readFdCheckSM();
            if (IceSMfd != -1)
                FD_SET(IceSMfd, &read_fds);

            {
                for (YPoll *s = fFirstPoll; s; s = s->fNext) {
                    PRECONDITION(s->fd != -1);
                    if (s->forRead()) {
                        FD_SET(s->fd, &read_fds);
                        MSG(("wait read"));
                    }
                    if (s->forWrite()) {
                        FD_SET(s->fd, &write_fds);
                        MSG(("wait connect"));
                    }
                }
            }

            timeout.tv_sec = 0;
            timeout.tv_usec = 0;
            getTimeout(&timeout);
            tp = 0;
            if (timeout.tv_sec != 0 || timeout.tv_usec != 0)
                tp = &timeout;
            else
                tp = 0;

            sigprocmask(SIG_UNBLOCK, &signalMask, NULL);

            rc = select(sizeof(fd_set),
                        SELECT_TYPE_ARG234 &read_fds,
                        SELECT_TYPE_ARG234 &write_fds,
                        0,
                        tp);

            sigprocmask(SIG_BLOCK, &signalMask, NULL);
#if 0
            sigset_t mask;
            sigpending(&mask);
            if (sigismember(&mask, SIGINT))
                handleSignal(SIGINT);
            if (sigismember(&mask, SIGTERM))
                handleSignal(SIGTERM);
            if (sigismember(&mask, SIGHUP))
                handleSignal(SIGHUP);
#endif

            if (rc == 0) {
                handleTimeouts();
            } else if (rc == -1) {
                if (errno != EINTR)
                    warn(_("Message Loop: select failed (errno=%d)"), errno);
            } else {
                if (signalPipe[0] != -1) {
                    if (FD_ISSET(signalPipe[0], &read_fds)) {
                        unsigned char sig;
                        if (read(signalPipe[0], &sig, 1) == 1) {
                            handleSignal(sig);
                        }
                    }
                }
                {
                    for (YPoll *s = fFirstPoll; s; s = s->fNext) {
                        PRECONDITION(s->fd != -1);
                        int fd = s->fd;
                        if (FD_ISSET(fd, &read_fds)) {
                            MSG(("got read"));
                            s->notifyRead();
                        }
                        if (FD_ISSET(fd, &write_fds)) {
                            MSG(("got connect"));
                            s->notifyWrite();
                        }
                    }
                }
                if (IceSMfd != -1 && FD_ISSET(IceSMfd, &read_fds)) {
                    readFdActionSM();
                }
            }
        }
    }
    fLoopLevel--;
    return fExitCode;
}

void YApplication::exitLoop(int exitCode) {
    fExitLoop = 1;
    fExitCode = exitCode;
}

void YApplication::exit(int exitCode) {
    fExitApp = 1;
    exitLoop(exitCode);
}

void YApplication::handleSignal(int sig) {
    if (sig == SIGCHLD) {
        int s, rc;
        do {
            rc = waitpid(-1, &s, WNOHANG);
        } while (rc > 0);
    }
}

void YApplication::handleIdle() {
}

void sig_handler(int sig) {
    unsigned char uc = sig;
    static const char *s = "icewm: signal error\n";
    if (write(signalPipe[1], &uc, 1) != 1)
        write(2, s, strlen(s));
}

void YApplication::catchSignal(int sig) {
    sigaddset(&signalMask, sig);
    sigprocmask(SIG_BLOCK, &signalMask, NULL);

    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(sig, &sa, NULL);
}

void YApplication::resetSignals() {
    sigset_t mask;
    //struct sigaction old_sig;

    //sigaction(SIGCHLD, &oldSignalCHLD, &old_sig);
    sigprocmask(SIG_SETMASK, &oldSignalMask, &mask);
}

int YApplication::runProgram(const char *path, const char *const *args) {
    flushXEvents();

    int cpid = -1;
    if (path && (cpid = fork()) == 0) {
        app->resetSignals();
        sigemptyset(&signalMask);
        sigaddset(&signalMask, SIGHUP);
        sigprocmask(SIG_UNBLOCK, &signalMask, NULL);

        /* perhaps the right thing to to:
         create ptys .. and show console window when an application
         attempts to use it (how do we detect input with no output?) */
        setsid();
#if 0
        close(0);
        if (open("/dev/null", O_RDONLY) != 0)
            _exit(1);
#endif
#if 1   /* for now, some debugging code */
        {
            /* close all files */

            int             i, max = 1024;
            struct rlimit   lim;

            if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
                max = lim.rlim_max;

            for (i = 3; i < max; i++) {
                int fl;
                if (fcntl(i, F_GETFD, &fl) == 0) {
                    if (!(fl & FD_CLOEXEC)) {
                        warn("file descriptor still open: %d. "
                             " Check /proc/$icewmpid/fd/%d when running next time. "
                             "Please report a bug (perhaps not an icewm problem)!", i, i);
                    }
                }
                close (i);
            }
        }
#endif

        if (args)
            execvp(path, (char **)args);
        else
            execlp(path, path, 0);

        _exit(99);
    }
    return cpid;
}

int YApplication::waitProgram(int p) {
    int status;

    if (p == -1)
        return -1;

    if (waitpid(p, &status, 0) != p)
        return -1;
    return status;
}

void YApplication::runCommand(const char *cmdline) {
#warning calling /bin/sh is considered to be bloat
    char const * argv[] = { "/bin/sh", "-c", cmdline, NULL };
    runProgram(argv[0], argv);
}

#ifndef NO_CONFIGURE
bool YApplication::loadConfig(struct cfoption *options, const char *name) {
    char *configFile = YApplication::findConfigFile(name);
    bool rc = false;
    if (configFile) {
        ::loadConfig(options, configFile);
        delete[] configFile;
        rc = true;
    }
    return rc;
}
#endif
<commit_msg>build fix<commit_after>/*
 * IceWM
 *
 * Copyright (C) 1998-2002 Marko Macek
 */
#include "config.h"
#include "yapp.h"

#include "ypoll.h"
#include "ytimer.h"
#include "yprefs.h"

#include "sysdep.h"
#include "sys/resource.h"

#include "intl.h"

extern char const *ApplicationName;
char const *&YApplication::Name = ApplicationName;

YApplication *app = 0;
static int signalPipe[2] = { 0, 0 };
static sigset_t oldSignalMask;
static sigset_t signalMask;

void initSignals() {
    sigemptyset(&signalMask);
    sigaddset(&signalMask, SIGHUP);
    sigprocmask(SIG_BLOCK, &signalMask, &oldSignalMask);
    sigemptyset(&signalMask);
    sigprocmask(SIG_BLOCK, &signalMask, &oldSignalMask);

    if (pipe(signalPipe) != 0)
        die(2, _("Failed to create anonymous pipe (errno=%d)."), errno);
    fcntl(signalPipe[1], F_SETFL, O_NONBLOCK);
    fcntl(signalPipe[0], F_SETFD, FD_CLOEXEC);
    fcntl(signalPipe[1], F_SETFD, FD_CLOEXEC);
}

const char *YApplication::getPrivConfDir() {
    static char cfgdir[PATH_MAX] = "";

    if (*cfgdir == '\0') {
    	const char *env = getenv("ICEWM_PRIVCFG");

	if (NULL == env) {
	    env = getenv("HOME");
	    strcpy(cfgdir, env ? env : "");
	    strcat(cfgdir, "/.icewm");
	} else {
	    strcpy(cfgdir, env);
	}

        msg("using %s for private configuration files", cfgdir);
    }

    return cfgdir;
}

char *YApplication::findConfigFile(const char *name) {
    return findConfigFile(name, R_OK);
}

char *YApplication::findConfigFile(const char *name, int mode) {
    char *p;

    if (name[0] == '/')
        return newstr(name);

    p = strJoin(getPrivConfDir(), "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    p = strJoin(configDir, "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    p = strJoin(REDIR_ROOT(libDir), "/", name, NULL);
    if (access(p, mode) == 0) return p;
    delete[] p;

    return 0;
}

YApplication::YApplication(int *argc, char ***argv) {
    app = this;
    fLoopLevel = 0;
    fExitApp = 0;
    fFirstTimer = fLastTimer = 0;
    fFirstPoll = fLastPoll = 0;

    {
	char const * cmd(**argv);
	char cwd[PATH_MAX + 1];

	if ('/' == *cmd)
	    fExecutable = newstr(cmd);
	else if (strchr (cmd, '/'))
	    fExecutable = strJoin(getcwd(cwd, sizeof(cwd)), "/", cmd, NULL);
	else
	    fExecutable = findPath(getenv("PATH"), X_OK, cmd);
    }

    initSignals();
#if 0
    struct sigaction sig;
    sig.sa_handler = SIG_IGN;
    sigemptyset(&sig.sa_mask);
    sig.sa_flags = 0;
    sigaction(SIGCHLD, &sig, &oldSignalCHLD);
#endif
}

YApplication::~YApplication() {
    delete[] fExecutable;

    app = NULL;
}

void YApplication::registerTimer(YTimer *t) {
    t->fPrev = 0;
    t->fNext = fFirstTimer;
    if (fFirstTimer)
        fFirstTimer->fPrev = t;
    else
        fLastTimer = t;
    fFirstTimer = t;
}

void YApplication::unregisterTimer(YTimer *t) {
    if (t->fPrev)
        t->fPrev->fNext = t->fNext;
    else
        fFirstTimer = t->fNext;
    if (t->fNext)
        t->fNext->fPrev = t->fPrev;
    else
        fLastTimer = t->fPrev;
    t->fPrev = t->fNext = 0;
}

void YApplication::getTimeout(struct timeval *timeout) {
    YTimer *t;
    struct timeval curtime;
    bool fFirst = true;

    gettimeofday(&curtime, 0);
    timeout->tv_sec += curtime.tv_sec;
    timeout->tv_usec += curtime.tv_usec;
    while (timeout->tv_usec >= 1000000) {
        timeout->tv_usec -= 1000000;
        timeout->tv_sec++;
    }

    t = fFirstTimer;
    while (t) {
        if (t->isRunning() && (fFirst || timercmp(timeout, &t->timeout, >))) {
            *timeout = t->timeout;
            fFirst = false;
        }
        t = t->fNext;
    }
    if ((curtime.tv_sec == timeout->tv_sec &&
         curtime.tv_usec == timeout->tv_usec)
        || timercmp(&curtime, timeout, >))
    {
        timeout->tv_sec = 0;
        timeout->tv_usec = 1;
    } else {
        timeout->tv_sec -= curtime.tv_sec;
        timeout->tv_usec -= curtime.tv_usec;
        while (timeout->tv_usec < 0) {
            timeout->tv_usec += 1000000;
            timeout->tv_sec--;
        }
    }
    //msg("set: %d %d", timeout->tv_sec, timeout->tv_usec);
    PRECONDITION(timeout->tv_sec >= 0);
    PRECONDITION(timeout->tv_usec >= 0);
}

void YApplication::handleTimeouts() {
    YTimer *t, *n;
    struct timeval curtime;
    gettimeofday(&curtime, 0);

    t = fFirstTimer;
    while (t) {
        n = t->fNext;
        if (t->isRunning() && timercmp(&curtime, &t->timeout, >)) {
            YTimerListener *l = t->getTimerListener();
            t->stopTimer();
            if (l && l->handleTimer(t))
                t->startTimer();
        }
        t = n;
    }
}

void YApplication::registerPoll(YPoll *t) {
    PRECONDITION(t->fd != -1);
    t->fPrev = 0;
    t->fNext = fFirstPoll;
    if (fFirstPoll)
        fFirstPoll->fPrev = t;
    else
        fLastPoll = t;
    fFirstPoll = t;
}

void YApplication::unregisterPoll(YPoll *t) {
    if (t->fPrev)
        t->fPrev->fNext = t->fNext;
    else
        fFirstPoll = t->fNext;
    if (t->fNext)
        t->fNext->fPrev = t->fPrev;
    else
        fLastPoll = t->fPrev;
    t->fPrev = t->fNext = 0;
}

struct timeval idletime;

int YApplication::mainLoop() {
    fLoopLevel++;
    if (!fExitApp)
        fExitLoop = 0;

    gettimeofday(&idletime, 0);

    struct timeval timeout, *tp;

    while (!fExitApp && !fExitLoop) {
        if (handleXEvents()) {
        } else {
            int rc;
            fd_set read_fds;
            fd_set write_fds;

            handleIdle();
            gettimeofday(&idletime, 0);

            FD_ZERO(&read_fds);
            FD_ZERO(&write_fds);
            if (readFDCheckX() != -1)
                FD_SET(readFDCheckX(), &read_fds);
            if (signalPipe[0] != -1)
                FD_SET(signalPipe[0], &read_fds);

#warning "make this more general"
            int IceSMfd = readFdCheckSM();
            if (IceSMfd != -1)
                FD_SET(IceSMfd, &read_fds);

            {
                for (YPoll *s = fFirstPoll; s; s = s->fNext) {
                    PRECONDITION(s->fd != -1);
                    if (s->forRead()) {
                        FD_SET(s->fd, &read_fds);
                        MSG(("wait read"));
                    }
                    if (s->forWrite()) {
                        FD_SET(s->fd, &write_fds);
                        MSG(("wait connect"));
                    }
                }
            }

            timeout.tv_sec = 0;
            timeout.tv_usec = 0;
            getTimeout(&timeout);
            tp = 0;
            if (timeout.tv_sec != 0 || timeout.tv_usec != 0)
                tp = &timeout;
            else
                tp = 0;

            sigprocmask(SIG_UNBLOCK, &signalMask, NULL);

            rc = select(sizeof(fd_set),
                        SELECT_TYPE_ARG234 &read_fds,
                        SELECT_TYPE_ARG234 &write_fds,
                        0,
                        tp);

            sigprocmask(SIG_BLOCK, &signalMask, NULL);
#if 0
            sigset_t mask;
            sigpending(&mask);
            if (sigismember(&mask, SIGINT))
                handleSignal(SIGINT);
            if (sigismember(&mask, SIGTERM))
                handleSignal(SIGTERM);
            if (sigismember(&mask, SIGHUP))
                handleSignal(SIGHUP);
#endif

            if (rc == 0) {
                handleTimeouts();
            } else if (rc == -1) {
                if (errno != EINTR)
                    warn(_("Message Loop: select failed (errno=%d)"), errno);
            } else {
                if (signalPipe[0] != -1) {
                    if (FD_ISSET(signalPipe[0], &read_fds)) {
                        unsigned char sig;
                        if (read(signalPipe[0], &sig, 1) == 1) {
                            handleSignal(sig);
                        }
                    }
                }
                {
                    for (YPoll *s = fFirstPoll; s; s = s->fNext) {
                        PRECONDITION(s->fd != -1);
                        int fd = s->fd;
                        if (FD_ISSET(fd, &read_fds)) {
                            MSG(("got read"));
                            s->notifyRead();
                        }
                        if (FD_ISSET(fd, &write_fds)) {
                            MSG(("got connect"));
                            s->notifyWrite();
                        }
                    }
                }
                if (IceSMfd != -1 && FD_ISSET(IceSMfd, &read_fds)) {
                    readFdActionSM();
                }
            }
        }
    }
    fLoopLevel--;
    return fExitCode;
}

void YApplication::exitLoop(int exitCode) {
    fExitLoop = 1;
    fExitCode = exitCode;
}

void YApplication::exit(int exitCode) {
    fExitApp = 1;
    exitLoop(exitCode);
}

void YApplication::handleSignal(int sig) {
    if (sig == SIGCHLD) {
        int s, rc;
        do {
            rc = waitpid(-1, &s, WNOHANG);
        } while (rc > 0);
    }
}

void YApplication::handleIdle() {
}

void sig_handler(int sig) {
    unsigned char uc = sig;
    static const char *s = "icewm: signal error\n";
    if (write(signalPipe[1], &uc, 1) != 1)
        write(2, s, strlen(s));
}

void YApplication::catchSignal(int sig) {
    sigaddset(&signalMask, sig);
    sigprocmask(SIG_BLOCK, &signalMask, NULL);

    struct sigaction sa;
    sa.sa_handler = sig_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(sig, &sa, NULL);
}

void YApplication::resetSignals() {
    sigset_t mask;
    //struct sigaction old_sig;

    //sigaction(SIGCHLD, &oldSignalCHLD, &old_sig);
    sigprocmask(SIG_SETMASK, &oldSignalMask, &mask);
}

int YApplication::runProgram(const char *path, const char *const *args) {
    flushXEvents();

    int cpid = -1;
    if (path && (cpid = fork()) == 0) {
        app->resetSignals();
        sigemptyset(&signalMask);
        sigaddset(&signalMask, SIGHUP);
        sigprocmask(SIG_UNBLOCK, &signalMask, NULL);

        /* perhaps the right thing to to:
         create ptys .. and show console window when an application
         attempts to use it (how do we detect input with no output?) */
        setsid();
#if 0
        close(0);
        if (open("/dev/null", O_RDONLY) != 0)
            _exit(1);
#endif
#if 1   /* for now, some debugging code */
        {
            /* close all files */

            int             i, max = 1024;
            struct rlimit   lim;

            if (getrlimit(RLIMIT_NOFILE, &lim) == 0)
                max = lim.rlim_max;

            for (i = 3; i < max; i++) {
                int fl;
                if (fcntl(i, F_GETFD, &fl) == 0) {
                    if (!(fl & FD_CLOEXEC)) {
                        warn("file descriptor still open: %d. "
                             " Check /proc/$icewmpid/fd/%d when running next time. "
                             "Please report a bug (perhaps not an icewm problem)!", i, i);
                    }
                }
                close (i);
            }
        }
#endif

        if (args)
            execvp(path, (char **)args);
        else
            execlp(path, path, 0);

        _exit(99);
    }
    return cpid;
}

int YApplication::waitProgram(int p) {
    int status;

    if (p == -1)
        return -1;

    if (waitpid(p, &status, 0) != p)
        return -1;
    return status;
}

void YApplication::runCommand(const char *cmdline) {
#warning calling /bin/sh is considered to be bloat
    char const * argv[] = { "/bin/sh", "-c", cmdline, NULL };
    runProgram(argv[0], argv);
}

#ifndef NO_CONFIGURE
bool YApplication::loadConfig(struct cfoption *options, const char *name) {
    char *configFile = YApplication::findConfigFile(name);
    bool rc = false;
    if (configFile) {
        ::loadConfig(options, configFile);
        delete[] configFile;
        rc = true;
    }
    return rc;
}
#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "core/sstring.hh"

#include <json/json.h>

namespace json {

template<typename Map>
inline sstring to_json(const Map& map) {
    Json::Value root(Json::arrayValue);
    for (auto&& kv : map) {
        Json::Value obj_value(Json::objectValue);
        obj_value[kv.first] = Json::Value(kv.second);
        root.append(obj_value);
    }
    Json::FastWriter writer;
    return writer.write(root);
}

inline std::map<sstring, sstring> to_map(const sstring& raw) {
    Json::Value root;
    Json::Reader reader;
    reader.parse(std::string{raw}, root);
    std::map<sstring, sstring> map;
    for (Json::ArrayIndex idx = 0; idx < root.size(); idx++) {
        auto item = root[idx];
        for (auto&& member : item.getMemberNames()) {
            map.emplace(member, item[member].asString());
        }
    }
    return map;
}

}
<commit_msg>json: fix (de)serialization of map<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "core/sstring.hh"

#include <json/json.h>

namespace json {

template<typename Map>
inline sstring to_json(const Map& map) {
    Json::Value root;
    for (auto&& kv : map) {
        root[kv.first] = Json::Value(kv.second);
    }
    Json::FastWriter writer;
    return writer.write(root);
}

inline std::map<sstring, sstring> to_map(const sstring& raw) {
    Json::Value root;
    Json::Reader reader;
    reader.parse(std::string{raw}, root);
    std::map<sstring, sstring> map;
    for (auto&& member : root.getMemberNames()) {
        map.emplace(member, root[member].asString());
    }
    return map;
}

}
<|endoftext|>


<commit_before>/* $Id: $ */
/* $Log$ */

//------------------------------------
// Configuration macro example:
//
// Do photon identification analysis with Generator data
// Gamma in PHOS. For EMCAL clusters change
// PHOS by EMCAL where necessary
//
// Author : Gustavo Conesa Balbastre (INFN-LNF)
//------------------------------------

AliAnaPartCorrMaker*  ConfigAnalysis()
{
  //
  // Configuration goes here
  //
  printf("======================== \n");
  printf("ConfigAnalysis() \n");
  printf("======================== \n");

  //Detector Fidutial Cuts
  AliFidutialCut * fidCut = new AliFidutialCut();
  fidCut->DoCTSFidutialCut(kTRUE) ;
  fidCut->DoEMCALFidutialCut(kTRUE) ;
  fidCut->DoPHOSFidutialCut(kTRUE) ;

  //fidCut->SetSimpleCTSFidutialCut(0.9,0.,360.);
  //fidCut->SetSimpleEMCALFidutialCut(0.7,80.,190.);
  //fidCut->SetSimplePHOSFidutialCut(0.13,220.,320.);

  fidCut->Print("");

  //-----------------------------------------------------------
  // Reader
  //-----------------------------------------------------------
  AliCaloTrackESDReader *reader = new AliCaloTrackESDReader();
  reader->SetDebug(-1);

  //Switch on or off the detectors information that you want
  reader->SwitchOffEMCAL();
  reader->SwitchOffCTS();
  reader->SwitchOnPHOS();

  //Min particle pT
  //reader->SetEMCALPtMin(0.5);
  reader->SetPHOSPtMin(0.5);
  //reader->SetCTSPtMin(0.2);
  reader->SwitchOnStack(); //On by default, remember to SwitchOnMCData() in analysis classes
  //In case of generating jet events (with PYTHIA), if pt hard bin is small
  //reject events with large difference between ptHard and triggered jet
  //reader->SetPtHardAndJetPtComparison(kTRUE);

  reader->SetFidutialCut(fidCut);

  //Anaysis of final particles, not pi0/eta etc.
  TArrayI statusArray(1) ;
  statusArray.SetAt(1,0);
  reader->AddStatusArray(statusArray)  ;
  reader->SwitchOnStatusSelection() ;

  //Keep pi0 in the list and not the 2 photon if decay angle is small.
  reader->SwitchOffOverlapCheck();

  reader->Print("");

  //---------------------------------------------------------------------
  // Analysis algorithm
  //---------------------------------------------------------------------

  //Detector Fidutial Cuts for analysis part
  AliFidutialCut * fidCut2 = new AliFidutialCut();
  fidCut2->DoCTSFidutialCut(kFALSE) ;
  fidCut2->DoEMCALFidutialCut(kFALSE) ;
  fidCut2->DoPHOSFidutialCut(kFALSE) ;

  //fidCut2->SetSimpleCTSFidutialCut(0.9,0.,360.);
  //fidCut2->SetSimpleEMCALFidutialCut(0.7,80.,190.);
  //fidCut2->SetSimplePHOSFidutialCut(0.13,220.,320.);

  fidCut2->Print("");

  AliAnaPhoton *ana = new AliAnaPhoton();
  ana->SetDebug(-1);
  ana->SetMinPt(5.);
  ana->SetMinDistanceToBadChannel(2, 4, 5);
  ana->SetCaloPID(pid);
  ana->SetFidutialCut(fidCut2);
  ana->SetCalorimeter("PHOS");
  ana->SwitchOnDataMC() ;//Access MC stack and fill more histograms
  ana->SwitchOffCaloPID(); //No need with MC reader
  ana->SwitchOffCaloPIDRecalculation(); //recommended for EMCAL, no need with MC reader
  ana->SwitchOffTrackMatchRejection(); //Only in use when OnCaloPID
  ana->SwitchOffFidutialCut();
  ana->SetOutputAODName("Photons");
  ana->SetOutputAODClassName("AliAODPWG4Particle");
  //Set Histrograms bins and ranges
//	ana->SetHistoPtRangeAndNBins(0, 50, 100) ;
//	ana->SetHistoPhiRangeAndNBins(0, TMath::TwoPi(), 100) ;
//	ana->SetHistoEtaRangeAndNBins(-0.7, 0.7, 100) ;
  ana->Print("");

  //---------------------------------------------------------------------
  // Set  analysis algorithm and reader
  //---------------------------------------------------------------------
  maker = new AliAnaPartCorrMaker();
  maker->SetReader(reader);//pointer to reader
  maker->AddAnalysis(ana,0);
  maker->SetAnaDebug(-1)  ;
  maker->SwitchOnHistogramsMaker()  ;
  maker->SwitchOnAODsMaker()  ;

  maker->Print("");
  //
  printf("======================== \n");
  printf("END ConfigAnalysis() \n");
  printf("======================== \n");
  return maker ;
}
<commit_msg>Correct reader initialization to MCReader and remove line with setting PID<commit_after>/* $Id: $ */
/* $Log$ */

//------------------------------------
// Configuration macro example:
//
// Do photon identification analysis with Generator data
// Gamma in PHOS. For EMCAL clusters change
// PHOS by EMCAL where necessary
//
// Author : Gustavo Conesa Balbastre (INFN-LNF)
//------------------------------------

AliAnaPartCorrMaker*  ConfigAnalysis()
{
  //
  // Configuration goes here
  //
  printf("======================== \n");
  printf("ConfigAnalysis() \n");
  printf("======================== \n");

  //Detector Fidutial Cuts
  AliFidutialCut * fidCut = new AliFidutialCut();
  fidCut->DoCTSFidutialCut(kTRUE) ;
  fidCut->DoEMCALFidutialCut(kTRUE) ;
  fidCut->DoPHOSFidutialCut(kTRUE) ;

  //fidCut->SetSimpleCTSFidutialCut(0.9,0.,360.);
  //fidCut->SetSimpleEMCALFidutialCut(0.7,80.,190.);
  //fidCut->SetSimplePHOSFidutialCut(0.13,220.,320.);

  fidCut->Print("");

  //-----------------------------------------------------------
  // Reader
  //-----------------------------------------------------------
  AliCaloTrackMCReader *reader = new AliCaloTrackMCReader();
  reader->SetDebug(-1);

  //Switch on or off the detectors information that you want
  reader->SwitchOffEMCAL();
  reader->SwitchOffCTS();
  reader->SwitchOnPHOS();

  //Min particle pT
  //reader->SetEMCALPtMin(0.5);
  reader->SetPHOSPtMin(0.5);
  //reader->SetCTSPtMin(0.2);
  reader->SwitchOnStack(); //On by default, remember to SwitchOnMCData() in analysis classes
  //In case of generating jet events (with PYTHIA), if pt hard bin is small
  //reject events with large difference between ptHard and triggered jet
  //reader->SetPtHardAndJetPtComparison(kTRUE);

  reader->SetFidutialCut(fidCut);

  //Anaysis of final particles, not pi0/eta etc.
  TArrayI statusArray(1) ;
  statusArray.SetAt(1,0);
  reader->AddStatusArray(statusArray)  ;
  reader->SwitchOnStatusSelection() ;

  //Keep pi0 in the list and not the 2 photon if decay angle is small.
  reader->SwitchOffOverlapCheck();

  reader->Print("");

  //---------------------------------------------------------------------
  // Analysis algorithm
  //---------------------------------------------------------------------

  //Detector Fidutial Cuts for analysis part
  AliFidutialCut * fidCut2 = new AliFidutialCut();
  fidCut2->DoCTSFidutialCut(kFALSE) ;
  fidCut2->DoEMCALFidutialCut(kFALSE) ;
  fidCut2->DoPHOSFidutialCut(kFALSE) ;

  //fidCut2->SetSimpleCTSFidutialCut(0.9,0.,360.);
  //fidCut2->SetSimpleEMCALFidutialCut(0.7,80.,190.);
  //fidCut2->SetSimplePHOSFidutialCut(0.13,220.,320.);

  fidCut2->Print("");

  AliAnaPhoton *ana = new AliAnaPhoton();
  ana->SetDebug(-1);
  ana->SetMinPt(5.);
  ana->SetMinDistanceToBadChannel(2, 4, 5);
  ana->SetFidutialCut(fidCut2);
  ana->SetCalorimeter("PHOS");
  ana->SwitchOnDataMC() ;//Access MC stack and fill more histograms
  ana->SwitchOffCaloPID(); //No need with MC reader
  ana->SwitchOffCaloPIDRecalculation(); //recommended for EMCAL, no need with MC reader
  ana->SwitchOffTrackMatchRejection(); //Only in use when OnCaloPID
  ana->SwitchOffFidutialCut();
  ana->SetOutputAODName("Photons");
  ana->SetOutputAODClassName("AliAODPWG4Particle");
  //Set Histrograms bins and ranges
//	ana->SetHistoPtRangeAndNBins(0, 50, 100) ;
//	ana->SetHistoPhiRangeAndNBins(0, TMath::TwoPi(), 100) ;
//	ana->SetHistoEtaRangeAndNBins(-0.7, 0.7, 100) ;
  ana->Print("");

  //---------------------------------------------------------------------
  // Set  analysis algorithm and reader
  //---------------------------------------------------------------------
  maker = new AliAnaPartCorrMaker();
  maker->SetReader(reader);//pointer to reader
  maker->AddAnalysis(ana,0);
  maker->SetAnaDebug(-1)  ;
  maker->SwitchOnHistogramsMaker()  ;
  maker->SwitchOnAODsMaker()  ;

  maker->Print("");
  //
  printf("======================== \n");
  printf("END ConfigAnalysis() \n");
  printf("======================== \n");
  return maker ;
}
<|endoftext|>


<commit_before>AliAnalysisTaskSEDs *AddTaskDs(Int_t storeNtuple=1,Bool_t readMC=kFALSE,
				     TString filename="DstoKKpiCuts.root")
{
  //
  // Test macro for the AliAnalysisTaskSE for Ds candidates

  //Invariant mass histogram and
  // association with MC truth (using MC info in AOD)
  // Origin: R. Bala, bala@to.infn.it
  // Modified for Ds meson: G.M. Innocenti innocent@to.infn.it
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDs", "No analysis manager to connect to.");
  }

  TFile* filecuts=TFile::Open(filename.Data());
  if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
    cout<<"Error: Input file not found!"<<endl;
    return 0;
  }

  //Analysis Task

  AliRDHFCutsDstoKKpi* analysiscuts=new AliRDHFCutsDstoKKpi();
  analysiscuts = (AliRDHFCutsDstoKKpi*)filecuts->Get("AnalysisCuts");

  AliAnalysisTaskSEDs *dsTask = new AliAnalysisTaskSEDs("DsAnalysis",analysiscuts,storeNtuple);

  dsTask->SetReadMC(readMC);
  //dsTask->SetDoLikeSign(kTRUE);
  //  dsTask->SetUseTPCpid(kTRUE);
  //dsTask->SetUseTOFpid(kTRUE);
  dsTask->SetDebugLevel(10);
  dsTask->SetUseSelectionBit(kTRUE);
  //dsTask->SetMassLimits(0.2);
  mgr->AddTask(dsTask);

  // Create containers for input/output

  AliAnalysisDataContainer *cinputDs = mgr->CreateContainer("cinputDs",TChain::Class(),
							       AliAnalysisManager::kInputContainer);
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_InvMassDs";

  AliAnalysisDataContainer *coutputDsCuts = mgr->CreateContainer("coutputDsCuts",TList::Class(),
								    AliAnalysisManager::kOutputContainer,
								    outputfile.Data());

  AliAnalysisDataContainer *coutputDs = mgr->CreateContainer("coutputDs",TList::Class(),
								AliAnalysisManager::kOutputContainer,
								outputfile.Data());
  AliAnalysisDataContainer *coutputDsNorm = mgr->CreateContainer("coutputDsNorm",AliNormalizationCounter::Class(),
								AliAnalysisManager::kOutputContainer,
								outputfile.Data());

   if(storeNtuple){
    AliAnalysisDataContainer *coutputDs2 = mgr->CreateContainer("coutputDs2",TNtuple::Class(),
								   AliAnalysisManager::kOutputContainer,
								   outputfile.Data());

    coutputDs2->SetSpecialOutput();
  }

  mgr->ConnectInput(dsTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dsTask,1,coutputDs);

  mgr->ConnectOutput(dsTask,2,coutputDsCuts);

  mgr->ConnectOutput(dsTask,3,coutputDsNorm);

  if(storeNtuple){
    mgr->ConnectOutput(dsTask,4,coutputDs2);
  }

  return dsTask;
}
<commit_msg>AddTacksDs adapted for running on lego train (Gian Michele)<commit_after>AliAnalysisTaskSEDs *AddTaskDs(Int_t system=0/*0=pp,1=PbPb*/,
                     Int_t storeNtuple=0,Bool_t readMC=kFALSE,
				     TString filename="")
{
  //
  // Test macro for the AliAnalysisTaskSE for Ds candidates

  //Invariant mass histogram and
  // association with MC truth (using MC info in AOD)
  // Origin: R. Bala, bala@to.infn.it
  // Modified for Ds meson: G.M. Innocenti innocent@to.infn.it
  // Get the pointer to the existing analysis manager via the static access method.
  //==============================================================================

  AliAnalysisManager *mgr = AliAnalysisManager::GetAnalysisManager();
  if (!mgr) {
    ::Error("AddTaskDs", "No analysis manager to connect to.");
  }

  Bool_t stdcuts=kFALSE;
  TFile* filecuts;
  if( filename.EqualTo("") ) {
    stdcuts=kTRUE;
  } else {
    filecuts=TFile::Open(filename.Data());
    if(!filecuts ||(filecuts&& !filecuts->IsOpen())){
	  AliFatal("Cut object not found: analysis will not start!\n");
    }
    else printf("Cut object correctly found\n");
  }

  //Analysis Task

  AliRDHFCutsDstoKKpi* analysiscuts=new AliRDHFCutsDstoKKpi();

  if(stdcuts) {
    if(system==0) {
      printf("Cut object not found: standard pp cut object used\n");
      analysiscuts->SetStandardCutsPP2010();
    }
    else AliFatal("Standard cut object not available for PbPb: analysis will not start!\n");
  }
  else analysiscuts = (AliRDHFCutsDstoKKpi*)filecuts->Get("AnalysisCuts");

  AliAnalysisTaskSEDs *dsTask = new AliAnalysisTaskSEDs("DsAnalysis",analysiscuts,storeNtuple);

  dsTask->SetReadMC(readMC);
  //dsTask->SetDoLikeSign(kTRUE);
  //  dsTask->SetUseTPCpid(kTRUE);
  //dsTask->SetUseTOFpid(kTRUE);
  dsTask->SetDebugLevel(10);
  dsTask->SetUseSelectionBit(kTRUE);
  //dsTask->SetMassLimits(0.2);
  mgr->AddTask(dsTask);

  // Create containers for input/output

  AliAnalysisDataContainer *cinputDs = mgr->CreateContainer("cinputDs",TChain::Class(),
							       AliAnalysisManager::kInputContainer);
  TString outputfile = AliAnalysisManager::GetCommonFileName();
  outputfile += ":PWG3_D2H_InvMassDs";

  AliAnalysisDataContainer *coutputDsCuts = mgr->CreateContainer("coutputDsCuts",TList::Class(),
								    AliAnalysisManager::kOutputContainer,
								    outputfile.Data());

  AliAnalysisDataContainer *coutputDs = mgr->CreateContainer("coutputDs",TList::Class(),
								AliAnalysisManager::kOutputContainer,
								outputfile.Data());
  AliAnalysisDataContainer *coutputDsNorm = mgr->CreateContainer("coutputDsNorm",AliNormalizationCounter::Class(),
								AliAnalysisManager::kOutputContainer,
								outputfile.Data());

   if(storeNtuple){
    AliAnalysisDataContainer *coutputDs2 = mgr->CreateContainer("coutputDs2",TNtuple::Class(),
								   AliAnalysisManager::kOutputContainer,
								   outputfile.Data());

    coutputDs2->SetSpecialOutput();
  }

  mgr->ConnectInput(dsTask,0,mgr->GetCommonInputContainer());

  mgr->ConnectOutput(dsTask,1,coutputDs);

  mgr->ConnectOutput(dsTask,2,coutputDsCuts);

  mgr->ConnectOutput(dsTask,3,coutputDsNorm);

  if(storeNtuple){
    mgr->ConnectOutput(dsTask,4,coutputDs2);
  }

  return dsTask;
}
<|endoftext|>


<commit_before>#include "plant_printer.h"

#include <algorithm>
#include <iostream>

#include "asdf_multiplat/main/asdf_defs.h"

using namespace std;
using namespace plantgen;

namespace plant_printer
{
    namespace
    {
        constexpr char string_var_delimiter = '%';
    }

    string_var_locations_t parse_print_string(string const& print_string)
    {
        string_var_locations_t var_locations;

        size_t pos = 0;
        size_t endpos = 0;

        while(true)
        {
            pos = print_string.find(string_var_delimiter, endpos);
            if(pos == string::npos)
                break;

            endpos = print_string.find(string_var_delimiter, pos+1);

            if(endpos == string::npos)
            {
                EXPLODE("unmached %%");
            }

            ASSERT(endpos > pos, "");
            ASSERT(endpos-pos >= 1, "");
            std::string key = print_string.substr(pos+1, endpos-pos-1);
            var_locations.insert({key,pos});

            endpos++; //move it past the percent sign for the next find call
        }

        return var_locations;
    }

    struct sorted_range_value_t
    {
        int percentage;
        std::string range_string;
    };

    std::vector<sorted_range_value_t> get_sorted_range(generated_node_t const& node)
    {
        if(node.generated_values.size() == 0)
            return std::vector<sorted_range_value_t>();

        //ASSERT(node.generated_values.size() > 0, "expected some flavors to sort");
        std::vector<sorted_range_value_t> sorted_values;
        sorted_values.reserve(node.generated_values.size());

        for(auto const& val : node.generated_values)
        {
            auto percent_sign_pos = val.find('%');

            ASSERT(percent_sign_pos != std::string::npos, "");
            if(percent_sign_pos != std::string::npos)
            {
                sorted_range_value_t sv =
                {
                    stoi(val.substr(0, percent_sign_pos)),
                    val.substr(percent_sign_pos + 2)
                };

                sorted_values.push_back(sv);
            }
        }

        std::sort(sorted_values.begin(), sorted_values.end(),
            [](sorted_range_value_t const& lhs, sorted_range_value_t const& rhs)
            {
                return lhs.percentage > rhs.percentage;
            });

        return sorted_values;
    }

    string print_range_value(generated_node_t const& range)
    {
        auto sorted_values = get_sorted_range(range);

        ASSERT(sorted_values.size() > 0, "");

        if(sorted_values[0].percentage >= 95)
        {
            return "completely " + sorted_values[0].range_string;
        }
        else if(sorted_values[0].percentage >= 90)
        {
            return "very " + sorted_values[0].range_string;
        }
        else if(sorted_values[0].percentage >= 70)
        {
            std::string ret = "mostly " + sorted_values[0].range_string;

            if(sorted_values.size() >= 2 && sorted_values[1].percentage > 20)
            {
                ret += " and slightly " + sorted_values[1].range_string;
            }

            return ret;
        }
        //else if(sorted_values[0].percentage >= 50)
        else
        {
            std::string ret = "somewhat " + sorted_values[0].range_string;

            if(sorted_values.size() >= 2 && sorted_values[1].percentage > 20)
            {
                ret += " and slightly " + sorted_values[1].range_string;
            }

            return ret;
        }
    }

    string print_multi_value(generated_node_t const& node)
    {
        if(node.generated_values.empty())
            return "";

        string property_string;// =  node.name + " that is ";

        if(node.generated_values.size() == 1)
            return node.generated_values[0];

        for(size_t i = 0; i < node.generated_values.size() - 1; ++i)
        {
            property_string += node.generated_values[i] + ", ";
        }

        property_string.resize(property_string.size() - 2);
        property_string += " and " + node.generated_values.back();

        return property_string;
    }

    string print_basic_property(generated_node_t const& node)
    {
        ASSERT(node.children.empty(), "");

        if(node.generated_values.size() == 1)
        {
            return node.generated_values[0];
        }
        else if(node.generated_values.size() > 1)
        {
            // if there is a % in the first few characters
            // (ie: if its XXX% or XX% or X%)
            if(node.generated_values[0].find('%') <= 3)
            {
                return print_range_value(node);
            }
            else
            {
                return print_multi_value(node);
            }
        }

        return "";
    }

    string print_sub_property(generated_node_t const& node, size_t level)
    {
        std::string summary;

        if(node.print_string.size() > 0)
        {
            summary += print_property_with_string(node);
        }
        else
        {
            if(node.children.empty() && node.value_nodes.empty())
            {
                return print_basic_property(node);
            }
            else
            {
                summary += to_string(node, level + 1, level); // depth of level + 1 (ie: only print this node, not its subnodes)

                for(auto const& child : node.children)
                    summary += print_sub_property(child, level + 1) + "\n";
                for(auto const& vn : node.value_nodes)
                    summary += print_sub_property(vn, level + 1) + "\n";
            }
        }

        return summary;
    }

    /// TODO: move to util file
    /// https://stackoverflow.com/a/5056797
    template<typename A, typename B>
    std::pair<B,A> flip_pair(const std::pair<A,B> &p)
    {
        return std::pair<B,A>(p.second, p.first);
    }

    template<typename A, typename B>
    std::multimap<B,A> flip_map(const std::map<A,B> &src)
    {
        std::multimap<B,A> dst;
        std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
                       flip_pair<A,B>);
        return dst;
    }
    ///

    string print_property_with_string(generated_node_t const& node)
    {
        WARN_IF(node.print_string.empty(), "node has no print string in a function that is based around having one");
        return print_property_with_string(node, node.print_string);
    }

    string print_property_with_string(generated_node_t const& node, string const& print_string)
    {
        if(print_string.empty())
            return "";

        std::string final_string = print_string;

        // sort locations by string position (earliest to latest)
        // so that I can adjust the string replacement positions
        // as the string changes size
        auto var_locations = parse_print_string(print_string);
        auto sorted_locs = flip_map(var_locations);
        int adjust = 0;

        for(auto const& var_loc : sorted_locs)
        {
            std::string var_str;
            auto prev_size = final_string.size();

            if(var_loc.second == "Name")
            {
                final_string.replace(var_loc.first + adjust, 4+2, node.name);
            }
            else
            {
                for(generated_node_t const& child : node.children)
                {
                    if(var_loc.second == child.name)
                    {
                        //string str = str_for_var(child);
                        string str = print_sub_property(child);
                        final_string.replace(var_loc.first + adjust, var_loc.second.size()+2, str);
                        break;
                    }
                }
            }

            adjust += int(final_string.size()) - int(prev_size);
        }

        return final_string;
    }

    string print_plant(generated_node_t const& plant_node)
    {
        return "This " + plant_node.name + " " + print_sub_property(plant_node);
    }
}<commit_msg>minor changes to printing sub-properties that have no PrintString<commit_after>#include "plant_printer.h"

#include <algorithm>
#include <iostream>

#include "asdf_multiplat/main/asdf_defs.h"

using namespace std;
using namespace plantgen;

namespace plant_printer
{
    namespace
    {
        constexpr char string_var_delimiter = '%';
    }

    string_var_locations_t parse_print_string(string const& print_string)
    {
        string_var_locations_t var_locations;

        size_t pos = 0;
        size_t endpos = 0;

        while(true)
        {
            pos = print_string.find(string_var_delimiter, endpos);
            if(pos == string::npos)
                break;

            endpos = print_string.find(string_var_delimiter, pos+1);

            if(endpos == string::npos)
            {
                EXPLODE("unmached %%");
            }

            ASSERT(endpos > pos, "");
            ASSERT(endpos-pos >= 1, "");
            std::string key = print_string.substr(pos+1, endpos-pos-1);
            var_locations.insert({key,pos});

            endpos++; //move it past the percent sign for the next find call
        }

        return var_locations;
    }

    struct sorted_range_value_t
    {
        int percentage;
        std::string range_string;
    };

    std::vector<sorted_range_value_t> get_sorted_range(generated_node_t const& node)
    {
        if(node.generated_values.size() == 0)
            return std::vector<sorted_range_value_t>();

        //ASSERT(node.generated_values.size() > 0, "expected some flavors to sort");
        std::vector<sorted_range_value_t> sorted_values;
        sorted_values.reserve(node.generated_values.size());

        for(auto const& val : node.generated_values)
        {
            auto percent_sign_pos = val.find('%');

            ASSERT(percent_sign_pos != std::string::npos, "");
            if(percent_sign_pos != std::string::npos)
            {
                sorted_range_value_t sv =
                {
                    stoi(val.substr(0, percent_sign_pos)),
                    val.substr(percent_sign_pos + 2)
                };

                sorted_values.push_back(sv);
            }
        }

        std::sort(sorted_values.begin(), sorted_values.end(),
            [](sorted_range_value_t const& lhs, sorted_range_value_t const& rhs)
            {
                return lhs.percentage > rhs.percentage;
            });

        return sorted_values;
    }

    string print_range_value(generated_node_t const& range)
    {
        auto sorted_values = get_sorted_range(range);

        ASSERT(sorted_values.size() > 0, "");

        if(sorted_values[0].percentage >= 95)
        {
            return "completely " + sorted_values[0].range_string;
        }
        else if(sorted_values[0].percentage >= 90)
        {
            return "very " + sorted_values[0].range_string;
        }
        else if(sorted_values[0].percentage >= 70)
        {
            std::string ret = "mostly " + sorted_values[0].range_string;

            if(sorted_values.size() >= 2 && sorted_values[1].percentage > 20)
            {
                ret += " and slightly " + sorted_values[1].range_string;
            }

            return ret;
        }
        //else if(sorted_values[0].percentage >= 50)
        else
        {
            std::string ret = "somewhat " + sorted_values[0].range_string;

            if(sorted_values.size() >= 2 && sorted_values[1].percentage > 20)
            {
                ret += " and slightly " + sorted_values[1].range_string;
            }

            return ret;
        }
    }

    string print_multi_value(generated_node_t const& node)
    {
        if(node.generated_values.empty())
            return "";

        string property_string;// =  node.name + " that is ";

        if(node.generated_values.size() == 1)
            return node.generated_values[0];

        for(size_t i = 0; i < node.generated_values.size() - 1; ++i)
        {
            property_string += node.generated_values[i] + ", ";
        }

        property_string.resize(property_string.size() - 2);
        property_string += " and " + node.generated_values.back();

        return property_string;
    }

    string print_basic_property(generated_node_t const& node)
    {
        ASSERT(node.children.empty(), "");

        if(node.generated_values.size() == 1)
        {
            return node.generated_values[0];
        }
        else if(node.generated_values.size() > 1)
        {
            // if there is a % in the first few characters
            // (ie: if its XXX% or XX% or X%)
            if(node.generated_values[0].find('%') <= 3)
            {
                return print_range_value(node);
            }
            else
            {
                return print_multi_value(node);
            }
        }

        return "";
    }

    string print_sub_property(generated_node_t const& node, size_t level)
    {
        std::string summary;

        if(node.print_string.size() > 0)
        {
            summary += print_property_with_string(node);
        }
        else
        {
            if(node.children.empty() && node.value_nodes.empty())
            {
                return print_basic_property(node);
            }
            else
            {
                summary += node.name_string() + "\n";

                for(auto const& child : node.children)
                    summary += print_sub_property(child, level + 1) + "; ";
                for(auto const& vn : node.value_nodes)
                    summary += print_sub_property(vn, level + 1) + "; ";

                summary.resize(summary.size() - 1);
                summary.back() = '\n';
            }
        }

        return summary;
    }

    /// TODO: move to util file
    /// https://stackoverflow.com/a/5056797
    template<typename A, typename B>
    std::pair<B,A> flip_pair(const std::pair<A,B> &p)
    {
        return std::pair<B,A>(p.second, p.first);
    }

    template<typename A, typename B>
    std::multimap<B,A> flip_map(const std::map<A,B> &src)
    {
        std::multimap<B,A> dst;
        std::transform(src.begin(), src.end(), std::inserter(dst, dst.begin()),
                       flip_pair<A,B>);
        return dst;
    }
    ///

    string print_property_with_string(generated_node_t const& node)
    {
        WARN_IF(node.print_string.empty(), "node has no print string in a function that is based around having one");
        return print_property_with_string(node, node.print_string);
    }

    string print_property_with_string(generated_node_t const& node, string const& print_string)
    {
        if(print_string.empty())
            return "";

        std::string final_string = print_string;

        // sort locations by string position (earliest to latest)
        // so that I can adjust the string replacement positions
        // as the string changes size
        auto var_locations = parse_print_string(print_string);
        auto sorted_locs = flip_map(var_locations);
        int adjust = 0;

        for(auto const& var_loc : sorted_locs)
        {
            std::string var_str;
            auto prev_size = final_string.size();

            if(var_loc.second == "Name")
            {
                final_string.replace(var_loc.first + adjust, 4+2, node.name);
            }
            else
            {
                for(generated_node_t const& child : node.children)
                {
                    if(var_loc.second == child.name)
                    {
                        //string str = str_for_var(child);
                        string str = print_sub_property(child);
                        final_string.replace(var_loc.first + adjust, var_loc.second.size()+2, str);
                        break;
                    }
                }
            }

            adjust += int(final_string.size()) - int(prev_size);
        }

        return final_string;
    }

    string print_plant(generated_node_t const& plant_node)
    {
        return "This " + plant_node.name + " " + print_sub_property(plant_node);
    }
}<|endoftext|>


<commit_before>#include "XInputFetcher.h"

int XInputFetcher::s_btnMaskMap[InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS] =
{
	XINPUT_GAMEPAD_DPAD_UP,
	XINPUT_GAMEPAD_DPAD_DOWN,
	XINPUT_GAMEPAD_DPAD_LEFT,
	XINPUT_GAMEPAD_DPAD_RIGHT,
	XINPUT_GAMEPAD_START,
	XINPUT_GAMEPAD_BACK,
	XINPUT_GAMEPAD_LEFT_THUMB,
	XINPUT_GAMEPAD_RIGHT_THUMB,
	XINPUT_GAMEPAD_LEFT_SHOULDER,
	XINPUT_GAMEPAD_RIGHT_SHOULDER,
	XINPUT_GAMEPAD_A,
	XINPUT_GAMEPAD_B,
	XINPUT_GAMEPAD_X,
	XINPUT_GAMEPAD_Y
};

XInputFetcher::XInputFetcher()
{
	DWORD dwResult;
	XINPUT_STATE state;
	ZeroMemory( &state, sizeof(XINPUT_STATE) );

	// Simply get the state of the controller from XInput.
	dwResult = XInputGetState( 0, &state );

	if( dwResult == ERROR_SUCCESS )
	{
		int korv = 1;
		// Controller is connected
	}
	else
	{
		int korv = 0;
		// Controller is not connected
	}
}

XInputFetcher::~XInputFetcher()
{
}

void XInputFetcher::update()
{
	XINPUT_STATE newState;
	XInputGetState( 0, &newState );
	for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS; i++)
	{
		bool pressed = newState.Gamepad.wButtons & s_btnMaskMap[i];
		m_btns[i] = InputHelper::calcState( m_btns[i], pressed );
	}

	m_analogs[InputHelper::THUMB_LX_POSITIVE] = m_currentState.Gamepad.sThumbLX;
	m_analogs[InputHelper::THUMB_LY_POSITIVE] = m_currentState.Gamepad.sThumbLY;
	m_analogs[InputHelper::THUMB_RX_POSITIVE] = m_currentState.Gamepad.sThumbRX;
	m_analogs[InputHelper::THUMB_RY_POSITIVE] = m_currentState.Gamepad.sThumbRY;
	m_analogs[InputHelper::THUMB_LX_NEGATIVE] = m_currentState.Gamepad.sThumbLX;
	m_analogs[InputHelper::THUMB_LY_NEGATIVE] = m_currentState.Gamepad.sThumbLY;
	m_analogs[InputHelper::THUMB_RX_NEGATIVE] = m_currentState.Gamepad.sThumbRX;
	m_analogs[InputHelper::THUMB_RY_NEGATIVE] = m_currentState.Gamepad.sThumbRY;
	m_analogs[InputHelper::TRIGGER_L] = (short)m_currentState.Gamepad.bLeftTrigger;
	m_analogs[InputHelper::TRIGGER_R] = (short)m_currentState.Gamepad.bRightTrigger;
	m_currentState = newState;
}

InputHelper::KEY_STATE XInputFetcher::getBtnState( int p_btn )
{
	if( 0 <= p_btn && p_btn < InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS )
		return m_btns[p_btn];
	else
		return InputHelper::KEY_STATE::NON_EXISTING_STATE;
}

short XInputFetcher::getAnalog( int p_analog )
{
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
		return m_analogs[p_analog];
	else
		return -1;
}

double XInputFetcher::getAnalogAsDouble( int p_analog )
{
	// Std-val. Whats returned if the analog isn't found.
	double val = (float)-1;

	// Make sure that p_analog is in range
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
	{
		short tmp = getAnalog( p_analog );

		// Triggers have a precision of 0-255 instead of 0-65k as the thumb sticks.
		// Take that into account when calculating 0.0 - 1.0
		if(p_analog == InputHelper::TRIGGER_L || p_analog == InputHelper::TRIGGER_R)
			val =  (double)tmp / 255; //BYTE_MAX
		else
			val = (double)tmp / SHRT_MAX;
	}

	return val;
}
<commit_msg>Fixed bug where input were recorded when no gamepad was connected<commit_after>#include "XInputFetcher.h"

int XInputFetcher::s_btnMaskMap[InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS] =
{
	XINPUT_GAMEPAD_DPAD_UP,
	XINPUT_GAMEPAD_DPAD_DOWN,
	XINPUT_GAMEPAD_DPAD_LEFT,
	XINPUT_GAMEPAD_DPAD_RIGHT,
	XINPUT_GAMEPAD_START,
	XINPUT_GAMEPAD_BACK,
	XINPUT_GAMEPAD_LEFT_THUMB,
	XINPUT_GAMEPAD_RIGHT_THUMB,
	XINPUT_GAMEPAD_LEFT_SHOULDER,
	XINPUT_GAMEPAD_RIGHT_SHOULDER,
	XINPUT_GAMEPAD_A,
	XINPUT_GAMEPAD_B,
	XINPUT_GAMEPAD_X,
	XINPUT_GAMEPAD_Y
};

XInputFetcher::XInputFetcher()
{
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
}

XInputFetcher::~XInputFetcher()
{
}

void XInputFetcher::update()
{
	//XINPUT_STATE newState;
	ZeroMemory( &m_currentState, sizeof(XINPUT_STATE) );
	unsigned long result = XInputGetState( 0, &m_currentState );
	if( result == ERROR_SUCCESS )
	{
		for( int i=0; i<InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS; i++)
		{
			bool pressed = m_currentState.Gamepad.wButtons & s_btnMaskMap[i];
			m_btns[i] = InputHelper::calcState( m_btns[i], pressed );
		}
	}
	//m_currentState = newState;

	m_analogs[InputHelper::THUMB_LX_POSITIVE] = m_currentState.Gamepad.sThumbLX;
	m_analogs[InputHelper::THUMB_LY_POSITIVE] = m_currentState.Gamepad.sThumbLY;
	m_analogs[InputHelper::THUMB_RX_POSITIVE] = m_currentState.Gamepad.sThumbRX;
	m_analogs[InputHelper::THUMB_RY_POSITIVE] = m_currentState.Gamepad.sThumbRY;
	m_analogs[InputHelper::THUMB_LX_NEGATIVE] = m_currentState.Gamepad.sThumbLX;
	m_analogs[InputHelper::THUMB_LY_NEGATIVE] = m_currentState.Gamepad.sThumbLY;
	m_analogs[InputHelper::THUMB_RX_NEGATIVE] = m_currentState.Gamepad.sThumbRX;
	m_analogs[InputHelper::THUMB_RY_NEGATIVE] = m_currentState.Gamepad.sThumbRY;
	m_analogs[InputHelper::TRIGGER_L] = (short)m_currentState.Gamepad.bLeftTrigger;
	m_analogs[InputHelper::TRIGGER_R] = (short)m_currentState.Gamepad.bRightTrigger;
}

InputHelper::KEY_STATE XInputFetcher::getBtnState( int p_btn )
{
	if( 0 <= p_btn && p_btn < InputHelper::NUM_XBOX360_CONTROLLER_DIGITALS )
		return m_btns[p_btn];
	else
		return InputHelper::KEY_STATE::NON_EXISTING_STATE;
}

short XInputFetcher::getAnalog( int p_analog )
{
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
		return m_analogs[p_analog];
	else
		return -1;
}

double XInputFetcher::getAnalogAsDouble( int p_analog )
{
	// Std-val. Whats returned if the analog isn't found.
	double val = (float)-1;

	// Make sure that p_analog is in range
	if( 0 <= p_analog && p_analog < InputHelper::NUM_XBOX360_CONTROLLER_ANALOGS )
	{
		short tmp = getAnalog( p_analog );

		// Triggers have a precision of 0-255 instead of 0-65k as the thumb sticks.
		// Take that into account when calculating 0.0 - 1.0
		if(p_analog == InputHelper::TRIGGER_L || p_analog == InputHelper::TRIGGER_R)
			val =  (double)tmp / 255; //BYTE_MAX
		else
			val = (double)tmp / SHRT_MAX;
	}

	return val;
}
<|endoftext|>