<commit_before>#include <cstdio>
#include <cstdlib>
#include <set>
#include <cstring>
#include <ctime>

#include "Search.h"
#include "Utils.h"

using namespace std;

//
// Utilities
//

/** Check if element |index| is set in the bitmask */
inline bool isSetBit(const uint64_t bitmask[], const uint8_t& index) {
  uint8_t bucket = index >> 6;
  uint8_t offset = index % 64;
  uint64_t mask = 0x1 << offset;
  return bitmask[bucket] & mask != 0;
}

/** Set element |index| in the bitmask */
inline bool setBit(uint64_t bitmask[], const uint8_t& index) {
  uint8_t bucket = index >> 6;
  uint8_t offset = index % 64;
  uint64_t mask = 0x1 << offset;
  bitmask[bucket] = bitmask[bucket] | mask;
}

//
// Class Path
//
Path::Path(const Path* parentOrNull, const word* fact, uint8_t factLength, edge_type edgeType,
           const uint64_t fixedBitmask[], uint8_t lastMutatedIndex)
    : parent(parentOrNull),
      fact(fact),
      factLength(factLength),
      lastMutationIndex(lastMutatedIndex),
      edgeType(edgeType),
      fixedBitmask{fixedBitmask[0], fixedBitmask[1], fixedBitmask[2], fixedBitmask[3]} { }

Path::Path(const word* fact, uint8_t factLength)
    : parent(NULL),
      fact(fact),
      factLength(factLength),
      lastMutationIndex(255),
      edgeType(255),
      fixedBitmask{0,0,0,0} { }

Path::~Path() {
};

bool Path::operator==(const Path& other) const {
  // Check metadata
  if ( !( edgeType == other.edgeType && factLength == other.factLength ) ) {
    return false;
  }
  // Check fact content
  for (int i = 0; i < factLength; ++i) {
    if (other.fact[i] != fact[i]) {
      return false;
    }
  }
  // Return true
  return true;
}

//
// Class SearchType
//

//
// Class BreadthFirstSearch
//
BreadthFirstSearch::BreadthFirstSearch()
    : fringeLength(0), fringeCapacity(1), fringeI(0),
      poolCapacity(1), poolLength(0), poppedRoot(false),
      sumOffset(0){
  this->fringe = (Path*) malloc(fringeCapacity * sizeof(Path));
  this->memoryPool = (word*) malloc(poolCapacity * sizeof(word*));
}

BreadthFirstSearch::~BreadthFirstSearch() {
  free(this->fringe);
  free(this->memoryPool);
  delete this->root;
}

inline const Path* BreadthFirstSearch::push(
    const Path* parent, uint8_t mutationIndex,
    uint8_t replaceLength, word replace1, word replace2, edge_type edge) {

  // Allocate new fact
  uint8_t mutatedLength = parent->factLength - 1 + replaceLength;
  // (ensure space)
  while (poolLength + mutatedLength >= poolCapacity) {
    // (re-allocate array)
    word* newPool = (word*) malloc(2 * poolCapacity * sizeof(word*));
    if (newPool == NULL) {
      printf("WARN: could not allocate new fact pool (new length=%lu)]\n", 2*poolCapacity);
      return NULL;
    }
    uint64_t startOffset = ((uint64_t) newPool) - ((uint64_t) memoryPool);
    memcpy(newPool, memoryPool, poolCapacity * sizeof(word*));
    free(memoryPool);
    memoryPool = newPool;
    poolCapacity = 2 * poolCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i <fringeLength; ++i) {
      fringe[i].fact = (word*) (startOffset + ((uint64_t) fringe[i].fact));
    }
  }
  // (allocate fact)
  word* mutated = &memoryPool[poolLength];
  poolLength += mutatedLength;
  // (mutate fact)
  memcpy(mutated, parent->fact, mutationIndex * sizeof(word));
  if (replaceLength > 0) { mutated[mutationIndex] = replace1; }
  if (replaceLength > 1) { mutated[mutationIndex + 1] = replace2; }
  if (mutationIndex < parent->factLength - 1) {
    memcpy(&(mutated[mutationIndex + replaceLength]),
           &(parent->fact[mutationIndex + 1]),
           (parent->factLength - mutationIndex - 1) * sizeof(word));
  }

  // Compute fixed bitmap
  uint64_t fixedBitmask[4];
  memcpy(fixedBitmask, parent->fixedBitmask, 4 * sizeof(uint64_t));
  if (mutationIndex != parent->lastMutationIndex) {
    setBit(fixedBitmask, parent->lastMutationIndex);
  }

  // Allocate new path
  // (ensure space)
  while (fringeLength >= fringeCapacity) {
    // (re-allocate array)
    Path* newFringe = (Path*) malloc(2 * fringeCapacity * sizeof(Path));
    if (newFringe == NULL) {
      printf("WARN: could not allocate new fringe (new length=%lu)]\n", 2*fringeCapacity);
      return NULL;
    }
    uint64_t startOffset = ((uint64_t) newFringe) - ((uint64_t) fringe);
    memcpy(newFringe, fringe, fringeCapacity * sizeof(Path));
    free(fringe);
    fringe = newFringe;
    fringeCapacity = 2 * fringeCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i < fringeLength; ++i) {
      if (fringe[i].parent != root) {
        fringe[i].parent = (Path*) (startOffset + ((uint64_t) fringe[i].parent));
      }
    }
    if (parent != root) {
      parent = (Path*) (startOffset + ((uint64_t) parent));
    }
  }
  // (allocate path)
  new(&fringe[fringeLength]) Path(parent, mutated, mutatedLength, edge, fixedBitmask, mutationIndex);
  fringeLength += 1;
  return parent;
}

const Path* BreadthFirstSearch::peek() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  return &this->fringe[this->fringeI];
}

inline const Path* BreadthFirstSearch::pop() {
  if (this->fringeI == 0 && !poppedRoot) {
    poppedRoot = true;
    return root;
  }
  this->fringeI += 1;
  return &this->fringe[this->fringeI - 1];
}

inline bool BreadthFirstSearch::isEmpty() {
  return (fringeI >= fringeLength && poppedRoot) || root == NULL;
}

//
// Class CacheStrategy
//

//
// Class CacheStrategyNone
//
bool CacheStrategyNone::isSeen(const Path&) {
  return false;
}

void CacheStrategyNone::add(const Path&) { }

//
// Function search()
//

// A helper to push elements to the queue en bulk
inline const Path* flushQueue(SearchType* fringe,
                              const Path* parent,
                              const uint8_t* indexToMutateArr,
                              const word* sinkArr,
                              const uint8_t* typeArr,
                              const uint8_t queueLength) {
  uint8_t i = 0;
  while (parent != NULL && i < queueLength) {
    parent = fringe->push(parent, indexToMutateArr[i], 1, sinkArr[i], 0, typeArr[i]);
    i += 1;
  }
  return parent;
}

// The main search() function
vector<const Path*> Search(Graph* graph, FactDB* knownFacts,
                     const word* queryFact, const uint8_t queryFactLength,
                     SearchType* fringe, CacheStrategy* cache,
                     const uint64_t timeout) {
  //
  // Setup
  //
  // Create a vector for the return value to occupy
  vector<const Path*> responses;
  // Create the start state
  fringe->root = new Path(queryFact, queryFactLength);  // I need the memory to not go away
  // Initialize timer (number of elements popped from the fringe)
  uint64_t time = 0;
  const uint32_t tickTime = 100;
  std::clock_t startTime = std::clock();

  //
  // Search
  //
  while (!fringe->isEmpty() && time < timeout) {
    // Get the next element from the fringe
    if (fringe->isEmpty()) {
      // (fringe is empty -- this should basically never be called)
      printf("IMPOSSIBLE: the search fringe is empty. This means (a) there are leaf nodes in the graph, and (b) this would have caused a memory leak.\n");
      std::exit(1);
    }
    const Path* parent = fringe->pop();
    // Update time
    time += 1;
    if (time % tickTime == 0) {
      const uint32_t tickOOM
        = tickTime < 1000 ? 1 : (tickTime < 1000000 ? 1000 : (tickTime  < 1000000000 ? 1000000 : 1) );
      printf("[%lu%s / %lu%s search tick]; %lu paths found (%lu ms elapsed)\n",
             time / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             timeout / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             responses.size(),
             (uint64_t) (1000.0 * ( std::clock() - startTime ) / ((double) CLOCKS_PER_SEC)));
    }

    // -- Check If Valid --
    printf("Checking %s\n", toString(*graph, parent->fact, parent->factLength).c_str());
    if (knownFacts->contains(parent->fact, parent->factLength)) {
      responses.push_back(parent);
    }

    // -- Mutations --
    // (variables)
    uint8_t parentLength = parent->factLength;
    const uint64_t fixedBitmask[4] = { parent->fixedBitmask[0], parent->fixedBitmask[1], parent->fixedBitmask[2], parent->fixedBitmask[3] };
    const word* parentFact = parent->fact;  // note: this can change over the course of the search
    // (mutation queue)
    uint8_t indexToMutateArr[256];
    word sinkArr[256];
    uint8_t typeArr[256];
    uint8_t queueLength = 0;
    // (algorithm)
    for (uint8_t indexToMutate = 0;
         indexToMutate < parentLength;
         ++indexToMutate) {  // for each index to mutate...
      if (isSetBit(fixedBitmask, indexToMutate)) { continue; }
      uint32_t numMutations = 0;
      const edge* mutations = graph->outgoingEdgesFast(parentFact[indexToMutate], &numMutations);
      for (int i = 0; i < numMutations; ++i) {
        // Prune edges to add
        if (mutations[i].type > 1) { continue; } // TODO(gabor) don't only do WordNet up
        // Flush if necessary (save memory)
        if (queueLength >= 256) {
          parent = flushQueue(fringe, parent, indexToMutateArr, sinkArr, typeArr, queueLength);
          if (parent == NULL) {
            printf("Error pushing to stack; returning\n");
            return responses;
          }
          parentFact = parent->fact;
          queueLength = 0;
        }
        // Add the state to the fringe
        // These are queued up in order to try to protect the cache; the push() call is
        // fairly expensive memory-wise.
        indexToMutateArr[queueLength] = indexToMutate;
        sinkArr[queueLength] = mutations[i].sink;
        typeArr[queueLength] = mutations[i].type;
        printf("\tmutation [%d] %s -> %s  (type %s)\n", indexToMutateArr[queueLength],
               graph->gloss(parent->fact[indexToMutateArr[queueLength]]),
               graph->gloss(sinkArr[queueLength]),
               toString(typeArr[queueLength]).c_str());
        queueLength += 1;
//        parent = fringe->push(parent, indexToMutate, 1, mutations[i].sink, 0, mutations[i].type);
      }
    }
    if (flushQueue(fringe, parent, indexToMutateArr, sinkArr, typeArr, queueLength) == NULL) {
      printf("Error pushing to stack; returning\n");
      return responses;
    }
  }

  return responses;
}

<commit_msg>Remove debugging statements<commit_after>#include <cstdio>
#include <cstdlib>
#include <set>
#include <cstring>
#include <ctime>

#include "Search.h"
#include "Utils.h"

using namespace std;

//
// Utilities
//

