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

#include <cassert>
#include <cstring>
#include <queue>
#include <stack>

#include "fpj.hpp"
#include "uintqueue.hpp"

namespace pg {

FPJSolver::FPJSolver(Oink *oink, Game *game) : Solver(oink, game)
{
}

FPJSolver::~FPJSolver()
{
}

/**
 * Variation 1: greedy justification
 */
void
FPJSolver::runSeqGreedy()
{
    /**
     * Allocate and initialize data structures
     */

    int *strategy = new int[nodecount()]; // the current strategy
    bitset justified(nodecount()); // whether a vertex is justified
    bitset distraction(nodecount()); // whether a vertex is won by the opponent

    bitset parity(nodecount()); // optimization: precompute the parity of every vertex's priority
    for (int v=0; v<nodecount(); v++) parity[v] = priority(v)&1;

    uintqueue Q(nodecount());

    /**
     * Initialize loop
     */

    int cur_parity = parity[0]; // parity of current block
    int i = 0; // the current vertex

    for (;;) {
        /**
         * First detect if we are at the end of a block (vertices of same parity)
         */
        bool blockended = false;
        if (i == nodecount()) {
            blockended = true;
        } else {
            if (disabled[i]) { i++; continue; }
            if (parity[i] != cur_parity) blockended = true;
        }

        if (blockended) {
            if (Q.nonempty()) {
                /**
                 * First set as distraction
                 */
                for (unsigned int n=0; n<Q.size(); n++) distraction[Q[n]] = true;
                /**
                 * We have to reset all justified vertices that are now no longer justified...
                 */
                while (!Q.empty()) {
                    const int v = Q.pop();
                    for (auto curedge = ins(v); *curedge != -1; curedge++) {
                        const int from = *curedge;
                        if (justified[from] and (strategy[from] == -1 or strategy[from] == v)) {
#ifndef NDEBUG
                            if (trace >= 2) logger << "\033[31;1mresetting\033[m " << label_vertex(from) << std::endl;
#endif
                            justified[from] = false;
                            distraction[from] = false; // reset it
                            Q.push(from);
                            if (from < i) i = from; // afterwards, continue at lowest unjustified vertex
                        }
                    }
                }
#ifndef NDEBUG
                if (trace) logger << "restarting after finding distractions of prio " << priority(i-1) << std::endl;
#endif
                iterations++;
            }

            if (i == nodecount()) break; // in case the last block didn't result in unjustifications

            // continue with the new block, update the current parity
            cur_parity = parity[i];
        }

        // if the current vertex is justified, we don't need to check it
        if (justified[i]) { i++; continue; }
        justified[i] = true;

        // compute one step winner of <i> and update the strategy
        int onestep_winner, str = -1;
        if (owner(i) == 0) {
            // see if player Even can go to a vertex currently good for Even
            onestep_winner = 1;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 0) {
                    // good for player Even
                    onestep_winner = 0;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        } else {
            // see if player Odd can go to a vertex currently good for Odd
            onestep_winner = 0;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 1) {
                    // good for player Odd
                    onestep_winner = 1;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        }

        strategy[i] = str;

        // evaluation stays the same
        if (cur_parity != onestep_winner) {
            Q.push(i); // add to Q
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified*\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        } else {
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        }

        i++;
    }

    // done
    for (int v=0; v<nodecount(); v++) {
        if (disabled[v]) continue;
        const int winner = parity[v] ^ distraction[v];
        oink->solve(v, winner, winner == owner(v) ? strategy[v] : -1);
    }

    // free allocated data structures
    delete[] strategy;

    logger << "solved with " << iterations << " iterations." << std::endl;
}

void
FPJSolver::runSeq()
{
    /**
     * Allocate and initialize data structures
     */

    int *strategy = new int[nodecount()]; // the current strategy
    bitset justified(nodecount()); // whether a vertex is justified
    bitset distraction(nodecount()); // whether a vertex is won by the opponent

    bitset parity(nodecount()); // optimization: precompute the parity of every vertex's priority
    for (int v=0; v<nodecount(); v++) parity[v] = priority(v)&1;

    uintqueue Q(nodecount());

    /**
     * Initialize loop
     */

    int cur_parity = parity[0]; // parity of current block
    int i = 0; // the current vertex
    int blockstart = 0; // first vertex of the current block

    for (;;) {
        /**
         * First detect if we are at the end of a block (vertices of same parity)
         */
        bool blockended = false;
        if (i == nodecount()) {
            blockended = true;
        } else {
            if (disabled[i]) { i++; continue; }
            if (parity[i] != cur_parity) blockended = true;
        }

        if (blockended) {
            if (Q.nonempty()) {
                /**
                 * First set as justified and distraction
                 */
                for (unsigned int n=0; n<Q.size(); n++) {
                    const int v = Q[n];
                    justified[v] = true;
                    distraction[v] = true;
#ifndef NDEBUG
                    if (trace >= 2) {
                        logger << "\033[38;5;165;1mjustified*\033[m " << label_vertex(v);
                        if (strategy[v] != -1) logger << " => " << label_vertex(strategy[v]);
                        logger << std::endl;
                    }
#endif
                }
                /**
                 * We have to reset all justified vertices that are now no longer justified...
                 */
                while (!Q.empty()) {
                    const int v = Q.pop();
                    for (auto curedge = ins(v); *curedge != -1; curedge++) {
                        const int from = *curedge;
                        if (justified[from]) {
                            if (strategy[from] == -1 or strategy[from] == v) {
#ifndef NDEBUG
                                if (trace >= 2) logger << "\033[31;1mresetting\033[m " << label_vertex(from) << std::endl;
#endif
                                justified[from] = false; // no longer justified
                                distraction[from] = false; // reset it
                                Q.push(from);
                                if (from < i) i = from; // afterwards, continue at lowest unjustified vertex
                            }
                        }
                    }
                }
#ifndef NDEBUG
                if (trace) logger << "restarting after finding distractions of prio " << priority(i-1) << std::endl;
#endif
                iterations++;
                if (i > blockstart) i = blockstart;
            } else {
                // We now know that the current strategy of all unjustified vertices of the block is justified
                for (int v=blockstart; v<i; v++) {
                    if (!disabled[v] and !justified[v]) {
                        justified[v] = true;
#ifndef NDEBUG
                        if (trace >= 2) {
                            logger << "\033[38;5;165;1mjustified\033[m " << label_vertex(v);
                            if (strategy[v] != -1) logger << " => " << label_vertex(strategy[v]);
                            logger << std::endl;
                        }
#endif
                    }
                }
            }

            if (i == nodecount()) break; // in case the last block didn't result in unjustifications

            // continue with the new block, update the current parity
            cur_parity = parity[i];
            blockstart = i;
        }

        // if the current vertex is justified, we don't need to check it
        if (justified[i]) {
            i++;
            continue;
        }

        // compute one step winner of <i> and update the strategy
        int onestep_winner, str = -1;
        if (owner(i) == 0) {
            // see if player Even can go to a vertex currently good for Even
            onestep_winner = 1;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 0) {
                    // good for player Even
                    onestep_winner = 0;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        } else {
            // see if player Odd can go to a vertex currently good for Odd
            onestep_winner = 0;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 1) {
                    // good for player Odd
                    onestep_winner = 1;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        }

        strategy[i] = str;

        // evaluation stays the same
        if (cur_parity != onestep_winner) {
            Q.push(i); // add to the Queue, because all justified predecessors are now invalid
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified*\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        }

        i++;
    }

    // done
    for (int v=0; v<nodecount(); v++) {
        if (disabled[v]) continue;
        const int winner = parity[v] ^ distraction[v];
        oink->solve(v, winner, winner == owner(v) ? strategy[v] : -1);
    }

    // free allocated data structures
    delete[] strategy;

    logger << "solved with " << iterations << " iterations." << std::endl;
}

void
FPJSolver::run()
{
    if (greedy) runSeqGreedy();
    else runSeq();
}

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

#include <cassert>
#include <cstring>
#include <queue>
#include <stack>

#include "fpj.hpp"
#include "uintqueue.hpp"

namespace pg {

FPJSolver::FPJSolver(Oink *oink, Game *game) : Solver(oink, game)
{
}

FPJSolver::~FPJSolver()
{
}

/**
 * Variation 1: greedy justification
 */
void
FPJSolver::runSeqGreedy()
{
    /**
     * Allocate and initialize data structures
     */

    int *strategy = new int[nodecount()]; // the current strategy
    bitset justified(nodecount()); // whether a vertex is justified
    bitset distraction(nodecount()); // whether a vertex is won by the opponent

    bitset parity(nodecount()); // optimization: precompute the parity of every vertex's priority
    for (int v=0; v<nodecount(); v++) parity[v] = priority(v)&1;

    uintqueue Q(nodecount());

    /**
     * Initialize loop
     */

    bool blockchanged = false; // did the current block change (new distractions)
    int cur_parity = parity[0]; // parity of current block
    int i = 0; // the current vertex

    for (;;) {
        /**
         * First detect if we are at the end of a block (vertices of same parity)
         */
        bool blockended = false;
        if (i == nodecount()) {
            blockended = true;
        } else {
            if (disabled[i]) { i++; continue; }
            if (parity[i] != cur_parity) blockended = true;
        }

        if (blockended) {
            if (blockchanged) {
                /**
                 * We have to reset all justified vertices that are now no longer justified...
                 */
                while (!Q.empty()) {
                    const int v = Q.pop();
                    for (auto curedge = ins(v); *curedge != -1; curedge++) {
                        const int from = *curedge;
                        if (justified[from]) {
                            if (strategy[from] == -1 or strategy[from] == v) {
#ifndef NDEBUG
                                if (trace >= 2) logger << "\033[31;1mresetting\033[m " << label_vertex(from) << std::endl;
#endif
                                justified[from] = false;
                                distraction[from] = false; // reset it
                                Q.push(from);
                                if (from < i) i = from; // afterwards, continue at lowest unjustified vertex
                            }
                        }
                    }
                }
#ifndef NDEBUG
                if (trace) logger << "restarting after finding distractions of prio " << priority(i-1) << std::endl;
#endif
                iterations++;
                blockchanged = false;
            }

            if (i == nodecount()) break; // in case the last block didn't result in unjustifications

            // continue with the new block, update the current parity
            cur_parity = parity[i];
        }

        // if the current vertex is justified, we don't need to check it
        if (justified[i]) { i++; continue; }
        justified[i] = true;

        // compute one step winner of <i> and update the strategy
        int onestep_winner, str = -1;
        if (owner(i) == 0) {
            // see if player Even can go to a vertex currently good for Even
            onestep_winner = 1;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 0) {
                    // good for player Even
                    onestep_winner = 0;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        } else {
            // see if player Odd can go to a vertex currently good for Odd
            onestep_winner = 0;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 1) {
                    // good for player Odd
                    onestep_winner = 1;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        }

        strategy[i] = str;

        // evaluation stays the same
        if (cur_parity != onestep_winner) {
            Q.push(i); // add to the Queue, because all justified predecessors are now invalid
            distraction[i] = true;
            blockchanged = true;
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified*\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        } else {
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        }

        i++;
    }

    // done
    for (int v=0; v<nodecount(); v++) {
        if (disabled[v]) continue;
        const int winner = parity[v] ^ distraction[v];
        oink->solve(v, winner, winner == owner(v) ? strategy[v] : -1);
    }

    // free allocated data structures
    delete[] strategy;

    logger << "solved with " << iterations << " iterations." << std::endl;
}

void
FPJSolver::runSeq()
{
    /**
     * Allocate and initialize data structures
     */

    int *strategy = new int[nodecount()]; // the current strategy
    bitset justified(nodecount()); // whether a vertex is justified
    bitset distraction(nodecount()); // whether a vertex is won by the opponent

    bitset parity(nodecount()); // optimization: precompute the parity of every vertex's priority
    for (int v=0; v<nodecount(); v++) parity[v] = priority(v)&1;

    uintqueue Q(nodecount());

    /**
     * Initialize loop
     */

    bool blockchanged = false; // did the current block change (new distractions)
    int cur_parity = parity[0]; // parity of current block
    int i = 0; // the current vertex
    int blockstart = 0; // first vertex of the current block

    for (;;) {
        /**
         * First detect if we are at the end of a block (vertices of same parity)
         */
        bool blockended = false;
        if (i == nodecount()) {
            blockended = true;
        } else {
            if (disabled[i]) { i++; continue; }
            if (parity[i] != cur_parity) blockended = true;
        }

        if (blockended) {
            if (blockchanged) {
                /**
                 * We have to reset all justified vertices that are now no longer justified...
                 */
                while (!Q.empty()) {
                    const int v = Q.pop();
                    for (auto curedge = ins(v); *curedge != -1; curedge++) {
                        const int from = *curedge;
                        if (disabled[from]) continue;
                        if (justified[from]) {
                            if (strategy[from] == -1 or strategy[from] == v) {
#ifndef NDEBUG
                                if (trace >= 2) logger << "\033[31;1mresetting\033[m " << label_vertex(from) << std::endl;
#endif
                                justified[from] = false;
                                distraction[from] = false; // reset it
                                Q.push(from);
                                if (from < i) i = from; // afterwards, continue at lowest unjustified vertex
                            }
                        }
                    }
                }
#ifndef NDEBUG
                if (trace) logger << "restarting after finding distractions of prio " << priority(i-1) << std::endl;
#endif
                iterations++;
                blockchanged = false;
                if (i > blockstart) i = blockstart;
            } else {
                // We now know that the current strategy of all unjustified vertices of the block is justified
                for (int v=blockstart; v<i; v++) {
                    if (!disabled[v] and !justified[v]) {
                        justified[v] = true;
#ifndef NDEBUG
                        if (trace >= 2) {
                            logger << "\033[38;5;165;1mjustified\033[m " << label_vertex(v);
                            if (strategy[v] != -1) logger << " => " << label_vertex(strategy[v]);
                            logger << std::endl;
                        }
#endif
                    }
                }
            }

            if (i == nodecount()) break; // in case the last block didn't result in unjustifications

            // continue with the new block, update the current parity
            cur_parity = parity[i];
            blockstart = i;
        }

        // if the current vertex is justified, we don't need to check it
        if (justified[i]) {
            i++;
            continue;
        }

        // compute one step winner of <i> and update the strategy
        int onestep_winner, str = -1;
        if (owner(i) == 0) {
            // see if player Even can go to a vertex currently good for Even
            onestep_winner = 1;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 0) {
                    // good for player Even
                    onestep_winner = 0;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        } else {
            // see if player Odd can go to a vertex currently good for Odd
            onestep_winner = 0;
            for (auto curedge = outs(i); *curedge != -1; curedge++) {
                int to = *curedge;
                if (disabled[to]) continue;
                const int winner_to = parity[to] ^ distraction[to];
                if (winner_to == 1) {
                    // good for player Odd
                    onestep_winner = 1;
                    // and set the strategy
                    str = to;
                    break;
                }
            }
        }

        strategy[i] = str;

        // evaluation stays the same
        if (cur_parity != onestep_winner) {
            Q.push(i); // add to the Queue, because all justified predecessors are now invalid
            distraction[i] = true;
            justified[i] = true;
            blockchanged = true;
#ifndef NDEBUG
            if (trace >= 2) {
                logger << "\033[38;5;165;1mjustified*\033[m " << label_vertex(i);
                if (strategy[i] != -1) logger << " => " << label_vertex(strategy[i]);
                logger << std::endl;
            }
#endif
        }

        i++;
    }

    // done
    for (int v=0; v<nodecount(); v++) {
        if (disabled[v]) continue;
        const int winner = parity[v] ^ distraction[v];
        oink->solve(v, winner, winner == owner(v) ? strategy[v] : -1);
    }

    // free allocated data structures
    delete[] strategy;

    logger << "solved with " << iterations << " iterations." << std::endl;
}

void
FPJSolver::run()
{
    if (greedy) runSeqGreedy();
    else runSeq();
}

}
<|endoftext|>


<commit_before>///
/// @file   CpuInfo.cpp
/// @brief  Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <exception>
#include <vector>
#include <string>

#if defined(__APPLE__)
  #if !defined(__has_include)
    #define APPLE_SYSCTL
  #elif __has_include(<sys/types.h>) && \
        __has_include(<sys/sysctl.h>)
    #define APPLE_SYSCTL
  #endif
#endif

#if defined(_WIN32)

#include <windows.h>

#elif defined(APPLE_SYSCTL)

#include <sys/types.h>
#include <sys/sysctl.h>

#else // all other OSes

#include <fstream>
#include <sstream>

using namespace std;

namespace {

string getString(const string& filename)
{
  ifstream file(filename);
  string str;

  if (file)
  {
    // https://stackoverflow.com/a/3177560/363778
    stringstream trimmer;
    trimmer << file.rdbuf();
    trimmer >> str;
  }

  return str;
}

size_t getValue(const string& filename)
{
  string str = getString(filename);
  size_t val = stol(str);

  if (!str.empty())
  {
    // Last character may be:
    // 'K' = kilobytes
    // 'M' = megabytes
    // 'G' = gigabytes
    if (str.back() == 'K')
      val *= 1024;
    if (str.back() == 'M')
      val *= 1024 * 1024;
    if (str.back() == 'G')
      val *= 1024 * 1024 * 1024;
  }

  return val;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    privateL2Cache_(false)
{
  try
  {
    initCache();

    if (!hasL1Cache() &&
        l1CacheSize_ > 0)
    {
      string msg = "invalid L1 cache size: " + to_string(l1CacheSize_);
      errors_.push_back(msg);
    }

    if (!hasL2Cache() &&
        l2CacheSize_ > 0)
    {
      string msg = "invalid L2 cache size: " + to_string(l2CacheSize_);
      errors_.push_back(msg);
    }
  }
  catch (exception& e)
  {
    errors_.push_back(e.what());
  }
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

bool CpuInfo::privateL2Cache() const
{
  return privateL2Cache_;
}

vector<string> CpuInfo::getErrors() const
{
  return errors_;
}

bool CpuInfo::hasL1Cache() const
{
  return l1CacheSize_ >= (1 << 12) &&
         l1CacheSize_ <= (1ull << 40);
}

bool CpuInfo::hasL2Cache() const
{
  return l2CacheSize_ >= (1 << 12) &&
         l2CacheSize_ <= (1ull << 40);
}

#if defined(APPLE_SYSCTL)

void CpuInfo::initCache()
{
  size_t l1Length = sizeof(l1CacheSize_);
  size_t l2Length = sizeof(l2CacheSize_);

  sysctlbyname("hw.l1dcachesize", &l1CacheSize_, &l1Length, NULL, 0);
  sysctlbyname("hw.l2cachesize" , &l2CacheSize_, &l2Length, NULL, 0);

  size_t size = 0;

  if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0))
  {
    size_t n = size / sizeof(size);
    vector<size_t> cacheconfig(n);

    if (cacheconfig.size() > 2)
    {
      // https://developer.apple.com/library/content/releasenotes/Performance/RN-AffinityAPI/index.html
      sysctlbyname("hw.cacheconfig" , &cacheconfig[0], &size, NULL, 0);
      size_t l2CpuSharing = cacheconfig[2];

      if (l2CpuSharing <= 1)
        privateL2Cache_ = true;
      else
      {
        size_t logicalcpu = 1;
        size = sizeof(size);
        sysctlbyname("hw.logicalcpu", &logicalcpu, &size, NULL, 0);
        logicalcpu = max<size_t>(1, logicalcpu);

        size_t physicalcpu = 1;
        size = sizeof(size);
        sysctlbyname("hw.physicalcpu", &physicalcpu, &size, NULL, 0);
        physicalcpu = max<size_t>(1, physicalcpu);

        if (l2CpuSharing <= logicalcpu / physicalcpu)
          privateL2Cache_ = true;
      }
    }
  }
}

#elif defined(_WIN32)

void CpuInfo::initCache()
{
  typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (!glpi)
    return;

  DWORD bytes = 0;
  glpi(0, &bytes);

  if (!bytes)
    return;

  size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);

