<commit_before>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <DNSServer.h>
#include <Ticker.h>

#include "helpers.hpp"
#include "defaults.hpp"
#include "radio.hpp"
#include "Config.hpp"
#include "TrackingData.hpp"
#include "ConfigServer.hpp"

#define DNS_PORT 53

Ticker wifiBlinker;

Config* conf = new Config();
Radio rf(conf);
TrackingData data(conf, DEFAULT_BUFFER_SIZE);
ConfigServer cfgSrv(conf, 80);

WebSocketsServer webSocket(81);
DNSServer dnsServer;
IPAddress localIP(10, 10, 10, 1);

void setup () {
    // Set up the EEPROM w/ a maximum size of 4096 bytes
    EEPROM.begin(4096);

    /// Set up the built-in LED and turn it on to let the user know the ESP is working
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    /// Open up the serial and TCP monitor
    Terminal::begin(115200);

    // Print some stats
    Terminal::printf("CPU running at %dMHz, Cycle %d, Flash chip running at %d MHz, VCC is at %d\n", ESP.getCpuFreqMHz(), ESP.getCycleCount(), ESP.getFlashChipSpeed()/1000000, ESP.getVcc());

    // If the pin is not pulled to ground read config or write the default one if its not
    if (digitalRead(RESET_CONF_PIN)) {
        conf->read(EEPROM_CONF_ADDR);
    } else {
        Terminal::println("Restoring factory settings...");
        conf->write(EEPROM_CONF_ADDR);
    }

    // If the pin is pulled to ground then disable tracking
    if (!digitalRead(DISABLE_TRACKING_PIN)) {
        Terminal::println("Disabling tracking...");
        conf->readFromString("{'active': false}");
        conf->write(EEPROM_CONF_ADDR);
    }

    // Set the hostname
    WiFi.hostname("FINDTracker");

    // Setup the radios according to the configuration
    rf.setup();

    MDNS.begin("FINDTracker");
    MDNS.addService("http", "tcp", 80);

    // Setup the OTA server
    OTA();

    // Setup the websocket server
    webSocket.begin();

    // Setup the DNS server
    dnsServer.setTTL(300);
    dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
    dnsServer.start(DNS_PORT, "findtracker", localIP);
}

void runServerHandlers() {
    ArduinoOTA.handle();
    cfgSrv.handle();
    Terminal::handle();
    webSocket.loop();
    dnsServer.processNextRequest();
}

int lastWatchdog;
int sleepTimeMS;
int lastScan;
int lastUpdate;
bool connected;
bool active;
void loop() {
    if (millis() - lastUpdate > 1500) {
        connected = rf.connected();
        active = conf->get<bool>("active");
        lastUpdate = millis();
    }

    // Check for a WiFi connection and attempt to reestablish it if it died
    if (
        (active && !connected) ||
        (!active && !connected && millis() - lastScan > 30000)
    ) {
        digitalWrite(LED_PIN, LOW);
        if (!rf.connect()) {
            Terminal::print("Connection failed. ");
            if (active) {
                // Enter deep sleep in case the connection failed
                sleepTimeMS = conf->get<int>("wifiReconnectionInterval");
                blink(); blink(); blink();
                Terminal::printf("Entering deep sleep mode for %dms ...\n", sleepTimeMS);
                ESP.deepSleep(sleepTimeMS * 1000, WAKE_NO_RFCAL);
            } else {
                Terminal::println("");
                wifiBlinker.attach(0.5, blinkSync);
            }
        } else {
            wifiBlinker.detach();
            digitalWrite(LED_PIN, HIGH);
        }
        lastScan = millis();
    }

    // TODO: The data.send() step takes way too long
    if (active) {
        /// Update the environment data (scan for networks)
        if (data.update()) {
            // Send the data to the FIND Server
            String response = data.send();

            /// Blink to indicate that we have sent our location
            if (response != "") {
                blink();
                webSocket.broadcastTXT(response);
            }
        }

        // Enter a very basic sleep mode and limit the amount of cycles to preserve power
        // (Turn off the radio and wake it up periodically to answer beacon signals from router)
        // TODO Only do this when nothing else is connected (low power mode setting maybe?)
        //      since it breaks all kind of things like websockets, HTTP etc.
        WiFi.setSleepMode(WIFI_MODEM_SLEEP);
        delay(500);
    } else {
        /// Let some background tasks run
        delay(100);
        yield();
    }

    /// Run all kinds of server handlers
    runServerHandlers();

    // Send a watchdog signal for all websocket clients
    if (millis() - lastWatchdog > 5000) {
        webSocket.broadcastTXT("watchdog");
        lastWatchdog = millis();
    }
}
<commit_msg>Removed startup delay<commit_after>#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ArduinoJson.h>
#include <DNSServer.h>
#include <Ticker.h>

#include "helpers.hpp"
#include "defaults.hpp"
#include "radio.hpp"
#include "Config.hpp"
#include "TrackingData.hpp"
#include "ConfigServer.hpp"

#define DNS_PORT 53

Ticker wifiBlinker;

Config* conf = new Config();
Radio rf(conf);
TrackingData data(conf, DEFAULT_BUFFER_SIZE);
ConfigServer cfgSrv(conf, 80);

WebSocketsServer webSocket(81);
DNSServer dnsServer;
IPAddress localIP(10, 10, 10, 1);

void setup () {
    // Set up the EEPROM w/ a maximum size of 4096 bytes
    EEPROM.begin(4096);

    /// Set up the built-in LED and turn it on to let the user know the ESP is working
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    /// Open up the serial and TCP monitor
    Terminal::begin(115200);

    // Print some stats
    Terminal::printf("CPU running at %dMHz, Cycle %d, Flash chip running at %d MHz, VCC is at %d\n", ESP.getCpuFreqMHz(), ESP.getCycleCount(), ESP.getFlashChipSpeed()/1000000, ESP.getVcc());

    // If the pin is not pulled to ground read config or write the default one if its not
    if (digitalRead(RESET_CONF_PIN)) {
        conf->read(EEPROM_CONF_ADDR);
    } else {
        Terminal::println("Restoring factory settings...");
        conf->write(EEPROM_CONF_ADDR);
    }

    // If the pin is pulled to ground then disable tracking
    if (!digitalRead(DISABLE_TRACKING_PIN)) {
        Terminal::println("Disabling tracking...");
        conf->readFromString("{'active': false}");
        conf->write(EEPROM_CONF_ADDR);
    }

    // Set the hostname
    WiFi.hostname("FINDTracker");

    // Setup the radios according to the configuration
    rf.setup();

    MDNS.begin("FINDTracker");
    MDNS.addService("http", "tcp", 80);

    // Setup the OTA server
    OTA();

    // Setup the websocket server
    webSocket.begin();

    // Setup the DNS server
    dnsServer.setTTL(300);
    dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
    dnsServer.start(DNS_PORT, "findtracker", localIP);
}

void runServerHandlers() {
    ArduinoOTA.handle();
    cfgSrv.handle();
    Terminal::handle();
    webSocket.loop();
    dnsServer.processNextRequest();
}

