<commit_before>/*
   Copyright (c) 2010, The Mineserver Project
   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 The Mineserver Project 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 HOLDER 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 <cstdlib>
#include <cstdio>
#include <iostream>
#include <deque>
#include <fstream>
#include <vector>
#include <ctime>
#include <math.h>
#ifdef WIN32
  #include <winsock2.h>
#else
  #include <netinet/in.h>
  #include <string.h>
#endif

#include "logger.h"
#include "constants.h"

#include "tools.h"
#include "map.h"
#include "user.h"
#include "chat.h"
#include "config.h"
#include "physics.h"

Chat &Chat::get()
{
  static Chat instance;
  return instance;
}

Chat::Chat()
{
  registerStandardCommands();
}

void Chat::registerCommand(std::string name, ChatCommand command, bool adminOnly)
{
  if(adminOnly)
    adminCommands[name] = command;
  else
    userCommands[name] = command;
}

bool Chat::checkMotd(std::string motdFile)
{
  //
  // Create motdfile is it doesn't exist
  //
  std::ifstream ifs(motdFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << motdFile << " not found. Creating..." << std::endl;

    std::ofstream motdofs(motdFile.c_str());
    motdofs << DEFAULTMOTDFILE << std::endl;
    motdofs.close();
  }

  ifs.close();

  return true;
}

bool Chat::loadAdmins(std::string adminFile)
{
  // Clear current admin-vector
  admins.clear();

  // Read admins to deque
  std::ifstream ifs(adminFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << adminFile << " not found. Creating..." << std::endl;

    std::ofstream adminofs(adminFile.c_str());
    adminofs << DEFAULTADMINFILE << std::endl;
    adminofs.close();

    return true;
  }

  std::string temp;
  while(getline(ifs, temp))
  {
    // If not commentline
    if(temp[0] != COMMENTPREFIX)
      admins.push_back(temp);
  }
  ifs.close();

  std::cout << "Loaded admins from " << adminFile << std::endl;

  return true;
}

bool Chat::sendUserlist(User *user)
{
  this->sendMsg(user, COLOR_BLUE + "[ Players online ]", USER);

  for(unsigned int i = 0; i < Users.size(); i++)
  {
    this->sendMsg(user, "> " + Users[i]->nick, USER);
  }

  return true;
}

std::deque<std::string> Chat::parseCmd(std::string cmd)
{
  int del;
  std::deque<std::string> temp;

  while(cmd.length() > 0)
  {
    while(cmd[0] == ' ')
      cmd = cmd.substr(1);

    del = cmd.find(' ');

    if(del > -1)
    {
      temp.push_back(cmd.substr(0, del));
      cmd = cmd.substr(del+1);
    }
    else
    {
      temp.push_back(cmd);
      break;
    }
  }

  if(temp.empty())
    temp.push_back("empty");

  return temp;
}

bool Chat::handleMsg(User *user, std::string msg)
{
  // Timestamp
  time_t rawTime = time(NULL);
  struct tm *Tm  = localtime(&rawTime);

  std::string timeStamp (asctime(Tm));
  timeStamp = timeStamp.substr(11, 5);

  //
  // Chat commands
  //

  // Servermsg (Admin-only)
  if(msg[0] == SERVERMSGPREFIX && user->admin)
  {
    // Decorate server message
    msg = COLOR_RED + "[!] " + COLOR_GREEN + msg.substr(1);
    this->sendMsg(user, msg, ALL);
  }

  // Adminchat
  else if(msg[0] == ADMINCHATPREFIX && user->admin)
  {
    msg = timeStamp + " @@ <"+ COLOR_DARK_MAGENTA + user->nick + COLOR_WHITE + "> " + msg.substr(1);
    this->sendMsg(user, msg, ADMINS);
  }

  // Command
  else if(msg[0] == CHATCMDPREFIX)
  {
    std::deque<std::string> cmd = this->parseCmd(msg.substr(1));

    std::string command         = cmd[0];
    cmd.pop_front();

    // User commands
    CommandList::iterator iter;
    if((iter = userCommands.find(command)) != userCommands.end())
      iter->second(user, command, cmd);
    else if(user->admin && (iter = adminCommands.find(command)) != adminCommands.end())
      iter->second(user, command, cmd);
  }
  // Normal message
  else
  {
    if(user->admin)
      msg = timeStamp + " <"+ COLOR_DARK_MAGENTA + user->nick + COLOR_WHITE + "> " + msg;
    else
      msg = timeStamp + " <"+ user->nick + "> " + msg;

    LOG(msg);

    this->sendMsg(user, msg, ALL);
  }

  return true;
}

bool Chat::sendMsg(User *user, std::string msg, MessageTarget action)
{
  size_t tmpArrayLen = msg.size()+3;
  uint8 *tmpArray    = new uint8[tmpArrayLen];

  tmpArray[0] = 0x03;
  tmpArray[1] = 0;
  tmpArray[2] = msg.size()&0xff;

  for(unsigned int i = 0; i < msg.size(); i++)
    tmpArray[i+3] = msg[i];

  switch(action)
  {
  case ALL:
    user->sendAll(tmpArray, tmpArrayLen);
    break;

  case USER:
    user->buffer.addToWrite(tmpArray, tmpArrayLen);
    break;

  case ADMINS:
    user->sendAdmins(tmpArray, tmpArrayLen);
    break;

  case OTHERS:
    user->sendOthers(tmpArray, tmpArrayLen);
    break;
  }

  delete[] tmpArray;

  return true;
}
<commit_msg>ban + whitelist<commit_after>/*
   Copyright (c) 2010, The Mineserver Project
   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 The Mineserver Project 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 HOLDER 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 <cstdlib>
#include <cstdio>
#include <iostream>
#include <deque>
#include <fstream>
#include <vector>
#include <ctime>
#include <math.h>
#ifdef WIN32
  #include <winsock2.h>
#else
  #include <netinet/in.h>
  #include <string.h>
#endif

#include "logger.h"
#include "constants.h"

#include "tools.h"
#include "map.h"
#include "user.h"
#include "chat.h"
#include "config.h"
#include "physics.h"

Chat &Chat::get()
{
  static Chat instance;
  return instance;
}

Chat::Chat()
{
  registerStandardCommands();
}

void Chat::registerCommand(std::string name, ChatCommand command, bool adminOnly)
{
  if(adminOnly)
    adminCommands[name] = command;
  else
    userCommands[name] = command;
}

bool Chat::checkMotd(std::string motdFile)
{
  //
  // Create motdfile is it doesn't exist
  //
  std::ifstream ifs(motdFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << motdFile << " not found. Creating..." << std::endl;

    std::ofstream motdofs(motdFile.c_str());
    motdofs << DEFAULTMOTDFILE << std::endl;
    motdofs.close();
  }

  ifs.close();

  return true;
}

bool Chat::loadAdmins(std::string adminFile)
{
  // Clear current admin-vector
  admins.clear();

  // Read admins to deque
  std::ifstream ifs(adminFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << adminFile << " not found. Creating..." << std::endl;

    std::ofstream adminofs(adminFile.c_str());
    adminofs << DEFAULTADMINFILE << std::endl;
    adminofs.close();

    return true;
  }

  std::string temp;
  while(getline(ifs, temp))
  {
    // If not commentline
    if(temp[0] != COMMENTPREFIX)
      admins.push_back(temp);
  }
  ifs.close();

  std::cout << "Loaded admins from " << adminFile << std::endl;

  return true;
}

bool Chat::loadBanned(std::string bannedFile)
{
  // Clear current banned-vector
  banned.clear();

  // Read banned to deque
  std::ifstream ifs(bannedFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << bannedFile << " not found. Creating..." << std::endl;

    std::ofstream bannedofs(bannedFile.c_str());
    bannedofs << DEFAULTBANNEDFILE << std::endl;
    bannedofs.close();

    return true;
  }

  std::string temp;
  while(getline(ifs, temp))
  {
    // If not commentline
    if(temp[0] != COMMENTPREFIX)
      banned.push_back(temp);
  }
  ifs.close();

  std::cout << "Loaded banned users from " << bannedFile << std::endl;

  return true;
}

bool Chat::loadWhitelist(std::string whitelistFile)
{
  // Clear current whitelist-vector
  whitelist.clear();

  // Read whitelist to deque
  std::ifstream ifs(whitelistFile.c_str());

  // If file does not exist
  if(ifs.fail())
  {
    std::cout << "> Warning: " << whitelistFile << " not found. Creating..." << std::endl;

    std::ofstream whitelistofs(whitelistFile.c_str());
    whitelistofs << DEFAULTWHITELISTFILE << std::endl;
    whitelistofs.close();

    return true;
  }

  std::string temp;
  while(getline(ifs, temp))
  {
    // If not commentline
    if(temp[0] != COMMENTPREFIX)
      whitelist.push_back(temp);
  }
  ifs.close();

  std::cout << "Loaded whitelisted users from " << whitelistFile << std::endl;

  return true;
}

bool Chat::sendUserlist(User *user)
{
  this->sendMsg(user, COLOR_BLUE + "[ Players online ]", USER);

  for(unsigned int i = 0; i < Users.size(); i++)
  {
    this->sendMsg(user, "> " + Users[i]->nick, USER);
  }

  return true;
}

std::deque<std::string> Chat::parseCmd(std::string cmd)
{
  int del;
  std::deque<std::string> temp;

  while(cmd.length() > 0)
  {
    while(cmd[0] == ' ')
      cmd = cmd.substr(1);

    del = cmd.find(' ');

    if(del > -1)
    {
      temp.push_back(cmd.substr(0, del));
      cmd = cmd.substr(del+1);
    }
    else
    {
      temp.push_back(cmd);
      break;
    }
  }

  if(temp.empty())
    temp.push_back("empty");

  return temp;
}

bool Chat::handleMsg(User *user, std::string msg)
{
  // Timestamp
  time_t rawTime = time(NULL);

  struct tm *Tm  = localtime(&rawTime);

  std::string timeStamp (asctime(Tm));
  timeStamp = timeStamp.substr(11, 5);

  //
  // Chat commands
  //

  // Servermsg (Admin-only)
  if(msg[0] == SERVERMSGPREFIX && user->admin)
  {
    // Decorate server message
    msg = COLOR_RED + "[!] " + COLOR_GREEN + msg.substr(1);
    this->sendMsg(user, msg, ALL);
  }

  // Adminchat
  else if(msg[0] == ADMINCHATPREFIX && user->admin)
  {
    msg = timeStamp + " @@ <"+ COLOR_DARK_MAGENTA + user->nick + COLOR_WHITE + "> " + msg.substr(1);
    this->sendMsg(user, msg, ADMINS);
  }

  // Command
  else if(msg[0] == CHATCMDPREFIX)
  {
    std::deque<std::string> cmd = this->parseCmd(msg.substr(1));

    std::string command         = cmd[0];
    cmd.pop_front();

    // User commands
    CommandList::iterator iter;
    if((iter = userCommands.find(command)) != userCommands.end())
      iter->second(user, command, cmd);
    else if(user->admin && (iter = adminCommands.find(command)) != adminCommands.end())
      iter->second(user, command, cmd);
  }
  // Normal message
  else
  {
    if(user->admin)
      msg = timeStamp + " <"+ COLOR_DARK_MAGENTA + user->nick + COLOR_WHITE + "> " + msg;
    else
      msg = timeStamp + " <"+ user->nick + "> " + msg;

    LOG(msg);

    this->sendMsg(user, msg, ALL);
  }

  return true;
}

bool Chat::sendMsg(User *user, std::string msg, MessageTarget action)
{
  size_t tmpArrayLen = msg.size()+3;
  uint8 *tmpArray    = new uint8[tmpArrayLen];

  tmpArray[0] = 0x03;
  tmpArray[1] = 0;
  tmpArray[2] = msg.size()&0xff;

  for(unsigned int i = 0; i < msg.size(); i++)
    tmpArray[i+3] = msg[i];

  switch(action)
  {
  case ALL:
    user->sendAll(tmpArray, tmpArrayLen);
    break;

  case USER:
    user->buffer.addToWrite(tmpArray, tmpArrayLen);
    break;

  case ADMINS:
    user->sendAdmins(tmpArray, tmpArrayLen);
    break;

  case OTHERS:
    user->sendOthers(tmpArray, tmpArrayLen);
    break;
  }

  delete[] tmpArray;

  return true;
}
<|endoftext|>


<commit_before>#include <Python.h>
#include "Quantuccia/ql/time/calendar.hpp"
#include "Quantuccia/ql/time/date.hpp"
#include "Quantuccia/ql/time/calendars/unitedkingdom.hpp"

static PyObject*
united_kingdom_is_business_day(PyObject *self, PyObject *args)
{
	int year;
	int month;
	int day;
    if (!PyArg_ParseTuple(args, "bbb|", &year, &month, &day))
        return NULL;
	QuantLib::Day d = QuantLib::Day(day);
	QuantLib::Month m = QuantLib::Month(month);
	QuantLib::Year y = QuantLib::Year(year);
	QuantLib::Date date = QuantLib::Date(d, m, y);
	QuantLib::Calendar calendar = QuantLib::UnitedKingdom::UnitedKingdom(QuantLib::UnitedKingdom::Market::Exchange);
    return PyBool_FromLong(calendar.isBusinessDay(date));
}

static PyMethodDef QuantucciaMethods[] = {
	{"united_kingdom_is_business_day", (PyCFunction)united_kingdom_is_business_day, METH_VARARGS, NULL},
	{NULL, NULL, 0, NULL}
};

static struct PyModuleDef quantuccia_module_def = {
	PyModuleDef_HEAD_INIT,
	"quantuccia",
	NULL,
	-1,
	QuantucciaMethods,
	NULL,
	NULL,
	NULL,
	NULL
};

PyMODINIT_FUNC PyInit_quantuccia(void){
    PyObject *m;
    m = PyModule_Create(&quantuccia_module_def);
    return m;
}
<commit_msg>Add missing 'new's.<commit_after>#include <Python.h>
#include "Quantuccia/ql/time/calendar.hpp"
#include "Quantuccia/ql/time/date.hpp"
#include "Quantuccia/ql/time/calendars/unitedkingdom.hpp"

static PyObject*
united_kingdom_is_business_day(PyObject *self, PyObject *args)
{
	int year;
	int month;
	int day;
    if (!PyArg_ParseTuple(args, "bbb|", &year, &month, &day))
        return NULL;
	QuantLib::Day d = new QuantLib::Day(day);
	QuantLib::Month m = new QuantLib::Month(month);
	QuantLib::Year y = new QuantLib::Year(year);
	QuantLib::Date date = new QuantLib::Date(d, m, y);
	QuantLib::Calendar calendar = new QuantLib::UnitedKingdom::UnitedKingdom(QuantLib::UnitedKingdom::Market::Exchange);
    return PyBool_FromLong(calendar.isBusinessDay(date));
}

static PyMethodDef QuantucciaMethods[] = {
	{"united_kingdom_is_business_day", (PyCFunction)united_kingdom_is_business_day, METH_VARARGS, NULL},
	{NULL, NULL, 0, NULL}
};

static struct PyModuleDef quantuccia_module_def = {
	PyModuleDef_HEAD_INIT,
	"quantuccia",
	NULL,
	-1,
	QuantucciaMethods,
	NULL,
	NULL,
	NULL,
	NULL
};

PyMODINIT_FUNC PyInit_quantuccia(void){
    PyObject *m;
    m = PyModule_Create(&quantuccia_module_def);
    return m;
}
<|endoftext|>


<commit_before>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CONTAINERS_SHARED_BUFFER_HPP_
#define CONTAINERS_SHARED_BUFFER_HPP_

#include "containers/counted.hpp"
#include "containers/scoped.hpp"
#include "errors.hpp"

/* A `shared_buffer_t` is a reference counted binary buffer.
You can have multiple `shared_buf_ref_t`s pointing to different offsets in
the same `shared_buffer_t`. */
class shared_buf_t {
public:
    shared_buf_t() = delete;