  if (!glpi(&info[0], &bytes))
    return;

  for (size_t i = 0; i < size; i++)
  {
    if (info[i].Relationship == RelationCache &&
        (info[i].Cache.Type == CacheData ||
         info[i].Cache.Type == CacheUnified))
    {
      if (info[i].Cache.Level == 1)
        l1CacheSize_ = info[i].Cache.Size;
      if (info[i].Cache.Level == 2)
        l2CacheSize_ = info[i].Cache.Size;

      // If the CPU has an L3 cache we assume the L2 cache
      // is private. This is more reliable than using
      // GetLogicalProcessorInformationEx() and
      // GROUP_AFFINITY.Mask
      if (info[i].Cache.Level == 3)
        privateL2Cache_ = true;
    }
  }
}

#else

/// This works on Linux and Android. We also use this
/// for all unknown OSes, it might work.
///
void CpuInfo::initCache()
{
  for (int i = 0; i <= 3; i++)
  {
    string filename = "/sys/devices/system/cpu/cpu0/cache/index" + to_string(i);
    string threadSiblingsList = "/sys/devices/system/cpu/cpu0/topology/thread_siblings_list";

    string cacheLevel = filename + "/level";
    string cacheSize = filename + "/size";
    string sharedCpuList = filename + "/shared_cpu_list";
    string cacheType = filename + "/type";

    size_t level = getValue(cacheLevel);
    string type = getString(cacheType);

    if (level == 1 &&
        (type == "Data" ||
         type == "Unified"))
    {
      l1CacheSize_ = getValue(cacheSize);
    }

    if (level == 2 &&
        (type == "Data" ||
         type == "Unified"))
    {
      l2CacheSize_ = getValue(cacheSize);
      sharedCpuList = getString(sharedCpuList);
      threadSiblingsList = getString(threadSiblingsList);

      // https://lwn.net/Articles/254445/
      if (sharedCpuList.empty())
        privateL2Cache_ = true;
      else if (sharedCpuList == threadSiblingsList)
        privateL2Cache_ = true;
    }
  }
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<commit_msg>Add Windows safety check<commit_after>///
/// @file   CpuInfo.cpp
/// @brief  Get the CPUs cache sizes in bytes.
///
/// Copyright (C) 2017 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primesieve/CpuInfo.hpp>

#include <cstddef>
#include <exception>
#include <vector>
#include <string>

#if defined(__APPLE__)
  #if !defined(__has_include)
    #define APPLE_SYSCTL
  #elif __has_include(<sys/types.h>) && \
        __has_include(<sys/sysctl.h>)
    #define APPLE_SYSCTL
  #endif
#endif

#if defined(_WIN32)

#include <windows.h>

#elif defined(APPLE_SYSCTL)

#include <sys/types.h>
#include <sys/sysctl.h>

#else // all other OSes

#include <fstream>
#include <sstream>

using namespace std;

namespace {

string getString(const string& filename)
{
  ifstream file(filename);
  string str;

  if (file)
  {
    // https://stackoverflow.com/a/3177560/363778
    stringstream trimmer;
    trimmer << file.rdbuf();
    trimmer >> str;
  }

  return str;
}

size_t getValue(const string& filename)
{
  string str = getString(filename);
  size_t val = stol(str);

  if (!str.empty())
  {
    // Last character may be:
    // 'K' = kilobytes
    // 'M' = megabytes
    // 'G' = gigabytes
    if (str.back() == 'K')
      val *= 1024;
    if (str.back() == 'M')
      val *= 1024 * 1024;
    if (str.back() == 'G')
      val *= 1024 * 1024 * 1024;
  }

  return val;
}

} // namespace

#endif

using namespace std;

namespace primesieve {

CpuInfo::CpuInfo()
  : l1CacheSize_(0),
    l2CacheSize_(0),
    privateL2Cache_(false)
{
  try
  {
    initCache();

    if (!hasL1Cache() &&
        l1CacheSize_ > 0)
    {
      string msg = "invalid L1 cache size: " + to_string(l1CacheSize_);
      errors_.push_back(msg);
    }

    if (!hasL2Cache() &&
        l2CacheSize_ > 0)
    {
      string msg = "invalid L2 cache size: " + to_string(l2CacheSize_);
      errors_.push_back(msg);
    }
  }
  catch (exception& e)
  {
    errors_.push_back(e.what());
  }
}

size_t CpuInfo::l1CacheSize() const
{
  return l1CacheSize_;
}

size_t CpuInfo::l2CacheSize() const
{
  return l2CacheSize_;
}

bool CpuInfo::privateL2Cache() const
{
  return privateL2Cache_;
}

vector<string> CpuInfo::getErrors() const
{
  return errors_;
}

bool CpuInfo::hasL1Cache() const
{
  return l1CacheSize_ >= (1 << 12) &&
         l1CacheSize_ <= (1ull << 40);
}

bool CpuInfo::hasL2Cache() const
{
  return l2CacheSize_ >= (1 << 12) &&
         l2CacheSize_ <= (1ull << 40);
}

#if defined(APPLE_SYSCTL)

void CpuInfo::initCache()
{
  size_t l1Length = sizeof(l1CacheSize_);
  size_t l2Length = sizeof(l2CacheSize_);

  sysctlbyname("hw.l1dcachesize", &l1CacheSize_, &l1Length, NULL, 0);
  sysctlbyname("hw.l2cachesize" , &l2CacheSize_, &l2Length, NULL, 0);

  size_t size = 0;

  if (!sysctlbyname("hw.cacheconfig", NULL, &size, NULL, 0))
  {
    size_t n = size / sizeof(size);
    vector<size_t> cacheconfig(n);

    if (cacheconfig.size() > 2)
    {
      // https://developer.apple.com/library/content/releasenotes/Performance/RN-AffinityAPI/index.html
      sysctlbyname("hw.cacheconfig" , &cacheconfig[0], &size, NULL, 0);
      size_t l2CpuSharing = cacheconfig[2];

      if (l2CpuSharing <= 1)
        privateL2Cache_ = true;
      else
      {
        size_t logicalcpu = 1;
        size = sizeof(size);
        sysctlbyname("hw.logicalcpu", &logicalcpu, &size, NULL, 0);
        logicalcpu = max<size_t>(1, logicalcpu);

        size_t physicalcpu = 1;
        size = sizeof(size);
        sysctlbyname("hw.physicalcpu", &physicalcpu, &size, NULL, 0);
        physicalcpu = max<size_t>(1, physicalcpu);

        if (l2CpuSharing <= logicalcpu / physicalcpu)
          privateL2Cache_ = true;
      }
    }
  }
}

#elif defined(_WIN32)

void CpuInfo::initCache()
{
  typedef BOOL (WINAPI *LPFN_GLPI)(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, PDWORD);

  LPFN_GLPI glpi = (LPFN_GLPI) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetLogicalProcessorInformation");

  if (!glpi)
    return;

  DWORD bytes = 0;
  glpi(0, &bytes);

  if (!bytes)
    return;

  size_t size = bytes / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> info(size);

  if (!glpi(&info[0], &bytes))
    return;

  for (size_t i = 0; i < size; i++)
  {
    if (info[i].Relationship == RelationCache &&
        (info[i].Cache.Type == CacheData ||
         info[i].Cache.Type == CacheUnified))
    {
      if (info[i].Cache.Level == 1)
        l1CacheSize_ = info[i].Cache.Size;
      if (info[i].Cache.Level == 2)
        l2CacheSize_ = info[i].Cache.Size;

      // If the CPU has an L3 cache we assume the L2 cache
      // is private. This is more reliable than using
      // GetLogicalProcessorInformationEx() and
      // GROUP_AFFINITY.Mask
      if (info[i].Cache.Level == 3 &&
          info[i].Cache.Size > 0)
        privateL2Cache_ = true;
    }
  }
}

#else

/// This works on Linux and Android. We also use this
/// for all unknown OSes, it might work.
///
void CpuInfo::initCache()
{
  for (int i = 0; i <= 3; i++)
  {
    string filename = "/sys/devices/system/cpu/cpu0/cache/index" + to_string(i);
    string threadSiblingsList = "/sys/devices/system/cpu/cpu0/topology/thread_siblings_list";

    string cacheLevel = filename + "/level";
    string cacheSize = filename + "/size";
    string sharedCpuList = filename + "/shared_cpu_list";
    string cacheType = filename + "/type";

    size_t level = getValue(cacheLevel);
    string type = getString(cacheType);

    if (level == 1 &&
        (type == "Data" ||
         type == "Unified"))
    {
      l1CacheSize_ = getValue(cacheSize);
    }

    if (level == 2 &&
        (type == "Data" ||
         type == "Unified"))
    {
      l2CacheSize_ = getValue(cacheSize);
      sharedCpuList = getString(sharedCpuList);
      threadSiblingsList = getString(threadSiblingsList);

      // https://lwn.net/Articles/254445/
      if (sharedCpuList.empty())
        privateL2Cache_ = true;
      else if (sharedCpuList == threadSiblingsList)
        privateL2Cache_ = true;
    }
  }
}

#endif

/// Singleton
const CpuInfo cpuInfo;

} // namespace
<|endoftext|>


<commit_before>//  RenderObject.cpp
//  nativeGraphics

#include "RenderObject.h"
#include "glsl_helper.h"
#include "obj_parser.h"
#include "transform.h"
#include "common.h"
#include "log.h"

RenderObject::RenderObject(const char *objFilename, const char *vertexShaderFilename, const char *fragmentShaderFilename) {

    // Parse obj file into an interleaved float buffer
    GLfloat * interleavedBuffer = getInterleavedBuffer((char *)resourceCallback(objFilename), numVertices, true, true);
    glGenBuffers(1, &gVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices * (3+3+2) * sizeof(float), interleavedBuffer, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    checkGlError("VertexBuffer Generation");
    free(interleavedBuffer);

    // Compile and link shader program
    gProgram = createProgram((char *)resourceCallback(vertexShaderFilename), (char *)resourceCallback(fragmentShaderFilename));

    // Get uniform and attrib locations
    gmvMatrixHandle = glGetUniformLocation(gProgram, "u_MVMatrix");
    gmvpMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
    gvPositionHandle = glGetAttribLocation(gProgram, "a_Position");
    gvNormals = glGetAttribLocation(gProgram, "a_Normal");
    gvTexCoords = glGetAttribLocation(gProgram, "a_TexCoordinate");
    textureUniform = glGetUniformLocation(gProgram, "u_Texture");
    checkGlError("glGetAttribLocation");
}

void RenderObject::AddTexture(const char *textureFilename) {
    // Load textures
    GLubyte *imageData = (GLubyte *)resourceCallback(textureFilename); // TODO: Free this

    GLuint texName; // TODO
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); // TODO: hardcoded size

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);
    free(imageData);

    checkGlError("AddTexture");
    textures.push_back(texName);
}

void RenderObject::RenderFrame() {

    if(numVertices == 0) {
        LOGE("Setup not yet called.");
        return;
    }

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    // Matrices setup
    GLfloat* mv_Matrix = (GLfloat*)mvMatrix();
    GLfloat* mvp_Matrix = (GLfloat*)mvpMatrix();

    glUniformMatrix4fv(gmvMatrixHandle, 1, GL_FALSE, mv_Matrix);
    glUniformMatrix4fv(gmvpMatrixHandle, 1, GL_FALSE, mvp_Matrix);
    checkGlError("glUniformMatrix4fv");
    delete mv_Matrix;
    delete mvp_Matrix;

    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);