int lastWatchdog = -999999;
int sleepTimeMS;
int lastScan = -999999;
int lastUpdate = -999999;
bool connected;
bool active;
void loop() {
    if (millis() - lastUpdate > 1500) {
        connected = rf.connected();
        active = conf->get<bool>("active");
        lastUpdate = millis();
    }

    // Check for a WiFi connection and attempt to reestablish it if it died
    if (
        (active && !connected) ||
        (!active && !connected && millis() - lastScan > 30000)
    ) {
        digitalWrite(LED_PIN, LOW);
        if (!rf.connect()) {
            Terminal::print("Connection failed. ");
            if (active) {
                // Enter deep sleep in case the connection failed
                sleepTimeMS = conf->get<int>("wifiReconnectionInterval");
                blink(); blink(); blink();
                Terminal::printf("Entering deep sleep mode for %dms ...\n", sleepTimeMS);
                ESP.deepSleep(sleepTimeMS * 1000, WAKE_NO_RFCAL);
            } else {
                Terminal::println("");
                wifiBlinker.attach(0.5, blinkSync);
            }
        } else {
            wifiBlinker.detach();
            digitalWrite(LED_PIN, HIGH);
        }
        lastScan = millis();
    }

    // TODO: The data.send() step takes way too long
    if (active) {
        /// Update the environment data (scan for networks)
        if (data.update()) {
            // Send the data to the FIND Server
            String response = data.send();

            /// Blink to indicate that we have sent our location
            if (response != "") {
                blink();
                webSocket.broadcastTXT(response);
            }
        }

        // Enter a very basic sleep mode and limit the amount of cycles to preserve power
        // (Turn off the radio and wake it up periodically to answer beacon signals from router)
        // TODO Only do this when nothing else is connected (low power mode setting maybe?)
        //      since it breaks all kind of things like websockets, HTTP etc.
        WiFi.setSleepMode(WIFI_MODEM_SLEEP);
        delay(500);
    } else {
        /// Let some background tasks run
        delay(100);
        yield();
    }

    /// Run all kinds of server handlers
    runServerHandlers();

    // Send a watchdog signal for all websocket clients
    if (millis() - lastWatchdog > 5000) {
        webSocket.broadcastTXT("watchdog");
        lastWatchdog = millis();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"
#include "common/value_map.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"
#include "gfx/support/render_normals.h"
#include "gfx/immediate_renderer.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"
#include "ui/pie_menu.h"

#include "strat/map.h"
#include "strat/wall.h"
#include "strat/water.h"
#include "strat/terrain.h"
#include "strat/player_state.h"

#include "procedural/terrain.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

struct Glfw_User_Data
{
  game::gfx::IDriver& driver;
  game::gfx::Camera& camera;
  game::ui::Element& root_hud;
  game::ui::Mouse_State& mouse_state;
};

void mouse_button_callback(GLFWwindow* window, int glfw_button, int action,int)
{
  using game::Vec; using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  bool down = (action == GLFW_PRESS);

  using namespace game::ui;
  Mouse_Button button;
  switch(glfw_button)
  {
    case GLFW_MOUSE_BUTTON_LEFT:
    {
      button = Mouse_Button_Left;
      break;
    }
    case GLFW_MOUSE_BUTTON_RIGHT:
    {
      button = Mouse_Button_Right;
      break;
    }
    case GLFW_MOUSE_BUTTON_MIDDLE:
    {
      button = Mouse_Button_Middle;
      break;
    }
  }

  if(down) mouse_state.buttons |= button;
  else mouse_state.buttons &= ~button;
}

void mouse_motion_callback(GLFWwindow* window, double x, double y)
{
  using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  mouse_state.position.x = x;
  mouse_state.position.y = y;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  mouse_state.scroll_delta = deltay;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

void error_callback(int error, const char* description)
{
  game::log_d("GLFW Error: % (Code = %)", description, error);
}

void resize_callback(GLFWwindow* window, int width, int height)
{
  // Change OpenGL viewport
  glViewport(0, 0, width, height);

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& idriver = user_ptr.driver;

  // Inform the driver of this change
  idriver.window_extents({width,height});

  // Change the camera aspect ratio
  user_ptr.camera.perspective.aspect = width / (float) height;

  // Perhaps relayout the hud here?
  user_ptr.root_hud.layout(game::Vec<int>{width, height});

}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Error callback
  glfwSetErrorCallback(error_callback);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

  glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  // Set GLFW callbacks
  glfwSetMouseButtonCallback(window, mouse_button_callback);
  glfwSetCursorPosCallback(window, mouse_motion_callback);
  glfwSetScrollCallback(window, scroll_callback);
  glfwSetWindowSizeCallback(window, resize_callback);

  // UI Controller
  ui::Simple_Controller controller;

  {
  // Make an OpenGL driver.

  // Don't rely on any window resolution. Query it again.
  // After this, we'll query the driver for the real size.
  int window_width, window_height;
  glfwGetWindowSize(window, &window_width, &window_height);
  gfx::gl::Driver driver{Vec<int>{window_width, window_height}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/vs");
  default_shader->load_fragment_part("shader/basic/fs");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = strat::make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();

  strat::Game_State game_state{&driver, gfx::make_isometric_camera(driver),
                               strat::Map{{1000, 1000}}}; // <-Map size for now

  strat::Player_State player_state{game_state};

  std::vector<Indexed_Mesh_Data> imd_vec;
  auto structures = strat::load_structures("structure/structures.json",
                                           ref_mo(structure_mesh),
                                           driver, &imd_vec);

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  hud->find_child_r("build_house")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      player_state.switch_state<strat::Building_State>(structures[0]);
    }});

  hud->find_child_r("build_gvn_build")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      player_state.switch_state<strat::Building_State>(structures[1]);
    }});
  hud->find_child_r("build_wall")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      strat::Wall_Type type{1, structures[2].aabb().width};
      player_state.switch_state<strat::Wall_Building_State>(type);
    }});

  hud->layout(driver.window_extents());

  auto cur_mouse = ui::Mouse_State{};

  // TODO: Put the camera somewhere else / Otherwise clean up the distinction
  // and usage of Glfw_User_Data, Game_State and Player_State.
  auto glfw_user_data = Glfw_User_Data{driver,game_state.cam, *hud, cur_mouse};
  glfwSetWindowUserPointer(window, &glfw_user_data);

  auto light_dir_pos = default_shader->get_location("light_dir");

  gfx::Immediate_Renderer ir{driver};
  std::size_t st_size = game_state.map.structures.size();
  while(!glfwWindowShouldClose(window))
  {
    ++fps;

    // Reset the scroll delta
    cur_mouse.scroll_delta = 0.0;

    if(st_size != game_state.map.structures.size()) ir.reset();

    // Update the mouse state.
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, game_state.cam);

    default_shader->set_vec3(light_dir_pos, glm::vec3(0.0f, 1.0f, 0.0f));

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    // These functions are bound to get the depth from the framebuffer. Make
    // sure the depth value is only based on the terrain.
    {
      if(!controller.step(hud, cur_mouse))
      {
        player_state.step_mouse(cur_mouse);
      }

      // Handle zoom
      gfx::apply_zoom(game_state.cam, cur_mouse.scroll_delta,
                      cur_mouse.position, driver);
    }
    // Render any structures.
    // Maybe the mouse?

    // We only want to be able to pan the terrain for now. That's why we need
    // to do this before any structure rendering.
    //auto mouse_world = gfx::unproject_screen(driver, game_state.cam,
                                             //glm::mat4(1.0f),
                                             //mouse_state.position);

    //player_state.handle_mouse(Vec<float>{mouse_world.x, mouse_world.z});

    //if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
       //player_state.type == strat::Player_State_Type::Nothing)
    //{
      //glfwSetWindowShouldClose(window, true);
    //}

    auto& pending_st = game_state.map.pending_structure;
    if(pending_st)
    {
      render_structure_instance(driver, pending_st.value());
    }

    // Render all the other structures.
    for(auto const& st : game_state.map.structures)
    {
      // TODO: Find/store correct y somehow?
      render_structure_instance(driver, st);

      if(st_size != game_state.map.structures.size())
      {
        if(&st.structure() == &structures[0])
        {
          gfx::render_normals(ir, imd_vec[0], st.model_matrix());
        }
        else if(&st.structure() == &structures[1])
        {
          gfx::render_normals(ir, imd_vec[1], st.model_matrix());
        }
      }
    }

    // Render walls
    if(game_state.map.pending_wall)
    {
      // Render the structure at the pending wall point.
      auto pos = game_state.map.pending_wall->pos;
      glm::mat4 model = glm::translate(glm::mat4(1.0f),
                                       glm::vec3(pos.x, 0.0f, pos.y));
      render_structure(driver, structures[2], model);
    }
    for(auto const& wall : game_state.map.walls)
    {
      render_wall(driver, wall, structures[2]);
    }

    ir.render(game_state.cam);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};

      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();

    st_size = game_state.map.structures.size();
  }
  }
  glfwTerminate();
  return 0;
}
<commit_msg>Stop rendering normals<commit_after>/*
 * Copyright (C) 2015 Luke San Antonio
 * All rights reserved.
 */
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <vector>
#include <thread>
#include <future>

#include "common/log.h"
#include "common/value_map.h"

#include "gfx/gl/driver.h"
#include "gfx/camera.h"
#include "gfx/mesh_chunk.h"
#include "gfx/idriver_ui_adapter.h"
#include "gfx/support/load_wavefront.h"
#include "gfx/support/mesh_conversion.h"
#include "gfx/support/generate_aabb.h"
#include "gfx/support/write_data_to_mesh.h"
#include "gfx/support/texture_load.h"
#include "gfx/support/software_texture.h"
#include "gfx/support/unproject.h"
#include "gfx/support/render_normals.h"
#include "gfx/immediate_renderer.h"

#include "ui/load.h"
#include "ui/freetype_renderer.h"
#include "ui/mouse_logic.h"
#include "ui/simple_controller.h"
#include "ui/pie_menu.h"

#include "strat/map.h"
#include "strat/wall.h"
#include "strat/water.h"
#include "strat/terrain.h"
#include "strat/player_state.h"

#include "procedural/terrain.h"

#include "glad/glad.h"
#include "glfw3.h"

#define GLM_FORCE_RADIANS
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

#include "uv.h"

#define CATCH_CONFIG_RUNNER
#include "catch/catch.hpp"

glm::vec4 project_point(glm::vec4 pt,
                        glm::mat4 const& model,
                        glm::mat4 const& view,
                        glm::mat4 const& proj) noexcept
{
  pt = proj * view * model * pt;
  pt /= pt.w;
  return pt;
}

struct Glfw_User_Data
{
  game::gfx::IDriver& driver;
  game::gfx::Camera& camera;
  game::ui::Element& root_hud;
  game::ui::Mouse_State& mouse_state;
};

void mouse_button_callback(GLFWwindow* window, int glfw_button, int action,int)
{
  using game::Vec; using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  bool down = (action == GLFW_PRESS);

  using namespace game::ui;
  Mouse_Button button;
  switch(glfw_button)
  {
    case GLFW_MOUSE_BUTTON_LEFT:
    {
      button = Mouse_Button_Left;
      break;
    }
    case GLFW_MOUSE_BUTTON_RIGHT:
    {
      button = Mouse_Button_Right;
      break;
    }
    case GLFW_MOUSE_BUTTON_MIDDLE:
    {
      button = Mouse_Button_Middle;
      break;
    }
  }

  if(down) mouse_state.buttons |= button;
  else mouse_state.buttons &= ~button;
}

void mouse_motion_callback(GLFWwindow* window, double x, double y)
{
  using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  mouse_state.position.x = x;
  mouse_state.position.y = y;
}

void scroll_callback(GLFWwindow* window, double, double deltay)
{
  using game::ui::Mouse_State;

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& mouse_state = user_ptr.mouse_state;

  mouse_state.scroll_delta = deltay;
}

void log_gl_limits(game::Log_Severity s) noexcept
{
  GLint i = 0;
  glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &i);
  log(s, "GL_MAX_ELEMENTS_VERTICES: %", i);
}

void error_callback(int error, const char* description)
{
  game::log_d("GLFW Error: % (Code = %)", description, error);
}

void resize_callback(GLFWwindow* window, int width, int height)
{
  // Change OpenGL viewport
  glViewport(0, 0, width, height);

  auto user_ptr = *(Glfw_User_Data*) glfwGetWindowUserPointer(window);
  auto& idriver = user_ptr.driver;

  // Inform the driver of this change
  idriver.window_extents({width,height});

  // Change the camera aspect ratio
  user_ptr.camera.perspective.aspect = width / (float) height;

  // Perhaps relayout the hud here?
  user_ptr.root_hud.layout(game::Vec<int>{width, height});

}