/** Check if element |index| is set in the bitmask */
inline bool isSetBit(const uint64_t bitmask[], const uint8_t& index) {
  uint8_t bucket = index >> 6;
  uint8_t offset = index % 64;
  uint64_t mask = 0x1 << offset;
  return bitmask[bucket] & mask != 0;
}

/** Set element |index| in the bitmask */
inline bool setBit(uint64_t bitmask[], const uint8_t& index) {
  uint8_t bucket = index >> 6;
  uint8_t offset = index % 64;
  uint64_t mask = 0x1 << offset;
  bitmask[bucket] = bitmask[bucket] | mask;
}

//
// Class Path
//
Path::Path(const Path* parentOrNull, const word* fact, uint8_t factLength, edge_type edgeType,
           const uint64_t fixedBitmask[], uint8_t lastMutatedIndex)
    : parent(parentOrNull),
      fact(fact),
      factLength(factLength),
      lastMutationIndex(lastMutatedIndex),
      edgeType(edgeType),
      fixedBitmask{fixedBitmask[0], fixedBitmask[1], fixedBitmask[2], fixedBitmask[3]} { }

Path::Path(const word* fact, uint8_t factLength)
    : parent(NULL),
      fact(fact),
      factLength(factLength),
      lastMutationIndex(255),
      edgeType(255),
      fixedBitmask{0,0,0,0} { }

Path::~Path() {
};

bool Path::operator==(const Path& other) const {
  // Check metadata
  if ( !( edgeType == other.edgeType && factLength == other.factLength ) ) {
    return false;
  }
  // Check fact content
  for (int i = 0; i < factLength; ++i) {
    if (other.fact[i] != fact[i]) {
      return false;
    }
  }
  // Return true
  return true;
}

//
// Class SearchType
//

//
// Class BreadthFirstSearch
//
BreadthFirstSearch::BreadthFirstSearch()
    : fringeLength(0), fringeCapacity(1), fringeI(0),
      poolCapacity(1), poolLength(0), poppedRoot(false),
      sumOffset(0){
  this->fringe = (Path*) malloc(fringeCapacity * sizeof(Path));
  this->memoryPool = (word*) malloc(poolCapacity * sizeof(word*));
}

BreadthFirstSearch::~BreadthFirstSearch() {
  free(this->fringe);
  free(this->memoryPool);
  delete this->root;
}

inline const Path* BreadthFirstSearch::push(
    const Path* parent, uint8_t mutationIndex,
    uint8_t replaceLength, word replace1, word replace2, edge_type edge) {

  // Allocate new fact
  uint8_t mutatedLength = parent->factLength - 1 + replaceLength;
  // (ensure space)
  while (poolLength + mutatedLength >= poolCapacity) {
    // (re-allocate array)
    word* newPool = (word*) malloc(2 * poolCapacity * sizeof(word*));
    if (newPool == NULL) {
      printf("WARN: could not allocate new fact pool (new length=%lu)]\n", 2*poolCapacity);
      return NULL;
    }
    uint64_t startOffset = ((uint64_t) newPool) - ((uint64_t) memoryPool);
    memcpy(newPool, memoryPool, poolCapacity * sizeof(word*));
    free(memoryPool);
    memoryPool = newPool;
    poolCapacity = 2 * poolCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i <fringeLength; ++i) {
      fringe[i].fact = (word*) (startOffset + ((uint64_t) fringe[i].fact));
    }
  }
  // (allocate fact)
  word* mutated = &memoryPool[poolLength];
  poolLength += mutatedLength;
  // (mutate fact)
  memcpy(mutated, parent->fact, mutationIndex * sizeof(word));
  if (replaceLength > 0) { mutated[mutationIndex] = replace1; }
  if (replaceLength > 1) { mutated[mutationIndex + 1] = replace2; }
  if (mutationIndex < parent->factLength - 1) {
    memcpy(&(mutated[mutationIndex + replaceLength]),
           &(parent->fact[mutationIndex + 1]),
           (parent->factLength - mutationIndex - 1) * sizeof(word));
  }

  // Compute fixed bitmap
  uint64_t fixedBitmask[4];
  memcpy(fixedBitmask, parent->fixedBitmask, 4 * sizeof(uint64_t));
  if (mutationIndex != parent->lastMutationIndex) {
    setBit(fixedBitmask, parent->lastMutationIndex);
  }

  // Allocate new path
  // (ensure space)
  while (fringeLength >= fringeCapacity) {
    // (re-allocate array)
    Path* newFringe = (Path*) malloc(2 * fringeCapacity * sizeof(Path));
    if (newFringe == NULL) {
      printf("WARN: could not allocate new fringe (new length=%lu)]\n", 2*fringeCapacity);
      return NULL;
    }
    uint64_t startOffset = ((uint64_t) newFringe) - ((uint64_t) fringe);
    memcpy(newFringe, fringe, fringeCapacity * sizeof(Path));
    free(fringe);
    fringe = newFringe;
    fringeCapacity = 2 * fringeCapacity;
    // (fix pointers -- and God help me for pointer arithmetic)
    for (int i = 0; i < fringeLength; ++i) {
      if (fringe[i].parent != root) {
        fringe[i].parent = (Path*) (startOffset + ((uint64_t) fringe[i].parent));
      }
    }
    if (parent != root) {
      parent = (Path*) (startOffset + ((uint64_t) parent));
    }
  }
  // (allocate path)
  new(&fringe[fringeLength]) Path(parent, mutated, mutatedLength, edge, fixedBitmask, mutationIndex);
  fringeLength += 1;
  return parent;
}

const Path* BreadthFirstSearch::peek() {
  if (!poppedRoot && this->fringeI == 0) {
    poppedRoot = true;
    return root;
  }
  return &this->fringe[this->fringeI];
}

inline const Path* BreadthFirstSearch::pop() {
  if (this->fringeI == 0 && !poppedRoot) {
    poppedRoot = true;
    return root;
  }
  this->fringeI += 1;
  return &this->fringe[this->fringeI - 1];
}

inline bool BreadthFirstSearch::isEmpty() {
  return (fringeI >= fringeLength && poppedRoot) || root == NULL;
}

//
// Class CacheStrategy
//

//
// Class CacheStrategyNone
//
bool CacheStrategyNone::isSeen(const Path&) {
  return false;
}

void CacheStrategyNone::add(const Path&) { }

//
// Function search()
//

// A helper to push elements to the queue en bulk
inline const Path* flushQueue(SearchType* fringe,
                              const Path* parent,
                              const uint8_t* indexToMutateArr,
                              const word* sinkArr,
                              const uint8_t* typeArr,
                              const uint8_t queueLength) {
  uint8_t i = 0;
  while (parent != NULL && i < queueLength) {
    parent = fringe->push(parent, indexToMutateArr[i], 1, sinkArr[i], 0, typeArr[i]);
    i += 1;
  }
  return parent;
}

// The main search() function
vector<const Path*> Search(Graph* graph, FactDB* knownFacts,
                     const word* queryFact, const uint8_t queryFactLength,
                     SearchType* fringe, CacheStrategy* cache,
                     const uint64_t timeout) {
  //
  // Setup
  //
  // Create a vector for the return value to occupy
  vector<const Path*> responses;
  // Create the start state
  fringe->root = new Path(queryFact, queryFactLength);  // I need the memory to not go away
  // Initialize timer (number of elements popped from the fringe)
  uint64_t time = 0;
  const uint32_t tickTime = 100;
  std::clock_t startTime = std::clock();

  //
  // Search
  //
  while (!fringe->isEmpty() && time < timeout) {
    // Get the next element from the fringe
    if (fringe->isEmpty()) {
      // (fringe is empty -- this should basically never be called)
      printf("IMPOSSIBLE: the search fringe is empty. This means (a) there are leaf nodes in the graph, and (b) this would have caused a memory leak.\n");
      std::exit(1);
    }
    const Path* parent = fringe->pop();
    // Update time
    time += 1;
    if (time % tickTime == 0) {
      const uint32_t tickOOM
        = tickTime < 1000 ? 1 : (tickTime < 1000000 ? 1000 : (tickTime  < 1000000000 ? 1000000 : 1) );
      printf("[%lu%s / %lu%s search tick]; %lu paths found (%lu ms elapsed)\n",
             time / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             timeout / tickOOM,
             tickTime < 1000 ? "" : (tickTime < 999999 ? "k" : (tickTime  < 999999999 ? "m" : "") ),
             responses.size(),
             (uint64_t) (1000.0 * ( std::clock() - startTime ) / ((double) CLOCKS_PER_SEC)));
    }

    // -- Check If Valid --
//    printf("Checking %s\n", toString(*graph, parent->fact, parent->factLength).c_str());
    if (knownFacts->contains(parent->fact, parent->factLength)) {
      responses.push_back(parent);
    }

    // -- Mutations --
    // (variables)
    uint8_t parentLength = parent->factLength;
    const uint64_t fixedBitmask[4] = { parent->fixedBitmask[0], parent->fixedBitmask[1], parent->fixedBitmask[2], parent->fixedBitmask[3] };
    const word* parentFact = parent->fact;  // note: this can change over the course of the search
    // (mutation queue)
    uint8_t indexToMutateArr[256];
    word sinkArr[256];
    uint8_t typeArr[256];
    uint8_t queueLength = 0;
    // (algorithm)
    for (uint8_t indexToMutate = 0;
         indexToMutate < parentLength;
         ++indexToMutate) {  // for each index to mutate...
      if (isSetBit(fixedBitmask, indexToMutate)) { continue; }
      uint32_t numMutations = 0;
      const edge* mutations = graph->outgoingEdgesFast(parentFact[indexToMutate], &numMutations);
      for (int i = 0; i < numMutations; ++i) {
        // Prune edges to add
        if (mutations[i].type != 1) { continue; } // TODO(gabor) don't only do WordNet down
        // Flush if necessary (save memory)
        if (queueLength >= 255) {
          parent = flushQueue(fringe, parent, indexToMutateArr, sinkArr, typeArr, queueLength);
          if (parent == NULL) {
            printf("Error pushing to stack; returning\n");
            return responses;
          }
          parentFact = parent->fact;
          queueLength = 0;
        }
        // Add the state to the fringe
        // These are queued up in order to try to protect the cache; the push() call is
        // fairly expensive memory-wise.
        indexToMutateArr[queueLength] = indexToMutate;
        sinkArr[queueLength] = mutations[i].sink;
        typeArr[queueLength] = mutations[i].type;
//        printf("\tmutation [%d] %s -> %s  (type %s)\n", indexToMutateArr[queueLength],
//               graph->gloss(parent->fact[indexToMutateArr[queueLength]]),
//               graph->gloss(sinkArr[queueLength]),
//               toString(typeArr[queueLength]).c_str());
        queueLength += 1;
//        parent = fringe->push(parent, indexToMutate, 1, mutations[i].sink, 0, mutations[i].type);
      }
    }
    if (flushQueue(fringe, parent, indexToMutateArr, sinkArr, typeArr, queueLength) == NULL) {
      printf("Error pushing to stack; returning\n");
      return responses;
    }
  }

  return responses;
}

<|endoftext|>


<commit_before>//
//  Token.cpp
//  Phantasma
//
//  Created by Thomas Harte on 08/12/2013.
//  Copyright (c) 2013 Thomas Harte. All rights reserved.
//