    // Vertices
    glEnableVertexAttribArray(gvPositionHandle);
    glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) 0);
    checkGlError("gvPositionHandle");

    // Normals
    glEnableVertexAttribArray(gvNormals);
    glVertexAttribPointer(gvNormals, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) (3 * sizeof(GLfloat)));
    checkGlError("gvNormals");

    //Textures
    glEnableVertexAttribArray(gvTexCoords);
    glVertexAttribPointer(gvTexCoords, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid *) (6 * sizeof(GLfloat)));
    checkGlError("gvTexCoords");

    if (textures.size() > 0) {

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glUniform1i(textureUniform, 0);
        checkGlError("texture");
    }

    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    checkGlError("glDrawArrays");

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
<commit_msg>Minor bug fix.<commit_after>//  RenderObject.cpp
//  nativeGraphics

#include "RenderObject.h"
#include "glsl_helper.h"
#include "obj_parser.h"
#include "transform.h"
#include "common.h"
#include "log.h"

RenderObject::RenderObject(const char *objFilename, const char *vertexShaderFilename, const char *fragmentShaderFilename) {

    // Parse obj file into an interleaved float buffer
    GLfloat * interleavedBuffer = getInterleavedBuffer((char *)resourceCallback(objFilename), numVertices, true, true);
    glGenBuffers(1, &gVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);
    glBufferData(GL_ARRAY_BUFFER, numVertices * (3+3+2) * sizeof(float), interleavedBuffer, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    checkGlError("VertexBuffer Generation");
    free(interleavedBuffer);

    // Compile and link shader program
    gProgram = createProgram((char *)resourceCallback(vertexShaderFilename), (char *)resourceCallback(fragmentShaderFilename));

    // Get uniform and attrib locations
    gmvMatrixHandle = glGetUniformLocation(gProgram, "u_MVMatrix");
    gmvpMatrixHandle = glGetUniformLocation(gProgram, "u_MVPMatrix");
    gvPositionHandle = glGetAttribLocation(gProgram, "a_Position");
    gvNormals = glGetAttribLocation(gProgram, "a_Normal");
    gvTexCoords = glGetAttribLocation(gProgram, "a_TexCoordinate");
    textureUniform = glGetUniformLocation(gProgram, "u_Texture");
    checkGlError("glGetAttribLocation");
}

void RenderObject::AddTexture(const char *textureFilename) {
    // Load textures
    GLubyte *imageData = (GLubyte *)resourceCallback(textureFilename);

    GLuint texName; // TODO
    glGenTextures(1, &texName);
    glBindTexture(GL_TEXTURE_2D, texName);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); // TODO: hardcoded size

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glGenerateMipmap(GL_TEXTURE_2D);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);

    glBindTexture(GL_TEXTURE_2D, 0);
    free(imageData);

    checkGlError("AddTexture");
    textures.push_back(texName);
}