int main(int argc, char** argv)
{
  using namespace game;

  set_log_level(Log_Severity::Debug);

  uv_chdir("assets/");

  // Initialize logger.
  Scoped_Log_Init log_init_raii_lock{};

  // Error callback
  glfwSetErrorCallback(error_callback);

  // Init glfw.
  if(!glfwInit())
    return EXIT_FAILURE;

  glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
  glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
  glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);

  glfwWindowHint(GLFW_RESIZABLE, GL_TRUE);

  auto window = glfwCreateWindow(1000, 1000, "Hello World", NULL, NULL);
  if(!window)
  {
    glfwTerminate();
    return EXIT_FAILURE;
  }

  // Init context + load gl functions.
  glfwMakeContextCurrent(window);
  gladLoadGLLoader((GLADloadproc) glfwGetProcAddress);

  // Log glfw version.
  log_i("Initialized GLFW %", glfwGetVersionString());

  int maj = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
  int min = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
  int rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);

  // Log GL profile.
  log_i("OpenGL core profile %.%.%", maj, min, rev);

  // Set GLFW callbacks
  glfwSetMouseButtonCallback(window, mouse_button_callback);
  glfwSetCursorPosCallback(window, mouse_motion_callback);
  glfwSetScrollCallback(window, scroll_callback);
  glfwSetWindowSizeCallback(window, resize_callback);

  // UI Controller
  ui::Simple_Controller controller;

  {
  // Make an OpenGL driver.

  // Don't rely on any window resolution. Query it again.
  // After this, we'll query the driver for the real size.
  int window_width, window_height;
  glfwGetWindowSize(window, &window_width, &window_height);
  gfx::gl::Driver driver{Vec<int>{window_width, window_height}};

  // Load our default shader.
  auto default_shader = driver.make_shader_repr();
  default_shader->load_vertex_part("shader/basic/vs");
  default_shader->load_fragment_part("shader/basic/fs");

  default_shader->set_projection_name("proj");
  default_shader->set_view_name("view");
  default_shader->set_model_name("model");
  default_shader->set_sampler_name("tex");
  default_shader->set_diffuse_name("dif");
  driver.use_shader(*default_shader);

  default_shader->set_sampler(0);

  // Load our textures.
  auto grass_tex = driver.make_texture_repr();
  load_png("tex/grass.png", *grass_tex);

  // Load the image
  Software_Texture terrain_image;
  load_png("map/default.png", terrain_image);

  // Convert it into a heightmap
  Maybe_Owned<Mesh> terrain = driver.make_mesh_repr();

  auto terrain_heightmap = strat::make_heightmap_from_image(terrain_image);
  auto terrain_data =
    make_terrain_mesh(terrain_heightmap, {20, 20}, .001f, .01);

  auto terrain_model = glm::scale(glm::mat4(1.0f),glm::vec3(5.0f, 1.0f, 5.0f));

  gfx::allocate_mesh_buffers(terrain_data.mesh, *terrain);
  gfx::write_data_to_mesh(terrain_data.mesh, ref_mo(terrain));
  gfx::format_mesh_buffers(*terrain);
  terrain->set_primitive_type(Primitive_Type::Triangle);

  // Map + structures.
  Maybe_Owned<Mesh> structure_mesh = driver.make_mesh_repr();

  strat::Game_State game_state{&driver, gfx::make_isometric_camera(driver),
                               strat::Map{{1000, 1000}}}; // <-Map size for now

  strat::Player_State player_state{game_state};

  std::vector<Indexed_Mesh_Data> imd_vec;
  auto structures = strat::load_structures("structure/structures.json",
                                           ref_mo(structure_mesh),
                                           driver, &imd_vec);

  int fps = 0;
  int time = glfwGetTime();

  // Set up some pre-rendering state.
  driver.clear_color_value(Color{0x55, 0x66, 0x77});
  driver.clear_depth_value(1.0);

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LEQUAL);

  glEnable(GL_CULL_FACE);

  // Load our ui
  gfx::IDriver_UI_Adapter ui_adapter{driver};
  ui::Freetype_Renderer freetype_font;

  auto ui_load_params = ui::Load_Params{freetype_font, ui_adapter};
  auto hud = ui::load("ui/hud.json", ui_load_params);

  hud->find_child_r("build_house")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      player_state.switch_state<strat::Building_State>(structures[0]);
    }});

  hud->find_child_r("build_gvn_build")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      player_state.switch_state<strat::Building_State>(structures[1]);
    }});
  hud->find_child_r("build_wall")->on_step_mouse(
    ui::On_Release_Handler{[&](auto const& ms)
    {
      strat::Wall_Type type{1, structures[2].aabb().width};
      player_state.switch_state<strat::Wall_Building_State>(type);
    }});

  hud->layout(driver.window_extents());

  auto cur_mouse = ui::Mouse_State{};

  // TODO: Put the camera somewhere else / Otherwise clean up the distinction
  // and usage of Glfw_User_Data, Game_State and Player_State.
  auto glfw_user_data = Glfw_User_Data{driver,game_state.cam, *hud, cur_mouse};
  glfwSetWindowUserPointer(window, &glfw_user_data);

  auto light_dir_pos = default_shader->get_location("light_dir");

  gfx::Immediate_Renderer ir{driver};
  std::size_t st_size = game_state.map.structures.size();
  while(!glfwWindowShouldClose(window))
  {
    ++fps;

    // Reset the scroll delta
    cur_mouse.scroll_delta = 0.0;

    if(st_size != game_state.map.structures.size()) ir.reset();

    // Update the mouse state.
    glfwPollEvents();

    // Clear the screen and render the terrain.
    driver.clear();
    use_camera(driver, game_state.cam);

    default_shader->set_vec3(light_dir_pos, glm::vec3(0.0f, 1.0f, 0.0f));

    driver.bind_texture(*grass_tex, 0);

    default_shader->set_diffuse(colors::white);
    default_shader->set_model(terrain_model);

    // Render the terrain before we calculate the depth of the mouse position.
    terrain->draw_elements(0, terrain_data.mesh.elements.size());

    // These functions are bound to get the depth from the framebuffer. Make
    // sure the depth value is only based on the terrain.
    {
      if(!controller.step(hud, cur_mouse))
      {
        player_state.step_mouse(cur_mouse);
      }

      // Handle zoom
      gfx::apply_zoom(game_state.cam, cur_mouse.scroll_delta,
                      cur_mouse.position, driver);
    }
    // Render any structures.
    // Maybe the mouse?

    // We only want to be able to pan the terrain for now. That's why we need
    // to do this before any structure rendering.
    //auto mouse_world = gfx::unproject_screen(driver, game_state.cam,
                                             //glm::mat4(1.0f),
                                             //mouse_state.position);

    //player_state.handle_mouse(Vec<float>{mouse_world.x, mouse_world.z});

    //if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS &&
       //player_state.type == strat::Player_State_Type::Nothing)
    //{
      //glfwSetWindowShouldClose(window, true);
    //}

    auto& pending_st = game_state.map.pending_structure;
    if(pending_st)
    {
      render_structure_instance(driver, pending_st.value());
    }

    // Render all the other structures.
    for(auto const& st : game_state.map.structures)
    {
      // TODO: Find/store correct y somehow?
      render_structure_instance(driver, st);
    }

    // Render walls
    if(game_state.map.pending_wall)
    {
      // Render the structure at the pending wall point.
      auto pos = game_state.map.pending_wall->pos;
      glm::mat4 model = glm::translate(glm::mat4(1.0f),
                                       glm::vec3(pos.x, 0.0f, pos.y));
      render_structure(driver, structures[2], model);
    }
    for(auto const& wall : game_state.map.walls)
    {
      render_wall(driver, wall, structures[2]);
    }

    ir.render(game_state.cam);

    {
      ui::Draw_Scoped_Lock scoped_draw_lock{ui_adapter};

      hud->render(ui_adapter);
    }
    glfwSwapBuffers(window);

    if(int(glfwGetTime()) != time)
    {
      time = glfwGetTime();
      log_d("fps: %", fps);
      fps = 0;
    }

    flush_log();

    st_size = game_state.map.structures.size();
  }
  }
  glfwTerminate();
  return 0;
}
<|endoftext|>


<commit_before>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/ImageViewer.h>
#include <tev/Ipc.h>
#include <tev/SharedQueue.h>
#include <tev/ThreadPool.h>

#include <args.hxx>
#include <ImfThreading.h>

#include <iostream>
#include <thread>

using namespace args;
using namespace filesystem;
using namespace std;

TEV_NAMESPACE_BEGIN

int mainFunc(const vector<string>& arguments) {
    ArgumentParser parser{
        "Inspection tool for images with a high dynamic range.",
        "",
    };

    HelpFlag helpFlag{
        parser,
        "help",
        "Display this help menu",
        {'h', "help"},
    };

    Flag newWindowFlag{
        parser,
        "new window",
        "Opens a new window of tev, even if one exists already.",
        {'n', "new"},
    };

    ValueFlag<float> exposureFlag{
        parser,
        "exposure",
        "Exposure scales the brightness of an image prior to tonemapping by 2^Exposure. "
        "It can be controlled via the GUI, or by pressing E/Shift+E.",
        {'e', "exposure"},
    };

    ValueFlag<string> filterFlag{
        parser,
        "filter",
        "Filters visible images and layers according to a supplied string. "
        "The string must have the format 'image:layer'. "
        "Only images whose name contains 'image' and layers whose name contains 'layer' will be visible.",
        {'f', "filter"},
    };

    ValueFlag<bool> maximizeFlag{
        parser,
        "maximize",
        "Whether to maximize the window on startup or not. "
        "If no images were supplied via the command line, then the default is false. "
        "Otherwise, the default is true.",
        {"max", "maximize"},
    };

    ValueFlag<string> metricFlag{
        parser,
        "metric",
        "The metric to use when comparing two images. "
        R"(
        The available metrics are:
        E   - Error
        AE  - Absolute Error
        SE  - Squared Error
        RAE - Relative Absolute Error
        RSE - Relative Squared Error
        )"
        "Default is E.",
        {'m', "metric"},
    };

    ValueFlag<float> offsetFlag{
        parser,
        "offset",
        "The offset is added to the image after exposure has been applied. "
        "It can be controlled via the GUI, or by pressing O/Shift+O.",
        {'o', "offset"},
    };

    ValueFlag<string> tonemapFlag{
        parser,
        "tonemap",
        "The tonemapping algorithm to use. "
        R"(
        The available tonemaps are:
        sRGB   - sRGB
        Gamma  - Gamma curve (2.2)
        FC     - False Color
        PN     - Positive=Green, Negative=Red
        )"
        "Default is sRGB.",
        {'t', "tonemap"},
    };

    PositionalList<string> imageFiles{
        parser,
        "images or channel selectors",
        "The image files to be opened by the viewer. "
        "If a filename starting with a ':' is encountered, "
        "then this filename is not treated as an image file "
        "but as a comma-separated channel selector. Until the next channel "
        "selector is encountered only channels containing "
        "elements from the current selector will be loaded. This is "
        "especially useful for selectively loading a specific "
        "part of a multi-part EXR file.",
    };

    // Parse command line arguments and react to parsing
    // errors using exceptions.
    try {
        parser.ParseArgs(arguments);
    } catch (args::Help) {
        std::cout << parser;
        return 0;
    } catch (args::ParseError e) {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return -1;
    } catch (args::ValidationError e) {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return -2;
    }

    auto ipc = make_shared<Ipc>();

    // If we're not the primary instance and did not request to open a new window,
    // simply send the to-be-opened images to the primary instance.
    if (!ipc->isPrimaryInstance() && !newWindowFlag) {
        string channelSelector;
        for (auto imageFile : get(imageFiles)) {
            if (!imageFile.empty() && imageFile[0] == ':') {
                channelSelector = imageFile.substr(1);
                continue;
            }

            try {
                ipc->sendToPrimaryInstance(path{imageFile}.make_absolute().str() + ":" + channelSelector);
            } catch (runtime_error e) {
                cerr << "Invalid file '" << imageFile << "': " << e.what() << endl;
            }
        }

        return 0;
    }

    Imf::setGlobalThreadCount(thread::hardware_concurrency());

    cout << "Loading window..." << endl;

    // Load images passed via command line in the background prior to
    // creating our main application such that they are not stalled
    // by the potentially slow initialization of opengl / glfw.
    shared_ptr<SharedQueue<ImageAddition>> imagesToAdd = make_shared<SharedQueue<ImageAddition>>();
    string channelSelector;
    for (auto imageFile : get(imageFiles)) {
        if (!imageFile.empty() && imageFile[0] == ':') {
            channelSelector = imageFile.substr(1);
            continue;
        }

        ThreadPool::singleWorker().enqueueTask([imageFile, channelSelector, &imagesToAdd] {
            auto image = tryLoadImage(imageFile, channelSelector);
            if (image) {
                imagesToAdd->push({false, image});
            }
        });
    }

    // Init nanogui application
    nanogui::init();

    {
        auto app = unique_ptr<ImageViewer>{new ImageViewer{ipc, imagesToAdd, !imageFiles}};
        app->drawAll();
        app->setVisible(true);

        // Do what the maximize flag tells us---if it exists---and
        // maximize if we have images otherwise.
        if (maximizeFlag ? get(maximizeFlag) : imageFiles) {
            app->maximize();
        }

        // Apply parameter flags
        if (exposureFlag) { app->setExposure(get(exposureFlag)); }
        if (filterFlag)   { app->setFilter(get(filterFlag)); }
        if (metricFlag)   { app->setMetric(toMetric(get(metricFlag))); }
        if (offsetFlag)   { app->setOffset(get(offsetFlag)); }
        if (tonemapFlag)  { app->setTonemap(toTonemap(get(tonemapFlag))); }

        // Refresh only every 250ms if there are no user interactions.
        // This makes an idling tev surprisingly energy-efficient. :)
        nanogui::mainloop(250);
    }

    // On some linux distributions glfwTerminate() (which is called by
    // nanogui::shutdown()) causes segfaults. Since we are done with our
    // program here anyways, let's let the OS clean up after us.
    //nanogui::shutdown();

    // Let all threads gracefully terminate.
    ThreadPool::shutdown();

    return 0;
}