    static scoped_ptr_t<shared_buf_t> create(size_t _size);
    static scoped_ptr_t<shared_buf_t> create_and_init(size_t _size, const char *_data);
    static void operator delete(void *p);

    char *data(size_t offset = 0);
    const char *data(size_t offset = 0) const;

private:
    // We duplicate the implementation of slow_atomic_countable_t here for the
    // sole purpose of having full control over the layout of fields. This
    // is required because we manually allocate memory for the data field,
    // and C++ doesn't guarantee any specific field memory layout under inheritance
    // (as far as I know).
    friend void counted_add_ref(const shared_buf_t *p);
    friend void counted_release(const shared_buf_t *p);
    friend intptr_t counted_use_count(const shared_buf_t *p);

    mutable intptr_t refcount_;
    // We actually allocate more memory than this.
    // It's crucial that this field is the last one in this class.
    char data_[1];

    DISABLE_COPYING(shared_buf_t);
};

/* A `shared_buf_ref_t` points at a specific offset of a `shared_buf_t`.
It is packed to reduce its memory footprint. Additionally you can specify
a smaller offset_t type if you don't need to access buffers of more than a certain
size. */
// TODO (daniel): This should be templated on the offset type, so we can
// save some memory when having buffers of a limited maximum size.
class shared_buf_ref_t {
public:
    shared_buf_ref_t(const counted_t<const shared_buf_t> &_buf, uint64_t _offset)
        : buf(_buf), offset(_offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t(shared_buf_ref_t &&movee) noexcept
        : buf(std::move(movee.buf)), offset(movee.offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t(const shared_buf_ref_t &copyee) noexcept
        : buf(copyee.buf), offset(copyee.offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t &operator=(shared_buf_ref_t &&movee) noexcept {
        buf = std::move(movee.buf);
        offset = movee.offset;
        rassert(buf.has());
        return *this;
    }
    shared_buf_ref_t &operator=(const shared_buf_ref_t &copyee) noexcept {
        buf = copyee.buf;
        offset = copyee.offset;
        rassert(buf.has());
        return *this;
    }
    const char *get() const {
        rassert(buf.has());
        return buf->data(offset);
    }
private:
    counted_t<const shared_buf_t> buf;
    uint64_t offset;
} __attribute__((__packed__));

inline void counted_add_ref(const shared_buf_t *p) {
    DEBUG_VAR intptr_t res = __sync_add_and_fetch(&p->refcount_, 1);
    rassert(res > 0);
}

inline void counted_release(const shared_buf_t *p) {
    intptr_t res = __sync_sub_and_fetch(&p->refcount_, 1);
    rassert(res >= 0);
    if (res == 0) {
        delete const_cast<shared_buf_t *>(p);
    }
}

inline intptr_t counted_use_count(const shared_buf_t *p) {
    // Finally a practical use for volatile.
    intptr_t tmp = static_cast<const volatile intptr_t&>(p->refcount_);
    rassert(tmp > 0);
    return tmp;
}

#endif  // CONTAINERS_SHARED_BUFFER_HPP_
<commit_msg>Fixes a compilation problem on GCC.<commit_after>// Copyright 2010-2014 RethinkDB, all rights reserved.
#ifndef CONTAINERS_SHARED_BUFFER_HPP_
#define CONTAINERS_SHARED_BUFFER_HPP_

#include "containers/counted.hpp"
#include "containers/scoped.hpp"
#include "errors.hpp"

/* A `shared_buffer_t` is a reference counted binary buffer.
You can have multiple `shared_buf_ref_t`s pointing to different offsets in
the same `shared_buffer_t`. */
class shared_buf_t {
public:
    shared_buf_t() = delete;

    static scoped_ptr_t<shared_buf_t> create(size_t _size);
    static scoped_ptr_t<shared_buf_t> create_and_init(size_t _size, const char *_data);
    static void operator delete(void *p);

    char *data(size_t offset = 0);
    const char *data(size_t offset = 0) const;

private:
    // We duplicate the implementation of slow_atomic_countable_t here for the
    // sole purpose of having full control over the layout of fields. This
    // is required because we manually allocate memory for the data field,
    // and C++ doesn't guarantee any specific field memory layout under inheritance
    // (as far as I know).
    friend void counted_add_ref(const shared_buf_t *p);
    friend void counted_release(const shared_buf_t *p);
    friend intptr_t counted_use_count(const shared_buf_t *p);

    mutable intptr_t refcount_;
    // We actually allocate more memory than this.
    // It's crucial that this field is the last one in this class.
    char data_[1];

    DISABLE_COPYING(shared_buf_t);
};

/* A `shared_buf_ref_t` points at a specific offset of a `shared_buf_t`.
It is packed to reduce its memory footprint. Additionally you can specify
a smaller offset_t type if you don't need to access buffers of more than a certain
size. */
// TODO (daniel): This should be templated on the offset type, so we can
// save some memory when having buffers of a limited maximum size.
class shared_buf_ref_t {
public:
    shared_buf_ref_t(const counted_t<const shared_buf_t> &_buf, uint64_t _offset)
        : buf(_buf), offset(_offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t(shared_buf_ref_t &&movee) noexcept
        : buf(std::move(movee.buf)), offset(movee.offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t(const shared_buf_ref_t &copyee) noexcept
        : buf(copyee.buf), offset(copyee.offset) {
        rassert(buf.has());
    }
    shared_buf_ref_t &operator=(shared_buf_ref_t &&movee) noexcept {
        buf = std::move(movee.buf);
        offset = movee.offset;
        rassert(buf.has());
        return *this;
    }
    shared_buf_ref_t &operator=(const shared_buf_ref_t &copyee) noexcept {
        buf = copyee.buf;
        offset = copyee.offset;
        rassert(buf.has());
        return *this;
    }
    const char *get() const {
        rassert(buf.has());
        return buf->data(offset);
    }
private:
    counted_t<const shared_buf_t> buf;
    uint64_t offset;
};

inline void counted_add_ref(const shared_buf_t *p) {
    DEBUG_VAR intptr_t res = __sync_add_and_fetch(&p->refcount_, 1);
    rassert(res > 0);
}

inline void counted_release(const shared_buf_t *p) {
    intptr_t res = __sync_sub_and_fetch(&p->refcount_, 1);
    rassert(res >= 0);
    if (res == 0) {
        delete const_cast<shared_buf_t *>(p);
    }
}

inline intptr_t counted_use_count(const shared_buf_t *p) {
    // Finally a practical use for volatile.
    intptr_t tmp = static_cast<const volatile intptr_t&>(p->refcount_);
    rassert(tmp > 0);
    return tmp;
}

#endif  // CONTAINERS_SHARED_BUFFER_HPP_
<|endoftext|>


<commit_before>#include "asset_manager.hpp"

#include "../utils/template_utils.hpp"
#include "../utils/log.hpp"

#include <physfs/physfs.h>

#include <cstring>
#include <cstdio>

#ifdef WIN
	#include <windows.h>
	#include <direct.h>
#else
	#include <sys/stat.h>
	#include <unistd.h>
#endif

#ifdef EMSCRIPTEN
	#include <emscripten.h>
#endif

using namespace lux::util;

namespace {

	std::string append_file(const std::string& folder, const std::string file) {
		if(ends_with(folder, "/") || starts_with(file, "/"))
			return folder+file;
		else
			return folder+"/"+file;
	}
	void create_dir(const std::string& dir) {
#ifdef WIN
		CreateDirectory(dir.c_str(), NULL);
#else
		mkdir(dir.c_str(), 0777);
#endif
	}

	std::vector<std::string> list_files(
			const std::string& dir, const std::string& prefix, const std::string& suffix)noexcept {
		std::vector<std::string> res;

		char **rc = PHYSFS_enumerateFiles(dir.c_str());

		for (char **i = rc; *i != nullptr; i++) {
			std::string str(*i);
			if(    (prefix.length()==0 || str.find(prefix)==0) &&
				   (suffix.length()==0 || str.find(suffix)==str.length()-suffix.length()) )
				res.emplace_back(std::move(str));
		}

		PHYSFS_freeList(rc);

		return res;
	}

	bool exists_file(const std::string path) {
		return PHYSFS_exists(path.c_str())!=0 && PHYSFS_isDirectory(path.c_str())==0;
	}
	bool exists_dir(const std::string path) {
		return PHYSFS_exists(path.c_str())!=0 && PHYSFS_isDirectory(path.c_str())!=0;
	}

	template<typename Stream>
	void print_dir_recursiv(const std::string& dir, uint8_t depth, Stream& stream) {
		std::string p;
		for(uint8_t i=0; i<depth; i++)
			p+="  ";

		stream<<p<<dir<<"\n";
		depth++;
		for(auto&& f : list_files(dir, "", "")) {
			if(depth>=5)
				stream<<p<<"  "<<f<<"\n";
			else
				print_dir_recursiv(f, depth, stream);
		}
	}

	constexpr auto default_source = {std::make_tuple("assets", false), std::make_tuple("assets.zip", true)};
}

namespace lux {
namespace asset {

	std::string pwd() {
		char cCurrentPath[FILENAME_MAX];

		#ifdef WINDOWS
			_getcwd(cCurrentPath, sizeof(cCurrentPath));
		#else
			getcwd(cCurrentPath, sizeof(cCurrentPath));
		#endif

		return cCurrentPath;
	}

	static Asset_manager* current_instance = nullptr;
	auto get_asset_manager() -> Asset_manager& {
		INVARIANT(current_instance!=nullptr, "Asset_manager has not been initialized!");
		return *current_instance;
	}

	Asset_manager::Asset_manager(const std::string& exe_name, const std::string& app_name) {
		if(!PHYSFS_init(exe_name.empty() ? nullptr : exe_name.c_str()))
			FAIL("PhysFS-Init failed for \""<<exe_name<<"\": "<< PHYSFS_getLastError());

		// TODO: Windows savegames should be stored in FOLDERID_SavedGames, but the API and conventions are a pain in the ass
		std::string write_dir_parent = append_file(PHYSFS_getUserDir(),
#ifdef WIN
			"Documents/My Games"
#else
			".config"
#endif
		);

#ifdef EMSCRIPTEN
		EM_ASM(
			FS.mkdir('/persistent_data');
			FS.mount(IDBFS, {}, '/persistent_data');

			Module.syncdone = 0;

			//populate persistent_data directory with existing persistent source data
			//stored with Indexed Db
			//first parameter = "true" mean synchronize from Indexed Db to
			//Emscripten file system,
			// "false" mean synchronize from Emscripten file system to Indexed Db
			//second parameter = function called when data are synchronized
			FS.syncfs(true, function(err) {
				//assert(!err);
				Module.print("end file sync..");
				Module.syncdone = 1;
			});
		);
		write_dir_parent = "/persistent_data";
#endif

		create_dir(write_dir_parent);

		std::string write_dir = append_file(write_dir_parent, app_name);
		create_dir(write_dir);

		INFO("Write dir: "<<write_dir);

		if(!PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1) ||
				!PHYSFS_addToSearchPath(append_file(PHYSFS_getBaseDir(), "..").c_str(), 1)  ||
				!PHYSFS_addToSearchPath(pwd().c_str(), 1) ||
				!PHYSFS_addToSearchPath(write_dir.c_str(), 0))
			FAIL("Unable to construct search path: "<< PHYSFS_getLastError());

		// add optional search path
		PHYSFS_addToSearchPath(append_file(append_file(append_file(PHYSFS_getBaseDir(), ".."), "magnum_opus"), "assets").c_str(), 1);

		if(!PHYSFS_setWriteDir(write_dir.c_str()))
			FAIL("Unable to set write-dir to \""<<write_dir<<"\": "<< PHYSFS_getLastError());

		auto add_source = [](const char* path){
			if(!PHYSFS_addToSearchPath(path, 1))
				WARN("Error adding custom archive \""<<path<<"\": "<<PHYSFS_getLastError());
		};

		auto archive_file = _open("archives.lst");
		if(!archive_file) {
			bool lost = true;
			for(auto& s : default_source) {
				const char* path;
				bool file;

				std::tie(path, file) = s;

				if(file ? exists_file(path) : exists_dir(path)) {
					add_source(path);
					lost = false;
				}
			}

			if(lost) {
				auto& log = util::fail (__func__, __FILE__, __LINE__);
				log<<"No archives.lst found. printing search-path...\n";
				print_dir_recursiv("/", 0, log);

				log<<std::endl; // crash with error

			} else {
				INFO("No archives.lst found. Using defaults.");
			}

		} else {
			// load other archives
			archive_file.process([&](istream& in) {
				for(auto&& l : in.lines()) {
					add_source(l.c_str());
				}
			});
		}

		for(auto&& df : list_files("", "assets", ".map")) {
			_open(df).process([this](istream& in) {
				for(auto&& l : in.lines()) {
					auto kvp =	util::split(l, "=");
					std::string path = util::trim_copy(kvp.second);
					if(!path.empty()) {
						_dispatcher.emplace(AID{kvp.first}, std::move(path));
					}
				}
			});
		}

		current_instance = this;
	}

	Asset_manager::~Asset_manager() {
		current_instance = nullptr;
		_assets.clear();
		PHYSFS_deinit();
	}

	void Asset_manager::_post_write() {
#ifdef EMSCRIPTEN
		//persist Emscripten current data to Indexed Db
		EM_ASM(
			FS.syncfs(false,function (err) {
				//assert(!err);
			});
		);
#endif
	}

	util::maybe<std::string> Asset_manager::_base_dir(Asset_type type)const {
		auto dir = _dispatcher.find(AID{type, ""}); // search for prefix-entry

		if(dir==_dispatcher.end())
			return util::nothing();

		std::string bdir = dir->second;
		return bdir;
	}

	std::vector<AID> Asset_manager::list(Asset_type type) {
		std::vector<AID> res;

		_base_dir(type).process([&](const std::string& dir){
			for(auto&& f : list_files(dir, "", ""))
				res.emplace_back(type, f);
		});

		return res;
	}

	util::maybe<istream> Asset_manager::_open(const std::string& path) {
		return _open(path, AID{"gen"_strid, path});
	}
	util::maybe<istream> Asset_manager::_open(const std::string& path, const AID& aid) {
		return exists_file(path) ? util::just(istream{aid, *this, path}) : util::nothing();
	}

	Asset_manager::Asset::Asset(std::shared_ptr<void> data, Reloader reloader, int64_t last_modified)
		: data(data), reloader(reloader), last_modified(last_modified) {}

	void Asset_manager::_add_asset(const AID& id, const std::string& path,
	                               Reloader reloader, std::shared_ptr<void> asset) {
		_assets.emplace(id, Asset{asset, reloader, PHYSFS_getLastModTime(path.c_str())});
	}

	auto Asset_manager::_locate(const AID& id, bool warn)const -> std::tuple<Location_type, std::string> {
		auto res = _dispatcher.find(id);

		if(res!=_dispatcher.end()) {
			if(exists_file(res->second))
				return std::make_tuple(Location_type::file, res->second);
			else if(util::contains(res->second, ":"))
				return std::make_tuple(Location_type::indirection, res->second);
			else if(warn)
				INFO("Asset not found in configured place: "<<res->second);
		}

		if(exists_file(id.name()))
			return std::make_tuple(Location_type::file, id.name());

		auto baseDir = _base_dir(id.type());

		if(baseDir.is_some()) {
			auto path = append_file(baseDir.get_or_throw(), id.name());
			if(exists_file(path))
				return std::make_tuple(Location_type::file, std::move(path));
			else if(warn)
				DEBUG("asset "<<id.str()<<" not found in "<<path);
		}

		return std::make_tuple(Location_type::none, std::string());
	}

	ostream Asset_manager::_create(const AID& id) throw(Loading_failed) {
		std::string path;

		auto path_res = _dispatcher.find(id);
		if(path_res!=_dispatcher.end())
			path = path_res->second;

		else {
			auto res = _dispatcher.find(AID{id.type(), ""}); // search for prefix-entry

			if(res!=_dispatcher.end()) {
				PHYSFS_mkdir(res->second.c_str());
				path = append_file(res->second, id.name());
			} else {
				path = id.name();
			}
		}

		if(exists_file(path))
			PHYSFS_delete(path.c_str());

		return {id, *this, path};
	}

	auto Asset_manager::physical_location(const AID& id, bool warn)const noexcept -> util::maybe<std::string>{
		using namespace std::literals;

		Location_type type;
		std::string location;
		std::tie(type, location) = _locate(id, warn);

		if(type!=Location_type::file)
			return util::nothing();

		auto dir = PHYSFS_getRealDir(location.c_str());
		if(!dir)
			return util::nothing();

		auto file = dir + "/"s + location;
		return exists_file(file) ? util::just(std::move(file)) : util::nothing();
	}

	void Asset_manager::reload() {
		for(auto& a : _assets) {
			Location_type type;
			std::string location;
			std::tie(type, location) = _locate(a.first);

			if(type==Location_type::file) {
				auto last_mod = PHYSFS_getLastModTime(location.c_str());
				if(last_mod!=-1 && last_mod>a.second.last_modified) {
					_open(location, a.first).process([&](istream& in){
						DEBUG("Reload: "<<a.first.str());
						try {
							a.second.reloader(a.second.data.get(), std::move(in));

						} catch(Loading_failed& e) {}

						a.second.last_modified = last_mod;
					});
				}
			}
		}
	}

	void Asset_manager::shrink_to_fit()noexcept {
		util::erase_if(_assets, [](const auto& v){return v.second.data.use_count()<=1;});
	}

	bool Asset_manager::exists(const AID& id)const noexcept {
		Location_type type;
		std::string location;
		std::tie(type, location) = _locate(id);

		switch(type) {
			case Location_type::none:
				return false;

			case Location_type::file:
				return exists_file(location);

			case Location_type::indirection:
				return true;
		}

		FAIL("Unexpected Location_type: "<<(int)type);
	}

	auto Asset_manager::load_raw(const AID& id) -> util::maybe<istream> {
		Location_type type;
		std::string path;
		std::tie(type, path) = _locate(id);

		if(type!=Location_type::file)
			return util::nothing();

		return _open(path, id);
	}
	auto Asset_manager::save_raw(const AID& id) -> ostream {
		_assets.erase(id);
		return _create(id);
	}

	auto Asset_manager::find_by_path(const std::string& path) -> util::maybe<AID> {
		static const auto working_dir = util::replace(pwd(), "\\", "/");
		auto path_cleared = util::replace(path,working_dir+"/", "");

		for(auto& aid_path : _dispatcher) {
			auto loc = physical_location(aid_path.first, false);
			if(loc.is_some()) {
				if(loc.get_or_throw()==path_cleared) {
					return util::justCopy(aid_path.first);
				}
			}
		}

		DEBUG("Couldn't finde asset for '"<<path_cleared<<"'");

		return util::nothing();
	}

} /* namespace asset */
}
<commit_msg>fixed backslashes in find_by_path<commit_after>#include "asset_manager.hpp"

#include "../utils/template_utils.hpp"
#include "../utils/log.hpp"

#include <physfs/physfs.h>

#include <cstring>
#include <cstdio>

#ifdef WIN
	#include <windows.h>
	#include <direct.h>
#else
	#include <sys/stat.h>
	#include <unistd.h>
#endif

#ifdef EMSCRIPTEN
	#include <emscripten.h>
#endif

using namespace lux::util;

namespace {

	std::string append_file(const std::string& folder, const std::string file) {
		if(ends_with(folder, "/") || starts_with(file, "/"))
			return folder+file;
		else
			return folder+"/"+file;
	}
	void create_dir(const std::string& dir) {
#ifdef WIN
		CreateDirectory(dir.c_str(), NULL);
#else
		mkdir(dir.c_str(), 0777);
#endif
	}

	std::vector<std::string> list_files(
			const std::string& dir, const std::string& prefix, const std::string& suffix)noexcept {
		std::vector<std::string> res;

		char **rc = PHYSFS_enumerateFiles(dir.c_str());

		for (char **i = rc; *i != nullptr; i++) {
			std::string str(*i);
			if(    (prefix.length()==0 || str.find(prefix)==0) &&
				   (suffix.length()==0 || str.find(suffix)==str.length()-suffix.length()) )
				res.emplace_back(std::move(str));
		}

		PHYSFS_freeList(rc);

		return res;
	}

	bool exists_file(const std::string path) {
		return PHYSFS_exists(path.c_str())!=0 && PHYSFS_isDirectory(path.c_str())==0;
	}
	bool exists_dir(const std::string path) {
		return PHYSFS_exists(path.c_str())!=0 && PHYSFS_isDirectory(path.c_str())!=0;
	}

	template<typename Stream>
	void print_dir_recursiv(const std::string& dir, uint8_t depth, Stream& stream) {
		std::string p;
		for(uint8_t i=0; i<depth; i++)
			p+="  ";

		stream<<p<<dir<<"\n";
		depth++;
		for(auto&& f : list_files(dir, "", "")) {
			if(depth>=5)
				stream<<p<<"  "<<f<<"\n";
			else
				print_dir_recursiv(f, depth, stream);
		}
	}

	constexpr auto default_source = {std::make_tuple("assets", false), std::make_tuple("assets.zip", true)};
}

namespace lux {
namespace asset {

	std::string pwd() {
		char cCurrentPath[FILENAME_MAX];

		#ifdef WINDOWS
			_getcwd(cCurrentPath, sizeof(cCurrentPath));
		#else
			getcwd(cCurrentPath, sizeof(cCurrentPath));
		#endif

		return cCurrentPath;
	}

	static Asset_manager* current_instance = nullptr;
	auto get_asset_manager() -> Asset_manager& {
		INVARIANT(current_instance!=nullptr, "Asset_manager has not been initialized!");
		return *current_instance;
	}

	Asset_manager::Asset_manager(const std::string& exe_name, const std::string& app_name) {
		if(!PHYSFS_init(exe_name.empty() ? nullptr : exe_name.c_str()))
			FAIL("PhysFS-Init failed for \""<<exe_name<<"\": "<< PHYSFS_getLastError());

		// TODO: Windows savegames should be stored in FOLDERID_SavedGames, but the API and conventions are a pain in the ass
		std::string write_dir_parent = append_file(PHYSFS_getUserDir(),
#ifdef WIN
			"Documents/My Games"
#else
			".config"
#endif
		);

#ifdef EMSCRIPTEN
		EM_ASM(
			FS.mkdir('/persistent_data');
			FS.mount(IDBFS, {}, '/persistent_data');

			Module.syncdone = 0;

			//populate persistent_data directory with existing persistent source data
			//stored with Indexed Db
			//first parameter = "true" mean synchronize from Indexed Db to
			//Emscripten file system,
			// "false" mean synchronize from Emscripten file system to Indexed Db
			//second parameter = function called when data are synchronized
			FS.syncfs(true, function(err) {
				//assert(!err);
				Module.print("end file sync..");
				Module.syncdone = 1;
			});
		);
		write_dir_parent = "/persistent_data";
#endif

		create_dir(write_dir_parent);

		std::string write_dir = append_file(write_dir_parent, app_name);
		create_dir(write_dir);

		INFO("Write dir: "<<write_dir);

		if(!PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1) ||
				!PHYSFS_addToSearchPath(append_file(PHYSFS_getBaseDir(), "..").c_str(), 1)  ||
				!PHYSFS_addToSearchPath(pwd().c_str(), 1) ||
				!PHYSFS_addToSearchPath(write_dir.c_str(), 0))
			FAIL("Unable to construct search path: "<< PHYSFS_getLastError());

		// add optional search path
		PHYSFS_addToSearchPath(append_file(append_file(append_file(PHYSFS_getBaseDir(), ".."), "magnum_opus"), "assets").c_str(), 1);

		if(!PHYSFS_setWriteDir(write_dir.c_str()))
			FAIL("Unable to set write-dir to \""<<write_dir<<"\": "<< PHYSFS_getLastError());

		auto add_source = [](const char* path){
			if(!PHYSFS_addToSearchPath(path, 1))
				WARN("Error adding custom archive \""<<path<<"\": "<<PHYSFS_getLastError());
		};

		auto archive_file = _open("archives.lst");
		if(!archive_file) {
			bool lost = true;
			for(auto& s : default_source) {
				const char* path;
				bool file;

				std::tie(path, file) = s;

				if(file ? exists_file(path) : exists_dir(path)) {
					add_source(path);
					lost = false;
				}
			}

			if(lost) {
				auto& log = util::fail (__func__, __FILE__, __LINE__);
				log<<"No archives.lst found. printing search-path...\n";
				print_dir_recursiv("/", 0, log);

				log<<std::endl; // crash with error

			} else {
				INFO("No archives.lst found. Using defaults.");
			}

		} else {
			// load other archives
			archive_file.process([&](istream& in) {
				for(auto&& l : in.lines()) {
					add_source(l.c_str());
				}
			});
		}

		for(auto&& df : list_files("", "assets", ".map")) {
			_open(df).process([this](istream& in) {
				for(auto&& l : in.lines()) {
					auto kvp =	util::split(l, "=");
					std::string path = util::trim_copy(kvp.second);
					if(!path.empty()) {
						_dispatcher.emplace(AID{kvp.first}, std::move(path));
					}
				}
			});
		}

		current_instance = this;
	}

	Asset_manager::~Asset_manager() {
		current_instance = nullptr;
		_assets.clear();
		PHYSFS_deinit();
	}

	void Asset_manager::_post_write() {
#ifdef EMSCRIPTEN
		//persist Emscripten current data to Indexed Db
		EM_ASM(
			FS.syncfs(false,function (err) {
				//assert(!err);
			});
		);
#endif
	}

	util::maybe<std::string> Asset_manager::_base_dir(Asset_type type)const {
		auto dir = _dispatcher.find(AID{type, ""}); // search for prefix-entry

		if(dir==_dispatcher.end())
			return util::nothing();

		std::string bdir = dir->second;
		return bdir;
	}

	std::vector<AID> Asset_manager::list(Asset_type type) {
		std::vector<AID> res;

		_base_dir(type).process([&](const std::string& dir){
			for(auto&& f : list_files(dir, "", ""))
				res.emplace_back(type, f);
		});

		return res;
	}

	util::maybe<istream> Asset_manager::_open(const std::string& path) {
		return _open(path, AID{"gen"_strid, path});
	}
	util::maybe<istream> Asset_manager::_open(const std::string& path, const AID& aid) {
		return exists_file(path) ? util::just(istream{aid, *this, path}) : util::nothing();
	}

	Asset_manager::Asset::Asset(std::shared_ptr<void> data, Reloader reloader, int64_t last_modified)
		: data(data), reloader(reloader), last_modified(last_modified) {}

	void Asset_manager::_add_asset(const AID& id, const std::string& path,
	                               Reloader reloader, std::shared_ptr<void> asset) {
		_assets.emplace(id, Asset{asset, reloader, PHYSFS_getLastModTime(path.c_str())});
	}

	auto Asset_manager::_locate(const AID& id, bool warn)const -> std::tuple<Location_type, std::string> {
		auto res = _dispatcher.find(id);

		if(res!=_dispatcher.end()) {
			if(exists_file(res->second))
				return std::make_tuple(Location_type::file, res->second);
			else if(util::contains(res->second, ":"))
				return std::make_tuple(Location_type::indirection, res->second);
			else if(warn)
				INFO("Asset not found in configured place: "<<res->second);
		}

		if(exists_file(id.name()))
			return std::make_tuple(Location_type::file, id.name());

		auto baseDir = _base_dir(id.type());

		if(baseDir.is_some()) {
			auto path = append_file(baseDir.get_or_throw(), id.name());
			if(exists_file(path))
				return std::make_tuple(Location_type::file, std::move(path));
			else if(warn)
				DEBUG("asset "<<id.str()<<" not found in "<<path);
		}

		return std::make_tuple(Location_type::none, std::string());
	}

	ostream Asset_manager::_create(const AID& id) throw(Loading_failed) {
		std::string path;

		auto path_res = _dispatcher.find(id);
		if(path_res!=_dispatcher.end())
			path = path_res->second;

		else {
			auto res = _dispatcher.find(AID{id.type(), ""}); // search for prefix-entry

			if(res!=_dispatcher.end()) {
				PHYSFS_mkdir(res->second.c_str());
				path = append_file(res->second, id.name());
			} else {
				path = id.name();
			}
		}

		if(exists_file(path))
			PHYSFS_delete(path.c_str());

		return {id, *this, path};
	}

	auto Asset_manager::physical_location(const AID& id, bool warn)const noexcept -> util::maybe<std::string>{
		using namespace std::literals;

		Location_type type;
		std::string location;
		std::tie(type, location) = _locate(id, warn);

		if(type!=Location_type::file)
			return util::nothing();

		auto dir = PHYSFS_getRealDir(location.c_str());
		if(!dir)
			return util::nothing();

		auto file = dir + "/"s + location;
		return exists_file(file) ? util::just(std::move(file)) : util::nothing();
	}

	void Asset_manager::reload() {
		for(auto& a : _assets) {
			Location_type type;
			std::string location;
			std::tie(type, location) = _locate(a.first);

			if(type==Location_type::file) {
				auto last_mod = PHYSFS_getLastModTime(location.c_str());
				if(last_mod!=-1 && last_mod>a.second.last_modified) {
					_open(location, a.first).process([&](istream& in){
						DEBUG("Reload: "<<a.first.str());
						try {
							a.second.reloader(a.second.data.get(), std::move(in));

						} catch(Loading_failed& e) {}

						a.second.last_modified = last_mod;
					});
				}
			}
		}
	}

	void Asset_manager::shrink_to_fit()noexcept {
		util::erase_if(_assets, [](const auto& v){return v.second.data.use_count()<=1;});
	}

	bool Asset_manager::exists(const AID& id)const noexcept {
		Location_type type;
		std::string location;
		std::tie(type, location) = _locate(id);

		switch(type) {
			case Location_type::none:
				return false;

			case Location_type::file:
				return exists_file(location);

			case Location_type::indirection:
				return true;
		}

		FAIL("Unexpected Location_type: "<<(int)type);
	}

	auto Asset_manager::load_raw(const AID& id) -> util::maybe<istream> {
		Location_type type;
		std::string path;
		std::tie(type, path) = _locate(id);

		if(type!=Location_type::file)
			return util::nothing();

		return _open(path, id);
	}
	auto Asset_manager::save_raw(const AID& id) -> ostream {
		_assets.erase(id);
		return _create(id);
	}

	auto Asset_manager::find_by_path(const std::string& path) -> util::maybe<AID> {
		static const auto working_dir = util::replace(pwd(), "\\", "/");
		auto path_cleared = util::replace( util::replace(path, "\\", "/"), working_dir+"/", "");

		for(auto& aid_path : _dispatcher) {
			auto loc = physical_location(aid_path.first, false);
			if(loc.is_some()) {
				if(loc.get_or_throw()==path_cleared) {
					return util::justCopy(aid_path.first);
				}
			}
		}

		DEBUG("Couldn't finde asset for '"<<path_cleared<<"'");

		return util::nothing();
	}

} /* namespace asset */
}
<|endoftext|>


<commit_before>#include "core.h"
#include <glibmm/init.h>

namespace Davix {

using namespace Glib;

Core::Core(AbstractSessionFactory* fsess) : _fsess(fsess)
{
    _s_buff = 65536;
    _timeout = 10;
}

RefPtr<Core> Core::create(AbstractSessionFactory* fsess){
    return Glib::RefPtr<Core>(new Core(fsess));
}

AbstractSessionFactory* Core::getSessionFactory(){
    return _fsess.get();
}

void Core::set_buffer_size(const size_t value){
    _s_buff = value;
}

} // namespace Davix

extern "C"{

// glibmm initialization
__attribute__((constructor))
void core_init(){
    g_thread_init(NULL);
    Glib::init();
}

}
<commit_msg>- remove glib C initialisation, done in background<commit_after>#include "core.h"
#include <glibmm/init.h>

namespace Davix {

using namespace Glib;

Core::Core(AbstractSessionFactory* fsess) : _fsess(fsess)
{
    _s_buff = 65536;
    _timeout = 10;
}

RefPtr<Core> Core::create(AbstractSessionFactory* fsess){
    return Glib::RefPtr<Core>(new Core(fsess));
}

AbstractSessionFactory* Core::getSessionFactory(){
    return _fsess.get();
}

void Core::set_buffer_size(const size_t value){
    _s_buff = value;
}

} // namespace Davix

extern "C"{

// glibmm initialization
__attribute__((constructor))
void core_init(){
    Glib::init();
}

}
<|endoftext|>


<commit_before>//––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––//

#include "dye.hpp"
#include <chrono>
#include <iostream>
#include <thread>

void cadence(size_t ms=750) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); }

int main() {
	std::cout << dye::black   << "black"   << std::endl; cadence();
	std::cout << dye::red     << "red"     << std::endl; cadence();
	std::cout << dye::green   << "green"   << std::endl; cadence();
	std::cout << dye::yellow  << "yellow"  << std::endl; cadence();
	std::cout << dye::blue    << "blue"    << std::endl; cadence();
	std::cout << dye::magenta << "magenta" << std::endl; cadence();
	std::cout << dye::cyan    << "cyan"    << std::endl; cadence();
	std::cout << dye::white   << "white"   << std::endl; cadence();
}

//–––––––––––––––––––––––––––––––––––– ∎ –––––––––––––––––––––––––––––––––––––//
<commit_msg>Adapt demo to showcase 256-palette and 24-bit colors<commit_after>//––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––//

#include "dye.hpp"
#include <chrono>
#include <iostream>
#include <thread>

void cadence(size_t ms=750) { std::this_thread::sleep_for(std::chrono::milliseconds(ms)); }

int main() {
	// Basic colors

	std::cout << dye::black   << "black"   << std::endl;
	std::cout << dye::red     << "red"     << std::endl;
	std::cout << dye::green   << "green"   << std::endl;
	std::cout << dye::yellow  << "yellow"  << std::endl;
	std::cout << dye::blue    << "blue"    << std::endl;
	std::cout << dye::magenta << "magenta" << std::endl;
	std::cout << dye::cyan    << "cyan"    << std::endl;
	std::cout << dye::white   << "white"   << std::endl;

	// 256 palette colors

	std::cout << dye::reset << std::endl;

	for (size_t i=0; i<256; ++i)
		std::cout << dye::bg(i)(" ");
	std::cout << std::endl;

	// 24-bit colors
	std::cout << std::endl;

	for (size_t i=0; i<256; ++i)
		std::cout << dye::bg(i,0,i)(" ");
	std::cout << std::endl;
}

//–––––––––––––––––––––––––––––––––––– ∎ –––––––––––––––––––––––––––––––––––––//
<|endoftext|>


<commit_before>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

String alloc_comment_group_string(gbAllocator a, CommentGroup g) {
	isize len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len == 0) {
		return make_string(nullptr, 0);
	}