void RenderObject::RenderFrame() {

    if(numVertices == 0) {
        LOGE("Setup not yet called.");
        return;
    }

    glUseProgram(gProgram);
    checkGlError("glUseProgram");

    // Matrices setup
    GLfloat* mv_Matrix = (GLfloat*)mvMatrix();
    GLfloat* mvp_Matrix = (GLfloat*)mvpMatrix();

    glUniformMatrix4fv(gmvMatrixHandle, 1, GL_FALSE, mv_Matrix);
    glUniformMatrix4fv(gmvpMatrixHandle, 1, GL_FALSE, mvp_Matrix);
    checkGlError("glUniformMatrix4fv");
    delete mv_Matrix;
    delete mvp_Matrix;

    glBindBuffer(GL_ARRAY_BUFFER, gVertexBuffer);

    // Vertices
    glEnableVertexAttribArray(gvPositionHandle);
    glVertexAttribPointer(gvPositionHandle, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) 0);
    checkGlError("gvPositionHandle");

    // Normals
    glEnableVertexAttribArray(gvNormals);
    glVertexAttribPointer(gvNormals, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid*) (3 * sizeof(GLfloat)));
    checkGlError("gvNormals");

    //Textures
    if(textures.size() > 0) {
    	glEnableVertexAttribArray(gvTexCoords);
    	glVertexAttribPointer(gvTexCoords, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(GLfloat), (const GLvoid *) (6 * sizeof(GLfloat)));
    	checkGlError("gvTexCoords");

        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glUniform1i(textureUniform, 0);
        checkGlError("texture");
    }

    glDrawArrays(GL_TRIANGLES, 0, numVertices);
    checkGlError("glDrawArrays");

    glBindBuffer(GL_ARRAY_BUFFER, 0);
}
<|endoftext|>


<commit_before>#include "Utils/Logging.hpp"

#include "Settings.hpp"

using Dissent::Utils::Logging;

namespace Dissent {
namespace Applications {
  Settings::Settings(const QString &file, bool actions) :
    _use_file(true),
    _settings(new QSettings(file, QSettings::IniFormat))
  {
    Init(actions);
  }

  Settings::Settings() :
    _use_file(false),
    _settings(new QSettings())
  {
    Init();
  }

  Settings::Settings(const QSharedPointer<QSettings> &settings,
      bool file, bool actions) :
    _use_file(file),
    _settings(settings)
  {
    Init(actions);
  }