#ifdef _WIN32
vector<string> arguments(int argc, char*[]) {
    vector<string> arguments;

    LPWSTR* arglist = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (arglist == NULL) {
        // tfm::format is not used due to a compiler issue in MSVC 2015 clashing with the "args" namespace.
        throw runtime_error{string{"Could not obtain command line: "} + errorString(lastError())};
    }

    for (int i = 1; i < argc; ++i) {
        wstring warg = arglist[i];
        string arg;
        if (!warg.empty()) {
            int size = WideCharToMultiByte(CP_UTF8, 0, &warg[0], (int)warg.size(), NULL, 0, NULL, NULL);
            arg.resize(size, 0);
            WideCharToMultiByte(CP_UTF8, 0, &warg[0], (int)warg.size(), &arg[0], size, NULL, NULL);
        }

        arguments.emplace_back(arg);
    }

    LocalFree(arglist);

    return arguments;
}
#else
vector<string> arguments(int argc, char* argv[]) {
    vector<string> arguments;
    for (int i = 1; i < argc; ++i) {
        string arg = argv[i];
        // OSX sometimes (seemingly sporadically) passes the
        // process serial number via a command line parameter.
        // We would like to ignore this.
        if (arg.find("-psn") == 0) {
            continue;
        }

        arguments.emplace_back(arg);
    }

    return arguments;
}
#endif

TEV_NAMESPACE_END

int main(int argc, char* argv[]) {
    try {
        tev::mainFunc(tev::arguments(argc, argv));
    } catch (const runtime_error& e) {
        cerr << "Uncaught exception: " << e.what() << endl;
        return 1;
    }
}
<commit_msg>Remove unnecessary explicit args:: prefix<commit_after>// This file was developed by Thomas Müller <thomas94@gmx.net>.
// It is published under the BSD 3-Clause License within the LICENSE file.

#include <tev/ImageViewer.h>
#include <tev/Ipc.h>
#include <tev/SharedQueue.h>
#include <tev/ThreadPool.h>

#include <args.hxx>
#include <ImfThreading.h>

#include <iostream>
#include <thread>

using namespace args;
using namespace filesystem;
using namespace std;

TEV_NAMESPACE_BEGIN

int mainFunc(const vector<string>& arguments) {
    ArgumentParser parser{
        "Inspection tool for images with a high dynamic range.",
        "",
    };

    HelpFlag helpFlag{
        parser,
        "help",
        "Display this help menu",
        {'h', "help"},
    };

    Flag newWindowFlag{
        parser,
        "new window",
        "Opens a new window of tev, even if one exists already.",
        {'n', "new"},
    };

    ValueFlag<float> exposureFlag{
        parser,
        "exposure",
        "Exposure scales the brightness of an image prior to tonemapping by 2^Exposure. "
        "It can be controlled via the GUI, or by pressing E/Shift+E.",
        {'e', "exposure"},
    };

    ValueFlag<string> filterFlag{
        parser,
        "filter",
        "Filters visible images and layers according to a supplied string. "
        "The string must have the format 'image:layer'. "
        "Only images whose name contains 'image' and layers whose name contains 'layer' will be visible.",
        {'f', "filter"},
    };

    ValueFlag<bool> maximizeFlag{
        parser,
        "maximize",
        "Whether to maximize the window on startup or not. "
        "If no images were supplied via the command line, then the default is false. "
        "Otherwise, the default is true.",
        {"max", "maximize"},
    };

    ValueFlag<string> metricFlag{
        parser,
        "metric",
        "The metric to use when comparing two images. "
        R"(
        The available metrics are:
        E   - Error
        AE  - Absolute Error
        SE  - Squared Error
        RAE - Relative Absolute Error
        RSE - Relative Squared Error
        )"
        "Default is E.",
        {'m', "metric"},
    };

    ValueFlag<float> offsetFlag{
        parser,
        "offset",
        "The offset is added to the image after exposure has been applied. "
        "It can be controlled via the GUI, or by pressing O/Shift+O.",
        {'o', "offset"},
    };

    ValueFlag<string> tonemapFlag{
        parser,
        "tonemap",
        "The tonemapping algorithm to use. "
        R"(
        The available tonemaps are:
        sRGB   - sRGB
        Gamma  - Gamma curve (2.2)
        FC     - False Color
        PN     - Positive=Green, Negative=Red
        )"
        "Default is sRGB.",
        {'t', "tonemap"},
    };

    PositionalList<string> imageFiles{
        parser,
        "images or channel selectors",
        "The image files to be opened by the viewer. "
        "If a filename starting with a ':' is encountered, "
        "then this filename is not treated as an image file "
        "but as a comma-separated channel selector. Until the next channel "
        "selector is encountered only channels containing "
        "elements from the current selector will be loaded. This is "
        "especially useful for selectively loading a specific "
        "part of a multi-part EXR file.",
    };

    // Parse command line arguments and react to parsing
    // errors using exceptions.
    try {
        parser.ParseArgs(arguments);
    } catch (Help) {
        std::cout << parser;
        return 0;
    } catch (ParseError e) {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return -1;
    } catch (ValidationError e) {
        std::cerr << e.what() << std::endl;
        std::cerr << parser;
        return -2;
    }

    auto ipc = make_shared<Ipc>();

    // If we're not the primary instance and did not request to open a new window,
    // simply send the to-be-opened images to the primary instance.
    if (!ipc->isPrimaryInstance() && !newWindowFlag) {
        string channelSelector;
        for (auto imageFile : get(imageFiles)) {
            if (!imageFile.empty() && imageFile[0] == ':') {
                channelSelector = imageFile.substr(1);
                continue;
            }

            try {
                ipc->sendToPrimaryInstance(path{imageFile}.make_absolute().str() + ":" + channelSelector);
            } catch (runtime_error e) {
                cerr << "Invalid file '" << imageFile << "': " << e.what() << endl;
            }
        }

        return 0;
    }

    Imf::setGlobalThreadCount(thread::hardware_concurrency());

    cout << "Loading window..." << endl;

    // Load images passed via command line in the background prior to
    // creating our main application such that they are not stalled
    // by the potentially slow initialization of opengl / glfw.
    shared_ptr<SharedQueue<ImageAddition>> imagesToAdd = make_shared<SharedQueue<ImageAddition>>();
    string channelSelector;
    for (auto imageFile : get(imageFiles)) {
        if (!imageFile.empty() && imageFile[0] == ':') {
            channelSelector = imageFile.substr(1);
            continue;
        }

        ThreadPool::singleWorker().enqueueTask([imageFile, channelSelector, &imagesToAdd] {
            auto image = tryLoadImage(imageFile, channelSelector);
            if (image) {
                imagesToAdd->push({false, image});
            }
        });
    }

    // Init nanogui application
    nanogui::init();

    {
        auto app = unique_ptr<ImageViewer>{new ImageViewer{ipc, imagesToAdd, !imageFiles}};
        app->drawAll();
        app->setVisible(true);

        // Do what the maximize flag tells us---if it exists---and
        // maximize if we have images otherwise.
        if (maximizeFlag ? get(maximizeFlag) : imageFiles) {
            app->maximize();
        }

        // Apply parameter flags
        if (exposureFlag) { app->setExposure(get(exposureFlag)); }
        if (filterFlag)   { app->setFilter(get(filterFlag)); }
        if (metricFlag)   { app->setMetric(toMetric(get(metricFlag))); }
        if (offsetFlag)   { app->setOffset(get(offsetFlag)); }
        if (tonemapFlag)  { app->setTonemap(toTonemap(get(tonemapFlag))); }

        // Refresh only every 250ms if there are no user interactions.
        // This makes an idling tev surprisingly energy-efficient. :)
        nanogui::mainloop(250);
    }

    // On some linux distributions glfwTerminate() (which is called by
    // nanogui::shutdown()) causes segfaults. Since we are done with our
    // program here anyways, let's let the OS clean up after us.
    //nanogui::shutdown();

    // Let all threads gracefully terminate.
    ThreadPool::shutdown();

    return 0;
}

#ifdef _WIN32
vector<string> arguments(int argc, char*[]) {
    vector<string> arguments;

    LPWSTR* arglist = CommandLineToArgvW(GetCommandLineW(), &argc);
    if (arglist == NULL) {
        // tfm::format is not used due to a compiler issue in MSVC 2015 clashing with the "args" namespace.
        throw runtime_error{string{"Could not obtain command line: "} + errorString(lastError())};
    }

    for (int i = 1; i < argc; ++i) {
        wstring warg = arglist[i];
        string arg;
        if (!warg.empty()) {
            int size = WideCharToMultiByte(CP_UTF8, 0, &warg[0], (int)warg.size(), NULL, 0, NULL, NULL);
            arg.resize(size, 0);
            WideCharToMultiByte(CP_UTF8, 0, &warg[0], (int)warg.size(), &arg[0], size, NULL, NULL);
        }

        arguments.emplace_back(arg);
    }

    LocalFree(arglist);

    return arguments;
}
#else
vector<string> arguments(int argc, char* argv[]) {
    vector<string> arguments;
    for (int i = 1; i < argc; ++i) {
        string arg = argv[i];
        // OSX sometimes (seemingly sporadically) passes the
        // process serial number via a command line parameter.
        // We would like to ignore this.
        if (arg.find("-psn") == 0) {
            continue;
        }

        arguments.emplace_back(arg);
    }

    return arguments;
}
#endif

