<commit_before>/**
 * @author Mike Bogochow
 * @version 2.4.0, Dec 8, 2015
 *
 * @file Bidder.cpp
 *
 * Bidder class implementation
 */

#include "Bidder.h"
#include "../lib_graphs/Graph.h"
#include "../lib_graphs/Subgraph.h"
#include "../lib_graphs/SpanningTree.h"
#include "../lib_graphs/Path.h"
#include "../lib_graphs/defs.h"
#include "../lib_auction/AuctionDefs.h"
#include "../lib_auction/DebugPrinter.h"

#include "MBUtils.h"

#include <boost/lexical_cast.hpp>

#include <algorithm> // std::remove
#include <chrono>
#include <thread>

Bidder::Bidder(void)
{
  m_iterations = 0;

  g = new Graph(__edges, __num_edges, __weights, __num_nodes);

  // TODO add me to the graph

  allocated.reserve(__num_nodes);
  unallocated.reserve(__num_nodes);

  for (Vertex i = 0; i < __num_nodes; i++)
    unallocated.push_back(i);

  rtc = 0;

  roundNumber = 0;
  roundUpdated = false;
  winnerUpdated = false;

  id = -1;
}

Bidder::~Bidder(void)
{
  delete g;
}

bool
Bidder::OnNewMail(MOOSMSG_LIST &NewMail)
{
  bool ret = AuctionMOOSApp::OnNewMail(NewMail);

  dp.dprintf(LVL_MID_VERB, "roundNum < numNodes (%lu < %lu)?\n", roundNumber, g->getNumVertices());
  if (roundNumber <= g->getNumVertices()) //TODO come up with better solution of stopping auctioneer
  {
    MOOSMSG_LIST::reverse_iterator p;
    for(p = NewMail.rbegin(); p!=NewMail.rend(); p++) {
      CMOOSMsg &msg = *p;
      std::string key   = msg.GetKey();

      if (key == MVAR_BID_START)
      {
        int num = boost::lexical_cast<int>(msg.GetString());
        if (num > roundNumber)
        {
          if (num != roundNumber + 1)
          {
            MOOSTrace("WARNING: received round number %i while on round %i",
                num, roundNumber);
          }

          roundUpdated = true;
          roundNumber = num;
          dp.dprintf(LVL_MIN_VERB, "Got %s mail: %i\n", MVAR_BID_START.c_str(),
              num);
        }
      }
      else if (key == MVAR_BID_WINNER)
      {
        winnerUpdated = true;
        winningBid = winningBidFromString(msg.GetString());
        dp.dprintf(LVL_MIN_VERB, "Got %s mail: %s\n", MVAR_BID_WINNER.c_str(),
            winningBid);
      }
    }
  }

  return ret;
}

bool
Bidder::Iterate(void)
{
  bool ret = AuctionMOOSApp::Iterate();

  if (winnerUpdated)
  {
    if (winningBid.winner == id)
    {
      allocated.push_back(winningBid.target);
      rtc += winningBid.bid;
    }
    unallocated.erase(
        std::remove(unallocated.begin(), unallocated.end(),
            winningBid.target), unallocated.end());
    winnerUpdated = false;
  }

  dp.dprintf(LVL_MID_VERB, "roundNum <= numNodes (%lu < %lu)?\n", roundNumber, g->getNumVertices());
  if (roundNumber <= g->getNumVertices())
  {
    if (roundUpdated)
    {
      performBiddingRound();
      roundUpdated = false;
    }
  }
  else //TODO come up with better solution of stopping bidder
  {
    assert(unallocated.size() == 0);

    // Do final cost calculation and submit path
    Subgraph *sub = Subgraph::fromGraph(g, allocated);
    SpanningTree *tree = SpanningTree::fromGraph(sub->getGraph());
    Path *path = Path::fromTree(tree);
    Loc *locs = new Loc[path->getLength()];

    DebugLevel LVL_FINAL_PATH = LVL_MID_VERB;
    if (dp.isValidLevel(LVL_FINAL_PATH))
    {
      dp.dprintf(LVL_FINAL_PATH, "Final allocated:\n");
      int count = 0;
      for (std::vector<Vertex>::iterator it = allocated.begin(); it != allocated.end(); it++)
      {
        dp.dprintf(LVL_FINAL_PATH, "\tallocated[%i]:%s\n", count++,
            boost::lexical_cast<std::string>(*it).c_str());
      }
      dp.dprintf(LVL_FINAL_PATH, "Final path:\n%s\n", path->toString().c_str());
    }

    path->convertPath(sub->getParentIndices());
    dp.dprintf(LVL_FINAL_PATH, "Converted path:\n%s\n", path->toString().c_str());

    path->getLocations(__locations, locs);

    doNotify(getPathVar(id), pathToString(locs, path->getLength()));

    delete sub;
    delete tree;
    delete path;
    delete locs;

    // Exit pBidder
    doNotify("EXITED_NORMALLY", "pBidder");
    // Ensure data is passed to auctioneer
    std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 10));
    exit(0);
  }

  return ret;
}

void
Bidder::performBiddingRound(void)
{
  // Bidding round
  Bid currentBid = std::make_pair(MAX_VERTEX, MAX_WEIGHT);

  Graph *sub;

  // Iterate through unallocated nodes to find bid
  for (std::vector<Vertex>::iterator t = unallocated.begin();
      t != unallocated.end(); t++)
  {
    Path *path;
    SpanningTree *tree;
    mbogo_weight_t cost;
    mbogo_weight_t bid;
    std::vector<Vertex> possibleAllocation;

    possibleAllocation.reserve(allocated.size() + 1);
    possibleAllocation = allocated;
    dp.dprintf(LVL_BID, "Adding %s for possible allocation\n",
        boost::lexical_cast<std::string>(*t).c_str());
    possibleAllocation.push_back(*t);

    // Catch simple cases for efficiency
    if (possibleAllocation.size() == 1)
    {
      cost = bid = 0;
    }
    else if (possibleAllocation.size() == 2)
    {
      path = Path::fromPair(
          std::make_pair(possibleAllocation.front(),
              possibleAllocation.back()));
      cost = path->getTotalCost(g->getGraph());
      bid = cost - rtc;

      delete path;
    }
    else
    {
      sub = g->getSubgraph(possibleAllocation);
      dp.dprintf(LVL_BID, "Subgraph:\n%s\n", sub->toString().c_str());

      tree = SpanningTree::fromGraph(sub->getGraph());
      dp.dprintf(LVL_BID, "Spanning Tree:\n%s\n", tree->toString().c_str());

      path = Path::fromTree(tree);
      dp.dprintf(LVL_BID, "Path:\n%s\n", path->toString().c_str());

      cost = path->getTotalCost(g->getGraph());//= get_path_cost(g, path); // TODO
      bid = cost - rtc;

      delete path;
      delete tree;
      delete sub;
    }

    dp.dprintf(LVL_BID, "bid[%lu_%s]=%s (cost-rtc)=(%s-%s)\n", roundNumber,
        boost::lexical_cast<std::string>(*t).c_str(),
        boost::lexical_cast<std::string>(bid).c_str(),
        boost::lexical_cast<std::string>(cost).c_str(),
        boost::lexical_cast<std::string>(rtc).c_str()
    );

    if (currentBid.second > bid && bid >= 0)
      currentBid = std::make_pair(*t, bid);

    dp.dprintf(LVL_BID, "cur_bid=%s:%s\n",
        boost::lexical_cast<std::string>(currentBid.first).c_str(),
        boost::lexical_cast<std::string>(currentBid.second).c_str());
  }

  assert(currentBid.first  != MAX_VERTEX
      && currentBid.second != MAX_WEIGHT);

  // Send bid to MOOSDB
  doNotify(getBidVar(id), bidToString(currentBid));
}

bool
Bidder::OnStartUp(void)
{
  bool ret;

  // Read the DebugOutput configuration field
  int debugLevel;
  if (!m_MissionReader.GetConfigurationParam("DebugOutput", debugLevel))
    debugLevel = LVL_OFF;
  dp.setLevel((DebugLevel)debugLevel);

  ret = AuctionMOOSApp::OnStartUp();

  // Read the AgentID configuration field
  if (!m_MissionReader.GetConfigurationParam("AgentID", id))
  {
    MOOSTrace("Warning: parameter 'AgentID' not specified.\n");
    MOOSTrace("Terminating\n");
    exit(-1);
  }

  RegisterVariables();

  return ret;
}

bool
Bidder::OnConnectToServer(void)
{
  bool ret = AuctionMOOSApp::OnConnectToServer();
  RegisterVariables();
  return ret;
}

void
Bidder::RegisterVariables(void)
{
  m_Comms.Register("BID_WINNER", 0);
  m_Comms.Register("BID_START", 0);
}
<commit_msg>Changed type and commented<commit_after>/**
 * @author Mike Bogochow
 * @version 2.4.0, Dec 8, 2015
 *
 * @file Bidder.cpp
 *
 * Bidder class implementation
 */

#include "Bidder.h"
#include "../lib_graphs/Graph.h"
#include "../lib_graphs/Subgraph.h"
#include "../lib_graphs/SpanningTree.h"
#include "../lib_graphs/Path.h"
#include "../lib_graphs/defs.h"
#include "../lib_auction/AuctionDefs.h"
#include "../lib_auction/DebugPrinter.h"

#include "MBUtils.h"

#include <boost/lexical_cast.hpp>

#include <algorithm> // std::remove
#include <chrono>
#include <thread>

Bidder::Bidder(void)
{
  m_iterations = 0;

  g = new Graph(__edges, __num_edges, __weights, __num_nodes);

  // TODO add me to the graph

  allocated.reserve(__num_nodes);
  unallocated.reserve(__num_nodes);

  for (Vertex i = 0; i < __num_nodes; i++)
    unallocated.push_back(i);

  rtc = 0;

  roundNumber = 0;
  roundUpdated = false;
  winnerUpdated = false;

  id = -1;
}

Bidder::~Bidder(void)
{
  delete g;
}