  void Settings::Init(bool actions)
  {
    if(_settings->value("help", false).toBool()) {
      Help = true;
      return;
    }
    Help = false;

    Console = false;
    EntryTunnel = false;
    ExitTunnel = false;
    LeaderId = Id::Zero();
    LocalId = Id::Zero();
    LocalNodeCount = 1;
    SessionType = "null";
    WebServer = false;

    QVariant peers = _settings->value(Param<Params::RemotePeers>());
    ParseUrlList("RemotePeer", peers, RemotePeers);

    QVariant endpoints = _settings->value(Param<Params::LocalEndPoints>());
    ParseUrlList("EndPoint", endpoints, LocalEndPoints);

    DemoMode = _settings->value(Param<Params::DemoMode>()).toBool();

    if(_settings->contains(Param<Params::LocalNodeCount>())) {
      LocalNodeCount = _settings->value(Param<Params::LocalNodeCount>()).toInt();
    }

    Console = _settings->value(Param<Params::Console>()).toBool();
    WebServer = _settings->value(Param<Params::WebServer>()).toBool();
    EntryTunnel = _settings->value(Param<Params::EntryTunnel>()).toBool();
    ExitTunnel = _settings->value(Param<Params::ExitTunnel>()).toBool();
    Multithreading = _settings->value(Param<Params::Multithreading>()).toBool();

    WebServerUrl = TryParseUrl(_settings->value(Param<Params::WebServerUrl>()).toString(), "http");
    EntryTunnelUrl = TryParseUrl(_settings->value(Param<Params::EntryTunnelUrl>()).toString(), "tcp");

    if(_settings->contains(Param<Params::SessionType>())) {
      SessionType = _settings->value(Param<Params::SessionType>()).toString();
    }

    if(_settings->contains(Param<Params::SubgroupPolicy>())) {
      QString ptype = _settings->value(Param<Params::SubgroupPolicy>()).toString();
      SubgroupPolicy = Group::StringToPolicyType(ptype);
    }

    if(_settings->contains(Param<Params::Log>())) {
      Log = _settings->value(Param<Params::Log>()).toString();
      QString lower = Log.toLower();

      if(actions) {
        if(lower == "stderr") {
          Logging::UseStderr();
        } else if(lower == "stdout") {
          Logging::UseStdout();
        } else if(Log.isEmpty()) {
          Logging::Disable();
        } else {
          Logging::UseFile(Log);
        }
      }
    }

    if(_settings->contains(Param<Params::LocalId>())) {
      LocalId = Id(_settings->value(Param<Params::LocalId>()).toString());
    }

    if(_settings->contains(Param<Params::LeaderId>())) {
      LeaderId = Id(_settings->value(Param<Params::LeaderId>()).toString());
    }

    if(_settings->contains(Param<Params::SuperPeer>())) {
      SuperPeer = _settings->value(Param<Params::SuperPeer>()).toBool();
    }
  }

  bool Settings::IsValid()
  {
    if(_use_file && (_settings->status() != QSettings::NoError)) {
      _reason = "File error";
      return false;
    }

    if(LocalEndPoints.count() == 0) {
      _reason = "No locally defined end points";
      return false;
    }

    if(WebServer && (!WebServerUrl.isValid() || WebServerUrl.isEmpty())) {
      _reason = "Invalid WebServerUrl: " + WebServerUrl.toString();
      return false;
    }

    if(EntryTunnel && (!EntryTunnelUrl.isValid() || EntryTunnelUrl.isEmpty())) {
      _reason = "Invalid EntryTunnelUrl: " + EntryTunnelUrl.toString();
      return false;
    }

    if(LeaderId == Id::Zero()) {
      _reason = "No leader Id";
      return false;
    }

    if(SubgroupPolicy == -1) {
      _reason = "Invalid subgroup policy";
      return false;
    }

    return true;
  }

  QString Settings::GetError()
  {
    IsValid();
    return _reason;
  }

  void Settings::ParseUrlList(const QString &name, const QVariant &values,
          QList<QUrl> &list)
  {
    if(values.isNull()) {
      return;
    }

    QVariantList varlist = values.toList();
    if(!varlist.empty()) {
      foreach(QVariant value, varlist) {
        ParseUrl(name, value, list);
      }
    } else {
      ParseUrl(name, values, list);
    }
  }

  inline void Settings::ParseUrl(const QString &name, const QVariant &value,
          QList<QUrl> &list)
  {
    QUrl url(value.toString());
    if(url.isValid()) {
      list << url;
    } else {
      qCritical() << "Invalid " << name << ": " << value.toString();
    }
  }

  QUrl Settings::TryParseUrl(const QString &string_rep, const QString &scheme)
  {
    QUrl url = QUrl(string_rep);
    if(url.toString() != string_rep) {
      return QUrl();
    }

    if(url.scheme() != scheme) {
      return QUrl();
    }
    return url;
  }

  void Settings::Save()
  {
    if(!_use_file) {
      return;
    }

    QStringList peers;
    foreach(QUrl peer, RemotePeers) {
      peers << peer.toString();
    }

    if(!peers.empty()) {
      _settings->setValue(Param<Params::RemotePeers>(), peers);
    }

    QStringList endpoints;
    foreach(QUrl endpoint, LocalEndPoints) {
      endpoints << endpoint.toString();
    }

    if(!endpoints.empty()) {
      _settings->setValue(Param<Params::LocalEndPoints>(), endpoints);
    }

    _settings->setValue(Param<Params::LocalNodeCount>(), LocalNodeCount);
    _settings->setValue(Param<Params::WebServer>(), WebServer);
    _settings->setValue(Param<Params::WebServerUrl>(), WebServerUrl);
    _settings->setValue(Param<Params::Console>(), Console);
    _settings->setValue(Param<Params::DemoMode>(), DemoMode);
    _settings->setValue(Param<Params::Log>(), Log);
    _settings->setValue(Param<Params::Multithreading>(), Multithreading);
    _settings->setValue(Param<Params::LocalId>(), LocalId.ToString());
    _settings->setValue(Param<Params::LeaderId>(), LeaderId.ToString());
    _settings->setValue(Param<Params::SubgroupPolicy>(),
        Group::PolicyTypeToString(SubgroupPolicy));
  }

  Settings Settings::CommandLineParse(const QStringList &params, bool actions)
  {
    QSharedPointer<QxtCommandOptions> options = GetOptions();
    options->parse(params);
    QSharedPointer<QSettings> settings;
    bool file = (options->positional().count() > 0);

    if(file) {
      settings = QSharedPointer<QSettings>(
          new QSettings(options->positional()[0], QSettings::IniFormat));
    } else {
      settings = QSharedPointer<QSettings>(new QSettings());
      if(params.size() == 1) {
        settings->setValue("help", true);
      }
    }

    QMultiHash<QString, QVariant> kv_params = options->parameters();

    if(kv_params.value("help", false).toBool() && file) {
      file = false;
      settings = QSharedPointer<QSettings>(new QSettings());
    }

    foreach(const QString &key, kv_params.uniqueKeys()) {
      if(options->value(key).type() == QVariant::String &&
          options->value(key).toString().isEmpty())
      {
        settings->setValue(key, true);
      } else {
        settings->setValue(key, options->value(key));
      }
    }

    if(options->count(Param<Params::WebServerUrl>()) == 1) {
      settings->setValue(Param<Params::WebServer>(), true);
    }

    if(options->count(Param<Params::EntryTunnelUrl>()) == 1) {
      settings->setValue(Param<Params::EntryTunnel>(), true);
    }

    return Settings(settings, file, actions);
  }

  QSharedPointer<QxtCommandOptions> Settings::GetOptions()
  {
    QSharedPointer<QxtCommandOptions> options(new QxtCommandOptions());

    options->add(Param<Params::Help>(),
        "help (this screen)",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::RemotePeers>(),
        "list of remote peers",
        QxtCommandOptions::ValueRequired | QxtCommandOptions::AllowMultiple);

    options->add(Param<Params::LocalEndPoints>(),
        "list of local end points",
        QxtCommandOptions::ValueRequired | QxtCommandOptions::AllowMultiple);

    options->add(Param<Params::LocalNodeCount>(),
        "number of virtual nodes to start",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::DemoMode>(),
        "start in demo mode",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::SessionType>(),
        "the type of session",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::Log>(),
        "logging mechanism",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::Console>(),
        "enable console",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::WebServerUrl>(),
        "web server url (enables web server)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::EntryTunnelUrl>(),
        "entry tunnel url (enables entry tunnel)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::ExitTunnel>(),
        "enables exit tunnel",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::Multithreading>(),
        "enables multithreading",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::LocalId>(),
        "160-bit base64 local id",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::LeaderId>(),
        "160-bit base64 leader id",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::SubgroupPolicy>(),
        "subgroup policy (defining servers)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::SuperPeer>(),
        "sets this peer as a capable super peer",
        QxtCommandOptions::NoValue);

    return options;
  }
}
}
<commit_msg>[Applications] settings log<commit_after>#include "Utils/Logging.hpp"

#include "Settings.hpp"

using Dissent::Utils::Logging;

namespace Dissent {
namespace Applications {
  Settings::Settings(const QString &file, bool actions) :
    _use_file(true),
    _settings(new QSettings(file, QSettings::IniFormat))
  {
    Init(actions);
  }

  Settings::Settings() :
    _use_file(false),
    _settings(new QSettings())
  {
    Init();
  }

  Settings::Settings(const QSharedPointer<QSettings> &settings,
      bool file, bool actions) :
    _use_file(file),
    _settings(settings)
  {
    Init(actions);
  }