	u8 *text = gb_alloc_array(a, u8, len+1);
	len = 0;
	for_array(i, g.list) {
		String comment = g.list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		comment = string_trim_whitespace(comment);
		gb_memmove(text+len, comment.text, comment.len);
		len += comment.len;
		text[len++] = '\n';
	}
	return make_string(text, len);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
	if (g == nullptr) {
		return false;
	}
	isize len = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len <= g->list.count) {
		return false;
	}

	isize count = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}
		if (comment.len > 0 && comment[0] == ' ') {
			comment.text += 1;
			comment.len  -= 1;
		}

		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	for_array(i, pkg->files) {
		AstFile *f = pkg->files[i];
		if (f->pkg_decl) {
			GB_ASSERT(f->pkg_decl->kind == Ast_PackageDecl);
			if (print_doc_comment_group_string(1, f->pkg_decl->PackageDecl.docs)) {
				print_doc_line(0, "");
			}
		}
	}

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				if (curr_entity_kind != Entity_Invalid) {
					print_doc_line(0, "");
				}
				curr_entity_kind = e->kind;
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
				comment = e->decl_info->comment;
				docs = e->decl_info->docs;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (print_doc_comment_group_string(3, docs)) {
					gb_printf("\n");
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<commit_msg>Ignore `+build` flags in packages comments with `odin doc`<commit_after>// Generates Documentation

gb_global int print_entity_kind_ordering[Entity_Count] = {
	/*Invalid*/     -1,
	/*Constant*/    0,
	/*Variable*/    1,
	/*TypeName*/    4,
	/*Procedure*/   2,
	/*ProcGroup*/   3,
	/*Builtin*/     -1,
	/*ImportName*/  -1,
	/*LibraryName*/ -1,
	/*Nil*/         -1,
	/*Label*/       -1,
};
gb_global char const *print_entity_names[Entity_Count] = {
	/*Invalid*/     "",
	/*Constant*/    "constants",
	/*Variable*/    "variables",
	/*TypeName*/    "types",
	/*Procedure*/   "procedures",
	/*ProcGroup*/   "proc_group",
	/*Builtin*/     "",
	/*ImportName*/  "import names",
	/*LibraryName*/ "library names",
	/*Nil*/         "",
	/*Label*/       "",
};

GB_COMPARE_PROC(cmp_entities_for_printing) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	Entity *x = *cast(Entity **)a;
	Entity *y = *cast(Entity **)b;
	int res = 0;
	res = string_compare(x->pkg->name, y->pkg->name);
	if (res != 0) {
		return res;
	}
	int ox = print_entity_kind_ordering[x->kind];
	int oy = print_entity_kind_ordering[y->kind];
	if (ox < oy) {
		return -1;
	} else if (ox > oy) {
		return +1;
	}
	res = string_compare(x->token.string, y->token.string);
	return res;
}