#include "Token.h"

uint32_t Token::GetValue(CGameState *gameState, uint32_t suggestedValue)
{
	switch(type)
	{
		case CONSTANT:	return value;
		case VARIABLE:	return gameState->GetVariable(value);
		default:		return suggestedValue;
	}
}
<commit_msg>Fleshed out implementation.<commit_after>//
//  Token.cpp
//  Phantasma
//
//  Created by Thomas Harte on 08/12/2013.
//  Copyright (c) 2013 Thomas Harte. All rights reserved.
//

#include "Token.h"

Token::Token(Type _type)
{
	type = _type;
}

Token::Token(std::string *_string)
{
	type = Token::STRINGLITERAL;
	string = _string;
}

Token::Token(Type _type, uint32_t _value)
{
	type = _type;
	value = _value;
}

Token::Type Token::getType()
{
	return type;
}

uint32_t Token::GetValue(CGameState *gameState, uint32_t suggestedValue)
{
	switch(type)
	{
		case CONSTANT:	return value;
		case VARIABLE:	return gameState->GetVariable(value);
		default:		return suggestedValue;
	}
}

Token::~Token()
{
	if(type == Token::STRINGLITERAL && string)
		delete string;
}
<|endoftext|>


<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 **/

#include <QObject>
#include <QProcessEnvironment>
#include <QStandardPaths>

#if defined(Q_OS_WIN32)
#include <QSettings>
#endif

#if defined(Q_OS_LINUX)
#include <QApplication>
#include <QDir>
#include <QFile>
#endif

#include "platform.h"