  void Settings::Init(bool actions)
  {
    if(_settings->value("help", false).toBool()) {
      Help = true;
      return;
    }
    Help = false;

    Console = false;
    EntryTunnel = false;
    ExitTunnel = false;
    LeaderId = Id::Zero();
    LocalId = Id::Zero();
    LocalNodeCount = 1;
    SessionType = "null";
    WebServer = false;

    QVariant peers = _settings->value(Param<Params::RemotePeers>());
    ParseUrlList("RemotePeer", peers, RemotePeers);

    QVariant endpoints = _settings->value(Param<Params::LocalEndPoints>());
    ParseUrlList("EndPoint", endpoints, LocalEndPoints);

    DemoMode = _settings->value(Param<Params::DemoMode>()).toBool();

    if(_settings->contains(Param<Params::LocalNodeCount>())) {
      LocalNodeCount = _settings->value(Param<Params::LocalNodeCount>()).toInt();
    }

    Console = _settings->value(Param<Params::Console>()).toBool();
    WebServer = _settings->value(Param<Params::WebServer>()).toBool();
    EntryTunnel = _settings->value(Param<Params::EntryTunnel>()).toBool();
    ExitTunnel = _settings->value(Param<Params::ExitTunnel>()).toBool();
    Multithreading = _settings->value(Param<Params::Multithreading>()).toBool();

    WebServerUrl = TryParseUrl(_settings->value(Param<Params::WebServerUrl>()).toString(), "http");
    EntryTunnelUrl = TryParseUrl(_settings->value(Param<Params::EntryTunnelUrl>()).toString(), "tcp");

    if(_settings->contains(Param<Params::SessionType>())) {
      SessionType = _settings->value(Param<Params::SessionType>()).toString();
    }

    if(_settings->contains(Param<Params::SubgroupPolicy>())) {
      QString ptype = _settings->value(Param<Params::SubgroupPolicy>()).toString();
      SubgroupPolicy = Group::StringToPolicyType(ptype);
    }

    if(_settings->contains(Param<Params::Log>())) {
      Log = _settings->value(Param<Params::Log>()).toString();
      QString lower = Log.toLower();

      if(actions) {
        if(lower == "stderr") {
          Logging::UseStderr();
        } else if(lower == "stdout") {
          Logging::UseStdout();
        } else if(Log.isEmpty()) {
          Logging::Disable();
        } else {
          Logging::UseFile(Log);
        }
      }
    }

    if(_settings->contains(Param<Params::LocalId>())) {
      LocalId = Id(_settings->value(Param<Params::LocalId>()).toString());
    }

    if(_settings->contains(Param<Params::LeaderId>())) {
      LeaderId = Id(_settings->value(Param<Params::LeaderId>()).toString());
    }

    if(_settings->contains(Param<Params::SuperPeer>())) {
      SuperPeer = _settings->value(Param<Params::SuperPeer>()).toBool();
    }
  }

  bool Settings::IsValid()
  {
    if(_use_file && (_settings->status() != QSettings::NoError)) {
      _reason = "File error";
      return false;
    }

    if(LocalEndPoints.count() == 0) {
      _reason = "No locally defined end points";
      return false;
    }

    if(WebServer && (!WebServerUrl.isValid() || WebServerUrl.isEmpty())) {
      _reason = "Invalid WebServerUrl: " + WebServerUrl.toString();
      return false;
    }

    if(EntryTunnel && (!EntryTunnelUrl.isValid() || EntryTunnelUrl.isEmpty())) {
      _reason = "Invalid EntryTunnelUrl: " + EntryTunnelUrl.toString();
      return false;
    }

    if(LeaderId == Id::Zero()) {
      _reason = "No leader Id";
      return false;
    }

    if(SubgroupPolicy == -1) {
      _reason = "Invalid subgroup policy";
      return false;
    }

    return true;
  }

  QString Settings::GetError()
  {
    IsValid();
    return _reason;
  }

  void Settings::ParseUrlList(const QString &name, const QVariant &values,
          QList<QUrl> &list)
  {
    if(values.isNull()) {
      return;
    }

    QVariantList varlist = values.toList();
    if(!varlist.empty()) {
      foreach(QVariant value, varlist) {
        ParseUrl(name, value, list);
      }
    } else {
      ParseUrl(name, values, list);
    }
  }

  inline void Settings::ParseUrl(const QString &name, const QVariant &value,
          QList<QUrl> &list)
  {
    QUrl url(value.toString());
    if(url.isValid()) {
      list << url;
    } else {
      qCritical() << "Invalid " << name << ": " << value.toString();
    }
  }

  QUrl Settings::TryParseUrl(const QString &string_rep, const QString &scheme)
  {
    QUrl url = QUrl(string_rep);
    if(url.toString() != string_rep) {
      return QUrl();
    }

    if(url.scheme() != scheme) {
      return QUrl();
    }
    return url;
  }

  void Settings::Save()
  {
    if(!_use_file) {
      return;
    }

    QStringList peers;
    foreach(QUrl peer, RemotePeers) {
      peers << peer.toString();
    }

    if(!peers.empty()) {
      _settings->setValue(Param<Params::RemotePeers>(), peers);
    }

    QStringList endpoints;
    foreach(QUrl endpoint, LocalEndPoints) {
      endpoints << endpoint.toString();
    }

    if(!endpoints.empty()) {
      _settings->setValue(Param<Params::LocalEndPoints>(), endpoints);
    }

    _settings->setValue(Param<Params::LocalNodeCount>(), LocalNodeCount);
    _settings->setValue(Param<Params::WebServer>(), WebServer);
    _settings->setValue(Param<Params::WebServerUrl>(), WebServerUrl);
    _settings->setValue(Param<Params::Console>(), Console);
    _settings->setValue(Param<Params::DemoMode>(), DemoMode);
    _settings->setValue(Param<Params::Log>(), Log);
    _settings->setValue(Param<Params::Multithreading>(), Multithreading);
    _settings->setValue(Param<Params::LocalId>(), LocalId.ToString());
    _settings->setValue(Param<Params::LeaderId>(), LeaderId.ToString());
    _settings->setValue(Param<Params::SubgroupPolicy>(),
        Group::PolicyTypeToString(SubgroupPolicy));
  }

  Settings Settings::CommandLineParse(const QStringList &params, bool actions)
  {
    QSharedPointer<QxtCommandOptions> options = GetOptions();
    options->parse(params);
    QSharedPointer<QSettings> settings;
    bool file = (options->positional().count() > 0);

    if(file) {
      settings = QSharedPointer<QSettings>(
          new QSettings(options->positional()[0], QSettings::IniFormat));
    } else {
      settings = QSharedPointer<QSettings>(new QSettings());
      if(params.size() == 1) {
        settings->setValue("help", true);
      }
    }

    QMultiHash<QString, QVariant> kv_params = options->parameters();

    if(kv_params.value("help", false).toBool() && file) {
      file = false;
      settings = QSharedPointer<QSettings>(new QSettings());
    }

    foreach(const QString &key, kv_params.uniqueKeys()) {
      if(options->value(key).type() == QVariant::String &&
          options->value(key).toString().isEmpty())
      {
        settings->setValue(key, true);
      } else {
        settings->setValue(key, options->value(key));
      }
    }

    if(options->count(Param<Params::WebServerUrl>()) == 1) {
      settings->setValue(Param<Params::WebServer>(), true);
    }

    if(options->count(Param<Params::EntryTunnelUrl>()) == 1) {
      settings->setValue(Param<Params::EntryTunnel>(), true);
    }

    return Settings(settings, file, actions);
  }

  QSharedPointer<QxtCommandOptions> Settings::GetOptions()
  {
    QSharedPointer<QxtCommandOptions> options(new QxtCommandOptions());

    options->add(Param<Params::Help>(),
        "help (this screen)",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::RemotePeers>(),
        "list of remote peers",
        QxtCommandOptions::ValueRequired | QxtCommandOptions::AllowMultiple);

    options->add(Param<Params::LocalEndPoints>(),
        "list of local end points",
        QxtCommandOptions::ValueRequired | QxtCommandOptions::AllowMultiple);

    options->add(Param<Params::LocalNodeCount>(),
        "number of virtual nodes to start",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::DemoMode>(),
        "start in demo mode",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::SessionType>(),
        "the type of session",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::Log>(),
        "logging mechanism: stderr, stdout, or a file path",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::Console>(),
        "enable console",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::WebServerUrl>(),
        "web server url (enables web server)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::EntryTunnelUrl>(),
        "entry tunnel url (enables entry tunnel)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::ExitTunnel>(),
        "enables exit tunnel",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::Multithreading>(),
        "enables multithreading",
        QxtCommandOptions::NoValue);

    options->add(Param<Params::LocalId>(),
        "160-bit base64 local id",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::LeaderId>(),
        "160-bit base64 leader id",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::SubgroupPolicy>(),
        "subgroup policy (defining servers)",
        QxtCommandOptions::ValueRequired);

    options->add(Param<Params::SuperPeer>(),
        "sets this peer as a capable super peer",
        QxtCommandOptions::NoValue);

    return options;
  }
}
}
<|endoftext|>


<commit_before>#include <iostream>
#include <stdio.h>
#include <ctype.h>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;

//parses the entered command putting each string seperated
//by spaces into a vector passed in by reference
//the function utilizes strtok to do this
void parse(char  x[], vector<string> &v){
    char* tmp;
    //separates the string by spaces
    tmp = strtok(x, " ");
    while(tmp != NULL){
        //stores in the vector
        v.push_back(tmp);
        //searches for the next " " character
        tmp = strtok(NULL, " ");
    }
}

//the function returns false if the command passed in
//is "exit" or any spaced variation of it.
//returnd false otherwise
bool isExit(char x[]){
    //sets up vars necessary for comparison
    string tmp = x;
    string hold = "exit";
    char spc = ' ';
    unsigned int k = 0;

    //if the size of the passed in char[] is less than that
    //necessary for it to be exit return false
    if(tmp.size() < hold.size()){
        return false;
    }

    //check each non-space character if within the first
    //four characters any of the characters dont align with "exit" return false
    //otherwise count how many more characters there are in the passed in string
    //if there are more than 4 return false otherwise return true
    //if a space appears when k is > 0 but < 4 return false, this prevents
    //bugs like "exi t" from working
    for(unsigned int i = 0; i < tmp.size(); i++){
        if(tmp.at(i) != spc){
            if(k < hold.size() && tmp.at(i) != hold.at(k)){
                return false;
            }
            k++;
        }
        else if(k > 0 && k < hold.size()){
            return false;
        }
    }
    if(k != hold.size()){
        return false;
    }
    else{
        return true;
    }
}