TEV_NAMESPACE_END

int main(int argc, char* argv[]) {
    try {
        tev::mainFunc(tev::arguments(argc, argv));
    } catch (const runtime_error& e) {
        cerr << "Uncaught exception: " << e.what() << endl;
        return 1;
    }
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <iostream>
#include <ios>

#include "hext/parser.h"
#include "hext/matcher.h"
#include "hext/print.h"

int main(int argc, char ** argv)
{
  // todo: boost::program_options
  if( argc < 3 )
  {
    std::cout << "Usage: " << argv[0]
              << " [rules.hext] [target.html]" << std::endl;
    return EXIT_SUCCESS;
  }

  try
  {
    auto rules = hext::parser::parse_file(argv[1]);
    hext::matcher m(argv[2]);

    for(const auto& r : rules)
    {
      hext::print_rule(r);
      std::unique_ptr<hext::match_tree> mt = m.match(&r);
      assert(mt.get() != nullptr);
      //hext::print_match_tree(mt.get());
      mt->to_json(std::cout);
    }
  }
  catch( std::ios_base::failure& e )
  {
    std::cerr << e.what() << '\n';
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

<commit_msg>disable iostreams syncing with stdio<commit_after>#include <cstdlib>
#include <iostream>
#include <ios>

#include "hext/parser.h"
#include "hext/matcher.h"
#include "hext/print.h"

int main(int argc, char ** argv)
{
  std::ios_base::sync_with_stdio(false);

  // todo: boost::program_options
  if( argc < 3 )
  {
    std::cout << "Usage: " << argv[0]
              << " [rules.hext] [target.html]" << std::endl;
    return EXIT_SUCCESS;
  }

  try
  {
    auto rules = hext::parser::parse_file(argv[1]);
    hext::matcher m(argv[2]);

    for(const auto& r : rules)
    {
      hext::print_rule(r);
      std::unique_ptr<hext::match_tree> mt = m.match(&r);
      assert(mt.get() != nullptr);
      //hext::print_match_tree(mt.get());
      mt->to_json(std::cout);
    }
  }
  catch( std::ios_base::failure& e )
  {
    std::cerr << e.what() << '\n';
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#include <loftili.h>
#include <server.h>

int main(int argc, char ** argv) {
  if(argc > 1)
    std::cout << LOFTILI_PKG_VERSION << std::endl;
  else
    return loftili::Server::run();
}
<commit_msg>updating includes in main.cpp to follow style<commit_after>#include "loftili.h"
#include "server.h"

int main(int argc, char ** argv) {
  if(argc > 1)
    std::cout << LOFTILI_PKG_VERSION << std::endl;
  else
    return loftili::Server::run();
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <chrono>
#include <thread>

using std::chrono::microseconds;

#if defined(__linux__)
#include <sys/prctl.h>
#endif

volatile int g_thread_2_continuing = 0;

void *
thread_1_func (void *input)
{
    // Waiting to be released by the debugger.
    while (!g_thread_2_continuing) // Another thread will change this value
    {
        std::this_thread::sleep_for(microseconds(1));
    }

    // Return
    return NULL;  // Set third breakpoint here
}

void *
thread_2_func (void *input)
{
    // Waiting to be released by the debugger.
    int child_thread_continue = 0;
    while (!child_thread_continue) // The debugger will change this value
    {
        std::this_thread::sleep_for(microseconds(1));  // Set second breakpoint here
    }

    // Release thread 1
    g_thread_2_continuing = 1;

    // Return
    return NULL;
}

int main(int argc, char const *argv[])
{
#if defined(__linux__)
    // Immediately enable any ptracer so that we can allow the stub attach
    // operation to succeed.  Some Linux kernels are locked down so that
    // only an ancestor process can be a ptracer of a process.  This disables that
    // restriction.  Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
    int prctl_result;

    // For now we execute on best effort basis.  If this fails for
    // some reason, so be it.
    prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
    (void) prctl_result;
#endif
#endif

    // Create a new thread
    std::thread thread_1(thread_1_func, nullptr);

    // Waiting to be attached by the debugger.
    int main_thread_continue = 0;
    while (!main_thread_continue) // The debugger will change this value
    {
        std::this_thread::sleep_for(microseconds(1));  // Set first breakpoint here
    }

    // Create another new thread
    std::thread thread_2(thread_2_func, nullptr);

    // Wait for the threads to finish.
    thread_1.join();
    thread_2.join();

    printf("Exiting now\n");
}
<commit_msg>Normalize line endings.<commit_after>#include <stdio.h>
#include <chrono>
#include <thread>

using std::chrono::microseconds;

#if defined(__linux__)
#include <sys/prctl.h>
#endif

volatile int g_thread_2_continuing = 0;

void *
thread_1_func (void *input)
{
    // Waiting to be released by the debugger.
    while (!g_thread_2_continuing) // Another thread will change this value
    {
        std::this_thread::sleep_for(microseconds(1));
    }

    // Return
    return NULL;  // Set third breakpoint here
}

void *
thread_2_func (void *input)
{
    // Waiting to be released by the debugger.
    int child_thread_continue = 0;
    while (!child_thread_continue) // The debugger will change this value
    {
        std::this_thread::sleep_for(microseconds(1));  // Set second breakpoint here
    }

    // Release thread 1
    g_thread_2_continuing = 1;

    // Return
    return NULL;
}

int main(int argc, char const *argv[])
{
#if defined(__linux__)
    // Immediately enable any ptracer so that we can allow the stub attach
    // operation to succeed.  Some Linux kernels are locked down so that
    // only an ancestor process can be a ptracer of a process.  This disables that
    // restriction.  Without it, attach-related stub tests will fail.
#if defined(PR_SET_PTRACER) && defined(PR_SET_PTRACER_ANY)
    int prctl_result;

    // For now we execute on best effort basis.  If this fails for
    // some reason, so be it.
    prctl_result = prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
    (void) prctl_result;
#endif
#endif

    // Create a new thread
    std::thread thread_1(thread_1_func, nullptr);

    // Waiting to be attached by the debugger.
    int main_thread_continue = 0;
    while (!main_thread_continue) // The debugger will change this value
    {
        std::this_thread::sleep_for(microseconds(1));  // Set first breakpoint here
    }

    // Create another new thread
    std::thread thread_2(thread_2_func, nullptr);

    // Wait for the threads to finish.
    thread_1.join();
    thread_2.join();

    printf("Exiting now\n");
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_query_cache_access_state.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  p9_query_cache_access_state.H
/// @brief Check the stop level for the EX caches and sets boolean scomable parameters
///
// *HWP HWP Owner: Christina Graves <clgraves@us.ibm.com>
// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner:  Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team: PM
// *HWP Level: 2
// *HWP Consumed by: FSP:HS:SBE
///
///-----------------------------------------------------------------------------

#ifndef _p9_query_cache_access_state_H_
#define _p9_query_cache_access_state_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include <fapi2.H>
#include <p9_pm.H>
#include <p9_quad_scom_addresses.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------

// function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_query_cache_access_state_FP_t) (
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>&,
    bool&,
    bool&,
    bool&,
    bool&);

extern "C"
{

//------------------------------------------------------------------------------
// Function prototype
//------------------------------------------------------------------------------

/// @brief Check the stop level for the EX caches and sets boolean scomable parameters
///
/// @param[in] i_target        EX target
///
/// @param[out] o_l2_is_scomable  L2 cache has clocks running and is scomable
/// @param[out[ o_l2_is_scannable L2 cache is powered up and has valid latch state
/// @param[out] o_l3_is_scomable  L3 cache has clocks running and is scomable
/// @param[out[ o_l2_is_scannable L3 cache is powered up and has valid latch state
///
/// @return FAPI2_RC_SUCCESS if success, else error code.

    fapi2::ReturnCode
    p9_query_cache_access_state(
        const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
        bool& o_l2_is_scomable,
        bool& o_l2_is_scannable,
        bool& o_l3_is_scomable,
        bool& o_l3_is_scannable);

} // extern "C"

#endif // _p9_query_cache_access_state_H_
<commit_msg>Fix bug in cache query state procedure<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_query_cache_access_state.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2016,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/// @file  p9_query_cache_access_state.H
/// @brief Check the stop level for the EX caches and sets boolean scomable parameters
///
// *HWP HWP Owner: Christina Graves <clgraves@us.ibm.com>
// *HWP Backup HWP Owner: Greg Still <stillgs@us.ibm.com>
// *HWP FW Owner:  Sangeetha T S <sangeet2@in.ibm.com>
// *HWP Team: PM
// *HWP Level: 2
// *HWP Consumed by: FSP:HS:SBE
///
///-----------------------------------------------------------------------------

#ifndef _p9_query_cache_access_state_H_
#define _p9_query_cache_access_state_H_

//------------------------------------------------------------------------------
// Includes
//------------------------------------------------------------------------------

#include <fapi2.H>
#include <p9_pm.H>
#include <p9_quad_scom_addresses.H>

//------------------------------------------------------------------------------
// Constant definitions
//------------------------------------------------------------------------------
#define MAX_L2_PER_QUAD 2 //shared by the core/ex
#define MAX_L3_PER_QUAD 2 //shared by the core/ex
// function pointer typedef definition for HWP call support
typedef fapi2::ReturnCode (*p9_query_cache_access_state_FP_t) (
    const fapi2::Target<fapi2::TARGET_TYPE_EQ>&,
    bool*,
    bool*,
    bool*,
    bool*);

extern "C"
{

//------------------------------------------------------------------------------
// Function prototype
//------------------------------------------------------------------------------

/// @brief Check the stop level for the EX caches and sets boolean scomable parameters
///
/// @param[in] i_target        EX target
///
/// @param[out] o_l2_is_scomable[MAX_L2_PER_QUAD]
//                           L2 cache has clocks running and is scomable
/// @param[out[ o_l2_is_scannable[MAX_L2_PER_QUAD]
//                           L2 cache is powered up and has valid latch state
/// @param[out] o_l3_is_scomable  L3 cache has clocks running and is scomable
/// @param[out[ o_l2_is_scannable L3 cache is powered up and has valid latch state
///
/// @return FAPI2_RC_SUCCESS if success, else error code.

    fapi2::ReturnCode
    p9_query_cache_access_state(
        const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
        bool  o_l2_is_scomable[MAX_L2_PER_QUAD],
        bool  o_l2_is_scannable[MAX_L2_PER_QUAD],
        bool  o_l3_is_scomable[MAX_L3_PER_QUAD],
        bool  o_l3_is_scannable[MAX_L3_PER_QUAD]);

/// @brief Check the stop level for the EX caches and sets boolean scomable parameters
///
/// @param[in] i_target        EX target
///
/// @param[out] o_l2_is_scomable[MAX_L2_PER_QUAD]
//                           L2 cache has clocks running and is scomable
/// @param[out] o_l3_is_scomable  L3 cache has clocks running and is scomable
///
/// @return FAPI2_RC_SUCCESS if success, else error code.

    fapi2::ReturnCode
    p9_query_cache_clock_state(
        const fapi2::Target<fapi2::TARGET_TYPE_EQ>& i_target,
        bool  o_l2_is_scomable[MAX_L2_PER_QUAD],
        bool  o_l3_is_scomable[MAX_L3_PER_QUAD]);

} // extern "C"

#endif // _p9_query_cache_access_state_H_
<|endoftext|>


<commit_before>/*======================================================================

This file is part of the elastix software.

Copyright (c) University Medical Center Utrecht. All rights reserved.
See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.

======================================================================*/

#ifndef __itkParameterFileParser_cxx
#define __itkParameterFileParser_cxx

#include "itkParameterFileParser.h"

#include <itksys/SystemTools.hxx>
#include <itksys/RegularExpression.hxx>

namespace itk
{

/**
 * **************** Constructor ***************
 */

ParameterFileParser
::ParameterFileParser()
{
  this->m_ParameterFileName = "";
  this->m_ParameterMap.clear();

} // end Constructor()

/**
 * **************** Destructor ***************
 */

ParameterFileParser
::~ParameterFileParser()
{
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.close();
  }

} // end Destructor()

/**
 * **************** GetParameterMap ***************
 */

const ParameterFileParser::ParameterMapType &
ParameterFileParser
::GetParameterMap( void ) const
{
  return this->m_ParameterMap;

} // end GetParameterMap()

/**
 * **************** ReadParameterFile ***************
 */

void
ParameterFileParser
::ReadParameterFile( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in );

  /** Check if it opened. */
  if ( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
      << this->m_ParameterFileName
      << " for reading." );
  }

  /** Clear the map. */
  this->m_ParameterMap.clear();

  /** Loop over the parameter file, line by line. */
  std::string lineIn = "";
  std::string lineOut = "";
  while ( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, lineIn );

    /** Check this line. */
    bool validLine = this->CheckLine( lineIn, lineOut );

    if ( validLine )
    {
      /** Get the parameter name from this line and store it. */
      this->GetParameterFromLine( lineIn, lineOut );
    }
    // Otherwise, we simply ignore this line

  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

} // end ReadParameterFile()

/**
 * **************** BasicFileChecking ***************
 */

void
ParameterFileParser
::BasicFileChecking( void ) const
{
  /** Check if the file name is given. */
  if ( this->m_ParameterFileName == "" )
  {
    itkExceptionMacro( << "ERROR: FileName has not been set." );
  }

  /** Basic error checking: existence. */
  bool exists = itksys::SystemTools::FileExists(
    this->m_ParameterFileName.c_str() );
  if ( !exists )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " does not exist." );
  }

  /** Basic error checking: file or directory. */
  bool isDir = itksys::SystemTools::FileIsDirectory(
    this->m_ParameterFileName.c_str() );
  if ( isDir )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " is a directory." );
  }

  /** Check the extension. */
  std::string ext = itksys::SystemTools::GetFilenameLastExtension(
    this->m_ParameterFileName );
  if ( ext != ".txt" )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " should be a text file (*.txt)." );
  }

} // end BasicFileChecking()