GB_COMPARE_PROC(cmp_ast_package_by_name) {
	GB_ASSERT(a != nullptr);
	GB_ASSERT(b != nullptr);
	AstPackage *x = *cast(AstPackage **)a;
	AstPackage *y = *cast(AstPackage **)b;
	return string_compare(x->name, y->name);
}

void print_doc_line(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
	gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
	while (indent --> 0) {
		gb_printf("\t");
	}
	va_list va;
	va_start(va, fmt);
	gb_printf_va(fmt, va);
	va_end(va);
}

bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
	if (g == nullptr) {
		return false;
	}
	isize len = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		len += comment.len;
		len += 1; // for \n
	}
	if (len <= g->list.count) {
		return false;
	}

	isize count = 0;
	for_array(i, g->list) {
		String comment = g->list[i].string;
		bool slash_slash = comment[1] == '/';
		if (comment[1] == '/') {
			comment.text += 2;
			comment.len  -= 2;
		} else if (comment[1] == '*') {
			comment.text += 2;
			comment.len  -= 4;
		}

		// Ignore the first space
		if (comment.len > 0 && comment[0] == ' ') {
			comment.text += 1;
			comment.len  -= 1;
		}

		if (slash_slash) {
			if (string_starts_with(comment, str_lit("+"))) {
				continue;
			}
		}
		if (string_starts_with(comment, str_lit("@("))) {
			continue;
		}

		print_doc_line(indent, "%.*s", LIT(comment));
		count += 1;
	}
	return count > 0;
}