//traverses the entered list of commands
//and checks to see how many different kinds of
//connectors there are, if there are more than one
//it returns true else returns false
bool multiConn(string x){
    int amp = 0;
    int ln = 0;
    int semi = 0;
    int total = 0;
    //if any part of the string does not
    //align with "exit" returns false, otherwise counts
    //all characters after the passed in command
    for(unsigned int i = 0; i < x.size(); i++){
        if(x.at(i) == '&' && i != x.size()-1){
            if(x.at(i+1) == '&'){
                amp++;
            }
        }
        if(x.at(i) == '|' && i != x.size()-1){
           if(x.at(i+1) == '|'){
               ln++;
           }
        }
        if(x.at(i) == ';'){
            semi++;
        }

    }
    //calculates the total amount of different connectors
    if(amp > 0){
        total++;
    }
    if(semi > 0){
        total++;
    }
    if(ln > 0){
        total++;
    }
    //if more than one return true
    if(total > 1){
        cerr << "Multiple connector types forbidden" << endl;
        return true;
    }
    //else false
    else{
        return false;
    }
}

//the function searches for the '#' and
//removes anything after that character
string commentRemoval(string x){
    int comm = x.find('#');
    //if no '#' is found return the entire string
    if(comm == -1){
        return x;
    }
    //if the '#' is the first character return nothing
    else if(comm == 0){
        return "";
    }
    //otherwise return every thing up to the '#'
    else{
        return x.substr(0, comm);
    }
}

bool isls(char x[]){
    string tmp = x;
    if(tmp.size() < 2){
        return false;
    }
    if(tmp.at(0) == 'l' && tmp.at(1) == 's'){
        return true;
    }
    return false;
}

bool multiCheck(string x, bool flags[]){
    string chk = "alR";
    for(unsigned int i = 1; i < x.size(); i++){
        if(chk.find(x.at(i)) < 0 || chk.find(x.at(i)) >= x.size()){
            return false;
        }
        else if(x.at(i) == 'a'){
            flags[0] = true;
        }
        else if(x.at(i) == 'l'){
            flags[1] = true;
        }
        else if(x.at(i) == 'R'){
            flags[2] = true;
        }
    }
    return true;
}

bool ls_parse(vector<string> cmd, bool flags[], vector<string> &files){
    if(cmd.size() < 0){
        return false;
    }
    if(cmd.at(0) != "ls"){
        return false;
    }
    for(unsigned int i = 1; i < cmd.size(); i++){
        if(cmd.at(i) == "-a"){
            flags[0] = true;
        }
        else if(cmd.at(i) == "-l"){
            flags[1] = true;
        }
        else if(cmd.at(i) == "-R"){
            flags[2] = true;
        }
        else if(cmd.at(i).at(0) == '-'){
            if(!multiCheck(cmd.at(i), flags)){
                return false;
            }
        }
        else{
            files.push_back(cmd.at(i));
        }
    }
    return true;
}

//this function runs the command using fork and execvp
//and returns once all commands from the entered char[]
//have been executed
void run(char str[]){

    //needed to parse with strtok
    char* pch;

    //holds the bool of if a command executed properly
    bool sucs = true;

    //holds the return status of a fork/execvp
    int status = 0;

    //holds the connector used for the current list of comamnds
    string connector;

    //holds a string version of the passed in char[] for later
    //comparing
    string strz = str;

    //the vector that holds the commands to be converted and executed
    vector<string> cmd;

    //cbegins breaking the entered commands up by connector
    pch = strtok(str, ";");

    //if the command is empty return
    if(pch==NULL){
        return;
    }

    //if using strtok with ";" changed the strz
    //set the connector to be ";"
    else if(pch != strz){
        connector = ";";
    }
    //else if strz was unchanged use strtok with "&&"
    //if this changes the string is NULL return
    //of if strtok changed from the original value of strz set the connector
    if(pch == strz){
        pch = strtok(str, "&&");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "&&";
        }
    }
    //repeat the above process but with "||" instead of "&&"
    if(pch == strz){
        pch = strtok(str, "||");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "||";
        }
    }

    //if the pch is not NULL and is the exit command exit the programm
    if(pch != NULL && isExit(pch)){
        exit(0);
    }

    //this while loop is where fork and execvp execute commands
    while(pch != NULL){

        if(isls(pch)){
            int pid = fork();
            if(pid == 0){
            bool flags[3];
            flags[0] = false;
            flags[1] = false;
            flags[2] = false;
            bool valid = false;
            vector<string> files;
            parse(pch, cmd);
            valid = ls_parse(cmd, flags, files);
            if(!valid){
                cerr << "Invalid flag" << endl;
                exit(1);
            }
            else{
                cout << flags[0] << " " << flags[1] <<  " " << flags[2] << endl;
                for(unsigned int i = 0; i < files.size(); i++){
                    cout << files.at(i) << endl;
                }
                status = 0;
            }
            cmd.clear();
            files.clear();
            flags[0] = false;
            flags[1] = false;
            flags[2] = false;
            exit(0);
            }
            else{
                waitpid(-1, &status, 0);
            }
        }

        else{
            //fork the programm
            int pid = fork();
            //if pid is -1 the fork failed so exit
            if(pid == -1){
                perror("fork");
                exit(1);
            }
            //if the pid is 0 the current id the current process is the child
            else if(pid == 0){
                //call the parsing function on the command and the cmd vector
            //to break it up into command and params
            parse(pch, cmd);
            //set the size of the dynamic char** that will be passed into execvp
            int cmd_size = cmd.size() + 1;
            char** argc = new char*[cmd_size];
            //for each string in cmd copy it into argc, which will be passed
                //into execvp
            for(unsigned int i = 0 ; i < cmd.size(); i++ ){
                argc[i] = new char[cmd.at(i).size()];
                strcpy(argc[i], cmd.at(i).c_str());
            }
            //set the last value of argc to be NULL so that execvp will work properly
            argc[cmd.size()] = NULL;
                //call execvp on the first element of argc and the entirety of it
                //if it returns -1 it has failed fo print an error and delete
                //the dynamically allocated memory
                if(-1 ==  execvp(argc[0], argc)){
                    perror("execvp");
                    delete[] argc;
                    exit(1);
                }
            }
            //otherwise it is the parrent process
            else{
                //wait for any process to exit, in this case I only created on,
                //and store its exit code in status
                if(-1 == waitpid(-1, &status, 0)){
        	        perror("waitpid");
    	        	exit(1);
                }
            }
        }
        //if the value of status is larger than 0
        //it failed
        if(status > 0){
            sucs = false;
        }
        //otherwise if succeeded
        else{
            sucs = true;
        }

        //clear the vector holding the command to execute
         cmd.clear();

        //run the next command if the connector logic and value of sucs allow it
        if((connector=="&&" && sucs) || (connector=="||" && !sucs) || (connector==";")){
            pch = strtok(NULL, connector.c_str());
        }
        //otherwise return
        else{
            return;
        }
        //if the next command is not NULL and is exit exit the program
        if(pch != NULL && isExit(pch)){
            exit(0);
        }
    }
    //if there are no more commands to execute/parse return
    return;
}

//main takes in commands and passes them to run to execute
int main(){

    //continue until terminated by a conditional branch within run
    while(true){

        //retrieves the login name
        //and checks to make sure there was no error
        char* login = getlogin();
        if(login == NULL){
            perror("getlogin");
        }

        //sets up the host name variable, maximum of 128 chars
        char host[128];

        //holds return value of gethostname
        int hostFlag;

        //sets up input var
        string input;

        //retrieves the host name and checks for errors
        if((hostFlag = gethostname(host, sizeof(host))) == -1){
            perror("gethostname");
        }

        //if both login and gethostname rerurned without error
        //cout the login@host
        if(login != NULL && hostFlag != -1){
            cout << login << "@" << host << "$ ";
        }
        //otherwise cout vanilla prompt
        else{
            cout << "$ ";
        }

        //retrieve user input including spaces
        getline(cin, input);

        //remove anything that is a comment from the users input
        input = commentRemoval(input);

        //check for multiple connectors
        if(!multiConn(input)){
            //determines the size of the input
            int input_size = input.size()+1;
            //dynamically allocates a char*[] of the size of the input + 1
            char* str = new char[input_size];
            //copies the input into the char* str[]
            strcpy(str, input.c_str());
            //calls run on the users entered commands
            run(str);
            //after running the dynamically allocated memory is deleted
            delete[] str;
        }
        //if there are more than one connector do not run commands
        //and cerr error
   }
   return 0;
}
<commit_msg>fixed ls parsing bug<commit_after>#include <iostream>
#include <stdio.h>
#include <ctype.h>
#include <cstring>
#include <vector>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/wait.h>
using namespace std;

//parses the entered command putting each string seperated
//by spaces into a vector passed in by reference
//the function utilizes strtok to do this
void parse(char  x[], vector<string> &v){
    char* tmp;
    //separates the string by spaces
    tmp = strtok(x, " ");
    while(tmp != NULL){
        //stores in the vector
        v.push_back(tmp);
        //searches for the next " " character
        tmp = strtok(NULL, " ");
    }
}