/**
 * **************** CheckLine ***************
 */

bool
ParameterFileParser
::CheckLine( const std::string & lineIn, std::string & lineOut ) const
{
  /** Preprocessing of lineIn:
   * 1) Replace tabs with spaces
   * 2) Remove everything after comment sign //
   * 3) Remove leading spaces
   * 4) Remove trailing spaces
   */
  lineOut = lineIn;
  itksys::SystemTools::ReplaceString( lineOut, "\t", " " );

  itksys::RegularExpression commentPart( "//" );
  if ( commentPart.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, commentPart.start() );
  }

  itksys::RegularExpression leadingSpaces( "^[ ]*(.*)" );
  leadingSpaces.find( lineOut );
  lineOut = leadingSpaces.match( 1 );

  itksys::RegularExpression trailingSpaces( "[ \t]+$" );
  if ( trailingSpaces.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, trailingSpaces.start() );
  }

  /**
   * Checks:
   * 1. Empty line -> false
   * 2. Comment (line starts with "//") -> false
   * 3. Line is not between brackets (...) -> exception
   * 4. Line contains less than two words -> exception
   *
   * Otherwise return true.
   */

  /** 1. Check for non-empty lines. */
  itksys::RegularExpression reNonEmptyLine( "[^ ]+" );
  bool match1 = reNonEmptyLine.find( lineOut );
  if ( !match1 )
  {
    return false;
  }

  /** 2. Check for comments. */
  itksys::RegularExpression reComment( "^//" );
  bool match2 = reComment.find( lineOut );
  if ( match2 )
  {
    return false;
  }

  /** 3. Check if line is between brackets. */
  if ( !itksys::SystemTools::StringStartsWith( lineOut.c_str(), "(" )
    || !itksys::SystemTools::StringEndsWith( lineOut.c_str(), ")" ) )
  {
    std::string hint = "Line is not between brackets: \"(...)\".";
    this->ThrowException( lineIn, hint );
  }

  /** Remove brackets. */
  lineOut = lineOut.substr( 1, lineOut.size() - 2 );

  /** 4. Check: the line should contain at least two words. */
  itksys::RegularExpression reTwoWords( "([ ]+)([^ ]+)" );
  bool match4 = reTwoWords.find( lineOut );
  if ( !match4 )
  {
    std::string hint = "Line does not contain a parameter name and value.";
    this->ThrowException( lineIn, hint );
  }

  /** At this point we know its at least a line containing a parameter.
   * However, this line can still be invalid, for example:
   * (string &^%^*)
   * This will be checked later.
   */

  return true;

} // end CheckLine()

/**
 * **************** GetParameterFromLine ***************
 */

void
ParameterFileParser
::GetParameterFromLine( const std::string & fullLine,
  const std::string & line )
{
  /** A line has a parameter name followed by one or more parameters.
   * They are all separated by one or more spaces (all tabs have been
   * removed previously) or by quotes in case of strings. So,
   * 1) we split the line at the spaces or quotes
   * 2) the first one is the parameter name
   * 3) the other strings that are not a series of spaces, are parameter values
   */

  /** 1) Split the line. */
  std::vector<std::string> splittedLine;
  this->SplitLine( fullLine, line, splittedLine );

  /** 2) Get the parameter name. */
  std::string parameterName = splittedLine[ 0 ];
  itksys::SystemTools::ReplaceString( parameterName, " ", "" );
  splittedLine.erase( splittedLine.begin() );

  /** 3) Get the parameter values. */
  std::vector< std::string > parameterValues;
  for ( unsigned int i = 0; i < splittedLine.size(); ++i )
  {
    if ( splittedLine[ i ] != "" )
    {
      parameterValues.push_back( splittedLine[ i ] );
    }
  }

  /** 4) Perform some checks on the parameter name. */
  itksys::RegularExpression reInvalidCharacters1( "[.,:;!@#$%^&-+|<>?]" );
  bool match = reInvalidCharacters1.find( parameterName );
  if ( match )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" contains invalid characters (.,:;!@#$%^&-+|<>?).";
    this->ThrowException( fullLine, hint );
  }

  /** 5) Perform checks on the parameter values. */
  itksys::RegularExpression reInvalidCharacters2( "[,;!@#$%^&|<>?]" );
  for ( unsigned int i = 0; i < parameterValues.size(); ++i )
  {
    /** For all entries some characters are not allowed. */
    if ( reInvalidCharacters2.find( parameterValues[ i ] ) )
    {
      std::string hint = "The parameter value \""
        + parameterValues[ i ]
      + "\" contains invalid characters (,;!@#$%^&|<>?).";
      this->ThrowException( fullLine, hint );
    }
  }

  /** 6) Insert this combination in the parameter map. */
  this->m_ParameterMap.insert( make_pair( parameterName, parameterValues ) );

} // end GetParameterFromLine()

/**
 * **************** SplitLine ***************
 */

void
ParameterFileParser
::SplitLine( const std::string & fullLine, const std::string & line,
  std::vector<std::string> & splittedLine ) const
{
  splittedLine.clear();
  splittedLine.resize( 1 );
  std::vector<itksys::String> splittedLine1;

  /** Count the number of quotes in the line. If it is an odd value, the
   * line contains an error; strings should start and end with a quote, so
   * the total number of quotes is even.
   */
  std::size_t numQuotes = itksys::SystemTools::CountChar( line.c_str(), '"' );
  if ( numQuotes % 2 == 1 )
  {
    /** An invalid parameter line. */
    std::string hint = "This line has an odd number of quotes (\").";
    this->ThrowException( fullLine, hint );
  }

  /** Loop over the line. */
  std::string::const_iterator it;
  unsigned int index = 0;
  numQuotes = 0;
  for ( it = line.begin(); it < line.end(); it++ )
  {
    if ( *it == '"' )
    {
      /** Start a new element. */
      splittedLine.push_back( "" );
      index++;
      numQuotes++;
    }
    else if ( *it == ' ' )
    {
      /** Only start a new element if it is not a quote, otherwise just add
       * the space to the string.
       */
      if ( numQuotes % 2 == 0 )
      {
        splittedLine.push_back( "" );
        index++;
      }
      else
      {
        splittedLine[ index ].push_back( *it );
      }
    }
    else
    {
      /** Add this character to the element. */
      splittedLine[ index ].push_back( *it );
    }
  }

} // end SplitLine()

/**
 * **************** ThrowException ***************
 */

void
ParameterFileParser
::ThrowException( const std::string & line, const std::string & hint ) const
{
  /** Construct an error message. */
  std::string errorMessage
    = "ERROR: the following line in your parameter file is invalid: \n\""
    + line
    + "\"\n"
    + hint
    + "\nPlease correct you parameter file!";

  /** Throw exception. */
  itkExceptionMacro( << errorMessage.c_str() );

} // end ThrowException()

/**
 * **************** ReturnParameterFileAsString ***************
 */