void print_doc_expr(Ast *expr) {
	gbString s = nullptr;
	if (build_context.cmd_doc_flags & CmdDocFlag_All) {
		s = expr_to_string(expr);
	} else {
		s = expr_to_string_shorthand(expr);
	}
	gb_file_write(gb_file_get_standard(gbFileStandard_Output), s, gb_string_length(s));
	gb_string_free(s);
}

void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
	if (pkg == nullptr) {
		return;
	}

	print_doc_line(0, "package %.*s", LIT(pkg->name));

	for_array(i, pkg->files) {
		AstFile *f = pkg->files[i];
		if (f->pkg_decl) {
			GB_ASSERT(f->pkg_decl->kind == Ast_PackageDecl);
			if (print_doc_comment_group_string(1, f->pkg_decl->PackageDecl.docs)) {
				print_doc_line(0, "");
			}
		}
	}

	if (pkg->scope != nullptr) {
		auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
		defer (array_free(&entities));
		for_array(i, pkg->scope->elements.entries) {
			Entity *e = pkg->scope->elements.entries[i].value;
			switch (e->kind) {
			case Entity_Invalid:
			case Entity_Builtin:
			case Entity_Nil:
			case Entity_Label:
				continue;
			case Entity_Constant:
			case Entity_Variable:
			case Entity_TypeName:
			case Entity_Procedure:
			case Entity_ProcGroup:
			case Entity_ImportName:
			case Entity_LibraryName:
				// Fine
				break;
			}
			array_add(&entities, e);
		}
		gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);

		EntityKind curr_entity_kind = Entity_Invalid;
		for_array(i, entities) {
			Entity *e = entities[i];
			if (e->pkg != pkg) {
				continue;
			}
			if (!is_entity_exported(e)) {
				continue;
			}

			if (curr_entity_kind != e->kind) {
				if (curr_entity_kind != Entity_Invalid) {
					print_doc_line(0, "");
				}
				curr_entity_kind = e->kind;
				print_doc_line(1, "%s", print_entity_names[e->kind]);
			}

			Ast *type_expr = nullptr;
			Ast *init_expr = nullptr;
			Ast *decl_node = nullptr;
			CommentGroup *comment = nullptr;
			CommentGroup *docs = nullptr;
			if (e->decl_info != nullptr) {
				type_expr = e->decl_info->type_expr;
				init_expr = e->decl_info->init_expr;
				decl_node = e->decl_info->decl_node;
				comment = e->decl_info->comment;
				docs = e->decl_info->docs;
			}
			GB_ASSERT(type_expr != nullptr || init_expr != nullptr);
			print_doc_line_no_newline(2, "%.*s", LIT(e->token.string));
			if (type_expr != nullptr) {
				gbString t = expr_to_string(type_expr);
				gb_printf(": %s ", t);
				gb_string_free(t);
			} else {
				gb_printf(" :");
			}
			if (e->kind == Entity_Variable) {
				if (init_expr != nullptr) {
					gb_printf("= ");
					print_doc_expr(init_expr);
				}
			} else {
				gb_printf(": ");
				print_doc_expr(init_expr);
			}

			gb_printf(";\n");

			if (build_context.cmd_doc_flags & CmdDocFlag_All) {
				if (comment) {
					// gb_printf(" <comment>");
				}
				if (print_doc_comment_group_string(3, docs)) {
					gb_printf("\n");
				}
			}
		}
		print_doc_line(0, "");
	}

	if (pkg->fullpath.len != 0) {
		print_doc_line(0, "");
		print_doc_line(1, "fullpath: %.*s", LIT(pkg->fullpath));
		print_doc_line(1, "files:");
		for_array(i, pkg->files) {
			AstFile *f = pkg->files[i];
			String filename = remove_directory_from_path(f->fullpath);
			print_doc_line(2, "%.*s", LIT(filename));
		}
	}

}