//the function returns false if the command passed in
//is "exit" or any spaced variation of it.
//returnd false otherwise
bool isExit(char x[]){
    //sets up vars necessary for comparison
    string tmp = x;
    string hold = "exit";
    char spc = ' ';
    unsigned int k = 0;

    //if the size of the passed in char[] is less than that
    //necessary for it to be exit return false
    if(tmp.size() < hold.size()){
        return false;
    }

    //check each non-space character if within the first
    //four characters any of the characters dont align with "exit" return false
    //otherwise count how many more characters there are in the passed in string
    //if there are more than 4 return false otherwise return true
    //if a space appears when k is > 0 but < 4 return false, this prevents
    //bugs like "exi t" from working
    for(unsigned int i = 0; i < tmp.size(); i++){
        if(tmp.at(i) != spc){
            if(k < hold.size() && tmp.at(i) != hold.at(k)){
                return false;
            }
            k++;
        }
        else if(k > 0 && k < hold.size()){
            return false;
        }
    }
    if(k != hold.size()){
        return false;
    }
    else{
        return true;
    }
}

//traverses the entered list of commands
//and checks to see how many different kinds of
//connectors there are, if there are more than one
//it returns true else returns false
bool multiConn(string x){
    int amp = 0;
    int ln = 0;
    int semi = 0;
    int total = 0;
    //if any part of the string does not
    //align with "exit" returns false, otherwise counts
    //all characters after the passed in command
    for(unsigned int i = 0; i < x.size(); i++){
        if(x.at(i) == '&' && i != x.size()-1){
            if(x.at(i+1) == '&'){
                amp++;
            }
        }
        if(x.at(i) == '|' && i != x.size()-1){
           if(x.at(i+1) == '|'){
               ln++;
           }
        }
        if(x.at(i) == ';'){
            semi++;
        }

    }
    //calculates the total amount of different connectors
    if(amp > 0){
        total++;
    }
    if(semi > 0){
        total++;
    }
    if(ln > 0){
        total++;
    }
    //if more than one return true
    if(total > 1){
        cerr << "Multiple connector types forbidden" << endl;
        return true;
    }
    //else false
    else{
        return false;
    }
}

//the function searches for the '#' and
//removes anything after that character
string commentRemoval(string x){
    int comm = x.find('#');
    //if no '#' is found return the entire string
    if(comm == -1){
        return x;
    }
    //if the '#' is the first character return nothing
    else if(comm == 0){
        return "";
    }
    //otherwise return every thing up to the '#'
    else{
        return x.substr(0, comm);
    }
}

bool isls(char x[]){
    string tmp = x;
    if(tmp.size() < 2){
        return false;
    }
    if(tmp.at(0) == 'l' && tmp.at(1) == 's'){
        return true;
    }
    return false;
}

bool multiCheck(string x, bool flags[]){
    string chk = "alR";
    for(unsigned int i = 1; i < x.size(); i++){
        if(chk.find(x.at(i)) < 0 || chk.find(x.at(i)) >= x.size()){
            return false;
        }
        else if(x.at(i) == 'a'){
            flags[0] = true;
        }
        else if(x.at(i) == 'l'){
            flags[1] = true;
        }
        else if(x.at(i) == 'R'){
            flags[2] = true;
        }
    }
    return true;
}

bool ls_parse(vector<string> cmd, bool flags[], vector<string> &files){
    if(cmd.size() < 0){
        return false;
    }
    if(cmd.at(0) != "ls"){
        return false;
    }
    for(unsigned int i = 1; i < cmd.size(); i++){
        if(cmd.at(i) == "-a"){
            flags[0] = true;
        }
        else if(cmd.at(i) == "-l"){
            flags[1] = true;
        }
        else if(cmd.at(i) == "-R"){
            flags[2] = true;
        }
        else if(cmd.at(i) == "-"){
            return false;
        }
        else if(cmd.at(i).at(0) == '-'){
            if(!multiCheck(cmd.at(i), flags)){
                return false;
            }
        }
        else{
            files.push_back(cmd.at(i));
        }
    }
    return true;
}

//this function runs the command using fork and execvp
//and returns once all commands from the entered char[]
//have been executed
void run(char str[]){

    //needed to parse with strtok
    char* pch;

    //holds the bool of if a command executed properly
    bool sucs = true;

    //holds the return status of a fork/execvp
    int status = 0;

    //holds the connector used for the current list of comamnds
    string connector;

    //holds a string version of the passed in char[] for later
    //comparing
    string strz = str;

    //the vector that holds the commands to be converted and executed
    vector<string> cmd;

    //cbegins breaking the entered commands up by connector
    pch = strtok(str, ";");

    //if the command is empty return
    if(pch==NULL){
        return;
    }

    //if using strtok with ";" changed the strz
    //set the connector to be ";"
    else if(pch != strz){
        connector = ";";
    }
    //else if strz was unchanged use strtok with "&&"
    //if this changes the string is NULL return
    //of if strtok changed from the original value of strz set the connector
    if(pch == strz){
        pch = strtok(str, "&&");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "&&";
        }
    }
    //repeat the above process but with "||" instead of "&&"
    if(pch == strz){
        pch = strtok(str, "||");
        if(pch == NULL){
            return;
        }
        if(pch != strz){
            connector = "||";
        }
    }

    //if the pch is not NULL and is the exit command exit the programm
    if(pch != NULL && isExit(pch)){
        exit(0);
    }

    //this while loop is where fork and execvp execute commands
    while(pch != NULL){

        if(isls(pch)){
            int pid = fork();
            if(pid == 0){
            bool flags[3];
            flags[0] = false;
            flags[1] = false;
            flags[2] = false;
            bool valid = false;
            vector<string> files;
            parse(pch, cmd);
            valid = ls_parse(cmd, flags, files);
            if(!valid){
                cerr << "Invalid flag" << endl;
                exit(1);
            }
            else{
                cout << flags[0] << " " << flags[1] <<  " " << flags[2] << endl;
                for(unsigned int i = 0; i < files.size(); i++){
                    cout << files.at(i) << endl;
                }
                status = 0;
            }
            cmd.clear();
            files.clear();
            flags[0] = false;
            flags[1] = false;
            flags[2] = false;
            exit(0);
            }
            else{
                waitpid(-1, &status, 0);
            }
        }

        else{
            //fork the programm
            int pid = fork();
            //if pid is -1 the fork failed so exit
            if(pid == -1){
                perror("fork");
                exit(1);
            }
            //if the pid is 0 the current id the current process is the child
            else if(pid == 0){
                //call the parsing function on the command and the cmd vector
            //to break it up into command and params
            parse(pch, cmd);
            //set the size of the dynamic char** that will be passed into execvp
            int cmd_size = cmd.size() + 1;
            char** argc = new char*[cmd_size];
            //for each string in cmd copy it into argc, which will be passed
                //into execvp
            for(unsigned int i = 0 ; i < cmd.size(); i++ ){
                argc[i] = new char[cmd.at(i).size()];
                strcpy(argc[i], cmd.at(i).c_str());
            }
            //set the last value of argc to be NULL so that execvp will work properly
            argc[cmd.size()] = NULL;
                //call execvp on the first element of argc and the entirety of it
                //if it returns -1 it has failed fo print an error and delete
                //the dynamically allocated memory
                if(-1 ==  execvp(argc[0], argc)){
                    perror("execvp");
                    delete[] argc;
                    exit(1);
                }
            }
            //otherwise it is the parrent process
            else{
                //wait for any process to exit, in this case I only created on,
                //and store its exit code in status
                if(-1 == waitpid(-1, &status, 0)){
        	        perror("waitpid");
    	        	exit(1);
                }
            }
        }
        //if the value of status is larger than 0
        //it failed
        if(status > 0){
            sucs = false;
        }
        //otherwise if succeeded
        else{
            sucs = true;
        }

        //clear the vector holding the command to execute
         cmd.clear();

        //run the next command if the connector logic and value of sucs allow it
        if((connector=="&&" && sucs) || (connector=="||" && !sucs) || (connector==";")){
            pch = strtok(NULL, connector.c_str());
        }
        //otherwise return
        else{
            return;
        }
        //if the next command is not NULL and is exit exit the program
        if(pch != NULL && isExit(pch)){
            exit(0);
        }
    }
    //if there are no more commands to execute/parse return
    return;
}

//main takes in commands and passes them to run to execute
int main(){

    //continue until terminated by a conditional branch within run
    while(true){

        //retrieves the login name
        //and checks to make sure there was no error
        char* login = getlogin();
        if(login == NULL){
            perror("getlogin");
        }

        //sets up the host name variable, maximum of 128 chars
        char host[128];

        //holds return value of gethostname
        int hostFlag;

        //sets up input var
        string input;

        //retrieves the host name and checks for errors
        if((hostFlag = gethostname(host, sizeof(host))) == -1){
            perror("gethostname");
        }

        //if both login and gethostname rerurned without error
        //cout the login@host
        if(login != NULL && hostFlag != -1){
            cout << login << "@" << host << "$ ";
        }
        //otherwise cout vanilla prompt
        else{
            cout << "$ ";
        }

        //retrieve user input including spaces
        getline(cin, input);

        //remove anything that is a comment from the users input
        input = commentRemoval(input);

        //check for multiple connectors
        if(!multiConn(input)){
            //determines the size of the input
            int input_size = input.size()+1;
            //dynamically allocates a char*[] of the size of the input + 1
            char* str = new char[input_size];
            //copies the input into the char* str[]
            strcpy(str, input.c_str());
            //calls run on the users entered commands
            run(str);
            //after running the dynamically allocated memory is deleted
            delete[] str;
        }
        //if there are more than one connector do not run commands
        //and cerr error
   }
   return 0;
}
<|endoftext|>