#if defined(Q_OS_WIN32)
const QString gRegistryPath("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
#endif

#if defined(Q_OS_LINUX)
const QString gAutoStartPath(QDir::homePath() + "/.config/autostart/nitroshare.desktop");
const QString gDesktopFile(
    "[Desktop Entry]\n"
    "Version=1.0\n"
    "Name=NitroShare\n"
    "Type=Application\n"
    "Exec=%1\n"
    "Terminal=false\n"
);
#endif

Platform::OperatingSystem Platform::currentOperatingSystem()
{
#if defined(Q_OS_WIN32)
    return OperatingSystem::Windows;
#elif defined(Q_OS_MACX)
    return OperatingSystem::OSX;
#elif defined(Q_OS_LINUX)
    return OperatingSystem::Linux;
#else
    return OperatingSystem::Unknown;
#endif
}

Platform::Architecture Platform::currentArchitecture()
{
    // Note: Qt doesn't provide the definitions we need to accurately
    // determine the CPU architecture - in order to do that, we'll need
    // to check a few preprocessor definitions ourselves

#if defined(__i386__) || defined(_M_IX86)
    return Architecture::x86;
#elif defined(__x86_64__) || defined(_M_X64)
    return Architecture::x64;
#else
    return Architecture::Unknown;
#endif
}

Platform::DesktopEnvironment Platform::currentDesktopEnvironment()
{
    QString desktop = QProcessEnvironment::systemEnvironment().value("XDG_CURRENT_DESKTOP").toLower();
    if(desktop == "unity") {
        return DesktopEnvironment::Unity;
    } else if(desktop.startsWith("gnome")) {
        return DesktopEnvironment::Gnome;
    } else if(desktop.endsWith("plasma")) {
        return DesktopEnvironment::KDE;
    } else if(desktop == "xfce") {
        return DesktopEnvironment::XFCE;
    } else if(desktop == "mate") {
        return DesktopEnvironment::MATE;
    } else if(desktop.endsWith("cinnamon")) {
        return DesktopEnvironment::Cinnamon;
    } else if(desktop == "pantheon") {
        return DesktopEnvironment::Pantheon;
    } else {
        return DesktopEnvironment::Unknown;
    }
}

QString Platform::operatingSystemName(OperatingSystem operatingSystem)
{
    switch(operatingSystem) {
    case OperatingSystem::Windows:
        return "windows";
    case OperatingSystem::OSX:
        return "osx";
    case OperatingSystem::Linux:
        return "linux";
    default:
        return "unknown";
    }
}

QString Platform::operatingSystemFriendlyName(OperatingSystem operatingSystem)
{
    switch(operatingSystem) {
    case OperatingSystem::Windows:
        return QObject::tr("Windows");
    case OperatingSystem::OSX:
        return QObject::tr("OS X");
    case OperatingSystem::Linux:
        return QObject::tr("Linux");
    default:
        return QObject::tr("Unknown");
    }
}

Platform::OperatingSystem Platform::operatingSystemForName(const QString &name)
{
    if(name == "windows") {
        return OperatingSystem::Windows;
    } else if(name == "osx") {
        return OperatingSystem::OSX;
    } else if(name == "linux") {
        return OperatingSystem::Linux;
    } else {
        return OperatingSystem::Unknown;
    }
}

QString Platform::architectureName(Architecture architecture)
{
    switch(architecture) {
    case Architecture::x86:
        return "x86";
    case Architecture::x64:
        return "x86_64";
    default:
        return "unknown";
    }
}

bool Platform::useIndicator()
{
    // Detecting the correct icon to display is incredibly difficult - the
    // algorithm currently being used goes something like this:
    //  - Windows: use QSystemTrayIcon
    //  - OS X: use QSystemTrayIcon
    //  - Linux:
    //     - Unity: use AppIndicator
    //     - Gnome: use AppIndicator
    //     - KDE: use QSystemTrayIcon
    //     - MATE: use AppIndicator
    //     - Cinnamon: use AppIndicator
    //     - Pantheon: use AppIndicator
    if(currentOperatingSystem() == OperatingSystem::Linux) {
        switch(currentDesktopEnvironment()) {
        case DesktopEnvironment::Unity:
        case DesktopEnvironment::Gnome:
        case DesktopEnvironment::MATE:
        case DesktopEnvironment::Cinnamon:
        case DesktopEnvironment::Pantheon:
            return true;
        default:
            return false;
        }
    }

    // For everything else, use QSystemTrayIcon
    return false;
}

bool Platform::autoStart()
{
#if defined(Q_OS_WIN32)
    return QSettings(gRegistryPath, QSettings::NativeFormat).contains("NitroShare");
#elif defined(Q_OS_MACX)
    return false;
#elif defined(Q_OS_LINUX)
    return QFile::exists(gAutoStartPath);
#else
    return false;
#endif
}

bool Platform::setAutoStart(bool enable)
{
    const QString execPath(QApplication::arguments().at(0));

#if defined(Q_OS_WIN32)
    QSettings settings(gRegistryPath, QSettings::NativeFormat);
    if (enable) {
        settings.setValue("NitroShare", execPath);
    } else {
        settings.remove("NitroShare");
    }
    return true;
#elif defined(Q_OS_MACX)
    return false;
#elif defined(Q_OS_LINUX)
    if (enable) {
        QFile file(gAutoStartPath);
        if (!file.open(QIODevice::WriteOnly)) {
            return false;
        }
        return file.write(gDesktopFile.arg(execPath).toUtf8()) != -1;
    } else {
        return QFile::remove(gAutoStartPath);
    }
#else
    return false;
#endif
}
<commit_msg>Fixed compilation error on Windows.<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 **/

#include <QApplication>
#include <QObject>
#include <QProcessEnvironment>
#include <QStandardPaths>

#if defined(Q_OS_WIN32)
#include <QSettings>
#endif

#if defined(Q_OS_LINUX)
#include <QDir>
#include <QFile>
#endif

#include "platform.h"

#if defined(Q_OS_WIN32)
const QString gRegistryPath("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run");
#endif

#if defined(Q_OS_LINUX)
const QString gAutoStartPath(QDir::homePath() + "/.config/autostart/nitroshare.desktop");
const QString gDesktopFile(
    "[Desktop Entry]\n"
    "Version=1.0\n"
    "Name=NitroShare\n"
    "Type=Application\n"
    "Exec=%1\n"
    "Terminal=false\n"
);
#endif

Platform::OperatingSystem Platform::currentOperatingSystem()
{
#if defined(Q_OS_WIN32)
    return OperatingSystem::Windows;
#elif defined(Q_OS_MACX)
    return OperatingSystem::OSX;
#elif defined(Q_OS_LINUX)
    return OperatingSystem::Linux;
#else
    return OperatingSystem::Unknown;
#endif
}

Platform::Architecture Platform::currentArchitecture()
{
    // Note: Qt doesn't provide the definitions we need to accurately
    // determine the CPU architecture - in order to do that, we'll need
    // to check a few preprocessor definitions ourselves

#if defined(__i386__) || defined(_M_IX86)
    return Architecture::x86;
#elif defined(__x86_64__) || defined(_M_X64)
    return Architecture::x64;
#else
    return Architecture::Unknown;
#endif
}

Platform::DesktopEnvironment Platform::currentDesktopEnvironment()
{
    QString desktop = QProcessEnvironment::systemEnvironment().value("XDG_CURRENT_DESKTOP").toLower();
    if(desktop == "unity") {
        return DesktopEnvironment::Unity;
    } else if(desktop.startsWith("gnome")) {
        return DesktopEnvironment::Gnome;
    } else if(desktop.endsWith("plasma")) {
        return DesktopEnvironment::KDE;
    } else if(desktop == "xfce") {
        return DesktopEnvironment::XFCE;
    } else if(desktop == "mate") {
        return DesktopEnvironment::MATE;
    } else if(desktop.endsWith("cinnamon")) {
        return DesktopEnvironment::Cinnamon;
    } else if(desktop == "pantheon") {
        return DesktopEnvironment::Pantheon;
    } else {
        return DesktopEnvironment::Unknown;
    }
}

QString Platform::operatingSystemName(OperatingSystem operatingSystem)
{
    switch(operatingSystem) {
    case OperatingSystem::Windows:
        return "windows";
    case OperatingSystem::OSX:
        return "osx";
    case OperatingSystem::Linux:
        return "linux";
    default:
        return "unknown";
    }
}

QString Platform::operatingSystemFriendlyName(OperatingSystem operatingSystem)
{
    switch(operatingSystem) {
    case OperatingSystem::Windows:
        return QObject::tr("Windows");
    case OperatingSystem::OSX:
        return QObject::tr("OS X");
    case OperatingSystem::Linux:
        return QObject::tr("Linux");
    default:
        return QObject::tr("Unknown");
    }
}

Platform::OperatingSystem Platform::operatingSystemForName(const QString &name)
{
    if(name == "windows") {
        return OperatingSystem::Windows;
    } else if(name == "osx") {
        return OperatingSystem::OSX;
    } else if(name == "linux") {
        return OperatingSystem::Linux;
    } else {
        return OperatingSystem::Unknown;
    }
}

QString Platform::architectureName(Architecture architecture)
{
    switch(architecture) {
    case Architecture::x86:
        return "x86";
    case Architecture::x64:
        return "x86_64";
    default:
        return "unknown";
    }
}

bool Platform::useIndicator()
{
    // Detecting the correct icon to display is incredibly difficult - the
    // algorithm currently being used goes something like this:
    //  - Windows: use QSystemTrayIcon
    //  - OS X: use QSystemTrayIcon
    //  - Linux:
    //     - Unity: use AppIndicator
    //     - Gnome: use AppIndicator
    //     - KDE: use QSystemTrayIcon
    //     - MATE: use AppIndicator
    //     - Cinnamon: use AppIndicator
    //     - Pantheon: use AppIndicator
    if(currentOperatingSystem() == OperatingSystem::Linux) {
        switch(currentDesktopEnvironment()) {
        case DesktopEnvironment::Unity:
        case DesktopEnvironment::Gnome:
        case DesktopEnvironment::MATE:
        case DesktopEnvironment::Cinnamon:
        case DesktopEnvironment::Pantheon:
            return true;
        default:
            return false;
        }
    }

    // For everything else, use QSystemTrayIcon
    return false;
}

bool Platform::autoStart()
{
#if defined(Q_OS_WIN32)
    return QSettings(gRegistryPath, QSettings::NativeFormat).contains("NitroShare");
#elif defined(Q_OS_MACX)
    return false;
#elif defined(Q_OS_LINUX)
    return QFile::exists(gAutoStartPath);
#else
    return false;
#endif
}

bool Platform::setAutoStart(bool enable)
{
    const QString execPath(QApplication::arguments().at(0));

#if defined(Q_OS_WIN32)
    QSettings settings(gRegistryPath, QSettings::NativeFormat);
    if (enable) {
        settings.setValue("NitroShare", execPath);
    } else {
        settings.remove("NitroShare");
    }
    return true;
#elif defined(Q_OS_MACX)
    return false;
#elif defined(Q_OS_LINUX)
    if (enable) {
        QFile file(gAutoStartPath);
        if (!file.open(QIODevice::WriteOnly)) {
            return false;
        }
        return file.write(gDesktopFile.arg(execPath).toUtf8()) != -1;
    } else {
        return QFile::remove(gAutoStartPath);
    }
#else
    return false;
#endif
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2003-2010 KenamicK Entertainment

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "Main.h"

#ifdef LINUX_BUILD
#include <sys/timeb.h>
#include <time.h>
#define _ftime	ftime
struct timeb   time_struct;
#else /*  LINUX_BUILD */
struct _timeb  time_struct;
#endif  /*  LINUX_BUILD */

static std::ofstream debug_file;

///////////////////////////////////////////////////////////////////////
// Name: FixAngle()
// Desc: angle E{ 0, PI*2 ) (RAD)
///////////////////////////////////////////////////////////////////////
void FixAngle(float *angle)
{
    float myangle	= *angle;
    bool  bfixed	= false;

    while ( !bfixed )
    {
        if ( myangle > PI2 )
        {
            myangle -= PI2;
        }
        else if ( myangle < 0.0f )
        {
            myangle += PI2;
        }
        else
        {
            bfixed = true;
        }
    }

    *angle = myangle;
}

///////////////////////////////////////////////////////////////////////
// Name: Rad2Deg()
// Desc: Keeps radians in the range of (-PI, PI)
///////////////////////////////////////////////////////////////////////
float FixRad(float rad)
{
	float fixed_rad = rad;

	fixed_rad = fixed_rad > PI ? fixed_rad - PI2 : fixed_rad;
	fixed_rad = fixed_rad < -PI ? PI2 + fixed_rad : fixed_rad;

	return fixed_rad;
}

///////////////////////////////////////////////////////////////////////
// Name: Rad2Deg()
// Desc: Convert radians (-PI, PI) to degress (0, 360)
///////////////////////////////////////////////////////////////////////
float Rad2Deg(float rad)
{
	float fixed_rad = rad > 0.0f ? rad : (PI2 + rad);

	return fixed_rad * RAD1;
}

///////////////////////////////////////////////////////////////////////
// Name: Deg2Rad()
// Desc: Convert degress (0, 360) to radians (-PI, PI)
///////////////////////////////////////////////////////////////////////
float Deg2Rad(float deg)
{
	deg = deg < 0.0 ? 360.0f - deg : deg;
	deg = deg > 360.0f ? deg - 360.0f : deg;

	float fixed_rad = deg * DEG1;
	fixed_rad = fixed_rad > PI ? fixed_rad - PI2 : fixed_rad;
	fixed_rad = fixed_rad < -PI ? PI2 + fixed_rad : fixed_rad;

	return fixed_rad;
}

///////////////////////////////////////////////////////////////////////
// Name: intGetRnd()
// Desc:
///////////////////////////////////////////////////////////////////////
int intGetRnd ( int min_val, int max_val )
{
    int range = max_val - min_val;
    int num = rand() % range;
    return ( num + min_val );
}

///////////////////////////////////////////////////////////////////////
// Name: fGetRnd()
// Desc:
///////////////////////////////////////////////////////////////////////
float fGetRnd ( float min_val, float max_val )
{
    return ( ( max_val - min_val ) * ( float ) rand() / ( float ) RAND_MAX ) + min_val;
}

/////////////////////////////////////////////////////////////////////////
//// Name: GetDistance()
//// Desc: Vryshta razstoqnieto m/u 2 tochki
/////////////////////////////////////////////////////////////////////////
//Uint16  GetDistance( int x1, int y1, int x2, int y2 )
//{
//	int dx = x2 - x1;
//	int dy = y2 - y1;
//	float product = (float)( dx*dx + dy*dy );
//
//	return (Uint16)sqrt( product );
//}

/////////////////////////////////////////////////////////////////////////
//// Name: fGetDistance()
//// Desc: Vryshta razstoqnieto m/u 2 tochki (FLOAT)
/////////////////////////////////////////////////////////////////////////
//float  fGetDistance( float x1, float y1, float x2, float y2 )
//{
//	float dx = x2 - x1;
//	float dy = y2 - y1;
//
//	return sqrt( (float)( dx*dx + dy*dy ) );
//}

///////////////////////////////////////////////////////////////////////
// Name: GetDistanceNSR()
// Desc: (INT)
///////////////////////////////////////////////////////////////////////
Uint32  GetDistanceNSR ( int x1, int y1, int x2, int y2 )
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    return ( Uint32 ) ( dx*dx + dy*dy );
}

///////////////////////////////////////////////////////////////////////
// Name: GetDistanceNSR()
// Desc: (FLOAT)
///////////////////////////////////////////////////////////////////////
float  fGetDistanceNSR ( float x1, float y1, float x2, float y2 )
{
    float dx = x2 - x1;
    float dy = y2 - y1;

    return ( dx*dx + dy*dy );
}

///////////////////////////////////////////////////////////////////////
// Name: InRange()
// Desc: check if value is between given range
///////////////////////////////////////////////////////////////////////
bool InRange ( float val, float rangeMin, float rangeMax )
{
    if ( rangeMin > rangeMax )
    {
        if ( val <= rangeMin && val >= rangeMax ) return true;
    }
    else if ( rangeMin < rangeMax )
    {
        if ( val <= rangeMax && val >= rangeMin ) return true;
    }

    return false;
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGetXY()
// Desc: Convert one range to another
///////////////////////////////////////////////////////////////////////
float	fRangeGetXY(int in, int inMin, int inMax, float min, float max)
{
	int inRange = (inMax - inMin);
	float newRange = (max - min);
	float result = (((in - inMin) * newRange) / inRange) + min;

	return result;
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGet0255()
// Desc:
///////////////////////////////////////////////////////////////////////
float	fRangeGet0255(int in, float min, float max)
{
	return fRangeGetXY(in, 0, 255, min, max);
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGet0255()
// Desc:
///////////////////////////////////////////////////////////////////////
bool	fIsZero(float value)
{
	return fabsf(value) < MIN_FLOAT;
}

///////////////////////////////////////////////////////////////////////
// Name: GetFormattedTime()
// Desc:
///////////////////////////////////////////////////////////////////////
inline String GetFormattedTime()
{
    char buf[255];

#ifdef LINUX_BUILD
    time_t cur_time;
    tm *ptm = NULL;

    time ( &cur_time );
    ptm = localtime( &cur_time );

    sprintf ( buf, "%d:%d:%d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
    //sprintf ( buf1, "%s", ctime( &cur_time ) );
#else
    _strtime ( buf );
#endif

    _ftime ( &time_struct );
    sprintf ( buf, "%s.%.3u ", buf, time_struct.millitm );

    return buf;
}

///////////////////////////////////////////////////////////////////////
// Name: OpenLog()
// Desc: open global log file
///////////////////////////////////////////////////////////////////////
bool OpenLog ( const char* filename )
{
    String time( GetFormattedTime() );

    // open debug file
    debug_file.open ( "debug.html", std::ios::out ); //ios::ate );
    if ( ! debug_file.good() )
      return false;

    debug_file << "<title>Savage Wheels Log File</title>
Savage Wheels V" << VER_MAJ << "." << VER_MIN << " - Log File
";
    debug_file << "

";
    debug_file <<  time << "Build: " << APP_NAME << "
";
    debug_file <<  time << "Copyright © 2003-2013 KenamicK Entertainment
";
    debug_file <<  time << "Opened on: " << __DATE__ << "
";
    debug_file <<  time << "Opened at: " << __TIME__ << "
";
    debug_file <<  time << LOG_DASH << "
";

    return true;
}

///////////////////////////////////////////////////////////////////////
// Name: AppendToLog()
// Desc: add a line to global log file
///////////////////////////////////////////////////////////////////////
void AppendToLog ( const char *dbgstring )
{
    String time( GetFormattedTime() );
    debug_file << time << dbgstring << "\n";

    // XXX: Flushing every time is brutally slow but helps
    //      against losing log info if game suddenly crashes !
    debug_file.flush();
}

/////////////////////////////////////////////////////////////////////////
//// Name: AppendToMultilog()
//// Desc: dobavq nqkolko niz-a kym Log-a
/////////////////////////////////////////////////////////////////////////
//void AppendToMultilog( char *dbgstring, ... )
//{
//	char *strnext = dbgstring;
//	va_list arg_list;
//	char buf1[64];
//
//#ifdef LINUX_BUILD
//	time_t cur_time;
//	time( &cur_time );
//	sprintf( buf1, "%s", ctime( &cur_time ) );
//#else
//	_strtime( buf1 );
//#endif
//
//	_ftime( &time_struct );
//	sprintf( buf1, "%s.%.3u", buf1, time_struct.millitm );
//
//	debug_file << buf1 << " ";
//
//	va_start( arg_list, dbgstring );
//
//	while ( strnext != NULL )
//	{
//		debug_file << strnext;
//		strnext = va_arg( arg_list, char* );
//	}
//
//	va_end( arg_list );
//
//	debug_file << "\n";
//
//	debug_file.flush();
//
//}

///////////////////////////////////////////////////////////////////////
// Name: CloseLog()
// Desc: close global log file
///////////////////////////////////////////////////////////////////////
void CloseLog ( void )
{
    AppendToLog ( "Game closed." );
    debug_file << "\n
";
    debug_file.close();
}

///////////////////////////////////////////////////////////////////////
// Name: ExtractFilename()
// Desc:
///////////////////////////////////////////////////////////////////////
String ExtractFilename ( const String strPath )
{
    String strResult ( strPath );
    String::size_type idx = strResult.find_last_of ( ANY_BACKSLASH );
    if ( idx != String::npos )
    {
        strResult.erase ( 0, idx + 1 );
    }

    return strResult;
}

///////////////////////////////////////////////////////////////////////
// Name: PathExists()
// Desc:
///////////////////////////////////////////////////////////////////////
bool PathExists ( const String strPath, struct stat* _pStats /*= NULL*/ )
{
//#ifndef LINUX_BUILD
#if 0
    if ( INVALID_FILE_ATTRIBUTES != ::GetFileAttributesA ( strPath.c_str() ) )
    {
        return true;
    }
    else
    {
        DBG ( "Failed to find file %s! lasterror=%d", strPath.c_str(), GetLastError(), NULL );
    }
#else
    if ( _pStats )
    {
        //pStats = _pStats;
        if ( -1 != stat( strPath.c_str(), _pStats ) )
            return true;
    }
    else
    {
        struct stat _stats;

        if ( -1 != stat( strPath.c_str(), &_stats ) )
            return true;
    }
#endif

    return false;
}
<commit_msg>Edited comments<commit_after>/*
    Copyright (c) 2003-2010 KenamicK Entertainment

    Permission is hereby granted, free of charge, to any person
    obtaining a copy of this software and associated documentation
    files (the "Software"), to deal in the Software without
    restriction, including without limitation the rights to use,
    copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the
    Software is furnished to do so, subject to the following
    conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
    OTHER DEALINGS IN THE SOFTWARE.

*/

#include "Main.h"

#ifdef LINUX_BUILD
#include <sys/timeb.h>
#include <time.h>
#define _ftime	ftime
struct timeb   time_struct;
#else /*  LINUX_BUILD */
struct _timeb  time_struct;
#endif  /*  LINUX_BUILD */

static std::ofstream debug_file;

///////////////////////////////////////////////////////////////////////
// Name: FixAngle()
// Desc: angle E{ 0, PI*2 ) (RAD)
///////////////////////////////////////////////////////////////////////
void FixAngle(float *angle)
{
    float myangle	= *angle;
    bool  bfixed	= false;

    while ( !bfixed )
    {
        if ( myangle > PI2 )
        {
            myangle -= PI2;
        }
        else if ( myangle < 0.0f )
        {
            myangle += PI2;
        }
        else
        {
            bfixed = true;
        }
    }

    *angle = myangle;
}

///////////////////////////////////////////////////////////////////////
// Name: Rad2Deg()
// Desc: Keeps radians in the range of (-PI, PI)
///////////////////////////////////////////////////////////////////////
float FixRad(float rad)
{
	float fixed_rad = rad;

	fixed_rad = fixed_rad > PI ? fixed_rad - PI2 : fixed_rad;
	fixed_rad = fixed_rad < -PI ? PI2 + fixed_rad : fixed_rad;

	return fixed_rad;
}

///////////////////////////////////////////////////////////////////////
// Name: Rad2Deg()
// Desc: Convert radians (-PI, PI) to degress (0, 360)
///////////////////////////////////////////////////////////////////////
float Rad2Deg(float rad)
{
	float fixed_rad = rad > 0.0f ? rad : (PI2 + rad);

	return fixed_rad * RAD1;
}

///////////////////////////////////////////////////////////////////////
// Name: Deg2Rad()
// Desc: Convert degress (0, 360) to radians (-PI, PI)
///////////////////////////////////////////////////////////////////////
float Deg2Rad(float deg)
{
	deg = deg < 0.0 ? 360.0f - deg : deg;
	deg = deg > 360.0f ? deg - 360.0f : deg;

	float fixed_rad = deg * DEG1;
	fixed_rad = fixed_rad > PI ? fixed_rad - PI2 : fixed_rad;
	fixed_rad = fixed_rad < -PI ? PI2 + fixed_rad : fixed_rad;

	return fixed_rad;
}

///////////////////////////////////////////////////////////////////////
// Name: intGetRnd()
// Desc:
///////////////////////////////////////////////////////////////////////
int intGetRnd ( int min_val, int max_val )
{
    int range = max_val - min_val;
    int num = rand() % range;
    return ( num + min_val );
}

///////////////////////////////////////////////////////////////////////
// Name: fGetRnd()
// Desc:
///////////////////////////////////////////////////////////////////////
float fGetRnd ( float min_val, float max_val )
{
    return ( ( max_val - min_val ) * ( float ) rand() / ( float ) RAND_MAX ) + min_val;
}

/////////////////////////////////////////////////////////////////////////
//// Name: GetDistance()
//// Desc: (Uint)
/////////////////////////////////////////////////////////////////////////
//Uint16  GetDistance( int x1, int y1, int x2, int y2 )
//{
//	int dx = x2 - x1;
//	int dy = y2 - y1;
//	float product = (float)( dx*dx + dy*dy );
//
//	return (Uint16)sqrt( product );
//}

/////////////////////////////////////////////////////////////////////////
//// Name: fGetDistance()
//// Desc: (FLOAT)
/////////////////////////////////////////////////////////////////////////
//float  fGetDistance( float x1, float y1, float x2, float y2 )
//{
//	float dx = x2 - x1;
//	float dy = y2 - y1;
//
//	return sqrt( (float)( dx*dx + dy*dy ) );
//}

///////////////////////////////////////////////////////////////////////
// Name: GetDistanceNSR()
// Desc: Get unsquared dance (int)
///////////////////////////////////////////////////////////////////////
Uint32 GetDistanceNSR ( int x1, int y1, int x2, int y2 )
{
    int dx = x2 - x1;
    int dy = y2 - y1;

    return (Uint32)(dx*dx + dy*dy);
}

///////////////////////////////////////////////////////////////////////
// Name: GetDistanceNSR()
// Desc: Get unsquared dance (float)
///////////////////////////////////////////////////////////////////////
float fGetDistanceNSR ( float x1, float y1, float x2, float y2 )
{
    float dx = x2 - x1;
    float dy = y2 - y1;

    return (dx*dx + dy*dy);
}

///////////////////////////////////////////////////////////////////////
// Name: InRange()
// Desc: check if value is between given range
///////////////////////////////////////////////////////////////////////
bool InRange ( float val, float rangeMin, float rangeMax )
{
    if ( rangeMin > rangeMax )
    {
        if ( val <= rangeMin && val >= rangeMax ) return true;
    }
    else if ( rangeMin < rangeMax )
    {
        if ( val <= rangeMax && val >= rangeMin ) return true;
    }

    return false;
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGetXY()
// Desc: Convert one range to another
///////////////////////////////////////////////////////////////////////
float	fRangeGetXY(int in, int inMin, int inMax, float min, float max)
{
	int inRange = (inMax - inMin);
	float newRange = (max - min);
	float result = (((in - inMin) * newRange) / inRange) + min;

	return result;
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGet0255()
// Desc:
///////////////////////////////////////////////////////////////////////
float	fRangeGet0255(int in, float min, float max)
{
	return fRangeGetXY(in, 0, 255, min, max);
}

///////////////////////////////////////////////////////////////////////
// Name: fRangeGet0255()
// Desc:
///////////////////////////////////////////////////////////////////////
bool	fIsZero(float value)
{
	return fabsf(value) < MIN_FLOAT;
}

///////////////////////////////////////////////////////////////////////
// Name: GetFormattedTime()
// Desc:
///////////////////////////////////////////////////////////////////////
inline String GetFormattedTime()
{
    char buf[255];

#ifdef LINUX_BUILD
    time_t cur_time;
    tm *ptm = NULL;

    time ( &cur_time );
    ptm = localtime( &cur_time );

    sprintf ( buf, "%d:%d:%d", ptm->tm_hour, ptm->tm_min, ptm->tm_sec );
    //sprintf ( buf1, "%s", ctime( &cur_time ) );
#else
    _strtime ( buf );
#endif

    _ftime ( &time_struct );
    sprintf ( buf, "%s.%.3u ", buf, time_struct.millitm );

    return buf;
}

///////////////////////////////////////////////////////////////////////
// Name: OpenLog()
// Desc: open global log file
///////////////////////////////////////////////////////////////////////
bool OpenLog ( const char* filename )
{
    String time( GetFormattedTime() );

    // open debug file
    debug_file.open ( "debug.html", std::ios::out ); //ios::ate );
    if ( ! debug_file.good() )
      return false;

    debug_file << "<title>Savage Wheels Log File</title>
Savage Wheels V" << VER_MAJ << "." << VER_MIN << " - Log File
";
    debug_file << "

";
    debug_file <<  time << "Build: " << APP_NAME << "
";
    debug_file <<  time << "Copyright © 2003-2013 KenamicK Entertainment
";
    debug_file <<  time << "Opened on: " << __DATE__ << "
";
    debug_file <<  time << "Opened at: " << __TIME__ << "
";
    debug_file <<  time << LOG_DASH << "
";

    return true;
}

///////////////////////////////////////////////////////////////////////
// Name: AppendToLog()
// Desc: add a line to global log file
///////////////////////////////////////////////////////////////////////
void AppendToLog ( const char *dbgstring )
{
    String time( GetFormattedTime() );
    debug_file << time << dbgstring << "\n";

    // XXX: Flushing every time is brutally slow but helps
    //      against losing log info if game suddenly crashes !
    debug_file.flush();
}

/////////////////////////////////////////////////////////////////////////
//// Name: AppendToMultilog()
//// Desc: dobavq nqkolko niz-a kym Log-a
/////////////////////////////////////////////////////////////////////////
//void AppendToMultilog( char *dbgstring, ... )
//{
//	char *strnext = dbgstring;
//	va_list arg_list;
//	char buf1[64];
//
//#ifdef LINUX_BUILD
//	time_t cur_time;
//	time( &cur_time );
//	sprintf( buf1, "%s", ctime( &cur_time ) );
//#else
//	_strtime( buf1 );
//#endif
//
//	_ftime( &time_struct );
//	sprintf( buf1, "%s.%.3u", buf1, time_struct.millitm );
//
//	debug_file << buf1 << " ";
//
//	va_start( arg_list, dbgstring );
//
//	while ( strnext != NULL )
//	{
//		debug_file << strnext;
//		strnext = va_arg( arg_list, char* );
//	}
//
//	va_end( arg_list );
//
//	debug_file << "\n";
//
//	debug_file.flush();
//
//}

///////////////////////////////////////////////////////////////////////
// Name: CloseLog()
// Desc: close global log file
///////////////////////////////////////////////////////////////////////
void CloseLog ( void )
{
    AppendToLog ( "Game closed." );
    debug_file << "\n
";
    debug_file.close();
}

///////////////////////////////////////////////////////////////////////
// Name: ExtractFilename()
// Desc:
///////////////////////////////////////////////////////////////////////
String ExtractFilename ( const String strPath )
{
    String strResult ( strPath );
    String::size_type idx = strResult.find_last_of ( ANY_BACKSLASH );
    if ( idx != String::npos )
    {
        strResult.erase ( 0, idx + 1 );
    }

    return strResult;
}

///////////////////////////////////////////////////////////////////////
// Name: PathExists()
// Desc:
///////////////////////////////////////////////////////////////////////
bool PathExists ( const String strPath, struct stat* _pStats /*= NULL*/ )
{
//#ifndef LINUX_BUILD
#if 0
    if ( INVALID_FILE_ATTRIBUTES != ::GetFileAttributesA ( strPath.c_str() ) )
    {
        return true;
    }
    else
    {
        DBG ( "Failed to find file %s! lasterror=%d", strPath.c_str(), GetLastError(), NULL );
    }
#else
    if ( _pStats )
    {
        //pStats = _pStats;
        if ( -1 != stat( strPath.c_str(), _pStats ) )
            return true;
    }
    else
    {
        struct stat _stats;

        if ( -1 != stat( strPath.c_str(), &_stats ) )
            return true;
    }
#endif

    return false;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg, Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/socket_io.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/escape_string.hpp"
#include <boost/bind.hpp>

namespace libtorrent {

	alert::alert() : m_timestamp(time_now()) {}
	alert::~alert() {}
	ptime alert::timestamp() const { return m_timestamp; }

	std::string torrent_alert::message() const
	{
		if (!handle.is_valid()) return " - ";
		if (handle.name().empty())
		{
			char msg[41];
			to_hex((char const*)&handle.info_hash()[0], 20, msg);
			return msg;
		}
		return handle.name();
	}

	std::string peer_alert::message() const
	{
		error_code ec;
		return torrent_alert::message() + " peer (" + ip.address().to_string(ec)
			+ ", " + identify_client(pid) + ")";
	}

	std::string tracker_alert::message() const
	{
		return torrent_alert::message() + " (" + url + ")";
	}

	std::string read_piece_alert::message() const
	{
		char msg[200];
		snprintf(msg, sizeof(msg), "%s: piece %s %u", torrent_alert::message().c_str()
			, buffer ? "successful" : "failed", piece);
		return msg;
	}

	std::string file_completed_alert::message() const
	{
		char msg[200 + TORRENT_MAX_PATH];
		snprintf(msg, sizeof(msg), "%s: file %d finished downloading"
			, torrent_alert::message().c_str(), index);
		return msg;
	}

	std::string file_renamed_alert::message() const
	{
		char msg[200 + TORRENT_MAX_PATH * 2];
		snprintf(msg, sizeof(msg), "%s: file %d renamed to %s", torrent_alert::message().c_str()
			, index, name.c_str());
		return msg;
	}

	std::string file_rename_failed_alert::message() const
	{
		char ret[200 + TORRENT_MAX_PATH * 2];
		snprintf(ret, sizeof(ret), "%s: failed to rename file %d: %s"
			, torrent_alert::message().c_str(), index, error.message().c_str());
		return ret;
	}

	std::string performance_alert::message() const
	{
		static char const* warning_str[] =
		{
			"max outstanding disk writes reached",
			"max outstanding piece requests reached",
			"upload limit too low (download rate will suffer)",
			"download limit too low (upload rate will suffer)",
			"send buffer watermark too low (upload rate will suffer)"
		};

		return torrent_alert::message() + ": performance warning: "
			+ warning_str[warning_code];
	}

	std::string state_changed_alert::message() const
	{
		static char const* state_str[] =
			{"checking (q)", "checking", "dl metadata"
			, "downloading", "finished", "seeding", "allocating"
			, "checking (r)"};

		return torrent_alert::message() + ": state changed to: "
			+ state_str[state];
	}

	std::string tracker_error_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s (%d) %s (%d)"
			, torrent_alert::message().c_str(), status_code
			, msg.c_str(), times_in_row);
		return ret;
	}

	std::string tracker_warning_alert::message() const
	{
		return tracker_alert::message() + " warning: " + msg;
	}

	std::string scrape_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s scrape reply: %u %u"
			, torrent_alert::message().c_str(), incomplete, complete);
		return ret;
	}

	std::string scrape_failed_alert::message() const
	{
		return tracker_alert::message() + " scrape failed: " + msg;
	}

	std::string tracker_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s received peers: %u"
			, torrent_alert::message().c_str(), num_peers);
		return ret;
	}

	std::string dht_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s received DHT peers: %u"
			, torrent_alert::message().c_str(), num_peers);
		return ret;
	}

	std::string tracker_announce_alert::message() const
	{
		const static char* event_str[] = {"none", "completed", "started", "stopped"};
		return tracker_alert::message() + " sending announce (" + event_str[event] + ")";
	}

	std::string hash_failed_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s hash for piece %u failed"
			, torrent_alert::message().c_str(), piece_index);
		return ret;
	}

	std::string peer_ban_alert::message() const
	{
		return peer_alert::message() + " banned peer";
	}

	std::string peer_unsnubbed_alert::message() const
	{
		return peer_alert::message() + " peer unsnubbed";
	}

	std::string peer_snubbed_alert::message() const
	{
		return peer_alert::message() + " peer snubbed";
	}

	std::string invalid_request_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer sent an invalid piece request (piece: %u start: %u len: %u)"
			, torrent_alert::message().c_str(), request.piece, request.start, request.length);
		return ret;
	}

	std::string piece_finished_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s piece: %u finished downloading"
			, torrent_alert::message().c_str(), piece_index);
		return ret;
	}

	std::string request_dropped_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer dropped block ( piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_timeout_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer timed out request ( piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_finished_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s block finished downloading (piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_downloading_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s requested block (piece: %u block: %u) %s"
			, torrent_alert::message().c_str(), piece_index, block_index, peer_speedmsg);
		return ret;
	}

	std::string unwanted_block_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s received block not in download queue (piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string listen_failed_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "listening on %s failed: %s"
			, print_endpoint(endpoint).c_str(), error.message().c_str());
		return ret;
	}

	std::string listen_succeeded_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "successfully listening on %s", print_endpoint(endpoint).c_str());
		return ret;
	}

	std::string portmap_error_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		return std::string("could not map port using ") + type_str[map_type]
			+ ": " + error.message();
	}

	std::string portmap_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		char ret[200];
		snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %u"
			, type_str[map_type], external_port);
		return ret;
	}

	std::string portmap_log_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		char ret[200];
		snprintf(ret, sizeof(ret), "%s: %s", type_str[map_type], msg.c_str());
		return ret;
	}

	std::string dht_announce_alert::message() const
	{
		error_code ec;
		char ih_hex[41];
		to_hex((const char*)&info_hash[0], 20, ih_hex);
		char msg[200];
		snprintf(msg, sizeof(msg), "incoming dht announce: %s:%u (%s)"
			, ip.to_string(ec).c_str(), port, ih_hex);
		return msg;
	}

	std::string dht_get_peers_alert::message() const
	{
		char ih_hex[41];
		to_hex((const char*)&info_hash[0], 20, ih_hex);
		char msg[200];
		snprintf(msg, sizeof(msg), "incoming dht get_peers: %s", ih_hex);
		return msg;
	}

	alert_manager::alert_manager(io_service& ios)
		: m_alert_mask(alert::error_notification)
		, m_queue_size_limit(queue_size_limit_default)
		, m_ios(ios)
	{}

	alert_manager::~alert_manager()
	{
		while (!m_alerts.empty())
		{
			delete m_alerts.front();
			m_alerts.pop();
		}
	}

	alert const* alert_manager::wait_for_alert(time_duration max_wait)
	{
		mutex::scoped_lock lock(m_mutex);

		if (!m_alerts.empty()) return m_alerts.front();

//		system_time end = get_system_time()
//			+ boost::posix_time::microseconds(total_microseconds(max_wait));

		// apparently this call can be interrupted
		// prematurely if there are other signals
//		while (m_condition.timed_wait(lock, end))
//			if (!m_alerts.empty()) return m_alerts.front();

		ptime start = time_now_hires();

		// TODO: change this to use an asio timer instead
		while (m_alerts.empty())
		{
			lock.unlock();
			sleep(50);
			lock.lock();
			if (time_now_hires() - start >= max_wait) return 0;
		}
		return m_alerts.front();
	}

	void alert_manager::set_dispatch_function(boost::function<void(alert const&)> const& fun)
	{
		mutex::scoped_lock lock(m_mutex);

		m_dispatch = fun;

		std::queue<alert*> alerts = m_alerts;
		while (!m_alerts.empty()) m_alerts.pop();
		lock.unlock();

		while (!alerts.empty())
		{
			m_dispatch(*alerts.front());
			delete alerts.front();
			alerts.pop();
		}
	}

	void dispatch_alert(boost::function<void(alert const&)> dispatcher
		, alert* alert_)
	{
		std::auto_ptr<alert> holder(alert_);
		dispatcher(*alert_);
	}

	void alert_manager::post_alert(const alert& alert_)
	{
		mutex::scoped_lock lock(m_mutex);

		if (m_dispatch)
		{
			TORRENT_ASSERT(m_alerts.empty());
			m_ios.post(boost::bind(&dispatch_alert, m_dispatch, alert_.clone().release()));
			return;
		}

		if (m_alerts.size() >= m_queue_size_limit) return;
		m_alerts.push(alert_.clone().release());
		m_condition.signal(lock);
		m_condition.clear(lock);
	}

	std::auto_ptr<alert> alert_manager::get()
	{
		mutex::scoped_lock lock(m_mutex);

		TORRENT_ASSERT(!m_alerts.empty());

		alert* result = m_alerts.front();
		m_alerts.pop();
		return std::auto_ptr<alert>(result);
	}

	bool alert_manager::pending() const
	{
		mutex::scoped_lock lock(m_mutex);

		return !m_alerts.empty();
	}

	size_t alert_manager::set_alert_queue_size_limit(size_t queue_size_limit_)
	{
		mutex::scoped_lock lock(m_mutex);

		std::swap(m_queue_size_limit, queue_size_limit_);
		return queue_size_limit_;
	}

} // namespace libtorrent