std::string
ParameterFileParser
::ReturnParameterFileAsString( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in );

  /** Check if it opened. */
  if ( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
      << this->m_ParameterFileName
      << " for reading." );
  }

  /** Loop over the parameter file, line by line. */
  std::string line = "";
  std::string output;
  while ( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, line ); // \todo: returns bool

    output += line + "\n";
  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

  /** Return the string. */
  return output;

} // end ReturnParameterFileAsString()

} // end namespace itk

#endif // end __itkParameterFileParser_cxx
<commit_msg>MS:<commit_after>/*======================================================================

This file is part of the elastix software.

Copyright (c) University Medical Center Utrecht. All rights reserved.
See src/CopyrightElastix.txt or http://elastix.isi.uu.nl/legal.php for
details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.

======================================================================*/

#ifndef __itkParameterFileParser_cxx
#define __itkParameterFileParser_cxx

#include "itkParameterFileParser.h"

#include <itksys/SystemTools.hxx>
#include <itksys/RegularExpression.hxx>

namespace itk
{

/**
 * **************** Constructor ***************
 */

ParameterFileParser
::ParameterFileParser()
{
  this->m_ParameterFileName = "";
  this->m_ParameterMap.clear();

} // end Constructor()

/**
 * **************** Destructor ***************
 */

ParameterFileParser
::~ParameterFileParser()
{
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.close();
  }

} // end Destructor()

/**
 * **************** GetParameterMap ***************
 */

const ParameterFileParser::ParameterMapType &
ParameterFileParser
::GetParameterMap( void ) const
{
  return this->m_ParameterMap;

} // end GetParameterMap()

/**
 * **************** ReadParameterFile ***************
 */

void
ParameterFileParser
::ReadParameterFile( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in );

  /** Check if it opened. */
  if ( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
      << this->m_ParameterFileName
      << " for reading." );
  }

  /** Clear the map. */
  this->m_ParameterMap.clear();

  /** Loop over the parameter file, line by line. */
  std::string lineIn = "";
  std::string lineOut = "";
  while ( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, lineIn );

    /** Check this line. */
    bool validLine = this->CheckLine( lineIn, lineOut );

    if ( validLine )
    {
      /** Get the parameter name from this line and store it. */
      this->GetParameterFromLine( lineIn, lineOut );
    }
    // Otherwise, we simply ignore this line

  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

} // end ReadParameterFile()

/**
 * **************** BasicFileChecking ***************
 */

void
ParameterFileParser
::BasicFileChecking( void ) const
{
  /** Check if the file name is given. */
  if ( this->m_ParameterFileName == "" )
  {
    itkExceptionMacro( << "ERROR: FileName has not been set." );
  }

  /** Basic error checking: existence. */
  bool exists = itksys::SystemTools::FileExists(
    this->m_ParameterFileName.c_str() );
  if ( !exists )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " does not exist." );
  }

  /** Basic error checking: file or directory. */
  bool isDir = itksys::SystemTools::FileIsDirectory(
    this->m_ParameterFileName.c_str() );
  if ( isDir )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " is a directory." );
  }

  /** Check the extension. */
  std::string ext = itksys::SystemTools::GetFilenameLastExtension(
    this->m_ParameterFileName );
  if ( ext != ".txt" )
  {
    itkExceptionMacro( << "ERROR: the file "
      << this->m_ParameterFileName
      << " should be a text file (*.txt)." );
  }

} // end BasicFileChecking()

/**
 * **************** CheckLine ***************
 */

bool
ParameterFileParser
::CheckLine( const std::string & lineIn, std::string & lineOut ) const
{
  /** Preprocessing of lineIn:
   * 1) Replace tabs with spaces
   * 2) Remove everything after comment sign //
   * 3) Remove leading spaces
   * 4) Remove trailing spaces
   */
  lineOut = lineIn;
  itksys::SystemTools::ReplaceString( lineOut, "\t", " " );

  itksys::RegularExpression commentPart( "//" );
  if ( commentPart.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, commentPart.start() );
  }

  itksys::RegularExpression leadingSpaces( "^[ ]*(.*)" );
  leadingSpaces.find( lineOut );
  lineOut = leadingSpaces.match( 1 );

  itksys::RegularExpression trailingSpaces( "[ \t]+$" );
  if ( trailingSpaces.find( lineOut ) )
  {
    lineOut = lineOut.substr( 0, trailingSpaces.start() );
  }

  /**
   * Checks:
   * 1. Empty line -> false
   * 2. Comment (line starts with "//") -> false
   * 3. Line is not between brackets (...) -> exception
   * 4. Line contains less than two words -> exception
   *
   * Otherwise return true.
   */

  /** 1. Check for non-empty lines. */
  itksys::RegularExpression reNonEmptyLine( "[^ ]+" );
  bool match1 = reNonEmptyLine.find( lineOut );
  if ( !match1 )
  {
    return false;
  }

  /** 2. Check for comments. */
  itksys::RegularExpression reComment( "^//" );
  bool match2 = reComment.find( lineOut );
  if ( match2 )
  {
    return false;
  }

  /** 3. Check if line is between brackets. */
  if ( !itksys::SystemTools::StringStartsWith( lineOut.c_str(), "(" )
    || !itksys::SystemTools::StringEndsWith( lineOut.c_str(), ")" ) )
  {
    std::string hint = "Line is not between brackets: \"(...)\".";
    this->ThrowException( lineIn, hint );
  }

  /** Remove brackets. */
  lineOut = lineOut.substr( 1, lineOut.size() - 2 );

  /** 4. Check: the line should contain at least two words. */
  itksys::RegularExpression reTwoWords( "([ ]+)([^ ]+)" );
  bool match4 = reTwoWords.find( lineOut );
  if ( !match4 )
  {
    std::string hint = "Line does not contain a parameter name and value.";
    this->ThrowException( lineIn, hint );
  }

  /** At this point we know its at least a line containing a parameter.
   * However, this line can still be invalid, for example:
   * (string &^%^*)
   * This will be checked later.
   */

  return true;

} // end CheckLine()

/**
 * **************** GetParameterFromLine ***************
 */

void
ParameterFileParser
::GetParameterFromLine( const std::string & fullLine,
  const std::string & line )
{
  /** A line has a parameter name followed by one or more parameters.
   * They are all separated by one or more spaces (all tabs have been
   * removed previously) or by quotes in case of strings. So,
   * 1) we split the line at the spaces or quotes
   * 2) the first one is the parameter name
   * 3) the other strings that are not a series of spaces, are parameter values
   */

  /** 1) Split the line. */
  std::vector<std::string> splittedLine;
  this->SplitLine( fullLine, line, splittedLine );

  /** 2) Get the parameter name. */
  std::string parameterName = splittedLine[ 0 ];
  itksys::SystemTools::ReplaceString( parameterName, " ", "" );
  splittedLine.erase( splittedLine.begin() );

  /** 3) Get the parameter values. */
  std::vector< std::string > parameterValues;
  for ( unsigned int i = 0; i < splittedLine.size(); ++i )
  {
    if ( splittedLine[ i ] != "" )
    {
      parameterValues.push_back( splittedLine[ i ] );
    }
  }

  /** 4) Perform some checks on the parameter name. */
  itksys::RegularExpression reInvalidCharacters1( "[.,:;!@#$%^&-+|<>?]" );
  bool match = reInvalidCharacters1.find( parameterName );
  if ( match )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" contains invalid characters (.,:;!@#$%^&-+|<>?).";
    this->ThrowException( fullLine, hint );
  }

  /** 5) Perform checks on the parameter values. */
  itksys::RegularExpression reInvalidCharacters2( "[,;!@#$%^&|<>?]" );
  for ( unsigned int i = 0; i < parameterValues.size(); ++i )
  {
    /** For all entries some characters are not allowed. */
    if ( reInvalidCharacters2.find( parameterValues[ i ] ) )
    {
      std::string hint = "The parameter value \""
        + parameterValues[ i ]
      + "\" contains invalid characters (,;!@#$%^&|<>?).";
      this->ThrowException( fullLine, hint );
    }
  }

  /** 6) Insert this combination in the parameter map. */
  if ( this->m_ParameterMap.count( parameterName ) )
  {
    std::string hint = "The parameter \""
      + parameterName
      + "\" is specified more than once.";
    this->ThrowException( fullLine, hint );
  }
  else
  {
    this->m_ParameterMap.insert( make_pair( parameterName, parameterValues ) );
  }

} // end GetParameterFromLine()

/**
 * **************** SplitLine ***************
 */

void
ParameterFileParser
::SplitLine( const std::string & fullLine, const std::string & line,
  std::vector<std::string> & splittedLine ) const
{
  splittedLine.clear();
  splittedLine.resize( 1 );
  std::vector<itksys::String> splittedLine1;

  /** Count the number of quotes in the line. If it is an odd value, the
   * line contains an error; strings should start and end with a quote, so
   * the total number of quotes is even.
   */
  std::size_t numQuotes = itksys::SystemTools::CountChar( line.c_str(), '"' );
  if ( numQuotes % 2 == 1 )
  {
    /** An invalid parameter line. */
    std::string hint = "This line has an odd number of quotes (\").";
    this->ThrowException( fullLine, hint );
  }

  /** Loop over the line. */
  std::string::const_iterator it;
  unsigned int index = 0;
  numQuotes = 0;
  for ( it = line.begin(); it < line.end(); it++ )
  {
    if ( *it == '"' )
    {
      /** Start a new element. */
      splittedLine.push_back( "" );
      index++;
      numQuotes++;
    }
    else if ( *it == ' ' )
    {
      /** Only start a new element if it is not a quote, otherwise just add
       * the space to the string.
       */
      if ( numQuotes % 2 == 0 )
      {
        splittedLine.push_back( "" );
        index++;
      }
      else
      {
        splittedLine[ index ].push_back( *it );
      }
    }
    else
    {
      /** Add this character to the element. */
      splittedLine[ index ].push_back( *it );
    }
  }

} // end SplitLine()

/**
 * **************** ThrowException ***************
 */

void
ParameterFileParser
::ThrowException( const std::string & line, const std::string & hint ) const
{
  /** Construct an error message. */
  std::string errorMessage
    = "ERROR: the following line in your parameter file is invalid: \n\""
    + line
    + "\"\n"
    + hint
    + "\nPlease correct you parameter file!";

  /** Throw exception. */
  itkExceptionMacro( << errorMessage.c_str() );

} // end ThrowException()

/**
 * **************** ReturnParameterFileAsString ***************
 */