bool
Bidder::OnNewMail(MOOSMSG_LIST &NewMail)
{
  bool ret = AuctionMOOSApp::OnNewMail(NewMail);

  dp.dprintf(LVL_MID_VERB, "roundNum < numNodes (%lu < %lu)?\n", roundNumber, g->getNumVertices());
  if (roundNumber <= g->getNumVertices()) //TODO come up with better solution of stopping auctioneer
  {
    MOOSMSG_LIST::reverse_iterator p;
    for(p = NewMail.rbegin(); p!=NewMail.rend(); p++) {
      CMOOSMsg &msg = *p;
      std::string key   = msg.GetKey();

      if (key == MVAR_BID_START)
      {
        size_t num = boost::lexical_cast<size_t>(msg.GetString());
        if (num > roundNumber) // ignore duplicate messages
        {
          if (num != roundNumber + 1)
          {
            MOOSTrace("WARNING: received round number %i while on round %i",
                num, roundNumber);
          }

          roundUpdated = true;
          roundNumber = num;
          dp.dprintf(LVL_MIN_VERB, "Got %s mail: %i\n", MVAR_BID_START.c_str(),
              num);
        }
      }
      else if (key == MVAR_BID_WINNER)
      {
        winnerUpdated = true;
        winningBid = winningBidFromString(msg.GetString());
        dp.dprintf(LVL_MIN_VERB, "Got %s mail: %s\n", MVAR_BID_WINNER.c_str(),
            winningBid);
      }
    }
  }

  return ret;
}

bool
Bidder::Iterate(void)
{
  bool ret = AuctionMOOSApp::Iterate();

  if (winnerUpdated)
  {
    if (winningBid.winner == id)
    {
      allocated.push_back(winningBid.target);
      rtc += winningBid.bid;
    }
    unallocated.erase(
        std::remove(unallocated.begin(), unallocated.end(),
            winningBid.target), unallocated.end());
    winnerUpdated = false;
  }

  dp.dprintf(LVL_MID_VERB, "roundNum <= numNodes (%lu < %lu)?\n", roundNumber, g->getNumVertices());
  if (roundNumber <= g->getNumVertices())
  {
    if (roundUpdated)
    {
      performBiddingRound();
      roundUpdated = false;
    }
  }
  else //TODO come up with better solution of stopping bidder
  {
    assert(unallocated.size() == 0);

    // Do final cost calculation and submit path
    Subgraph *sub = Subgraph::fromGraph(g, allocated);
    SpanningTree *tree = SpanningTree::fromGraph(sub->getGraph());
    Path *path = Path::fromTree(tree);
    Loc *locs = new Loc[path->getLength()];

    DebugLevel LVL_FINAL_PATH = LVL_MID_VERB;
    if (dp.isValidLevel(LVL_FINAL_PATH))
    {
      dp.dprintf(LVL_FINAL_PATH, "Final allocated:\n");
      int count = 0;
      for (std::vector<Vertex>::iterator it = allocated.begin(); it != allocated.end(); it++)
      {
        dp.dprintf(LVL_FINAL_PATH, "\tallocated[%i]:%s\n", count++,
            boost::lexical_cast<std::string>(*it).c_str());
      }
      dp.dprintf(LVL_FINAL_PATH, "Final path:\n%s\n", path->toString().c_str());
    }

    path->convertPath(sub->getParentIndices());
    dp.dprintf(LVL_FINAL_PATH, "Converted path:\n%s\n", path->toString().c_str());

    path->getLocations(__locations, locs);

    doNotify(getPathVar(id), pathToString(locs, path->getLength()));

    delete sub;
    delete tree;
    delete path;
    delete locs;

    // Exit pBidder
    doNotify("EXITED_NORMALLY", "pBidder");
    // Ensure data is passed to auctioneer
    std::this_thread::sleep_for(std::chrono::milliseconds(1000 * 10));
    exit(0);
  }

  return ret;
}

void
Bidder::performBiddingRound(void)
{
  // Bidding round
  Bid currentBid = std::make_pair(MAX_VERTEX, MAX_WEIGHT);

  Graph *sub;

  // Iterate through unallocated nodes to find bid
  for (std::vector<Vertex>::iterator t = unallocated.begin();
      t != unallocated.end(); t++)
  {
    Path *path;
    SpanningTree *tree;
    mbogo_weight_t cost;
    mbogo_weight_t bid;
    std::vector<Vertex> possibleAllocation;

    possibleAllocation.reserve(allocated.size() + 1);
    possibleAllocation = allocated;
    dp.dprintf(LVL_BID, "Adding %s for possible allocation\n",
        boost::lexical_cast<std::string>(*t).c_str());
    possibleAllocation.push_back(*t);

    // Catch simple cases for efficiency
    if (possibleAllocation.size() == 1)
    {
      cost = bid = 0;
    }
    else if (possibleAllocation.size() == 2)
    {
      path = Path::fromPair(
          std::make_pair(possibleAllocation.front(),
              possibleAllocation.back()));
      cost = path->getTotalCost(g->getGraph());
      bid = cost - rtc;

      delete path;
    }
    else
    {
      sub = g->getSubgraph(possibleAllocation);
      dp.dprintf(LVL_BID, "Subgraph:\n%s\n", sub->toString().c_str());

      tree = SpanningTree::fromGraph(sub->getGraph());
      dp.dprintf(LVL_BID, "Spanning Tree:\n%s\n", tree->toString().c_str());

      path = Path::fromTree(tree);
      dp.dprintf(LVL_BID, "Path:\n%s\n", path->toString().c_str());

      cost = path->getTotalCost(g->getGraph());//= get_path_cost(g, path); // TODO
      bid = cost - rtc;

      delete path;
      delete tree;
      delete sub;
    }

    dp.dprintf(LVL_BID, "bid[%lu_%s]=%s (cost-rtc)=(%s-%s)\n", roundNumber,
        boost::lexical_cast<std::string>(*t).c_str(),
        boost::lexical_cast<std::string>(bid).c_str(),
        boost::lexical_cast<std::string>(cost).c_str(),
        boost::lexical_cast<std::string>(rtc).c_str()
    );

    if (currentBid.second > bid && bid >= 0)
      currentBid = std::make_pair(*t, bid);

    dp.dprintf(LVL_BID, "cur_bid=%s:%s\n",
        boost::lexical_cast<std::string>(currentBid.first).c_str(),
        boost::lexical_cast<std::string>(currentBid.second).c_str());
  }

  assert(currentBid.first  != MAX_VERTEX
      && currentBid.second != MAX_WEIGHT);

  // Send bid to MOOSDB
  doNotify(getBidVar(id), bidToString(currentBid));
}

bool
Bidder::OnStartUp(void)
{
  bool ret;

  // Read the DebugOutput configuration field
  int debugLevel;
  if (!m_MissionReader.GetConfigurationParam("DebugOutput", debugLevel))
    debugLevel = LVL_OFF;
  dp.setLevel((DebugLevel)debugLevel);

  ret = AuctionMOOSApp::OnStartUp();

  // Read the AgentID configuration field
  if (!m_MissionReader.GetConfigurationParam("AgentID", id))
  {
    MOOSTrace("Warning: parameter 'AgentID' not specified.\n");
    MOOSTrace("Terminating\n");
    exit(-1);
  }

  RegisterVariables();

  return ret;
}

bool
Bidder::OnConnectToServer(void)
{
  bool ret = AuctionMOOSApp::OnConnectToServer();
  RegisterVariables();
  return ret;
}

void
Bidder::RegisterVariables(void)
{
  m_Comms.Register("BID_WINNER", 0);
  m_Comms.Register("BID_START", 0);
}
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef ABC_MEMORY_HXX
#define ABC_MEMORY_HXX

#include <abc/core.hxx>
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <abc/exception.hxx>

#if ABC_HOST_API_POSIX

   #include <stdlib.h> // free() malloc() realloc()
   #include <memory.h> // memcpy() memmove() memset()

#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX

   // Clean up pollution caused by previous headers.
   extern "C" {

   // Rtl*Memory*

   #undef RtlZeroMemory
   WINBASEAPI void WINAPI RtlZeroMemory(void UNALIGNED * pDst, size_t cb);

   #undef RtlFillMemory
   WINBASEAPI void WINAPI RtlFillMemory(void UNALIGNED * pDst, size_t cb, UCHAR iValue);

   #undef RtlFillMemoryUlong
   WINBASEAPI void WINAPI RtlFillMemoryUlong(void * pDst, size_t cb, ULONG iValue);

   #undef RtlFillMemoryUlonglong
   WINBASEAPI void WINAPI RtlFillMemoryUlonglong(void * pDst, size_t cb, ULONGLONG iValue);

   #undef RtlCopyMemory
   WINBASEAPI void WINAPI RtlCopyMemory(
      void UNALIGNED * pDst, void UNALIGNED const * pSrc, size_t cb
   );

   #undef RtlMoveMemory
   WINBASEAPI void WINAPI RtlMoveMemory(
      void UNALIGNED * pDst, void UNALIGNED const * pSrc, size_t cb
   );

   } //extern "C"

#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32

/** TODO: comment or remove.
*/
#if ABC_HOST_GCC
   #define _abc_alloca(cb) \
      __builtin_alloca((cb))
#elif ABC_HOST_MSC
   extern "C" void * ABC_STL_CALLCONV _alloca(size_t cb);
   #define _abc_alloca(cb) \
      _alloca(cb)
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// :: globals - standard new/delete operators

#if ABC_HOST_MSC
   #pragma warning(push)
   // “'operator': exception specification does not match previous declaration”
   #pragma warning(disable: 4986)
#endif