void generate_documentation(Checker *c) {
	CheckerInfo *info = &c->info;

	if (build_context.doc_packages.count != 0) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		bool was_error = false;
		for_array(j, build_context.doc_packages) {
			bool found = false;
			String name = build_context.doc_packages[j];
			for_array(i, info->packages.entries) {
				AstPackage *pkg = info->packages.entries[i].value;
				if (name == pkg->name) {
					found = true;
					array_add(&pkgs, pkg);
					break;
				}
			}
			if (!found) {
				gb_printf_err("Unknown package %.*s\n", LIT(name));
				was_error = true;
			}
		}
		if (was_error) {
			gb_exit(1);
			return;
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
		auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
		for_array(i, info->packages.entries) {
			AstPackage *pkg = info->packages.entries[i].value;
			array_add(&pkgs, pkg);
		}

		gb_sort_array(pkgs.data, pkgs.count, cmp_ast_package_by_name);

		for_array(i, pkgs) {
			print_doc_package(info, pkgs[i]);
		}
	} else {
		GB_ASSERT(info->init_scope->flags & ScopeFlag_Pkg);
		AstPackage *pkg = info->init_scope->pkg;
		print_doc_package(info, pkg);

	}
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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 <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifdef WIN32

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
typedef int mode_t;

#else

#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#endif

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

namespace fs = boost::filesystem;

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
//		if (m == (mode_in | mode_out)) return O_RDWR | O_BINARY;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}
}