std::string
ParameterFileParser
::ReturnParameterFileAsString( void )
{
  /** Perform some basic checks. */
  this->BasicFileChecking();

  /** Open the parameter file for reading. */
  if ( this->m_ParameterFile.is_open() )
  {
    this->m_ParameterFile.clear();
    this->m_ParameterFile.close();
  }
  this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in );

  /** Check if it opened. */
  if ( !this->m_ParameterFile.is_open() )
  {
    itkExceptionMacro( << "ERROR: could not open "
      << this->m_ParameterFileName
      << " for reading." );
  }

  /** Loop over the parameter file, line by line. */
  std::string line = "";
  std::string output;
  while ( this->m_ParameterFile.good() )
  {
    /** Extract a line. */
    itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, line ); // \todo: returns bool

    output += line + "\n";
  }

  /** Close the parameter file. */
  this->m_ParameterFile.clear();
  this->m_ParameterFile.close();

  /** Return the string. */
  return output;

} // end ReturnParameterFileAsString()

} // end namespace itk

#endif // end __itkParameterFileParser_cxx
<|endoftext|>


<commit_before>#include "game.hpp"
#include "window.hpp"
#include "clock.hpp"
#include "events.hpp"
#include <iostream>

// "Game" specific data
namespace {
	bool gIsRunning = false;

	class GameEventEar : public EventEar {
	public:
		void onWindowClose()
		{
			Game::stop();
		}
	};
	GameEventEar gEar;
}

void Game::run()
{
	// Don't run it twice.
	if (gIsRunning)
		return;

	// Initialize the basics
	Window::open(800, 600);
	Clock::setTime(0.0);
	Events::addEar(&gEar);

	// Run the game loop
	gIsRunning = true;
	Clock::Timer frameCapTimer;
	while (gIsRunning)
	{
		// Poll for new events
		Events::poll();

		// Perform drawing, logic, etc...

		// Cap the framerate at 60
		Clock::sleepFor((1.0 / 60.0) - dt.get());
		frameCapTimer.set(0.0);
	}

	// Close the basics
	Events::removeEar(&gEar);
	Window::close();
}

void Game::stop()
{
	gIsRunning = false;
}
<commit_msg>Fix mistaken local variable name.<commit_after>#include "game.hpp"
#include "window.hpp"
#include "clock.hpp"
#include "events.hpp"
#include <iostream>

// "Game" specific data
namespace {
	bool gIsRunning = false;

	class GameEventEar : public EventEar {
	public:
		void onWindowClose()
		{
			Game::stop();
		}
	};
	GameEventEar gEar;
}

void Game::run()
{
	// Don't run it twice.
	if (gIsRunning)
		return;

	// Initialize the basics
	Window::open(800, 600);
	Clock::setTime(0.0);
	Events::addEar(&gEar);

	// Run the game loop
	gIsRunning = true;
	Clock::Timer frameCapTimer;
	while (gIsRunning)
	{
		// Poll for new events
		Events::poll();

		// Perform drawing, logic, etc...

		// Cap the framerate at 60
		Clock::sleepFor((1.0 / 60.0) - frameCapTimer.get());
		frameCapTimer.set(0.0);
	}

	// Close the basics
	Events::removeEar(&gEar);
	Window::close();
}

void Game::stop()
{
	gIsRunning = false;
}
<|endoftext|>


<commit_before>#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <unistd.h>
#include <vector>
#include <string>
#include <iostream>

#include "functions.h"

int main(int argc, char** argv)
{
  // hold a raw line of input
  std::string line;

  // print welcome message and prompt
  printf("Welcome to rshell!\n");

  while (true)
  {
    // holds a single command and its arguments
    Command cmd;
    // holds multiple commands
    std::vector<Command> cmds;

    // print prompt and get a line of text (done in condition)
    printf("$ ");
    getline(std::cin, line);

    // look for comments
    if (line.find("#") != std::string::npos)
    {
      // remove them if necessary (they're useless)
      line = line.substr(0, line.find("#"));
    }

    // remove leading whitespace
    while (line.size() > 0 && (line[0] == ' ' || line[0] == ';'))
    {
      line = line.substr(1, line.size() - 1);
    }

    // adding a space to the end makes parsing easier
    line += ' ';

    if (std::cin.fail())
    {
      printf("\nGoodbye!\n");
      exit(0);
    }

    int mode = GETWORD;
    unsigned begin = 0;

    // temporary: show pre-processed input to know what's being dealt with
    printf("You entered: \"%s\"\n", line.c_str());

    // prepare cmd
    cmd.connector = NONE;

    // syntax error flag
    bool se = false;

    // starts with a connector? I don't think so
    if (line.size() > 0 && isConn(line[0]))
    {
      se = true;
    }

    // handle the input
    for(unsigned i = 0; i < line.size() && !se; ++i)
    {
      bool con   = isConn(line[i]);
      bool space = isspace(line[i]);

      // if we're getting a word and there's a whitespace or connector here
      if (mode == GETWORD && (space || con))
      {
        // chunk the last term and throw it into the vector
        char* c = stocstr(line.substr(begin, i - begin));
        if (strlen(c) > 0)
        {
          cmd.args.push_back(c);
        }
        else
        {
          printf("Oh no! Recieved a word with no length\n");
          break;
        }

        if (space)
        {
          mode = TRIMSPACE;
        }
        else // it's a connector
        {
          handleCon(cmds, cmd, line, mode, i, se);
        }
      }
      else if (mode == TRIMSPACE && (!space || con))
      {
        if (con && cmd.args.empty())
        {
          se = true;
        }
        else if (con)
        {
          handleCon(cmds, cmd, line, mode, i, se);
        }
        else
        {
          mode = GETWORD;
          begin = i;
        }
      }

      if (i + 1 == line.size() && !cmd.args.empty()) // parsing the last character
      {
        // if it has a continuation connector, and we're finished with parsing, syntax error
        if (cmd.connector == AND || cmd.connector == OR)
        {
          se = true;
        }
        else
        {
          cmds.push_back(cmd);
        }
      }
    }

    // if the last command has a continuation connector, syntax error
    if (cmds.size() > 0 && (cmds[cmds.size() - 1].connector == AND
                        ||  cmds[cmds.size() - 1].connector == OR))
    {
      se = true;
    }

    // if there was a syntax error
    if (se)
    {
      printf("Syntax error detected\n");
      continue;
    }

    for(unsigned i = 0; i < cmds.size(); ++i)
    {
      printf("Command %u:\n", i);
      for(unsigned j = 0; j < cmds[i].args.size(); ++j)
      {
        printf("\t\"%s\"\n", cmds[i].args[j]);
      }
      switch(cmds[i].connector)
      {
        case AND:
          printf("\t&&\n");
          break;
        case OR:
          printf("\t||\n");
          break;
        case SEMI:
          printf("\t;\n");
          break;
        case NONE:
          printf("\tNo connector\n");
          break;
        default:
          printf("\tERROR: no valid connector specified\n");
      }
    }

    // deallocate allocated memory
    for(unsigned i = 0; i < cmds.size(); ++i)
    {
      for(unsigned j = 0; j < cmds[i].args.size(); ++j)
      {
        delete[] cmds[i].args[j];
      }
    }
  }
  return 0;
}

<commit_msg>changed messages to the user<commit_after>#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <unistd.h>
#include <vector>
#include <string>
#include <iostream>

#include "functions.h"

int main(int argc, char** argv)
{
  // hold a raw line of input
  std::string line;

  // print welcome message and prompt
  printf("Welcome to rshell!\n");

  while (true)
  {
    // holds a single command and its arguments
    Command cmd;
    // holds multiple commands
    std::vector<Command> cmds;

    // print prompt and get a line of text (done in condition)
    printf("$ ");
    getline(std::cin, line);

    // look for comments
    if (line.find("#") != std::string::npos)
    {
      // remove them if necessary (they're useless)
      line = line.substr(0, line.find("#"));
    }

    // remove leading whitespace
    while (line.size() > 0 && (line[0] == ' ' || line[0] == ';'))
    {
      line = line.substr(1, line.size() - 1);
    }

    // adding a space to the end makes parsing easier
    line += ' ';

    if (std::cin.fail())
    {
      printf("\nGoodbye!\n");
      exit(0);
    }

    int mode = GETWORD;
    unsigned begin = 0;

    // temporary: show pre-processed input to know what's being dealt with
    printf("You entered: \"%s\"\n", line.c_str());

    // prepare cmd
    cmd.connector = NONE;

    // syntax error flag
    bool se = false;

    // starts with a connector? I don't think so
    if (line.size() > 0 && isConn(line[0]))
    {
      se = true;
    }

    // handle the input
    for(unsigned i = 0; i < line.size() && !se; ++i)
    {
      bool con   = isConn(line[i]);
      bool space = isspace(line[i]);

      // if we're getting a word and there's a whitespace or connector here
      if (mode == GETWORD && (space || con))
      {
        // chunk the last term and throw it into the vector
        char* c = stocstr(line.substr(begin, i - begin));
        if (strlen(c) > 0)
        {
          cmd.args.push_back(c);
        }
        else
        {
          // only happens when nothing is entered. breaks so nothing more happens
          break;
        }

        if (space)
        {
          mode = TRIMSPACE;
        }
        else // it's a connector
        {
          handleCon(cmds, cmd, line, mode, i, se);
        }
      }
      else if (mode == TRIMSPACE && (!space || con))
      {
        if (con && cmd.args.empty())
        {
          se = true;
        }
        else if (con)
        {
          handleCon(cmds, cmd, line, mode, i, se);
        }
        else
        {
          mode = GETWORD;
          begin = i;
        }
      }

      if (i + 1 == line.size() && !cmd.args.empty()) // parsing the last character
      {
        // if it has a continuation connector, and we're finished with parsing, syntax error
        if (cmd.connector == AND || cmd.connector == OR)
        {
          se = true;
        }
        else
        {
          cmds.push_back(cmd);
        }
      }
    }

    // if the last command has a continuation connector, syntax error
    if (cmds.size() > 0 && (cmds[cmds.size() - 1].connector == AND
                        ||  cmds[cmds.size() - 1].connector == OR))
    {
      se = true;
    }

    // if there was a syntax error
    if (se)
    {
      printf("Syntax error\n");
      continue;
    }

    for(unsigned i = 0; i < cmds.size(); ++i)
    {
      printf("Command %u:\n", i);
      for(unsigned j = 0; j < cmds[i].args.size(); ++j)
      {
        printf("\t\"%s\"\n", cmds[i].args[j]);
      }
      switch(cmds[i].connector)
      {
        case AND:
          printf("\t&&\n");
          break;
        case OR:
          printf("\t||\n");
          break;
        case SEMI:
          printf("\t;\n");
          break;
        case NONE:
          printf("\tNo connector\n");
          break;
        default:
          printf("\tERROR: no valid connector specified\n");
      }
    }

    // deallocate allocated memory
    for(unsigned i = 0; i < cmds.size(); ++i)
    {
      for(unsigned j = 0; j < cmds[i].args.size(); ++j)
      {
        delete[] cmds[i].args[j];
      }
    }
  }
  return 0;
}

<|endoftext|>