<commit_msg>extended portmap log alert message cap to 600 characters<commit_after>/*

Copyright (c) 2003, Arvid Norberg, Daniel Wallin
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/pch.hpp"

#include "libtorrent/alert.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/io_service.hpp"
#include "libtorrent/socket_io.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/error_code.hpp"
#include "libtorrent/escape_string.hpp"
#include <boost/bind.hpp>

namespace libtorrent {

	alert::alert() : m_timestamp(time_now()) {}
	alert::~alert() {}
	ptime alert::timestamp() const { return m_timestamp; }

	std::string torrent_alert::message() const
	{
		if (!handle.is_valid()) return " - ";
		if (handle.name().empty())
		{
			char msg[41];
			to_hex((char const*)&handle.info_hash()[0], 20, msg);
			return msg;
		}
		return handle.name();
	}

	std::string peer_alert::message() const
	{
		error_code ec;
		return torrent_alert::message() + " peer (" + ip.address().to_string(ec)
			+ ", " + identify_client(pid) + ")";
	}

	std::string tracker_alert::message() const
	{
		return torrent_alert::message() + " (" + url + ")";
	}

	std::string read_piece_alert::message() const
	{
		char msg[200];
		snprintf(msg, sizeof(msg), "%s: piece %s %u", torrent_alert::message().c_str()
			, buffer ? "successful" : "failed", piece);
		return msg;
	}

	std::string file_completed_alert::message() const
	{
		char msg[200 + TORRENT_MAX_PATH];
		snprintf(msg, sizeof(msg), "%s: file %d finished downloading"
			, torrent_alert::message().c_str(), index);
		return msg;
	}

	std::string file_renamed_alert::message() const
	{
		char msg[200 + TORRENT_MAX_PATH * 2];
		snprintf(msg, sizeof(msg), "%s: file %d renamed to %s", torrent_alert::message().c_str()
			, index, name.c_str());
		return msg;
	}

	std::string file_rename_failed_alert::message() const
	{
		char ret[200 + TORRENT_MAX_PATH * 2];
		snprintf(ret, sizeof(ret), "%s: failed to rename file %d: %s"
			, torrent_alert::message().c_str(), index, error.message().c_str());
		return ret;
	}

	std::string performance_alert::message() const
	{
		static char const* warning_str[] =
		{
			"max outstanding disk writes reached",
			"max outstanding piece requests reached",
			"upload limit too low (download rate will suffer)",
			"download limit too low (upload rate will suffer)",
			"send buffer watermark too low (upload rate will suffer)"
		};

		return torrent_alert::message() + ": performance warning: "
			+ warning_str[warning_code];
	}

	std::string state_changed_alert::message() const
	{
		static char const* state_str[] =
			{"checking (q)", "checking", "dl metadata"
			, "downloading", "finished", "seeding", "allocating"
			, "checking (r)"};

		return torrent_alert::message() + ": state changed to: "
			+ state_str[state];
	}

	std::string tracker_error_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s (%d) %s (%d)"
			, torrent_alert::message().c_str(), status_code
			, msg.c_str(), times_in_row);
		return ret;
	}

	std::string tracker_warning_alert::message() const
	{
		return tracker_alert::message() + " warning: " + msg;
	}

	std::string scrape_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s scrape reply: %u %u"
			, torrent_alert::message().c_str(), incomplete, complete);
		return ret;
	}

	std::string scrape_failed_alert::message() const
	{
		return tracker_alert::message() + " scrape failed: " + msg;
	}

	std::string tracker_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s received peers: %u"
			, torrent_alert::message().c_str(), num_peers);
		return ret;
	}

	std::string dht_reply_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s received DHT peers: %u"
			, torrent_alert::message().c_str(), num_peers);
		return ret;
	}

	std::string tracker_announce_alert::message() const
	{
		const static char* event_str[] = {"none", "completed", "started", "stopped"};
		return tracker_alert::message() + " sending announce (" + event_str[event] + ")";
	}

	std::string hash_failed_alert::message() const
	{
		char ret[400];
		snprintf(ret, sizeof(ret), "%s hash for piece %u failed"
			, torrent_alert::message().c_str(), piece_index);
		return ret;
	}

	std::string peer_ban_alert::message() const
	{
		return peer_alert::message() + " banned peer";
	}

	std::string peer_unsnubbed_alert::message() const
	{
		return peer_alert::message() + " peer unsnubbed";
	}

	std::string peer_snubbed_alert::message() const
	{
		return peer_alert::message() + " peer snubbed";
	}

	std::string invalid_request_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer sent an invalid piece request (piece: %u start: %u len: %u)"
			, torrent_alert::message().c_str(), request.piece, request.start, request.length);
		return ret;
	}

	std::string piece_finished_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s piece: %u finished downloading"
			, torrent_alert::message().c_str(), piece_index);
		return ret;
	}

	std::string request_dropped_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer dropped block ( piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_timeout_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s peer timed out request ( piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_finished_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s block finished downloading (piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string block_downloading_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s requested block (piece: %u block: %u) %s"
			, torrent_alert::message().c_str(), piece_index, block_index, peer_speedmsg);
		return ret;
	}

	std::string unwanted_block_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "%s received block not in download queue (piece: %u block: %u)"
			, torrent_alert::message().c_str(), piece_index, block_index);
		return ret;
	}

	std::string listen_failed_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "listening on %s failed: %s"
			, print_endpoint(endpoint).c_str(), error.message().c_str());
		return ret;
	}

	std::string listen_succeeded_alert::message() const
	{
		char ret[200];
		snprintf(ret, sizeof(ret), "successfully listening on %s", print_endpoint(endpoint).c_str());
		return ret;
	}

	std::string portmap_error_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		return std::string("could not map port using ") + type_str[map_type]
			+ ": " + error.message();
	}

	std::string portmap_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		char ret[200];
		snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %u"
			, type_str[map_type], external_port);
		return ret;
	}

	std::string portmap_log_alert::message() const
	{
		static char const* type_str[] = {"NAT-PMP", "UPnP"};
		char ret[600];
		snprintf(ret, sizeof(ret), "%s: %s", type_str[map_type], msg.c_str());
		return ret;
	}

	std::string dht_announce_alert::message() const
	{
		error_code ec;
		char ih_hex[41];
		to_hex((const char*)&info_hash[0], 20, ih_hex);
		char msg[200];
		snprintf(msg, sizeof(msg), "incoming dht announce: %s:%u (%s)"
			, ip.to_string(ec).c_str(), port, ih_hex);
		return msg;
	}

	std::string dht_get_peers_alert::message() const
	{
		char ih_hex[41];
		to_hex((const char*)&info_hash[0], 20, ih_hex);
		char msg[200];
		snprintf(msg, sizeof(msg), "incoming dht get_peers: %s", ih_hex);
		return msg;
	}

	alert_manager::alert_manager(io_service& ios)
		: m_alert_mask(alert::error_notification)
		, m_queue_size_limit(queue_size_limit_default)
		, m_ios(ios)
	{}

	alert_manager::~alert_manager()
	{
		while (!m_alerts.empty())
		{
			delete m_alerts.front();
			m_alerts.pop();
		}
	}

	alert const* alert_manager::wait_for_alert(time_duration max_wait)
	{
		mutex::scoped_lock lock(m_mutex);

		if (!m_alerts.empty()) return m_alerts.front();

//		system_time end = get_system_time()
//			+ boost::posix_time::microseconds(total_microseconds(max_wait));

		// apparently this call can be interrupted
		// prematurely if there are other signals
//		while (m_condition.timed_wait(lock, end))
//			if (!m_alerts.empty()) return m_alerts.front();

		ptime start = time_now_hires();

		// TODO: change this to use an asio timer instead
		while (m_alerts.empty())
		{
			lock.unlock();
			sleep(50);
			lock.lock();
			if (time_now_hires() - start >= max_wait) return 0;
		}
		return m_alerts.front();
	}

	void alert_manager::set_dispatch_function(boost::function<void(alert const&)> const& fun)
	{
		mutex::scoped_lock lock(m_mutex);

		m_dispatch = fun;

		std::queue<alert*> alerts = m_alerts;
		while (!m_alerts.empty()) m_alerts.pop();
		lock.unlock();

		while (!alerts.empty())
		{
			m_dispatch(*alerts.front());
			delete alerts.front();
			alerts.pop();
		}
	}

	void dispatch_alert(boost::function<void(alert const&)> dispatcher
		, alert* alert_)
	{
		std::auto_ptr<alert> holder(alert_);
		dispatcher(*alert_);
	}

	void alert_manager::post_alert(const alert& alert_)
	{
		mutex::scoped_lock lock(m_mutex);

		if (m_dispatch)
		{
			TORRENT_ASSERT(m_alerts.empty());
			m_ios.post(boost::bind(&dispatch_alert, m_dispatch, alert_.clone().release()));
			return;
		}

		if (m_alerts.size() >= m_queue_size_limit) return;
		m_alerts.push(alert_.clone().release());
		m_condition.signal(lock);
		m_condition.clear(lock);
	}

	std::auto_ptr<alert> alert_manager::get()
	{
		mutex::scoped_lock lock(m_mutex);

		TORRENT_ASSERT(!m_alerts.empty());

		alert* result = m_alerts.front();
		m_alerts.pop();
		return std::auto_ptr<alert>(result);
	}

	bool alert_manager::pending() const
	{
		mutex::scoped_lock lock(m_mutex);

		return !m_alerts.empty();
	}

	size_t alert_manager::set_alert_queue_size_limit(size_t queue_size_limit_)
	{
		mutex::scoped_lock lock(m_mutex);

		std::swap(m_queue_size_limit, queue_size_limit_);
		return queue_size_limit_;
	}

} // namespace libtorrent

<|endoftext|>


<commit_before>#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

using namespace std;

bool execute (string pass)
{
	char* test[80];
	//valid = 1;
	vector<string> command;
	string temp= "";
	unsigned j = 0;
	unsigned i = 0;

	while (i < pass.size())
	{
		for (j = i ; j < pass.size(); ++j)
		{
			if (pass.at(j) ==' ')
			{
				//this means we are moving to next word.
				++j;
				break;
			}
			else
			{
				temp = temp + pass.at(j);
			}
		}

		if (temp == "exit")
		{
			cout << "exiting! (in parse)" << endl;
			exit(0);
		}

		command.push_back(temp);
		temp.clear();

		//so we can start basing on where we left off in pass string
		i = j;
	}

	unsigned k = 0;

	for(; k < command.size() ;++k)
    {
    	string temp_str = command.at(k);
        test[k] = (char*)temp_str.c_str();
    }

    test[k] = '\0';

	pid_t pid = fork();

	//if pid is less than 0, then fork failed
 	if (pid < 0)
 	{
 		perror("Fork failed");
 		exit(-1);
 	}

	/*run execvp in the child because execvp automatically terminates all
	  processes after it executes*/
 	if (pid == 0) //child process
    {
    	//if execvp returns -1, the command did not execute
        if (execvp(test[0], test) == -1)
        {
        	perror("exec");
        	command.clear();
        	return false;
        }
    }

	if (pid > 0) //parent process
    {
        if (wait(0) == -1)
        {
        	perror("wait");
        	command.clear();
            return false;
        }
    }

	command.clear();
	return true;
}