void * ABC_STL_CALLCONV operator new(size_t cb) ABC_STL_NOEXCEPT_FALSE((std::bad_alloc));
void * ABC_STL_CALLCONV operator new[](size_t cb) ABC_STL_NOEXCEPT_FALSE((std::bad_alloc));
void * ABC_STL_CALLCONV operator new(size_t cb, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();
void * ABC_STL_CALLCONV operator new[](size_t cb, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();

void ABC_STL_CALLCONV operator delete(void * p) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete[](void * p) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete(void * p, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete[](void * p, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();

#if ABC_HOST_MSC
   #pragma warning(pop)
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory::deleter

namespace abc {

namespace memory {

// Forward declaration.
template <typename T>
void free(T * pt);

/** Deleter that deallocates memory using memory::free().
*/
template <typename T>
struct deleter {

   /** Deallocates the specified memory block.

   pt
      Pointer to the object to delete.
   */
   void operator()(T * pt) const {
      free(pt);
   }
};

// Specialization for arrays.
template <typename T>
struct deleter<T[]> :
   public deleter<T> {

   /** Deallocates the specified array. See also deleter<T>::operator()().

   pt
      Pointer to the array to deallocate.
   */
   void operator()(T * pt) const {
      free(pt);
   }
};

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory::conditional_deleter

namespace abc {

namespace memory {

/** Wrapper that invokes a deleter if and only if a set condition is true.
*/
template <typename T, typename TDeleter = std::default_delete<T>>
class conditional_deleter :
   public TDeleter {
public:

   /** Constructor.

   bDelete
      If true, the deleter will delete objects when invoked; if false, it will do nothing.
   */
   conditional_deleter(bool bDelete) :
      TDeleter(),
      m_bDelete(bDelete) {
   }

   /** Deletes the specified object if the condition set in the constructor was true.

   pt
      Pointer to the object to delete.
   */
   void operator()(T * pt) const {
      if (m_bDelete) {
         TDeleter::operator()(pt);
      }
   }

protected:

   bool m_bDelete;
};

// Specialization for arrays.
template <typename T, typename TDeleter>
class conditional_deleter<T[], TDeleter> :
   public conditional_deleter<T, TDeleter> {
public:

   /** See conditional_deleter<T>::conditional_deleter().
   */
   conditional_deleter(bool bDelete) :
      conditional_deleter<T, TDeleter>(bDelete) {
   }

   /** Deletes the specified array if the condition set in the constructor was true. See also
   conditional_deleter<T, TDeleter>::operator()().

   pt
      Pointer to the array to delete.
   */
   void operator()(T * pt) const {
      if (this->m_bDelete) {
         TDeleter::operator()(pt);
      }
   }
};

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory::noop_deleter

namespace abc {

namespace memory {

/** No-op deleter. It assumes the memory doesn’t need to be released.
*/
template <typename T>
struct noop_deleter {

   /** Deallocates the specified memory block.

   TODO: comment signature.
   */
   void operator()(T * pt) const {
      ABC_UNUSED_ARG(pt);
   }
};

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory globals - management

namespace abc {

namespace memory {

/** Allows to use the keyword auto to declare std::unique_ptr objects that use memory::deleter.

TODO: comment signature.
*/
template <typename T>
inline std::unique_ptr<T, deleter<T>> make_unique_ptr(T * pt = nullptr) {
   return std::unique_ptr<T, deleter<T>>(pt);
}

/** Requests the dynamic allocation of a memory block of the specified number of bytes.

TODO: comment signature.
*/
inline void * _raw_alloc(size_t cb) {
   void * p(::malloc(cb));
   if (!p) {
      ABC_THROW(memory_allocation_error, ());
   }
   return p;
}

/** Resizes a dynamically allocated memory block.

TODO: comment signature.
*/
inline void * _raw_realloc(void * p, size_t cb) {
   p = ::realloc(p, cb);
   if (!p) {
      ABC_THROW(memory_allocation_error, ());
   }
   return p;
}

/** Requests the dynamic allocation of a memory block large enough to contain c objects of type T,
plus an additional cbExtra bytes. With specialization that ignores types (void) and allocates the
specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline std::unique_ptr<T, deleter<T>> alloc(size_t c = 1, size_t cbExtra = 0) {
   return make_unique_ptr<T>(static_cast<T *>(_raw_alloc(sizeof(T) * c + cbExtra)));
}
template <>
inline std::unique_ptr<void, deleter<void>> alloc(size_t cb /*= 1*/, size_t cbExtra /*= 0*/) {
   return make_unique_ptr<void>(_raw_alloc(cb + cbExtra));
}

/** Releases a block of dynamically allocated memory.

TODO: comment signature.
*/
template <typename T>
inline void free(T * pt) {
   ::free(pt);
}

/** Changes the size of a block of dynamically allocated memory. Both overloads have a
specialization that ignores pointer types (void), and allocates the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * realloc(T * pt, size_t c, size_t cbExtra = 0) {
   return static_cast<T *>(_raw_realloc(pt, sizeof(T) * c + cbExtra));
}
template <>
inline void * realloc(void * p, size_t cb, size_t cbExtra /*= 0*/) {
   return _raw_realloc(p, cb + cbExtra);
}
template <typename T>
inline void realloc(std::unique_ptr<T, deleter<T>> * ppt, size_t c, size_t cbExtra = 0) {
   T * pt(static_cast<T *>(_raw_realloc(ppt->get(), sizeof(T) * c + cbExtra)));
   ppt->release();
   ppt->reset(pt);
}
template <>
inline void realloc(std::unique_ptr<void, deleter<void>> * pp, size_t cb, size_t cbExtra /*= 0*/) {
   void * p(_raw_realloc(pp->get(), cb + cbExtra));
   pp->release();
   pp->reset(p);
}

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory globals - manipulation

namespace abc {

namespace memory {

/** Sets to the value 0 every item in an array.

TODO: comment signature.
*/
template <typename T>
inline T * clear(T * ptDst, size_t c = 1) {
   return static_cast<T *>(clear<void>(ptDst, sizeof(T) * c));
}
template <>
inline void * clear(void * pDst, size_t cb /*= 1*/) {
#if ABC_HOST_API_POSIX
   ::memset(pDst, 0, cb);
#elif ABC_HOST_API_WIN32
   ::RtlZeroMemory(pDst, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies memory, by number of items. With specialization that ignores pointer types (void), and
copies the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * copy(T * ptDst, T const * ptSrc) {
   // Optimization: if the copy can be made by mem-reg-mem transfers, avoid calling a function, so
   // that the compiler can inline the copy.
   switch (sizeof(T)) {
      case sizeof(int8_t):
         *reinterpret_cast<int8_t *>(ptDst) = *reinterpret_cast<int8_t const *>(ptSrc);
         break;
      case sizeof(int16_t):
         *reinterpret_cast<int16_t *>(ptDst) = *reinterpret_cast<int16_t const *>(ptSrc);
         break;
      case sizeof(int32_t):
         *reinterpret_cast<int32_t *>(ptDst) = *reinterpret_cast<int32_t const *>(ptSrc);
         break;
      case sizeof(int64_t):
         *reinterpret_cast<int64_t *>(ptDst) = *reinterpret_cast<int64_t const *>(ptSrc);
         break;
      default:
         copy<void>(ptDst, ptSrc, sizeof(T));
         break;
   }
   return static_cast<T *>(ptDst);
}
// Nobody should want to use this, but it’s here for consistency.
template <>
inline void * copy(void * pDst, void const * pSrc) {
   *reinterpret_cast<int8_t *>(pDst) = *reinterpret_cast<int8_t const *>(pSrc);
   return pDst;
}
template <typename T>
inline T * copy(T * ptDst, T const * ptSrc, size_t c) {
   return static_cast<T *>(copy<void>(ptDst, ptSrc, sizeof(T) * c));
}
template <>
inline void * copy(void * pDst, void const * pSrc, size_t cb) {
#if ABC_HOST_API_POSIX
   ::memcpy(pDst, pSrc, cb);
#elif ABC_HOST_API_WIN32
   ::RtlMoveMemory(pDst, pSrc, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies possibly overlapping memory, by number of items. With specialization that ignores pointer
types (void), and copies the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * move(T * ptDst, T const * ptSrc, size_t c) {
   return static_cast<T *>(move<void>(ptDst, ptSrc, sizeof(T) * c));
}
template <>
inline void * move(void * pDst, void const * pSrc, size_t cb) {
#if ABC_HOST_API_POSIX
   ::memmove(pDst, pSrc, cb);
#elif ABC_HOST_API_WIN32
   ::RtlMoveMemory(pDst, pSrc, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies a value over each item of a static array.

TODO: comment signature.
*/
template <typename T>
inline T * set(T * ptDst, T const & tValue, size_t c) {
   switch (sizeof(T)) {
#if ABC_HOST_API_POSIX
      case sizeof(int8_t):
         ::memset(ptDst, tValue, c);
         break;
#elif ABC_HOST_API_WIN32
      case sizeof(UCHAR):
         ::RtlFillMemory(ptDst, c, tValue);
         break;
#endif
      default:
         for (T const * ptDstMax(ptDst + c); ptDst < ptDstMax; ++ptDst) {
            copy(ptDst, &tValue);
         }
         break;
   }
   return ptDst;
}

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifdef ABC_MEMORY_HXX

<commit_msg>Remove unused abc::memory::noop_deleter<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2010, 2011, 2012, 2013, 2014
Raffaello D. Di Napoli

This file is part of Application-Building Components (henceforth referred to as ABC).

ABC is free software: you can redistribute it and/or modify it under the terms of the GNU General
Public License as published by the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.

ABC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.

You should have received a copy of the GNU General Public License along with ABC. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef ABC_MEMORY_HXX
#define ABC_MEMORY_HXX

#include <abc/core.hxx>
#ifdef ABC_CXX_PRAGMA_ONCE
   #pragma once
#endif

#include <abc/exception.hxx>

#if ABC_HOST_API_POSIX

   #include <stdlib.h> // free() malloc() realloc()
   #include <memory.h> // memcpy() memmove() memset()

#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX

   // Clean up pollution caused by previous headers.
   extern "C" {

   // Rtl*Memory*

   #undef RtlZeroMemory
   WINBASEAPI void WINAPI RtlZeroMemory(void UNALIGNED * pDst, size_t cb);

   #undef RtlFillMemory
   WINBASEAPI void WINAPI RtlFillMemory(void UNALIGNED * pDst, size_t cb, UCHAR iValue);

   #undef RtlFillMemoryUlong
   WINBASEAPI void WINAPI RtlFillMemoryUlong(void * pDst, size_t cb, ULONG iValue);

   #undef RtlFillMemoryUlonglong
   WINBASEAPI void WINAPI RtlFillMemoryUlonglong(void * pDst, size_t cb, ULONGLONG iValue);

   #undef RtlCopyMemory
   WINBASEAPI void WINAPI RtlCopyMemory(
      void UNALIGNED * pDst, void UNALIGNED const * pSrc, size_t cb
   );

   #undef RtlMoveMemory
   WINBASEAPI void WINAPI RtlMoveMemory(
      void UNALIGNED * pDst, void UNALIGNED const * pSrc, size_t cb
   );

   } //extern "C"

#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32

/** TODO: comment or remove.
*/
#if ABC_HOST_GCC
   #define _abc_alloca(cb) \
      __builtin_alloca((cb))
#elif ABC_HOST_MSC
   extern "C" void * ABC_STL_CALLCONV _alloca(size_t cb);
   #define _abc_alloca(cb) \
      _alloca(cb)
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// :: globals - standard new/delete operators

#if ABC_HOST_MSC
   #pragma warning(push)
   // “'operator': exception specification does not match previous declaration”
   #pragma warning(disable: 4986)
#endif

void * ABC_STL_CALLCONV operator new(size_t cb) ABC_STL_NOEXCEPT_FALSE((std::bad_alloc));
void * ABC_STL_CALLCONV operator new[](size_t cb) ABC_STL_NOEXCEPT_FALSE((std::bad_alloc));
void * ABC_STL_CALLCONV operator new(size_t cb, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();
void * ABC_STL_CALLCONV operator new[](size_t cb, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();

void ABC_STL_CALLCONV operator delete(void * p) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete[](void * p) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete(void * p, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();
void ABC_STL_CALLCONV operator delete[](void * p, std::nothrow_t const &) ABC_STL_NOEXCEPT_TRUE();

#if ABC_HOST_MSC
   #pragma warning(pop)
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory::deleter

namespace abc {

namespace memory {

// Forward declaration.
template <typename T>
void free(T * pt);

/** Deleter that deallocates memory using memory::free().
*/
template <typename T>
struct deleter {

   /** Deallocates the specified memory block.

   pt
      Pointer to the object to delete.
   */
   void operator()(T * pt) const {
      free(pt);
   }
};

// Specialization for arrays.
template <typename T>
struct deleter<T[]> :
   public deleter<T> {

   /** Deallocates the specified array. See also deleter<T>::operator()().

   pt
      Pointer to the array to deallocate.
   */
   void operator()(T * pt) const {
      free(pt);
   }
};

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory::conditional_deleter

namespace abc {

namespace memory {

/** Wrapper that invokes a deleter if and only if a set condition is true.
*/
template <typename T, typename TDeleter = std::default_delete<T>>
class conditional_deleter :
   public TDeleter {
public:

   /** Constructor.

   bDelete
      If true, the deleter will delete objects when invoked; if false, it will do nothing.
   */
   conditional_deleter(bool bDelete) :
      TDeleter(),
      m_bDelete(bDelete) {
   }

   /** Deletes the specified object if the condition set in the constructor was true.

   pt
      Pointer to the object to delete.
   */
   void operator()(T * pt) const {
      if (m_bDelete) {
         TDeleter::operator()(pt);
      }
   }

protected:

   bool m_bDelete;
};

// Specialization for arrays.
template <typename T, typename TDeleter>
class conditional_deleter<T[], TDeleter> :
   public conditional_deleter<T, TDeleter> {
public:

   /** See conditional_deleter<T>::conditional_deleter().
   */
   conditional_deleter(bool bDelete) :
      conditional_deleter<T, TDeleter>(bDelete) {
   }

   /** Deletes the specified array if the condition set in the constructor was true. See also
   conditional_deleter<T, TDeleter>::operator()().

   pt
      Pointer to the array to delete.
   */
   void operator()(T * pt) const {
      if (this->m_bDelete) {
         TDeleter::operator()(pt);
      }
   }
};

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory globals - management

namespace abc {

namespace memory {

/** Allows to use the keyword auto to declare std::unique_ptr objects that use memory::deleter.

TODO: comment signature.
*/
template <typename T>
inline std::unique_ptr<T, deleter<T>> make_unique_ptr(T * pt = nullptr) {
   return std::unique_ptr<T, deleter<T>>(pt);
}

/** Requests the dynamic allocation of a memory block of the specified number of bytes.

TODO: comment signature.
*/
inline void * _raw_alloc(size_t cb) {
   void * p(::malloc(cb));
   if (!p) {
      ABC_THROW(memory_allocation_error, ());
   }
   return p;
}

/** Resizes a dynamically allocated memory block.

TODO: comment signature.
*/
inline void * _raw_realloc(void * p, size_t cb) {
   p = ::realloc(p, cb);
   if (!p) {
      ABC_THROW(memory_allocation_error, ());
   }
   return p;
}

/** Requests the dynamic allocation of a memory block large enough to contain c objects of type T,
plus an additional cbExtra bytes. With specialization that ignores types (void) and allocates the
specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline std::unique_ptr<T, deleter<T>> alloc(size_t c = 1, size_t cbExtra = 0) {
   return make_unique_ptr<T>(static_cast<T *>(_raw_alloc(sizeof(T) * c + cbExtra)));
}
template <>
inline std::unique_ptr<void, deleter<void>> alloc(size_t cb /*= 1*/, size_t cbExtra /*= 0*/) {
   return make_unique_ptr<void>(_raw_alloc(cb + cbExtra));
}

/** Releases a block of dynamically allocated memory.

TODO: comment signature.
*/
template <typename T>
inline void free(T * pt) {
   ::free(pt);
}

/** Changes the size of a block of dynamically allocated memory. Both overloads have a
specialization that ignores pointer types (void), and allocates the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * realloc(T * pt, size_t c, size_t cbExtra = 0) {
   return static_cast<T *>(_raw_realloc(pt, sizeof(T) * c + cbExtra));
}
template <>
inline void * realloc(void * p, size_t cb, size_t cbExtra /*= 0*/) {
   return _raw_realloc(p, cb + cbExtra);
}
template <typename T>
inline void realloc(std::unique_ptr<T, deleter<T>> * ppt, size_t c, size_t cbExtra = 0) {
   T * pt(static_cast<T *>(_raw_realloc(ppt->get(), sizeof(T) * c + cbExtra)));
   ppt->release();
   ppt->reset(pt);
}
template <>
inline void realloc(std::unique_ptr<void, deleter<void>> * pp, size_t cb, size_t cbExtra /*= 0*/) {
   void * p(_raw_realloc(pp->get(), cb + cbExtra));
   pp->release();
   pp->reset(p);
}

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::memory globals - manipulation

namespace abc {

namespace memory {

/** Sets to the value 0 every item in an array.

TODO: comment signature.
*/
template <typename T>
inline T * clear(T * ptDst, size_t c = 1) {
   return static_cast<T *>(clear<void>(ptDst, sizeof(T) * c));
}
template <>
inline void * clear(void * pDst, size_t cb /*= 1*/) {
#if ABC_HOST_API_POSIX
   ::memset(pDst, 0, cb);
#elif ABC_HOST_API_WIN32
   ::RtlZeroMemory(pDst, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies memory, by number of items. With specialization that ignores pointer types (void), and
copies the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * copy(T * ptDst, T const * ptSrc) {
   // Optimization: if the copy can be made by mem-reg-mem transfers, avoid calling a function, so
   // that the compiler can inline the copy.
   switch (sizeof(T)) {
      case sizeof(int8_t):
         *reinterpret_cast<int8_t *>(ptDst) = *reinterpret_cast<int8_t const *>(ptSrc);
         break;
      case sizeof(int16_t):
         *reinterpret_cast<int16_t *>(ptDst) = *reinterpret_cast<int16_t const *>(ptSrc);
         break;
      case sizeof(int32_t):
         *reinterpret_cast<int32_t *>(ptDst) = *reinterpret_cast<int32_t const *>(ptSrc);
         break;
      case sizeof(int64_t):
         *reinterpret_cast<int64_t *>(ptDst) = *reinterpret_cast<int64_t const *>(ptSrc);
         break;
      default:
         copy<void>(ptDst, ptSrc, sizeof(T));
         break;
   }
   return static_cast<T *>(ptDst);
}
// Nobody should want to use this, but it’s here for consistency.
template <>
inline void * copy(void * pDst, void const * pSrc) {
   *reinterpret_cast<int8_t *>(pDst) = *reinterpret_cast<int8_t const *>(pSrc);
   return pDst;
}
template <typename T>
inline T * copy(T * ptDst, T const * ptSrc, size_t c) {
   return static_cast<T *>(copy<void>(ptDst, ptSrc, sizeof(T) * c));
}
template <>
inline void * copy(void * pDst, void const * pSrc, size_t cb) {
#if ABC_HOST_API_POSIX
   ::memcpy(pDst, pSrc, cb);
#elif ABC_HOST_API_WIN32
   ::RtlMoveMemory(pDst, pSrc, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies possibly overlapping memory, by number of items. With specialization that ignores pointer
types (void), and copies the specified number of bytes.

TODO: comment signature.
*/
template <typename T>
inline T * move(T * ptDst, T const * ptSrc, size_t c) {
   return static_cast<T *>(move<void>(ptDst, ptSrc, sizeof(T) * c));
}
template <>
inline void * move(void * pDst, void const * pSrc, size_t cb) {
#if ABC_HOST_API_POSIX
   ::memmove(pDst, pSrc, cb);
#elif ABC_HOST_API_WIN32
   ::RtlMoveMemory(pDst, pSrc, cb);
#else
   #error TODO-PORT: HOST_API
#endif
   return pDst;
}

/** Copies a value over each item of a static array.

TODO: comment signature.
*/
template <typename T>
inline T * set(T * ptDst, T const & tValue, size_t c) {
   switch (sizeof(T)) {
#if ABC_HOST_API_POSIX
      case sizeof(int8_t):
         ::memset(ptDst, tValue, c);
         break;
#elif ABC_HOST_API_WIN32
      case sizeof(UCHAR):
         ::RtlFillMemory(ptDst, c, tValue);
         break;
#endif
      default:
         for (T const * ptDstMax(ptDst + c); ptDst < ptDstMax; ++ptDst) {
            copy(ptDst, &tValue);
         }
         break;
   }
   return ptDst;
}

} //namespace memory

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////

#endif //ifdef ABC_MEMORY_HXX

<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <limits>
#include <algorithm>

using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

/*void splitSpaces(char* argument, char **pendingArgs, int pos){
    string temp(argument);
    int count = 1; //used for debugging
    for(unsigned int i = 0; i < temp.size(); ++i){
        if(temp.at(i) == ' '){
            int j = i;
            while(temp.at(j) == ' '){
                j++;
            }
            string part1 = temp.substr(0, i);
            cout << "PART" << count << ": "  << part1 << endl;
            pendingArgs[pos] = const_cast<char*>(part1.c_str());
            string part2 = temp.substr(j, temp.size());
            pos = pos + 1;
            count = count + 1;
            cout << "PART" << count << ": " << part2  << endl;
            pendingArgs[pos] = const_cast<char*>(part2.c_str());
            return;
        }
    }
}*/

void splitSpaces(char* argument, char **pendingArgs, int pos){
    string temp(argument);
    string first_word, second_word;

    for(unsigned int i = 0; i < temp.size(); ++i){
        if( !(isspace(temp.at(i))) && (second_word.size() == 0) ){
            first_word += temp.at(i);
        }
        else if( (isspace(temp.at(i)))){
            if( !(isspace(temp.at(i+1))) ){
                second_word += temp.at(i+1);
                ++i;
            }
        }
        else if( !(isspace(temp.at(i))) ){
            second_word += temp.at(i);
        }
    }

    cout << "THE FIRST PIECE: " << first_word << endl;
    pendingArgs[pos] = const_cast<char*>(first_word.c_str());

    pos++;

    cout << "THE SECOND PIECE: " << second_word << endl;
    pendingArgs[pos] = const_cast<char*>(second_word.c_str());

    pos++;
    pendingArgs[pos] = NULL; //YOUR ARGUMENT ARRAY MUST END IN A NULL PTR
    return;
}

int executeCommand(char **args){
    int pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        if(-1 == execvp(args[0], args)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(-1 == wait(0)){
            perror("There was an error with wait()");
        }
    }

    return 0; //if everything goes well, return 0
}

int extractCommands(string &commandLine, char **cmds){
    const char* args = commandLine.c_str(); //the user input is converted to a const char* as we need it for execvp
    char* args_Mutatable = const_cast<char*>(args); //it needs to be mutable for us to tokenize it
    char *single_command;
    single_command = strtok(args_Mutatable, ";&|"); //execute strtok with delimeters

    int numOfArgs = 0; //when you add one --> argv[1]

    while(single_command != NULL){
        //cout << single_command << endl;
        cmds[numOfArgs] = strdup(single_command); //this processes each command into the command array for execution
        cout << "at position " << numOfArgs << ": " << cmds[numOfArgs];
        cout << endl;
        single_command = strtok(NULL, ";&|");
        numOfArgs++;
    }

    cmds[numOfArgs] = NULL;
    return numOfArgs;
}

vector<string>  extractConnectors(string inputLine){
    vector<string> cnctors;
    for(unsigned int i = 0; i < inputLine.size(); ++i){
        if(inputLine.at(i)  == ';'){
            cnctors.push_back(";");
        }
        if((inputLine.at(i) == '&' && inputLine.at(i+1) == '&')){
            cnctors.push_back("&&");
        }
        if((inputLine.at(i) == '|' && inputLine.at(i+1) == '|')){
            cnctors.push_back("||");
        }
    }
    return cnctors;
}

bool noSpace(char* single){
    string temp(single);
    for(unsigned int i = 0; i < temp.size(); ++i){
        if(temp.at(i) == ' '){
            return false;
        }
    }

    return true;
}

void run(vector<string> &connectors, char **cmds){
    char *pendingArgs[10000]; //arguments waiting to be executed depending on connector
    if(connectors.size() == 0){
        if(noSpace(cmds[0])){
           pendingArgs[0] = cmds[0];
           pendingArgs[1] = NULL;
           executeCommand(pendingArgs);
           return;
        }
        cout << "PASSES FIRST TEST" << endl;
        splitSpaces(cmds[0], pendingArgs, 0);
        cout << "FIRST ARGUMENT with no multiples: " << pendingArgs[0];
        cout << endl;
        executeCommand(pendingArgs);
        return;
    }
    for(unsigned int i = 0; i < connectors.size(); ++i){
        if(connectors.at(i) == ";"){
            /*cout << "BEFORE: " << cmds[i] << endl;
            pendingArgs[i] = cmds[i];
            cout << "AFTER: " << pendingArgs[i] << endl;
            executeCommand(pendingArgs);*/
            cout << "REACHED3" << endl;
            splitSpaces(cmds[i], pendingArgs, i);
            cout << "REACHED4" << endl;
            cout << "First arg: " << pendingArgs[0];
            cout << "READED5" << endl;
            cout << "Second arg: " << pendingArgs[1];
            executeCommand(pendingArgs);
        }
    }
}

int main(){
    string userInput; //command line in string format
    char *cmds[10000];
    do{
        displayPrompt(); //displays current user and hostname

        getline(cin, userInput); //get's input from user and stores it in a string

        /*gets all the delimeters and stores into a vector*/
        vector<string> connectors = extractConnectors(userInput);
        cout << "CONNECTORS: ";
        for(unsigned i = 0; i < connectors.size(); ++i){
            cout << connectors.at(i) << ' ';
        }
        cout << endl;

        //cout << userInput << endl; //NEED TO DELETE UPON COMPLETETION

        int numArgs = extractCommands(userInput, cmds); //retrieve number of arguments by parsing the string

        if(numArgs <= 0){continue;} //if there are no arguments, simply continue to the next iteration

        /*checks if first argument is exit and quits iff it's the only argument*/
        if( (strcmp(cmds[0], "exit") == 0) && (numArgs == 1) ) { break; }

        run(connectors, cmds);

        /*if(executeCommand(cmds) != 0){
            cout << "Error in executing commands" << endl;
        }*/

    }while(1);

    return 0;
}
<commit_msg>go back to this if you mess up<commit_after>#include <iostream>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <limits>
#include <algorithm>

using namespace std;

void displayPrompt(){
    char *user = getlogin(); //I assign the login name to a user pointer
    if(user == NULL){
        perror("getlogin");
        exit(1);
    }

    char hostname[100]; //I allocate space for the hostname
    if(gethostname(hostname, sizeof(hostname)) == -1){ //checking for errors withostname
        perror("gethostname");
        exit(1);
    }

    cout << user << '@' << hostname << '$' << ' '; //here I output the user and hostanme to the screen.

}

/*void splitSpaces(char* argument, char **pendingArgs, int pos){
    string temp(argument);
    string first_word, second_word;

    for(unsigned int i = 0; i < temp.size(); ++i){
        if( !(isspace(temp.at(i))) && (second_word.size() == 0) ){
            first_word += temp.at(i);
        }
        else if( (isspace(temp.at(i)))){
            if( !(isspace(temp.at(i+1))) ){
                second_word += temp.at(i+1);
                ++i;
            }
        }
        else if( !(isspace(temp.at(i))) ){
            second_word += temp.at(i);
        }
    }

    cout << "THE FIRST PIECE: " << first_word << endl;
    pendingArgs[pos] = const_cast<char*>(first_word.c_str());

    pos++;

    cout << "THE SECOND PIECE: " << second_word << endl;
    pendingArgs[pos] = const_cast<char*>(second_word.c_str());

    pos++;
    pendingArgs[pos] = NULL; //YOUR ARGUMENT ARRAY MUST END IN A NULL PTR
    return;
}*/

void splitSpaces(char* argument, char **pendingArgs, int pos){
    char *token = strtok(argument, " ");
    while(token != NULL){
        cout << token << endl;
        token = strtok(NULL, " ");

        pendingArgs[pos] = token;
        pos++;

    }

    pendingArgs[pos] = NULL;
    cout << "position: " << pos << endl;
    cout << "arguments: " << pendingArgs[0] << ' ' << pendingArgs[1] << ' ' << pendingArgs[2];
    return;
}

int executeCommand(char **pendingArgs){
    int  pid = fork();

    if(pid == -1){
        perror("There was some error with fork()");
        exit(1);
    }
    else if(pid == 0){
        if(-1 == execvp(pendingArgs[0], pendingArgs)){
            perror("There was an error with execvp");
            exit(1);
        }
    }
    else if(pid > 0){
        if(wait(0) == -1){
            perror("There was some error with wait");
            exit(1);
        }
    }

    return 0; //if everything goes well, return 0
}

int extractCommands(string &commandLine, char **cmds){
    const char* args = commandLine.c_str(); //the user input is converted to a const char* as we need it for execvp
    char* args_Mutatable = const_cast<char*>(args); //it needs to be mutable for us to tokenize it
    char *single_command;
    single_command = strtok(args_Mutatable, ";&|"); //execute strtok with delimeters

    int numOfArgs = 0; //when you add one --> argv[1]

    while(single_command != NULL){
        //cout << single_command << endl;
        cmds[numOfArgs] = strdup(single_command); //this processes each command into the command array for execution
        cout << "at position " << numOfArgs << ": " << cmds[numOfArgs];
        cout << endl;
        single_command = strtok(NULL, ";&|");
        numOfArgs++;
    }

    cmds[numOfArgs] = NULL;
    return numOfArgs;
}

vector<string>  extractConnectors(string inputLine){
    vector<string> cnctors;
    for(unsigned int i = 0; i < inputLine.size(); ++i){
        if(inputLine.at(i)  == ';'){
            cnctors.push_back(";");
        }
        if((inputLine.at(i) == '&' && inputLine.at(i+1) == '&')){
            cnctors.push_back("&&");
        }
        if((inputLine.at(i) == '|' && inputLine.at(i+1) == '|')){
            cnctors.push_back("||");
        }
    }
    return cnctors;
}

bool noSpace(char* single){
    string temp(single);
    for(unsigned int i = 0; i < temp.size(); ++i){
        if(temp.at(i) == ' '){
            return false;
        }
    }

    return true;
}

void run(vector<string> &connectors, char **cmds){
    char *pendingArgs[10000]; //arguments waiting to be executed depending on connector
    if(connectors.size() == 0){
        if(noSpace(cmds[0])){
           pendingArgs[0] = cmds[0];
           pendingArgs[1] = NULL;
           executeCommand(pendingArgs);
           return;
        }
        else if(connectors.size() == 0 && sizeof(cmds[0]) >= 2){
            cout << "PASSES FIRST TEST" << endl;
            splitSpaces(cmds[0], pendingArgs, 0);
            executeCommand(pendingArgs);
            return;
        }
    }
    /*for(unsigned int i = 0; i < connectors.size(); ++i){
        if(connectors.at(i) == ";"){
            cout << "BEFORE: " << cmds[i] << endl;
            pendingArgs[i] = cmds[i];
            cout << "AFTER: " << pendingArgs[i] << endl;
            executeCommand(pendingArgs);
            cout << "REACHED3" << endl;
            splitSpaces(cmds[i], pendingArgs, i);
            cout << "REACHED4" << endl;
            cout << "First arg: " << pendingArgs[0];
            cout << "READED5" << endl;
            cout << "Second arg: " << pendingArgs[1];
            executeCommand(pendingArgs);
        }
    }*/
}

int main(){
    string userInput; //command line in string format
    char *cmds[10000];
    do{
        displayPrompt(); //displays current user and hostname

        getline(cin, userInput); //get's input from user and stores it in a string

        /*gets all the delimeters and stores into a vector*/
        vector<string> connectors = extractConnectors(userInput);
        cout << "CONNECTORS: ";
        for(unsigned i = 0; i < connectors.size(); ++i){
            cout << connectors.at(i) << ' ';
        }
        cout << endl;

        //cout << userInput << endl; //NEED TO DELETE UPON COMPLETETION

        int numArgs = extractCommands(userInput, cmds); //retrieve number of arguments by parsing the string

        if(numArgs <= 0){continue;} //if there are no arguments, simply continue to the next iteration

        /*checks if first argument is exit and quits iff it's the only argument*/
        if( (strcmp(cmds[0], "exit") == 0) && (numArgs == 1) ) { break; }

        run(connectors, cmds);

        /*if(executeCommand(cmds) != 0){
            cout << "Error in executing commands" << endl;
        }*/

    }while(1);

    return 0;
}
<|endoftext|>


<commit_before>/*
 * Menu
 *
 * Copyright (C)2016 Laurentiu Badea
 *
 * This file may be redistributed under the terms of the MIT license.
 * A copy of this license has been included with this distribution in the file LICENSE.
 */
#include <EEPROM.h>
#include "menu.h"

#define BLACK 0
#define WHITE 1
#define INVERSE 2

/*
 * Class hierarchy
 * BaseMenu
 *     ActionItem
 *     MultiSelect
 *           RangeSelector
 *           ListSelector
 *                NamedListSelector
 *           Menu
 */

/*
 * BaseMenu: shared functionality
 */
BaseMenu::BaseMenu(const char *description, int(*onselect)(int))
:onselect(onselect),
 description(description)
{
};

void BaseMenu::cancel(void){
}

void BaseMenu::select(void){
    if (onselect){
        onselect(0);
    }
}

void BaseMenu::sync(void){
}

int BaseMenu::render(DISPLAY_DEVICE display, int rows){
    Serial.println(description);
    Serial.println("---------------------");
    display.println(description); rows--;
    if (rows > 4){
        display.print("---------------------"); rows--;
    }
    return rows;
}

ActionItem::ActionItem(const char *description, int(*onselect)(int))
:BaseMenu(description, onselect)
{
};

/*
 * MultiSelect: share functionality among the other menu classes
 */
MultiSelect::MultiSelect(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int))
:BaseMenu(description, onselect),
 value(value),
 default_val(default_val),
 eeprom(eeprom)
{
    // override default with eeprom value, if set
    if (eeprom){
        EEPROM.get(eeprom, this->default_val);
    }
    if (this->default_val <= 0){
        this->default_val = default_val;
    }
    if (value){
        *value = this->default_val;
    }
}

void MultiSelect::cancel(void){
    //pointer = pos;
    active = false;
}

void MultiSelect::next(void){
    if (pointer < count-1){
        pointer++;
    }
}
void MultiSelect::prev(void){
    if (pointer > 0){
        pointer--;
    }
}
void MultiSelect::select(void){
    pos = pointer;
    MultiSelect::sync();
    if (onselect){
        onselect(*value);
    }
}
void MultiSelect::sync(void){
    if (eeprom){
        EEPROM.put(eeprom, *value);
    }
}

int MultiSelect::calc_start(int rows){
    int start = 0;
    if (count > rows && pointer > rows/2){
        if (pointer < count - rows/2){
            start = pointer - rows/2;
        } else {
            start = count - rows;
        }
    }
    return start;
}

int MultiSelect::render(DISPLAY_DEVICE display, int rows){
    active = true;
    return BaseMenu::render(display, rows);
}

/*
 * RangeSelector: a number with up/down controls
 */
RangeSelector::RangeSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                             int min_val, int max_val, int step)
:MultiSelect(description, value, default_val, eeprom, onselect),
 min_val(min_val), max_val(max_val), step(step)
{
    pointer = this->default_val;
    pos = pointer;
};

void RangeSelector::next(void){
    if (pointer > min_val){
        pointer -= step;
    }
}
void RangeSelector::prev(void){
    if (pointer < max_val){
        pointer += step;
    }
}
void RangeSelector::select(void){
    *value = pointer;
    MultiSelect::select();
    cancel();
}
void RangeSelector::sync(void){
    pointer = *value % step;
    if (pointer > max_val) pointer = max_val;
    if (pointer < min_val) pointer = min_val;
    pos = pointer;
    MultiSelect::sync();
}

int RangeSelector::render(DISPLAY_DEVICE display, int rows){
    const char *marker;
    rows = MultiSelect::render(display, rows);

    marker = (pointer < max_val) ? " \x1e": "";
    display.println(marker); rows--;

    if (pointer == pos) display.setTextColor(BLACK, WHITE);

    Serial.println(pointer);
    display.println(pointer); rows--;

    if (pointer == pos) display.setTextColor(WHITE, BLACK);

    marker = (pointer > min_val) ? " \x1f": "";
    display.println(marker); rows--;
    return rows;
}

/*
 * ListSelector: list of numeric options
 */
ListSelector::ListSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                           int count, const int values[])
:MultiSelect(description, value, default_val, eeprom, onselect),
 values(values)
{
    this->count = count;
    // find the position corresponding to the default value
    for (pos=count-1; pos > 0; pos--){
        if (values[pos] == this->default_val){
            break;
        }
    }
    pointer = pos;
};

void ListSelector::select(void){
    *value = values[pointer];
    MultiSelect::select();
    cancel();
}
void ListSelector::sync(void){
    // find the position corresponding to the default value
    for (pos=count-1; pos > 0; pos--){
        if (values[pos] == *value){
            break;
        }
    }
    pointer = pos;
    MultiSelect::sync();
}

int ListSelector::render(DISPLAY_DEVICE display, int rows){
    char buf[16];
    int start;

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        snprintf(buf, sizeof(buf), "%d", values[i]);

        Serial.print((i==pointer) ? ">" : " ");
        display.print((i==pointer) ? '\x10' : ' ');

        if (i == pos) display.setTextColor(BLACK, WHITE);
        Serial.println(buf);
        display.print(buf);
        if (i == pos) display.setTextColor(WHITE, BLACK);

        display.println((i==pointer) ? '\x11' : ' ');
    }
    return 0;
}

/*
 * NamedListSelector: list of named numeric options
 */
NamedListSelector::NamedListSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                                     int count, const char * const names[], const int values[])
:ListSelector(description, value, default_val, eeprom, onselect, count, values),
 names(names)
{
}

int NamedListSelector::render(DISPLAY_DEVICE display, int rows){
    int start;

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        Serial.print((i==pointer) ? ">" : " ");
        display.print((i==pointer) ? '\x10' : ' ');

        if (i == pos) display.setTextColor(BLACK, WHITE);
        Serial.println(names[i]);
        display.print(names[i]);
        if (i == pos) display.setTextColor(WHITE, BLACK);

        display.println((i==pointer) ? '\x11' : ' ');
    }
    return 0;
}

/*
 * Menu: this is regular navigation menu, nothing is set here
 * but all events are passed down to active children
 */
Menu::Menu(const char *description, int count, BaseMenu* const *menus)
:MultiSelect(description, NULL, 0, 0, NULL),
 menus(menus)
{
    pos = 0;
    this->count = count;
    active_submenu = NULL;
}

/*
 * CANCEL action, should go back one level
 */
void Menu::cancel(void){
    if (active_submenu){         // passthrough
        active_submenu->cancel();
        // check if submenu is still active,
        // as the cancel action may have propagated more than one level
        if (active_submenu->getClassID() != Menu::class_id || !active_submenu->active){
            active_submenu = NULL;
        }
    } else {
        // not resetting pos via MultiSelect::cancel() allows us to return to same menu position
        MultiSelect::cancel();
    }
}

/*
 * Move selector to next item in list
 */
void Menu::next(void){
    if (active_submenu){         // passthrough
        active_submenu->next();
    } else {
        MultiSelect::next();
    }
}

/*
 * Move selector to previous item in list
 */
void Menu::prev(void){
    if (active_submenu){         // passthrough
        active_submenu->prev();
    } else {
        MultiSelect::prev();
    }
}

/*
 * Open the currently selected item
 * which can be a submenu, a selection list or action
 */
void Menu::select(void){
    if (active_submenu){        // passthrough
        active_submenu->select();
        if (!active_submenu->active){
            active_submenu = NULL;
        }
    } else {
        MultiSelect::select();
        if (menus[pos]->getClassID() != ActionItem::class_id){
            active_submenu = (MultiSelect*)menus[pos];
        } else {
            menus[pos]->select();
        }
    }
}

/*
 * cascade sync (write all current settings to EEPROM)
 */
void Menu::sync(void){
    for (int i=0; i<count; i++){
        menus[i]->sync();
    }
}

/*
 * Display either the menu or active submenu/selection
 */
int Menu::render(DISPLAY_DEVICE display, int rows){
    int start;

    if (active_submenu){        // passthrough
        rows = active_submenu->render(display, rows);
        return rows;
    }

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        if (i == pointer){
            Serial.print(">");
            display.setTextColor(BLACK, WHITE);
        }
        Serial.println(menus[i]->description);
        display.println(menus[i]->description);
        if (i == pointer){
            display.setTextColor(WHITE, BLACK);
        }
    }
    return 0;
}
<commit_msg>Quiet gcc warning: implicit dereference<commit_after>/*
 * Menu
 *
 * Copyright (C)2016 Laurentiu Badea
 *
 * This file may be redistributed under the terms of the MIT license.
 * A copy of this license has been included with this distribution in the file LICENSE.
 */
#include <EEPROM.h>
#include "menu.h"

#define BLACK 0
#define WHITE 1
#define INVERSE 2

/*
 * Class hierarchy
 * BaseMenu
 *     ActionItem
 *     MultiSelect
 *           RangeSelector
 *           ListSelector
 *                NamedListSelector
 *           Menu
 */

/*
 * BaseMenu: shared functionality
 */
BaseMenu::BaseMenu(const char *description, int(*onselect)(int))
:onselect(onselect),
 description(description)
{
};

void BaseMenu::cancel(void){
}

void BaseMenu::select(void){
    if (onselect){
        onselect(0);
    }
}

void BaseMenu::sync(void){
}

int BaseMenu::render(DISPLAY_DEVICE display, int rows){
    Serial.println(description);
    Serial.println("---------------------");
    display.println(description); rows--;
    if (rows > 4){
        display.print("---------------------"); rows--;
    }
    return rows;
}

ActionItem::ActionItem(const char *description, int(*onselect)(int))
:BaseMenu(description, onselect)
{
};

/*
 * MultiSelect: share functionality among the other menu classes
 */
MultiSelect::MultiSelect(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int))
:BaseMenu(description, onselect),
 value(value),
 default_val(default_val),
 eeprom(eeprom)
{
    // override default with eeprom value, if set
    if (eeprom){
        EEPROM.get(eeprom, this->default_val);
    }
    if (this->default_val <= 0){
        this->default_val = default_val;
    }
    if (value){
        *value = this->default_val;
    }
}

void MultiSelect::cancel(void){
    //pointer = pos;
    active = false;
}

void MultiSelect::next(void){
    if (pointer < count-1){
        pointer++;
    }
}
void MultiSelect::prev(void){
    if (pointer > 0){
        pointer--;
    }
}
void MultiSelect::select(void){
    pos = pointer;
    MultiSelect::sync();
    if (onselect){
        onselect(*value);
    }
}
void MultiSelect::sync(void){
    if (eeprom){
        int v = *value;
        EEPROM.put(eeprom, v);
    }
}

int MultiSelect::calc_start(int rows){
    int start = 0;
    if (count > rows && pointer > rows/2){
        if (pointer < count - rows/2){
            start = pointer - rows/2;
        } else {
            start = count - rows;
        }
    }
    return start;
}

int MultiSelect::render(DISPLAY_DEVICE display, int rows){
    active = true;
    return BaseMenu::render(display, rows);
}

/*
 * RangeSelector: a number with up/down controls
 */
RangeSelector::RangeSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                             int min_val, int max_val, int step)
:MultiSelect(description, value, default_val, eeprom, onselect),
 min_val(min_val), max_val(max_val), step(step)
{
    pointer = this->default_val;
    pos = pointer;
};

void RangeSelector::next(void){
    if (pointer > min_val){
        pointer -= step;
    }
}
void RangeSelector::prev(void){
    if (pointer < max_val){
        pointer += step;
    }
}
void RangeSelector::select(void){
    *value = pointer;
    MultiSelect::select();
    cancel();
}
void RangeSelector::sync(void){
    pointer = *value % step;
    if (pointer > max_val) pointer = max_val;
    if (pointer < min_val) pointer = min_val;
    pos = pointer;
    MultiSelect::sync();
}

int RangeSelector::render(DISPLAY_DEVICE display, int rows){
    const char *marker;
    rows = MultiSelect::render(display, rows);

    marker = (pointer < max_val) ? " \x1e": "";
    display.println(marker); rows--;

    if (pointer == pos) display.setTextColor(BLACK, WHITE);

    Serial.println(pointer);
    display.println(pointer); rows--;

    if (pointer == pos) display.setTextColor(WHITE, BLACK);

    marker = (pointer > min_val) ? " \x1f": "";
    display.println(marker); rows--;
    return rows;
}

/*
 * ListSelector: list of numeric options
 */
ListSelector::ListSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                           int count, const int values[])
:MultiSelect(description, value, default_val, eeprom, onselect),
 values(values)
{
    this->count = count;
    // find the position corresponding to the default value
    for (pos=count-1; pos > 0; pos--){
        if (values[pos] == this->default_val){
            break;
        }
    }
    pointer = pos;
};

void ListSelector::select(void){
    *value = values[pointer];
    MultiSelect::select();
    cancel();
}
void ListSelector::sync(void){
    // find the position corresponding to the default value
    for (pos=count-1; pos > 0; pos--){
        if (values[pos] == *value){
            break;
        }
    }
    pointer = pos;
    MultiSelect::sync();
}

int ListSelector::render(DISPLAY_DEVICE display, int rows){
    char buf[16];
    int start;

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        snprintf(buf, sizeof(buf), "%d", values[i]);

        Serial.print((i==pointer) ? ">" : " ");
        display.print((i==pointer) ? '\x10' : ' ');

        if (i == pos) display.setTextColor(BLACK, WHITE);
        Serial.println(buf);
        display.print(buf);
        if (i == pos) display.setTextColor(WHITE, BLACK);

        display.println((i==pointer) ? '\x11' : ' ');
    }
    return 0;
}

/*
 * NamedListSelector: list of named numeric options
 */
NamedListSelector::NamedListSelector(const char *description, volatile int *value, int default_val, int eeprom, int(*onselect)(int),
                                     int count, const char * const names[], const int values[])
:ListSelector(description, value, default_val, eeprom, onselect, count, values),
 names(names)
{
}

int NamedListSelector::render(DISPLAY_DEVICE display, int rows){
    int start;

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        Serial.print((i==pointer) ? ">" : " ");
        display.print((i==pointer) ? '\x10' : ' ');

        if (i == pos) display.setTextColor(BLACK, WHITE);
        Serial.println(names[i]);
        display.print(names[i]);
        if (i == pos) display.setTextColor(WHITE, BLACK);

        display.println((i==pointer) ? '\x11' : ' ');
    }
    return 0;
}

/*
 * Menu: this is regular navigation menu, nothing is set here
 * but all events are passed down to active children
 */
Menu::Menu(const char *description, int count, BaseMenu* const *menus)
:MultiSelect(description, NULL, 0, 0, NULL),
 menus(menus)
{
    pos = 0;
    this->count = count;
    active_submenu = NULL;
}

/*
 * CANCEL action, should go back one level
 */
void Menu::cancel(void){
    if (active_submenu){         // passthrough
        active_submenu->cancel();
        // check if submenu is still active,
        // as the cancel action may have propagated more than one level
        if (active_submenu->getClassID() != Menu::class_id || !active_submenu->active){
            active_submenu = NULL;
        }
    } else {
        // not resetting pos via MultiSelect::cancel() allows us to return to same menu position
        MultiSelect::cancel();
    }
}

/*
 * Move selector to next item in list
 */
void Menu::next(void){
    if (active_submenu){         // passthrough
        active_submenu->next();
    } else {
        MultiSelect::next();
    }
}

/*
 * Move selector to previous item in list
 */
void Menu::prev(void){
    if (active_submenu){         // passthrough
        active_submenu->prev();
    } else {
        MultiSelect::prev();
    }
}

/*
 * Open the currently selected item
 * which can be a submenu, a selection list or action
 */
void Menu::select(void){
    if (active_submenu){        // passthrough
        active_submenu->select();
        if (!active_submenu->active){
            active_submenu = NULL;
        }
    } else {
        MultiSelect::select();
        if (menus[pos]->getClassID() != ActionItem::class_id){
            active_submenu = (MultiSelect*)menus[pos];
        } else {
            menus[pos]->select();
        }
    }
}

/*
 * cascade sync (write all current settings to EEPROM)
 */
void Menu::sync(void){
    for (int i=0; i<count; i++){
        menus[i]->sync();
    }
}

/*
 * Display either the menu or active submenu/selection
 */
int Menu::render(DISPLAY_DEVICE display, int rows){
    int start;

    if (active_submenu){        // passthrough
        rows = active_submenu->render(display, rows);
        return rows;
    }

    rows = MultiSelect::render(display, rows);
    start = calc_start(rows);

    for (int i=start; i<start+rows && i<count; i++){
        if (i == pointer){
            Serial.print(">");
            display.setTextColor(BLACK, WHITE);
        }
        Serial.println(menus[i]->description);
        display.println(menus[i]->description);
        if (i == pointer){
            display.setTextColor(WHITE, BLACK);
        }
    }
    return 0;
}
<|endoftext|>


<commit_before>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

// used to test loading jpegs from imagenet etc
// this will take mnist dataset, and generate jpegs, in directories, one
// directory per category, and an appropriate manifest file
// when we read the images, we will assume all images have the same
// dimensions

// note that the labels are part of the manifest, which will have the following
// format:
// # format=deepcl-jpeg-list-v1 planes=1 width=28 height=28 N=10000
// [relative file path]  [category number, zero-based]

#include <iostream>
#include <fstream>

#include "loaders/GenericLoader.h"
#include "util/FileHelper.h"
#include "util/mt19937defs.h"
#include "util/stringhelper.h"
#include "util/JpegHelper.h"

using namespace std;

void run(string mnistImagesFile, string outDirectory, int numExamples) {
    int N, planes, size;
    GenericLoader::getDimensions( mnistImagesFile.c_str(), &N, &planes, &size );
    float *imageData = new float[ N * planes * size * size ];
    int *labels = new int[N];
    GenericLoader::load( mnistImagesFile.c_str(), imageData, labels, 0, numExamples );

    // now we've loaded the data, write it out in deepcl-jpeg-list-v1 format
    // we need to do the following:
    // - create a sub-folder for each category
    // - write each image as a jpeg to this folder
    // - write the manifest

    // creating the folders should be easy enough... I guess... ?
    MT19937 myrandom;
    int inputCubeSize = planes * size * size;
    uchar *ucharValues = new uchar[ inputCubeSize ];
    for( int i = 0; i < 10; i++ ) {
        myrandom.seed((unsigned int)i);
        int thisref = myrandom() % 10000;
        string folderPath = outDirectory + "/R131" + toString( thisref ); // make the name a bit imagenet-like
        if( !FileHelper::folderExists( folderPath ) ) {
            FileHelper::createDirectory( folderPath );
        }
    }
    // write the jpegs
    ofstream manifest(outDirectory + "/manifest.txt");
    manifest << "# format=deepcl-jpeg-list-v1 N=" << numExamples << " planes=" << planes << " width=" << size << " height=" << size << endl;
    for( int n = 0; n < numExamples; n++ ) {
        int label = labels[n];
        myrandom.seed((unsigned int)label);
        int thisref = myrandom() % 10000;
        string folderPath = outDirectory + "/R131" + toString( thisref ); // make the name a bit imagenet-like
        float *inputCube = imageData + n * inputCubeSize;
        for( int j = 0; j < inputCubeSize; j++ ) {
            ucharValues[j] = inputCube[j];
        }
        string filePath = folderPath + "/" + toString( n ) + ".JPEG";
        JpegHelper::write( filePath, planes, size, size, ucharValues );
        manifest << filePath << " " << label << endl;
    }
    manifest.close();

    delete[] ucharValues;
    delete[] labels;
    delete[] imageData;
}

int main( int argc, char *argv[] ) {
    if( argc != 4 ) {
        cout << "Usage: " << argv[0] << " [mnist images file (input)] [output directory] [num examples]" << endl;
        return 1;
    }
    string mnistImagesFile = argv[1];
    string outDirectory = argv[2];
    int numExamples = atoi(argv[3]);
    try {
        run(mnistImagesFile, outDirectory, numExamples);
    } catch(runtime_error e) {
        cout << "something went wrong: " << e.what() << endl;
        return -1;
    }

    return 0;
}

<commit_msg>mnist-to-jpegs no longer uess zero seed (which crashes on winodws)<commit_after>// Copyright Hugh Perkins 2015 hughperkins at gmail
//
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file, You can
// obtain one at http://mozilla.org/MPL/2.0/.

// used to test loading jpegs from imagenet etc
// this will take mnist dataset, and generate jpegs, in directories, one
// directory per category, and an appropriate manifest file
// when we read the images, we will assume all images have the same
// dimensions

// note that the labels are part of the manifest, which will have the following
// format:
// # format=deepcl-jpeg-list-v1 planes=1 width=28 height=28 N=10000
// [relative file path]  [category number, zero-based]

#include <iostream>
#include <fstream>

#include "loaders/GenericLoader.h"
#include "util/FileHelper.h"
#include "util/mt19937defs.h"
#include "util/stringhelper.h"
#include "util/JpegHelper.h"

using namespace std;

void run(string mnistImagesFile, string outDirectory, int numExamples) {
    int N, planes, size;
    GenericLoader::getDimensions( mnistImagesFile.c_str(), &N, &planes, &size );
    float *imageData = new float[ N * planes * size * size ];
    int *labels = new int[N];
    GenericLoader::load( mnistImagesFile.c_str(), imageData, labels, 0, numExamples );

    // now we've loaded the data, write it out in deepcl-jpeg-list-v1 format
    // we need to do the following:
    // - create a sub-folder for each category
    // - write each image as a jpeg to this folder
    // - write the manifest

    // creating the folders should be easy enough... I guess... ?
    MT19937 myrandom;
    int inputCubeSize = planes * size * size;
    uchar *ucharValues = new uchar[ inputCubeSize ];
    for( int i = 0; i < 10; i++ ) {
        myrandom.seed((unsigned int)(i + 1));
        int thisref = myrandom() % 10000;
        string folderPath = outDirectory + "/R131" + toString( thisref ); // make the name a bit imagenet-like
        if( !FileHelper::folderExists( folderPath ) ) {
            FileHelper::createDirectory( folderPath );
        }
    }
    // write the jpegs
    ofstream manifest(outDirectory + "/manifest.txt");
    manifest << "# format=deepcl-jpeg-list-v1 N=" << numExamples << " planes=" << planes << " width=" << size << " height=" << size << endl;
    for( int n = 0; n < numExamples; n++ ) {
        int label = labels[n];
        myrandom.seed((unsigned int)(label + 1));
        int thisref = myrandom() % 10000;
        string folderPath = outDirectory + "/R131" + toString( thisref ); // make the name a bit imagenet-like
        float *inputCube = imageData + n * inputCubeSize;
        for( int j = 0; j < inputCubeSize; j++ ) {
            ucharValues[j] = inputCube[j];
        }
        string filePath = folderPath + "/" + toString( n ) + ".JPEG";
        JpegHelper::write( filePath, planes, size, size, ucharValues );
        manifest << filePath << " " << label << endl;
    }
    manifest.close();

    delete[] ucharValues;
    delete[] labels;
    delete[] imageData;
}

int main( int argc, char *argv[] ) {
    if( argc != 4 ) {
        cout << "Usage: " << argv[0] << " [mnist images file (input)] [output directory] [num examples]" << endl;
        return 1;
    }
    string mnistImagesFile = argv[1];
    string outDirectory = argv[2];
    int numExamples = atoi(argv[3]);
    try {
        run(mnistImagesFile, outDirectory, numExamples);
    } catch(runtime_error e) {
        cout << "something went wrong: " << e.what() << endl;
        return -1;
    }

    return 0;
}

<|endoftext|>


<commit_before>#ifndef WIDGET_HPP
#define WIDGET_HPP

#include <SFML/Window/Window.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Sprite.hpp>

#include "gui/signal.hpp"

namespace qrw
{
    class Widget : public sf::Sprite
    {
        public:
            Widget(sf::Window* window, float width, float height);
            Widget(sf::Window* window, sf::Vector2f size);
            ~Widget();

            void handleEvent(const sf::Event& event);

            void setVisible(bool visibility = true);

            void disconnectAllSignals();

            void setSize(sf::Vector2f size);
            sf::Vector2f getSize() const;

            // Signals
            Signal signalclicked;
            Signal signalmouseentered;
            Signal signalmouseleft;
            Signal signalmousemoved;
            Signal signalleftmousebuttonpressed;

        protected:
            bool hasMouseFocus();
            const sf::Window* window;

        private:
            /**
             * @brief Registeres when left mouse button is pressed.
             *
             * Is set to true if the left mouse button was pressed while mouse cursor was on the widget. If the mouse
             * is released again while on the widget a click event took place. Reset leftMouseButtonpressRegistered if
             * mouse leaves focus.
             */
            bool leftMouseButtonPressRegistered;
            bool mouseFocus;

            bool visible;

            /**
             * Holds size of the widget.
             */
            sf::Vector2f size;
    };
}
#endif
<commit_msg>Added some documentation for Widget::mouseFocus attribute.<commit_after>#ifndef WIDGET_HPP
#define WIDGET_HPP

#include <SFML/Window/Window.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics/Sprite.hpp>

#include "gui/signal.hpp"

namespace qrw
{
    class Widget : public sf::Sprite
    {
        public:
            Widget(sf::Window* window, float width, float height);
            Widget(sf::Window* window, sf::Vector2f size);
            ~Widget();

            void handleEvent(const sf::Event& event);

            void setVisible(bool visibility = true);

            void disconnectAllSignals();

            void setSize(sf::Vector2f size);
            sf::Vector2f getSize() const;

            // Signals
            Signal signalclicked;
            Signal signalmouseentered;
            Signal signalmouseleft;
            Signal signalmousemoved;
            Signal signalleftmousebuttonpressed;

        protected:
            bool hasMouseFocus();
            const sf::Window* window;

        private:
            /**
             * @brief Registeres when left mouse button is pressed.
             *
             * Is set to true if the left mouse button was pressed while mouse cursor was on the widget. If the mouse
             * is released again while on the widget a click event took place. Reset leftMouseButtonpressRegistered if
             * mouse leaves focus.
             */
            bool leftMouseButtonPressRegistered;

            /**
             * @brief Saves the last known mouse focus state.
             *
             * Is used to determine if a signalmouseleft or signalmouseentered signal has to be emitted. It holds the last
             * known mouse focus state which means that in case of mouseFocus followed by hasMouseFocus() == true the mouse
             * cursor entered the widget or other way round left the widget.
             */
            bool mouseFocus;

            bool visible;

            /**
             * Holds size of the widget.
             */
            sf::Vector2f size;
    };
}
#endif
<|endoftext|>


<commit_before>#pragma once

#include <vector>
#include <utility>

namespace helene
{
template <class T, class Allocator = std::allocator<T>>
class handle_map
{
public:
    typedef typename std::vector<T>::size_type size_type;
    typedef typename std::vector<size_type>::size_type handle_type;

public:
    class iterator
    {
    public:
    private:
        std::vector<T>* dense_ref_;
        std::vector<size_type>* sparse_ref_;
        handle_type current_;
    };

    typedef typename std::vector<T>::iterator iterator;
    typedef typename std::vector<T>::const_iterator const_iterator;

public:
    handle_type
    insert(const T& value)
    {
        // always insert at end of dense storage
        dense_.push_back(value);

        handle_type new_handle;
        // find new handle
        if(free_.empty())
        {
            // no free handle slots, push back new slot
            sparse_.push_back(dense_.size() - 1);

            new_handle = sparse_.size() - 1;
        }
        else
        {
            // slot is available for new handle
            new_handle = free_.back();
            sparse_[new_handle] = dense_.size() - 1;
            free_.pop_back();
        }

        reverse_.push_back(new_handle);

        return new_handle;
    }

    void
    erase(handle_type n)
    {
        // find handle of dense's back
        const auto index_of_dense_back = dense_.size() - 1;
        const auto back_handle = reverse_[index_of_dense_back];

        // swap element to erase with back element
        std::swap(dense_[sparse_[n]], dense_.back());
        std::swap(reverse_[n], reverse_[index_of_dense_back]);

        // update handle reference to new dense location
        sparse_[back_handle] = sparse_[n];

        // pop back
        dense_.pop_back();
        reverse_.pop_back();

        // add handle to free list
        free_.push_back(n);
    }

    size_type
    size() const
    {
        return dense_.size();
    }

    T& operator[](handle_type n)
    {
        return dense_[sparse_[n]];
    }

    const T& operator[](handle_type n) const
    {
        return dense_[sparse_[n]];
    }

private:
    std::vector<T> dense_;
    std::vector<size_type> sparse_;
    std::vector<handle_type> reverse_;
    std::vector<handle_type> free_;
};
} // namespace helene
<commit_msg>Add begin, end, cbegin, and cend member functions to handle_map. 	modified:   include/handle_map.hpp<commit_after>#pragma once

#include <vector>
#include <utility>

namespace helene
{
template <class T, class Allocator = std::allocator<T>>
class handle_map
{
public:
    typedef typename std::vector<T>::size_type size_type;
    typedef typename std::vector<size_type>::size_type handle_type;

public:
    typedef typename std::vector<T>::iterator iterator;
    typedef typename std::vector<T>::const_iterator const_iterator;

public:
    handle_type
    insert(const T& value)
    {
        // always insert at end of dense storage
        dense_.push_back(value);

        handle_type new_handle;
        // find new handle
        if(free_.empty())
        {
            // no free handle slots, push back new slot
            sparse_.push_back(dense_.size() - 1);

            new_handle = sparse_.size() - 1;
        }
        else
        {
            // slot is available for new handle
            new_handle = free_.back();
            sparse_[new_handle] = dense_.size() - 1;
            free_.pop_back();
        }

        reverse_.push_back(new_handle);

        return new_handle;
    }

    void
    erase(handle_type n)
    {
        // find handle of dense's back
        const auto index_of_dense_back = dense_.size() - 1;
        const auto back_handle = reverse_[index_of_dense_back];

        // swap element to erase with back element
        std::swap(dense_[sparse_[n]], dense_.back());
        std::swap(reverse_[n], reverse_[index_of_dense_back]);

        // update handle reference to new dense location
        sparse_[back_handle] = sparse_[n];

        // pop back
        dense_.pop_back();
        reverse_.pop_back();

        // add handle to free list
        free_.push_back(n);
    }

    size_type
    size() const
    {
        return dense_.size();
    }

    T& operator[](handle_type n)
    {
        return dense_[sparse_[n]];
    }

    const T& operator[](handle_type n) const
    {
        return dense_[sparse_[n]];
    }

    iterator
    begin()
    {
        return dense_.begin();
    }

    iterator
    end()
    {
        return dense_.end();
    }

    const_iterator
    cbegin() const
    {
        return dense_.cbegin();
    }

    const_iterator
    cend() const
    {
        return dense_.cend();
    }

private:
    std::vector<T> dense_;
    std::vector<size_type> sparse_;
    std::vector<handle_type> reverse_;
    std::vector<handle_type> free_;
};
} // namespace helene
<|endoftext|>