namespace libtorrent
{

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			close();
			m_fd = ::open(
				path.native_file_string().c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

			std::stringstream str;
			str << "fd: " << m_fd << "\n";

			::close(m_fd);
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode == mode_in);
			assert(m_fd != -1);

			size_type ret = ::read(m_fd, buf, num_bytes);
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode == mode_out);
			assert(m_fd != -1);

			size_type ret = ::write(m_fd, buf, num_bytes);
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void seek(size_type offset, int m)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}

		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(boost::filesystem::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(boost::filesystem::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::seek(size_type pos, file::seek_mode m)
	{
		m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<commit_msg>*** empty log message ***<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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 <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifdef WIN32

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#else

#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#endif

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

namespace fs = boost::filesystem;

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
//		if (m == (mode_in | mode_out)) return O_RDWR | O_BINARY;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}
}

namespace libtorrent
{

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			close();
			m_fd = ::open(
				path.native_file_string().c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

			std::stringstream str;
			str << "fd: " << m_fd << "\n";

			::close(m_fd);
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode == mode_in);
			assert(m_fd != -1);

			size_type ret = ::read(m_fd, buf, num_bytes);
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode == mode_out);
			assert(m_fd != -1);

			size_type ret = ::write(m_fd, buf, num_bytes);
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void seek(size_type offset, int m)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}

		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(boost::filesystem::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(boost::filesystem::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::seek(size_type pos, file::seek_mode m)
	{
		m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<|endoftext|>


<commit_before>/*

Copyright (c) 2003, Arvid Norberg
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"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
			size_type pos = tell();
			// Only set size if current file size not equals s.
			// 2 as "m" argument is to be sure seek() sets SEEK_END on
			// all compilers.
			if(s != seek(0, 2))
			{
				seek(s - 1);
				char dummy = 0;
				read(&dummy, 1);
				seek(s - 1);
				write(&dummy, 1);
			}
			seek(pos);
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<commit_msg>changed to use ftruncate to allocate files<commit_after>/*

Copyright (c) 2003, Arvid Norberg
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"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		assert(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			assert(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_in);
			assert(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			assert(m_open_mode & mode_out);
			assert(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << strerror(errno);
				throw file_error(msg.str());
			}
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			assert(m_open_mode);
			assert(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			assert(m_open_mode);
			assert(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<|endoftext|>


<commit_before>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
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 Stanford University 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.
*/

/*flit.cpp
 *
 *flit struct is a flit, carries all the control signals that a flit needs
 *Add additional signals as necessary. Flits has no concept of length
 *it is a singluar object.
 *
 *When adding objects make sure to set a default value in this constructor
 */

#include "booksim.hpp"
#include "flit.hpp"

stack<Flit *> Flit::_pool;

ostream& operator<<( ostream& os, const Flit& f )
{
  os << "  Flit ID: " << f.id << " (" << &f << ")"
     << " Packet ID: " << f.pid
     << " Type: " << f.type
     << " Head: " << f.head << " Tail: " << f.tail << endl;
  os << "  Source: " << f.src << "  Dest: " << f.dest << " Intm: "<<f.intm<<endl;
  os << "  Injection time: " << f.time << " Transaction start: " << f.ttime << "Arrival time: " << f.atime << " Phase: "<<f.ph<< endl;
  os << "  From router "<<f.from_router<< " VC: " << f.vc << endl;
  return os;
}

Flit::Flit()
{
  Reset();
}

void Flit::Reset()
{
  type      = ANY_TYPE ;
  vc        = -1 ;
  head      = false ;
  tail      = false ;
  true_tail = false ;
  time      = -1 ;
  ttime     = -1 ;
  atime     = -1 ;
  sn        = 0 ;
  rob_time  = 0 ;
  id        = -1 ;
  pid       = -1 ;
  hops      = 0 ;
  watch     = false ;
  record    = false ;
  intm = 0;
  src = -1;
  dest = -1;
  pri = 0;
  intm =-1;
  ph = -1;
  dr = -1;
  minimal = 1;
  ring_par = -1;
  x_then_y = -1;
  data = 0;
  from_router = -1;
}

Flit * Flit::New() {
  Flit * f;
  if(_pool.empty()) {
    f = new Flit;
  } else {
    f = _pool.top();
    f->Reset();
    _pool.pop();
  }
  return f;
}

void Flit::Free() {
  _pool.push(this);
}

void Flit::FreePool() {
  while(_pool.empty()) {
    delete _pool.top();
    _pool.pop();
  }
}
<commit_msg>fix flit pool free<commit_after>// $Id$

/*
Copyright (c) 2007-2009, Trustees of The Leland Stanford Junior University
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 Stanford University 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.
*/

/*flit.cpp
 *
 *flit struct is a flit, carries all the control signals that a flit needs
 *Add additional signals as necessary. Flits has no concept of length
 *it is a singluar object.
 *
 *When adding objects make sure to set a default value in this constructor
 */

#include "booksim.hpp"
#include "flit.hpp"

stack<Flit *> Flit::_pool;

ostream& operator<<( ostream& os, const Flit& f )
{
  os << "  Flit ID: " << f.id << " (" << &f << ")"
     << " Packet ID: " << f.pid
     << " Type: " << f.type
     << " Head: " << f.head << " Tail: " << f.tail << endl;
  os << "  Source: " << f.src << "  Dest: " << f.dest << " Intm: "<<f.intm<<endl;
  os << "  Injection time: " << f.time << " Transaction start: " << f.ttime << "Arrival time: " << f.atime << " Phase: "<<f.ph<< endl;
  os << "  From router "<<f.from_router<< " VC: " << f.vc << endl;
  return os;
}

Flit::Flit()
{
  Reset();
}

void Flit::Reset()
{
  type      = ANY_TYPE ;
  vc        = -1 ;
  head      = false ;
  tail      = false ;
  true_tail = false ;
  time      = -1 ;
  ttime     = -1 ;
  atime     = -1 ;
  sn        = 0 ;
  rob_time  = 0 ;
  id        = -1 ;
  pid       = -1 ;
  hops      = 0 ;
  watch     = false ;
  record    = false ;
  intm = 0;
  src = -1;
  dest = -1;
  pri = 0;
  intm =-1;
  ph = -1;
  dr = -1;
  minimal = 1;
  ring_par = -1;
  x_then_y = -1;
  data = 0;
  from_router = -1;
}

Flit * Flit::New() {
  Flit * f;
  if(_pool.empty()) {
    f = new Flit;
  } else {
    f = _pool.top();
    f->Reset();
    _pool.pop();
  }
  return f;
}

void Flit::Free() {
  _pool.push(this);
}

void Flit::FreePool() {
  while(!_pool.empty()) {
    delete _pool.top();
    _pool.pop();
  }
}
<|endoftext|>