void parse (vector<string> &input)
{
	vector<string> reverse_input;

	//reverse the vector of inputs
	//so we can use pop_back (we could make a quene but we did this instead)
	for (int i = input.size() - 1; i >= 0; --i)
	{
		reverse_input.push_back(input.at(i));
	}

	//check if the 1st command is exit
	//if it is, exit the program
	if (input.at(0) == "exit")
	{
		input.clear();
		reverse_input.clear();
		cout << "exiting (exit is only input)" << endl;
		exit(0);
	}

	//execute 1st command;
	bool  valid;
	int size = reverse_input.size();
	valid = execute(reverse_input.at(size - 1));
	reverse_input.pop_back();

	//parse this vector and execute accordingly
	for (int i = reverse_input.size() - 1; i >= 0; i = i - 2)
	{
		if (reverse_input.at(i) == ";")
		{
			//check for exit command
			if (reverse_input.at(i - 1) == "exit")
			{
				execute(reverse_input.at(i - 1));
			}

			//always execute a command that follows a semicolon
			execute(reverse_input.at(i - 1));
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
		else if (reverse_input.at(i) == "&&")
		{
			if (valid == true) //1st command executed properly
			{
				//check for exit command
				if (reverse_input.at(i - 1) == "exit")
				{
					execute(reverse_input.at(i - 1));
				}

				//execute 2nd command
				execute(reverse_input.at(i - 1));
			}
			//if the 1st command is NOT valid, we do NOT want to execute the 2nd one
			/*whether we execute or not, we still want to pop_back() 3 times to
			  move to the next command*/
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
		else if (reverse_input.at(i) == "||")
		{
			if (valid == false) //1st command did not execute
			{
				//check for exit command
				if (reverse_input.at(i - 1) == "exit")
				{
					execute(reverse_input.at(i - 1));
				}

				execute(reverse_input.at(i - 1));
			}

			//if the 1st command is VALID, we do NOT want to execute the 2nd one
			/*whether we execute or not, we still want to pop_back() 3 times to
			  move to the next command*/
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
	}
}

int main()
{
	//loop until the user exits
	while (1)
	{
		//command line inputted by user
		char userInput[100];

		//get hostname (extra credit)
		char hostname[80];
	    gethostname(hostname, sizeof hostname);

		//print a command prompt (e.g. $)
		printf("%s $ ", hostname);
		// cout << "$ ";

		//read in command as one line
		cin.getline(userInput, 100);

		char userInput_no_comments[100];
		if(userInput[0] == '\0')
		{
			// //keep looping
			// cout <<"Keep looping" ;
		}
		else
		{
			//ignore everything after '#' (everything after '#' is a comment)
			for (int i = 0; userInput[i] != '\0'; ++i)
			{
				if (userInput[i] == '#')
				{
					break;
				}

				userInput_no_comments[i] = userInput[i];
				userInput_no_comments[i + 1] = '\0';
			}

			//get connectors from userInput and store it into a vector
			//but in this vector && and || are stored as & & and | |
			vector<char> vector_connectors_separated;

			//FIX THIS LATER IF THERE IS TIME
			//DOES NOT ACCOUNT FOR JUST '&', JUST '|', OR MORE THAN TWO '&'s OR '|'s
			//ALSO DOES NOT ACCOUNT FOR MORE THAN ONE ';' IN A ROW
			for (unsigned i = 0; userInput_no_comments[i] != '\0'; ++i)
			{
				if (userInput_no_comments[i] == ';'|| userInput_no_comments[i] == '&'
					|| userInput_no_comments[i] == '|')
				{
					vector_connectors_separated.push_back(userInput[i]);
				}
			}

			//NOW COMBIN & and & into && and | and | into ||
			vector<string> vector_connectors;

			for (unsigned i = 0; i < vector_connectors_separated.size(); ++i)
			{
				if (vector_connectors_separated.at(i) == '&')
				{
					vector_connectors.push_back("&&");
					++i;
				}
				else if (vector_connectors_separated.at(i) == '|')
				{
					vector_connectors.push_back("||");
					++i;
				}
				else if (vector_connectors_separated.at(i) == ';')
				{
					vector_connectors.push_back(";");
				}
			}

			//use strtok to separate input into "tokens"
			char* tokens; //command and its arguments
			char delimiters[] = ";&&||";
			tokens = strtok(userInput_no_comments, delimiters);

			//stores all the commands and its arguments as separate "tokens"
			vector<char*> vector_tokens;

			while (tokens != NULL)
			{
				// int position =0;
				// while(())
				//remove first whitespace in token
				if (tokens[0] == ' ')
				{
					++tokens; //go to next character (ignore 1st white space)
				}

				vector_tokens.push_back(tokens);
				tokens = strtok(NULL, delimiters);
			}

			//convert the tokens from char* to string
			vector<string> vector_tokens_str;

			for (unsigned i = 0; i < vector_tokens.size(); ++i)
			{
				char* s = vector_tokens.at(i);
				string str(s);
				vector_tokens_str.push_back(str);
			}

			//put everything into one vector called input
			vector<string> input;

			for (unsigned i = 0; i < vector_tokens_str.size() - 1; ++i)
			{
				input.push_back(vector_tokens_str.at(i));
				input.push_back(vector_connectors.at(i));
			}

			//add in the last command
			/*if we put this in the for loop above, it would go out of range, because
			  vector_connectors is smalled than vector_tokens_str by one*/
			int size = vector_tokens_str.size();
			input.push_back(vector_tokens_str.at(size - 1));

			//clearing everyyything
			vector_tokens_str.clear();
			vector_connectors.clear();
			vector_connectors_separated.clear();
			// userInput = "";
			//delete[] userInput;
			// userInput_no_comments("");

			//run execute on commands
			parse(input);
		}
	}

	return 0;
}<commit_msg>took out empty if statement for ENTER<commit_after>#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <unistd.h>
#include <stdio.h>
#include <sys/unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

using namespace std;

bool execute (string pass)
{
	char* test[80];
	//valid = 1;
	vector<string> command;
	string temp= "";
	unsigned j = 0;
	unsigned i = 0;

	while (i < pass.size())
	{
		for (j = i ; j < pass.size(); ++j)
		{
			if (pass.at(j) ==' ')
			{
				//this means we are moving to next word.
				++j;
				break;
			}
			else
			{
				temp = temp + pass.at(j);
			}
		}

		if (temp == "exit")
		{
			cout << "exiting! (in parse)" << endl;
			exit(0);
		}

		command.push_back(temp);
		temp.clear();

		//so we can start basing on where we left off in pass string
		i = j;
	}

	unsigned k = 0;

	for(; k < command.size() ;++k)
    {
    	string temp_str = command.at(k);
        test[k] = (char*)temp_str.c_str();
    }

    test[k] = '\0';

	pid_t pid = fork();

	//if pid is less than 0, then fork failed
 	if (pid < 0)
 	{
 		perror("Fork failed");
 		exit(-1);
 	}

	/*run execvp in the child because execvp automatically terminates all
	  processes after it executes*/
 	if (pid == 0) //child process
    {
    	//if execvp returns -1, the command did not execute
        if (execvp(test[0], test) == -1)
        {
        	perror("exec");
        	command.clear();
        	return false;
        }
    }

	if (pid > 0) //parent process
    {
        if (wait(0) == -1)
        {
        	perror("wait");
        	command.clear();
            return false;
        }
    }

	command.clear();
	return true;
}

void parse (vector<string> &input)
{
	vector<string> reverse_input;

	//reverse the vector of inputs
	//so we can use pop_back (we could make a quene but we did this instead)
	for (int i = input.size() - 1; i >= 0; --i)
	{
		reverse_input.push_back(input.at(i));
	}

	//check if the 1st command is exit
	//if it is, exit the program
	if (input.at(0) == "exit")
	{
		input.clear();
		reverse_input.clear();
		cout << "exiting (exit is only input)" << endl;
		exit(0);
	}

	//execute 1st command;
	bool  valid;
	int size = reverse_input.size();
	valid = execute(reverse_input.at(size - 1));
	reverse_input.pop_back();

	//parse this vector and execute accordingly
	for (int i = reverse_input.size() - 1; i >= 0; i = i - 2)
	{
		if (reverse_input.at(i) == ";")
		{
			//check for exit command
			if (reverse_input.at(i - 1) == "exit")
			{
				execute(reverse_input.at(i - 1));
			}

			//always execute a command that follows a semicolon
			execute(reverse_input.at(i - 1));
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
		else if (reverse_input.at(i) == "&&")
		{
			if (valid == true) //1st command executed properly
			{
				//check for exit command
				if (reverse_input.at(i - 1) == "exit")
				{
					execute(reverse_input.at(i - 1));
				}

				//execute 2nd command
				execute(reverse_input.at(i - 1));
			}
			//if the 1st command is NOT valid, we do NOT want to execute the 2nd one
			/*whether we execute or not, we still want to pop_back() 3 times to
			  move to the next command*/
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
		else if (reverse_input.at(i) == "||")
		{
			if (valid == false) //1st command did not execute
			{
				//check for exit command
				if (reverse_input.at(i - 1) == "exit")
				{
					execute(reverse_input.at(i - 1));
				}

				execute(reverse_input.at(i - 1));
			}

			//if the 1st command is VALID, we do NOT want to execute the 2nd one
			/*whether we execute or not, we still want to pop_back() 3 times to
			  move to the next command*/
			reverse_input.pop_back();
			reverse_input.pop_back();
		}
	}
}

int main()
{
	//loop until the user exits
	while (1)
	{
		//command line inputted by user
		char userInput[100];

		//get hostname (extra credit)
		char hostname[80];
	    gethostname(hostname, sizeof hostname);

		//print a command prompt (e.g. $)
		printf("%s $ ", hostname);
		// cout << "$ ";

		//read in command as one line
		cin.getline(userInput, 100);

		char userInput_no_comments[100];

		// if(userInput[0] == '\0')
		// {
		// 	//if the user enters, nothing will happen and keeps on looping for next input.
		// }
		if(userInput[0] != '\0')
		{
			//ignore everything after '#' (everything after '#' is a comment)
			for (int i = 0; userInput[i] != '\0'; ++i)
			{
				if (userInput[i] == '#')
				{
					break;
				}

				userInput_no_comments[i] = userInput[i];
				userInput_no_comments[i + 1] = '\0';
			}

			//get connectors from userInput and store it into a vector
			//but in this vector && and || are stored as & & and | |
			vector<char> vector_connectors_separated;

			//FIX THIS LATER IF THERE IS TIME
			//DOES NOT ACCOUNT FOR JUST '&', JUST '|', OR MORE THAN TWO '&'s OR '|'s
			//ALSO DOES NOT ACCOUNT FOR MORE THAN ONE ';' IN A ROW
			for (unsigned i = 0; userInput_no_comments[i] != '\0'; ++i)
			{
				if (userInput_no_comments[i] == ';'|| userInput_no_comments[i] == '&'
					|| userInput_no_comments[i] == '|')
				{
					vector_connectors_separated.push_back(userInput[i]);
				}
			}

			//NOW COMBIN & and & into && and | and | into ||
			vector<string> vector_connectors;

			for (unsigned i = 0; i < vector_connectors_separated.size(); ++i)
			{
				if (vector_connectors_separated.at(i) == '&')
				{
					vector_connectors.push_back("&&");
					++i;
				}
				else if (vector_connectors_separated.at(i) == '|')
				{
					vector_connectors.push_back("||");
					++i;
				}
				else if (vector_connectors_separated.at(i) == ';')
				{
					vector_connectors.push_back(";");
				}
			}

			//use strtok to separate input into "tokens"
			char* tokens; //command and its arguments
			char delimiters[] = ";&&||";
			tokens = strtok(userInput_no_comments, delimiters);

			//stores all the commands and its arguments as separate "tokens"
			vector<char*> vector_tokens;

			while (tokens != NULL)
			{
				// int position =0;
				// while(())
				//remove first whitespace in token
				if (tokens[0] == ' ')
				{
					++tokens; //go to next character (ignore 1st white space)
				}

				vector_tokens.push_back(tokens);
				tokens = strtok(NULL, delimiters);
			}

			//convert the tokens from char* to string
			vector<string> vector_tokens_str;

			for (unsigned i = 0; i < vector_tokens.size(); ++i)
			{
				char* s = vector_tokens.at(i);
				string str(s);
				vector_tokens_str.push_back(str);
			}

			//put everything into one vector called input
			vector<string> input;

			for (unsigned i = 0; i < vector_tokens_str.size() - 1; ++i)
			{
				input.push_back(vector_tokens_str.at(i));
				input.push_back(vector_connectors.at(i));
			}

			//add in the last command
			/*if we put this in the for loop above, it would go out of range, because
			  vector_connectors is smalled than vector_tokens_str by one*/
			int size = vector_tokens_str.size();
			input.push_back(vector_tokens_str.at(size - 1));

			//clearing everyyything
			vector_tokens_str.clear();
			vector_connectors.clear();
			vector_connectors_separated.clear();
			// userInput = "";
			//delete[] userInput;
			// userInput_no_comments("");

			//run execute on commands
			parse(input);
		}
	}

	return 0;
}<|endoftext|>