<commit_before>#ifndef __UTILS_HPP__
#define __UTILS_HPP__

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <stddef.h>
#include <unistd.h>

#include <google/protobuf/message.h>

#include <glog/logging.h>

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

#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <list>

#include <boost/lexical_cast.hpp>

#include "common/foreach.hpp"
#include "common/result.hpp"
#include "common/tokenize.hpp"

#ifdef __APPLE__
#define gethostbyname2_r(name, af, ret, buf, buflen, result, h_errnop)  \
  ({ *(result) = gethostbyname2(name, af); 0; })
#endif // __APPLE__

namespace mesos { namespace internal { namespace utils {

template <typename T>
T copy(const T& t) { return t; }

template <typename T>
std::string stringify(T t)
{
  try {
    return boost::lexical_cast<std::string>(t);
  } catch (const boost::bad_lexical_cast&) {
    LOG(FATAL) << "Failed to stringify!";
  }
}

template <typename T>
std::string stringify(const std::set<T>& set)
{
  std::ostringstream out;
  out << "{ ";
  typename std::set<T>::const_iterator iterator = set.begin();
  while (iterator != set.end()) {
    out << utils::stringify(*iterator);
    if (++iterator != set.end()) {
      out << ", ";
    }
  }
  out << " }";
  return out.str();
}

namespace protobuf {

// Write out the given protobuf to the specified file descriptor by
// first writing out the length of the protobuf followed by the
// contents.
inline Result<bool> write(int fd, const google::protobuf::Message& message)
{
  if (!message.IsInitialized()) {
    LOG(ERROR) << "Failed to write protocol buffer to file, "
               << "protocol buffer is not initialized!";
    return false;
  }

  uint32_t size = message.ByteSize();

  ssize_t length = ::write(fd, (void*) &size, sizeof(size));

  if (length == -1) {
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    return Result<bool>::error(error);
  }

  CHECK(length != 0);
  CHECK(length == sizeof(size)); // TODO(benh): Handle a non-blocking fd?

  return message.SerializeToFileDescriptor(fd);
}

// Read the next protobuf from the file by first reading the "size"
// followed by the contents (as written by 'write' above).
inline Result<bool> read(int fd, google::protobuf::Message* message)
{
  CHECK(message != NULL);

  message->Clear();

  // Save the offset so we can re-adjust if something goes wrong.
  off_t offset = lseek(fd, 0, SEEK_CUR);

  if (offset < 0) {
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    return Result<bool>::error(error);
  }

  uint32_t size;
  ssize_t length = ::read(fd, (void*) &size, sizeof(size));

  if (length == 0) {
    return Result<bool>::none();
  } else if (length == -1) {
    // Save the error, reset the file offset, and return the error.
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    return result;
  } else if (length != sizeof(size)) {
    return false;
  }

  char* temp = new char[size];

  length = ::read(fd, temp, size);

  if (length == 0) {
    delete[] temp;
    return Result<bool>::none();
  } else if (length == -1) {
    // Save the error, reset the file offset, and return the error.
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    delete[] temp;
    return result;
  } else if (length != size) {
    delete[] temp;
    return false;
  }

  google::protobuf::io::ArrayInputStream stream(temp, length);
  bool parsed = message->ParseFromZeroCopyStream(&stream);

  delete[] temp;

  if (!parsed) {
    // Save the error, reset the file offset, and return the error.
    std::string error = "Failed to parse protobuf";
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    return result;
  }

  return true;
}

} // namespace protobuf {

namespace os {

// Checks if the specified key is in the environment variables.
inline bool hasenv(const std::string& key)
{
  char* value = ::getenv(key.c_str());

  return value != NULL;
}

// Looks in the environment variables for the specified key and
// returns a string representation of it's value. If 'expected' is
// true (default) and no environment variable matching key is found,
// this function will exit the process.
inline std::string getenv(const std::string& key, bool expected = true)
{
  char* value = ::getenv(key.c_str());

  if (expected && value == NULL) {
    LOG(FATAL) << "Expecting '" << key << "' in environment variables";
  }

  return std::string(value);
}

// Sets the value associated with the specfied key in the set of
// environment variables.
inline void setenv(const std::string& key,
                   const std::string& value,
                   bool overwrite = true)
{
  ::setenv(key.c_str(), value.c_str(), overwrite ? 1 : 0);
}

// Unsets the value associated with the specfied key in the set of
// environment variables.
inline void unsetenv(const std::string& key)
{
  ::unsetenv(key.c_str());
}

inline Result<int> open(const std::string& path, int oflag, mode_t mode = 0)
{
  int fd = ::open(path.c_str(), oflag, mode);

  if (fd < 0) {
    return Result<int>::error(strerror(errno));
  }

  return Result<int>::some(fd);
}

inline Result<bool> close(int fd)
{
  if (::close(fd) != 0) {
    return Result<bool>::error(strerror(errno));
  }

  return true;
}

inline Result<bool> rm(const std::string& path)
{
  if (::remove(path.c_str()) != 0) {
    return Result<bool>::error(strerror(errno));
  }

  return true;
}

inline std::string basename(const std::string& path)
{
  return ::basename(const_cast<char*>(path.c_str()));
}

inline bool mkdir(const std::string& directory)
{
  try {
    std::vector<std::string> tokens = tokenize::split(directory, "/");

    std::string path = "";

    // We got an absolute path, so keep the leading slash.
    if (directory.find_first_of("/") == 0) {
      path = "/";
    }

    foreach (const std::string& token, tokens) {
      path += token;
      if (::mkdir(path.c_str(), 0755) < 0 && errno != EEXIST) {
        PLOG(ERROR) << "Failed to make directory, mkdir";
        return false;
      }
      path += "/";
    }
  } catch (...) {
    return false;
  }

  return true;
}

// Changes the specified file's user and group ownership to that of
// the specified user..
inline bool chown(const std::string& user, const std::string& file)
{
  struct passwd* passwd;
  if ((passwd = ::getpwnam(user.c_str())) == NULL) {
    PLOG(ERROR) << "Failed to get user information for '"
                << user
                << "', getpwnam";
    return false;
  }

  if (::chown(file.c_str(), passwd->pw_uid, passwd->pw_gid) < 0) {
    PLOG(ERROR) << "Failed to change file user and group ownership, chown";
    return false;
  }

  return true;
}

inline bool chdir(const std::string& directory)
{
  if (chdir(directory.c_str()) < 0) {
    PLOG(ERROR) << "Failed to change directory, chdir";
    return false;
  }

  return true;
}

inline bool su(const std::string& user)
{
  struct passwd* passwd;
  if ((passwd = ::getpwnam(user.c_str())) == NULL) {
    PLOG(ERROR) << "Failed to get user information for '"
                << user
                << "', getpwnam";
    return false;
  }

  if (::setgid(passwd->pw_gid) < 0) {
    PLOG(ERROR) << "Failed to set group id, setgid";
    return false;
  }

  if (::setuid(passwd->pw_uid) < 0) {
    PLOG(ERROR) << "Failed to set user id, setuid";
    return false;
  }

  return true;
}

inline std::string getcwd()
{
  size_t size = 100;

  while (true) {
    char* temp = new char[size];
    if (::getcwd(temp, size) == temp) {
      std::string result(temp);
      delete[] temp;
      return result;
    } else {
      if (errno != ERANGE) {
        delete[] temp;
        return std::string();
      }
      size *= 2;
      delete[] temp;
    }
  }

  return std::string();
}

inline std::list<std::string> listdir(const std::string& directory)
{
  std::list<std::string> result;

  DIR* dir = opendir(directory.c_str());

  if (dir == NULL) {
    return std::list<std::string>();
  }

  // Calculate the size for a "directory entry".
  long name_max = fpathconf(dirfd(dir), _PC_NAME_MAX);

  // If we don't get a valid size, check NAME_MAX, but fall back on
  // 255 in the worst case ... Danger, Will Robinson!
  if (name_max == -1) {
    name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
  }

  size_t name_end =
    (size_t) offsetof(dirent, d_name) + name_max + 1;

  size_t size = (name_end > sizeof(dirent)
                 ? name_end
                 : sizeof(dirent));

  dirent* temp = (dirent*) malloc(size);

  if (temp == NULL) {
    free(temp);
    closedir(dir);
    return std::list<std::string>();
  }

  struct dirent* entry;

  int error;

  while ((error = readdir_r(dir, temp, &entry)) == 0 && entry != NULL) {
    result.push_back(entry->d_name);
  }

  free(temp);
  closedir(dir);

  if (error != 0) {
    return std::list<std::string>();
  }

  return result;
}

inline Result<std::string> hostname()
{
  char host[512];

  if (gethostname(host, sizeof(host)) < 0) {
    return Result<std::string>::error(strerror(errno));
  }

  struct hostent he, *hep;
  char* temp;
  size_t length;
  int result;
  int herrno;

  // Allocate temporary buffer for gethostbyname2_r.
  length = 1024;
  temp = new char[length];

  while ((result = gethostbyname2_r(host, AF_INET, &he, temp,
				    length, &hep, &herrno)) == ERANGE) {
    // Enlarge the buffer.
    delete[] temp;
    length *= 2;
    temp = new char[length];
  }

  if (result != 0 || hep == NULL) {
    delete[] temp;
    return Result<std::string>::error(hstrerror(herrno));
  }

  std::string hostname = hep->h_name;
  delete[] temp;
  return Result<std::string>::some(hostname);
}

} // namespace os {

}}} // namespace mesos { namespace internal { namespace utils {

#endif // __UTILS_HPP__
<commit_msg>Added a heuristic to deal with reading a protobuf from a file that might have gotten corrupted.<commit_after>#ifndef __UTILS_HPP__
#define __UTILS_HPP__

#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <limits.h>
#include <netdb.h>
#include <pwd.h>
#include <stddef.h>
#include <unistd.h>

#include <google/protobuf/message.h>

#include <glog/logging.h>

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

#include <google/protobuf/io/zero_copy_stream_impl.h>

#include <list>

#include <boost/lexical_cast.hpp>

#include "common/foreach.hpp"
#include "common/result.hpp"
#include "common/tokenize.hpp"

#ifdef __APPLE__
#define gethostbyname2_r(name, af, ret, buf, buflen, result, h_errnop)  \
  ({ *(result) = gethostbyname2(name, af); 0; })
#endif // __APPLE__

namespace mesos { namespace internal { namespace utils {

template <typename T>
T copy(const T& t) { return t; }

template <typename T>
std::string stringify(T t)
{
  try {
    return boost::lexical_cast<std::string>(t);
  } catch (const boost::bad_lexical_cast&) {
    LOG(FATAL) << "Failed to stringify!";
  }
}

template <typename T>
std::string stringify(const std::set<T>& set)
{
  std::ostringstream out;
  out << "{ ";
  typename std::set<T>::const_iterator iterator = set.begin();
  while (iterator != set.end()) {
    out << utils::stringify(*iterator);
    if (++iterator != set.end()) {
      out << ", ";
    }
  }
  out << " }";
  return out.str();
}

namespace protobuf {

// Write out the given protobuf to the specified file descriptor by
// first writing out the length of the protobuf followed by the
// contents.
inline Result<bool> write(int fd, const google::protobuf::Message& message)
{
  if (!message.IsInitialized()) {
    LOG(ERROR) << "Failed to write protocol buffer to file, "
               << "protocol buffer is not initialized!";
    return false;
  }

  uint32_t size = message.ByteSize();

  ssize_t length = ::write(fd, (void*) &size, sizeof(size));

  if (length == -1) {
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    return Result<bool>::error(error);
  }

  CHECK(length != 0);
  CHECK(length == sizeof(size)); // TODO(benh): Handle a non-blocking fd?

  return message.SerializeToFileDescriptor(fd);
}

// Read the next protobuf from the file by first reading the "size"
// followed by the contents (as written by 'write' above).
inline Result<bool> read(int fd, google::protobuf::Message* message)
{
  CHECK(message != NULL);

  message->Clear();

  // Save the offset so we can re-adjust if something goes wrong.
  off_t offset = lseek(fd, 0, SEEK_CUR);

  if (offset < 0) {
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    return Result<bool>::error(error);
  }

  uint32_t size;
  ssize_t length = ::read(fd, (void*) &size, sizeof(size));

  if (length == 0) {
    return Result<bool>::none();
  } else if (length == -1) {
    // Save the error, reset the file offset, and return the error.
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    return result;
  } else if (length != sizeof(size)) {
    return false;
  }

  // TODO(benh): Use a different format for writing a protobuf to disk
  // so that we don't need to have broken heuristics like this!
  if (size > 10 * 1024 * 1024) { // 10 MB
    // Save the error, reset the file offset, and return the error.
    std::string error = "Size > 10 MB, possible corruption detected";
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    return result;
  }

  char* temp = new char[size];

  length = ::read(fd, temp, size);

  if (length == 0) {
    delete[] temp;
    return Result<bool>::none();
  } else if (length == -1) {
    // Save the error, reset the file offset, and return the error.
    std::string error = strerror(errno);
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    delete[] temp;
    return result;
  } else if (length != size) {
    delete[] temp;
    return false;
  }

  google::protobuf::io::ArrayInputStream stream(temp, length);
  bool parsed = message->ParseFromZeroCopyStream(&stream);

  delete[] temp;

  if (!parsed) {
    // Save the error, reset the file offset, and return the error.
    std::string error = "Failed to parse protobuf";
    error = error + " (" + __FILE__ + ":" + utils::stringify(__LINE__) + ")";
    Result<bool> result = Result<bool>::error(error);
    lseek(fd, offset, SEEK_SET);
    return result;
  }

  return true;
}

} // namespace protobuf {

namespace os {

// Checks if the specified key is in the environment variables.
inline bool hasenv(const std::string& key)
{
  char* value = ::getenv(key.c_str());

  return value != NULL;
}

// Looks in the environment variables for the specified key and
// returns a string representation of it's value. If 'expected' is
// true (default) and no environment variable matching key is found,
// this function will exit the process.
inline std::string getenv(const std::string& key, bool expected = true)
{
  char* value = ::getenv(key.c_str());

  if (expected && value == NULL) {
    LOG(FATAL) << "Expecting '" << key << "' in environment variables";
  }

  return std::string(value);
}

// Sets the value associated with the specfied key in the set of
// environment variables.
inline void setenv(const std::string& key,
                   const std::string& value,
                   bool overwrite = true)
{
  ::setenv(key.c_str(), value.c_str(), overwrite ? 1 : 0);
}

// Unsets the value associated with the specfied key in the set of
// environment variables.
inline void unsetenv(const std::string& key)
{
  ::unsetenv(key.c_str());
}

inline Result<int> open(const std::string& path, int oflag, mode_t mode = 0)
{
  int fd = ::open(path.c_str(), oflag, mode);

  if (fd < 0) {
    return Result<int>::error(strerror(errno));
  }

  return Result<int>::some(fd);
}

inline Result<bool> close(int fd)
{
  if (::close(fd) != 0) {
    return Result<bool>::error(strerror(errno));
  }

  return true;
}

inline Result<bool> rm(const std::string& path)
{
  if (::remove(path.c_str()) != 0) {
    return Result<bool>::error(strerror(errno));
  }

  return true;
}

inline std::string basename(const std::string& path)
{
  return ::basename(const_cast<char*>(path.c_str()));
}

inline bool mkdir(const std::string& directory)
{
  try {
    std::vector<std::string> tokens = tokenize::split(directory, "/");

    std::string path = "";

    // We got an absolute path, so keep the leading slash.
    if (directory.find_first_of("/") == 0) {
      path = "/";
    }

    foreach (const std::string& token, tokens) {
      path += token;
      if (::mkdir(path.c_str(), 0755) < 0 && errno != EEXIST) {
        PLOG(ERROR) << "Failed to make directory, mkdir";
        return false;
      }
      path += "/";
    }
  } catch (...) {
    return false;
  }

  return true;
}

// Changes the specified file's user and group ownership to that of
// the specified user..
inline bool chown(const std::string& user, const std::string& file)
{
  struct passwd* passwd;
  if ((passwd = ::getpwnam(user.c_str())) == NULL) {
    PLOG(ERROR) << "Failed to get user information for '"
                << user
                << "', getpwnam";
    return false;
  }

  if (::chown(file.c_str(), passwd->pw_uid, passwd->pw_gid) < 0) {
    PLOG(ERROR) << "Failed to change file user and group ownership, chown";
    return false;
  }

  return true;
}

inline bool chdir(const std::string& directory)
{
  if (chdir(directory.c_str()) < 0) {
    PLOG(ERROR) << "Failed to change directory, chdir";
    return false;
  }

  return true;
}

inline bool su(const std::string& user)
{
  struct passwd* passwd;
  if ((passwd = ::getpwnam(user.c_str())) == NULL) {
    PLOG(ERROR) << "Failed to get user information for '"
                << user
                << "', getpwnam";
    return false;
  }

  if (::setgid(passwd->pw_gid) < 0) {
    PLOG(ERROR) << "Failed to set group id, setgid";
    return false;
  }

  if (::setuid(passwd->pw_uid) < 0) {
    PLOG(ERROR) << "Failed to set user id, setuid";
    return false;
  }

  return true;
}

inline std::string getcwd()
{
  size_t size = 100;

  while (true) {
    char* temp = new char[size];
    if (::getcwd(temp, size) == temp) {
      std::string result(temp);
      delete[] temp;
      return result;
    } else {
      if (errno != ERANGE) {
        delete[] temp;
        return std::string();
      }
      size *= 2;
      delete[] temp;
    }
  }

  return std::string();
}

inline std::list<std::string> listdir(const std::string& directory)
{
  std::list<std::string> result;

  DIR* dir = opendir(directory.c_str());

  if (dir == NULL) {
    return std::list<std::string>();
  }

  // Calculate the size for a "directory entry".
  long name_max = fpathconf(dirfd(dir), _PC_NAME_MAX);

  // If we don't get a valid size, check NAME_MAX, but fall back on
  // 255 in the worst case ... Danger, Will Robinson!
  if (name_max == -1) {
    name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
  }

  size_t name_end =
    (size_t) offsetof(dirent, d_name) + name_max + 1;

  size_t size = (name_end > sizeof(dirent)
                 ? name_end
                 : sizeof(dirent));

  dirent* temp = (dirent*) malloc(size);

  if (temp == NULL) {
    free(temp);
    closedir(dir);
    return std::list<std::string>();
  }

  struct dirent* entry;

  int error;

  while ((error = readdir_r(dir, temp, &entry)) == 0 && entry != NULL) {
    result.push_back(entry->d_name);
  }

  free(temp);
  closedir(dir);

  if (error != 0) {
    return std::list<std::string>();
  }

  return result;
}

inline Result<std::string> hostname()
{
  char host[512];

  if (gethostname(host, sizeof(host)) < 0) {
    return Result<std::string>::error(strerror(errno));
  }

  struct hostent he, *hep;
  char* temp;
  size_t length;
  int result;
  int herrno;

  // Allocate temporary buffer for gethostbyname2_r.
  length = 1024;
  temp = new char[length];

  while ((result = gethostbyname2_r(host, AF_INET, &he, temp,
				    length, &hep, &herrno)) == ERANGE) {
    // Enlarge the buffer.
    delete[] temp;
    length *= 2;
    temp = new char[length];
  }

  if (result != 0 || hep == NULL) {
    delete[] temp;
    return Result<std::string>::error(hstrerror(herrno));
  }

  std::string hostname = hep->h_name;
  delete[] temp;
  return Result<std::string>::some(hostname);
}

} // namespace os {

}}} // namespace mesos { namespace internal { namespace utils {

#endif // __UTILS_HPP__
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#include "sort.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>

#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/ptr_container/ptr_unordered_map.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/variant/recursive_variant.hpp>

#include "db/driver.hh"
#include "db/query.h"
#include "db/statement-driver.hh"
#include "lexer.hh"

using std::cerr;
using std::endl;
using std::memcpy;
using std::string;
using std::vector;

using namespace boost::spirit;

namespace flint {
namespace compiler {
namespace sort {

struct Compound;

typedef boost::variant<boost::recursive_wrapper<Compound>,
					   std::string,
					   int,
					   flint::lexer::Real
					   > Expr;

struct Compound {
	std::vector<Expr> children;
};

struct Entry {
	std::string uuid;
	std::string name;
	Expr expr;
};

}
}
}

BOOST_FUSION_ADAPT_STRUCT(flint::compiler::sort::Compound,
						  (std::vector<flint::compiler::sort::Expr>, children))

BOOST_FUSION_ADAPT_STRUCT(flint::compiler::sort::Entry,
						  (std::string, uuid)
						  (std::string, name)
						  (flint::compiler::sort::Expr, expr))

namespace flint {
namespace compiler {
namespace sort {
namespace {

class DependencyCollector : public boost::static_visitor<> {
public:
	DependencyCollector(const string &name,
						const std::unordered_map<string, size_t> &candidates,
						std::unordered_set<size_t> *dependencies)
		: name_(name)
		, candidates_(candidates)
		, dependencies_(dependencies)
	{}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator it, end = c.children.end();
		for (it=c.children.begin();it!=end;++it) {
			boost::apply_visitor(*this, *it);
		}
	}

	void operator()(const std::string &s) const {
		if (s == name_)
			return;
		std::unordered_map<string, size_t>::const_iterator it = candidates_.find(s);
		if (it != candidates_.cend())
			dependencies_->insert(it->second);
	}

	void operator()(int /*i*/) const {
		// nothing to do
	}

	void operator()(const flint::lexer::Real &) const {
		// nothing to do
	}

private:
	const string &name_;
	const std::unordered_map<string, size_t> &candidates_;
	std::unordered_set<size_t> *dependencies_;
};

class Printer : public boost::static_visitor<> {
public:
	explicit Printer(std::ostream *os)
		: os_(os)
	{
	}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator bit = c.children.begin();
		std::vector<Expr>::const_iterator eit = c.children.end();
		os_->put('(');
		for (std::vector<Expr>::const_iterator it=bit;it!=eit;++it) {
			if (it != bit) os_->put(' ');
			boost::apply_visitor(*this, *it);
		}
		os_->put(')');
	}

	void operator()(const std::string &s) const {
		*os_ << s;
	}

	void operator()(int i) const {
		*os_ << i;
	}

	void operator()(const flint::lexer::Real &r) const {
		*os_ << r.lexeme;
	}

private:
	std::ostream *os_;
};

template<typename TLexer>
struct Lexer : lex::lexer<TLexer> {

	Lexer() {
		this->self.add_pattern
			("DIGIT", "[0-9]")
			("SIGN", "[-+]")
			("EXPONENT", "[eE]{SIGN}?{DIGIT}+")
			("FLOAT", "{SIGN}?({DIGIT}*\".\"{DIGIT}+{EXPONENT}?|{DIGIT}+{EXPONENT})")
			;

		uuid36 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
		real = "{FLOAT}";
		integer = "{SIGN}?{DIGIT}+";
		id = "[%@][a-zA-Z_][a-zA-Z_0-9:#]*";
		keyword = "[$]?[a-zA-Z_][a-zA-Z_0-9]*";

		this->self = lex::token_def<>('\n') | '\r' | '(' | ')' | ' ';
		this->self += uuid36 | real | integer | id | keyword;
	}

	lex::token_def<std::string> uuid36, id, keyword;
	lex::token_def<int> integer;
	lex::token_def<flint::lexer::Real> real;
};

template<typename TIterator>
struct Grammar : qi::grammar<TIterator, Expr()> {

	template<typename TTokenDef>
	Grammar(TTokenDef const &td)
	: Grammar::base_type(expr)
	{
		expr %= (compound | td.real | td.integer | td.id | td.keyword);

		compound %= '(' >> (expr % ' ') >> ')';
	}

	qi::rule<TIterator, Expr()> expr;
	qi::rule<TIterator, Compound()> compound;
};

class Line {
public:
	Line(const Line &) = delete;
	Line &operator=(const Line &) = delete;

	Line(const std::string &name, const Expr &expr)
		: name_(name),
		  expr_(expr)
	{
	}

	const string &name() const {return name_;}

	size_t CollectDependencies(const std::unordered_map<string, size_t> &candidates, std::unordered_set<size_t> *dependencies) {
		boost::apply_visitor(DependencyCollector(name_, candidates, dependencies), expr_);
		return dependencies->size();
	}

	std::string GetMath() const {
		std::ostringstream oss;
		boost::apply_visitor(Printer(&oss), expr_);
		return oss.str();
	}

private:
	std::string name_;
	Expr expr_;
};

class LineVector {
public:
	LineVector(const LineVector &) = delete;
	LineVector &operator=(const LineVector &) = delete;

	LineVector() {}

	size_t GetSize() const {
		return lines_.size();
	}

	void Add(const std::string &name, const Expr &expr) {
		std::unique_ptr<Line> line(new Line(name, expr));
		lines_.push_back(std::move(line));
	}

	bool CalculateLevels(const boost::uuids::uuid &uuid, int *levels) {
		size_t n = lines_.size();
		std::unordered_map<string, size_t> nm;
		for (size_t i=0;i<n;i++) {
			auto p = nm.insert(std::make_pair(lines_[i]->name(), i));
			if (!p.second) {
				cerr << "more than one entries for " << p.first->first << endl;
				return false;
			}
			levels[i] = -1;
		}
		std::unique_ptr<std::unordered_set<size_t>[]> dependencies(new std::unordered_set<size_t>[n]);
		size_t total = 0;
		for (size_t i=0;i<n;i++) {
			auto &line = lines_[i];
			if (line->CollectDependencies(nm, dependencies.get()+i) == 0) {
				levels[i] = 0;
				total++;
			}
		}
		if (total == 0) {
			// we have nothing to do if there is no level 0
			return true;
		}
		int level = 1;
		while (total < n) {
			bool found = false;
			for (size_t i=0;i<n;i++) {
				if (levels[i] >= 0) continue;
				if (std::all_of(dependencies[i].begin(), dependencies[i].end(),
								[&levels, level](size_t k){return 0 <= levels[k] && levels[k] < level;})) {
					levels[i] = level;
					total++;
					found = true;
				}
			}
			if (!found) {
				cerr << "failed to calculate level in "
					 << uuid
					 << ':'
					 << endl;
				for (size_t i=0;i<n;i++) {
					if (levels[i] < 0)
						cerr << ' ' << lines_[i]->name()
							 << ": "
							 << lines_[i]->GetMath()
							 << endl;
				}
				return false;
			}
			level++;
		}
		return true;
	}

	const Line &at(size_t m) const {
		return *lines_.at(m);
	}

private:
	std::vector<std::unique_ptr<Line> > lines_;
};

class IndexAndLevel {
public:
	IndexAndLevel(size_t index, int level) : index_(index), level_(level) {}

	size_t index() const {return index_;}

	bool operator<(const IndexAndLevel &other) const {
		return level_ < other.level_;
	}

private:
	size_t index_;
	int level_;
};

typedef boost::ptr_unordered_map<boost::uuids::uuid, LineVector> UuidMap;

/*
 * This class creates and keeps both tokens and grammar objects which
 * construction is expensive in terms of performance.
 */
class Parser {
public:
	typedef const char *base_iterator_type;
	typedef lex::lexertl::token<base_iterator_type> token_type;
	typedef lex::lexertl::lexer<token_type> lexer_type;
	typedef Lexer<lexer_type> RealLexer;
	typedef Grammar<RealLexer::iterator_type> RealGrammar;

	explicit Parser(UuidMap *um)
		: tokens_()
		, grammar_(tokens_)
		, um_(um)
	{
	}

	int Parse(const boost::uuids::uuid &uuid, const char *name, const char *math) {
		base_iterator_type it = math;
		base_iterator_type eit = math + std::strlen(math);
		Expr expr;
		bool r = lex::tokenize_and_parse(it, eit, tokens_, grammar_, expr);
		if (!r || it != eit) {
			cerr << "failed to parse: " << *it << endl;
			return 1;
		}
		(*um_)[uuid].Add(name, expr);
		return 0;
	}

private:
	RealLexer tokens_;
	RealGrammar grammar_;
	UuidMap *um_;
};

int Process(void *data, int argc, char **argv, char **names)
{
	(void)names;
	assert(argc == 3);
	Parser *parser = static_cast<Parser *>(data);
	assert(argv[0]);
	boost::uuids::uuid u;
	memcpy(&u, argv[0], u.size());
	return parser->Parse(u, argv[1], argv[2]);
}

class Inserter : db::StatementDriver {
public:
	explicit Inserter(sqlite3 *db)
		: db::StatementDriver(db, "INSERT INTO sorts VALUES (?, ?, ?)")
	{
	}

	bool Insert(const boost::uuids::uuid &uuid, const char *name, const char *math) {
		int e;
		e = sqlite3_bind_blob(stmt(), 1, &uuid, uuid.size(), SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind uuid: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 2, name, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind name: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 3, math, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind math: " << e << endl;
			return false;
		}
		e = sqlite3_step(stmt());
		if (e != SQLITE_DONE) {
			cerr << "failed to step: " << e << endl;
			return false;
		}
		sqlite3_reset(stmt());
		return true;
	}
};

}

bool Sort(sqlite3 *db)
{
	UuidMap um;
	{
		Parser parser(&um);
		char *em;
		int e;
		e = sqlite3_exec(db, "SELECT * FROM asts", Process, &parser, &em);
		if (e != SQLITE_OK) {
			cerr << "failed to exec: " << e
				 << ": " << em << endl;
			sqlite3_free(em);
			return false;
		}
	}

	if (!BeginTransaction(db))
		return false;
	if (!CreateTable(db, "sorts", "(uuid BLOB, name TEXT, math TEXT)"))
		return false;

	Inserter inserter(db);
	for (UuidMap::iterator umit=um.begin();umit!=um.end();++umit) {
		size_t n = umit->second->GetSize();
		std::unique_ptr<int[]> arr(new int[n]);
		if (!umit->second->CalculateLevels(umit->first, arr.get())) {
			return false;
		}
		vector<IndexAndLevel> v;
		for (size_t k=0;k<n;k++) {
			v.push_back(IndexAndLevel(k, arr[k]));
		}
		std::stable_sort(v.begin(), v.end());
		for (vector<IndexAndLevel>::const_iterator vit=v.begin();vit!=v.end();++vit) {
			size_t m = vit->index();
			const Line &line(umit->second->at(m));
			std::string math = line.GetMath();
			if (!inserter.Insert(umit->first,
								 line.name().c_str(),
								 math.c_str()))
				return false;
		}
	}
	return CommitTransaction(db);
}

}
}
}
<commit_msg>Replace boost::ptr_unordered_map with std::unordered_map<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- vim:set ts=4 sw=4 sts=4 noet: */
#include "sort.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>

#include <boost/functional/hash.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_multi_pass.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/variant/recursive_variant.hpp>

#include "db/driver.hh"
#include "db/query.h"
#include "db/statement-driver.hh"
#include "lexer.hh"

using std::cerr;
using std::endl;
using std::memcpy;
using std::string;
using std::vector;

using namespace boost::spirit;

namespace flint {
namespace compiler {
namespace sort {

struct Compound;

typedef boost::variant<boost::recursive_wrapper<Compound>,
					   std::string,
					   int,
					   flint::lexer::Real
					   > Expr;

struct Compound {
	std::vector<Expr> children;
};

struct Entry {
	std::string uuid;
	std::string name;
	Expr expr;
};

}
}
}

BOOST_FUSION_ADAPT_STRUCT(flint::compiler::sort::Compound,
						  (std::vector<flint::compiler::sort::Expr>, children))

BOOST_FUSION_ADAPT_STRUCT(flint::compiler::sort::Entry,
						  (std::string, uuid)
						  (std::string, name)
						  (flint::compiler::sort::Expr, expr))

namespace flint {
namespace compiler {
namespace sort {
namespace {

class DependencyCollector : public boost::static_visitor<> {
public:
	DependencyCollector(const string &name,
						const std::unordered_map<string, size_t> &candidates,
						std::unordered_set<size_t> *dependencies)
		: name_(name)
		, candidates_(candidates)
		, dependencies_(dependencies)
	{}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator it, end = c.children.end();
		for (it=c.children.begin();it!=end;++it) {
			boost::apply_visitor(*this, *it);
		}
	}

	void operator()(const std::string &s) const {
		if (s == name_)
			return;
		std::unordered_map<string, size_t>::const_iterator it = candidates_.find(s);
		if (it != candidates_.cend())
			dependencies_->insert(it->second);
	}

	void operator()(int /*i*/) const {
		// nothing to do
	}

	void operator()(const flint::lexer::Real &) const {
		// nothing to do
	}

private:
	const string &name_;
	const std::unordered_map<string, size_t> &candidates_;
	std::unordered_set<size_t> *dependencies_;
};

class Printer : public boost::static_visitor<> {
public:
	explicit Printer(std::ostream *os)
		: os_(os)
	{
	}

	void operator()(const Compound &c) const {
		std::vector<Expr>::const_iterator bit = c.children.begin();
		std::vector<Expr>::const_iterator eit = c.children.end();
		os_->put('(');
		for (std::vector<Expr>::const_iterator it=bit;it!=eit;++it) {
			if (it != bit) os_->put(' ');
			boost::apply_visitor(*this, *it);
		}
		os_->put(')');
	}

	void operator()(const std::string &s) const {
		*os_ << s;
	}

	void operator()(int i) const {
		*os_ << i;
	}

	void operator()(const flint::lexer::Real &r) const {
		*os_ << r.lexeme;
	}

private:
	std::ostream *os_;
};

template<typename TLexer>
struct Lexer : lex::lexer<TLexer> {

	Lexer() {
		this->self.add_pattern
			("DIGIT", "[0-9]")
			("SIGN", "[-+]")
			("EXPONENT", "[eE]{SIGN}?{DIGIT}+")
			("FLOAT", "{SIGN}?({DIGIT}*\".\"{DIGIT}+{EXPONENT}?|{DIGIT}+{EXPONENT})")
			;

		uuid36 = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
		real = "{FLOAT}";
		integer = "{SIGN}?{DIGIT}+";
		id = "[%@][a-zA-Z_][a-zA-Z_0-9:#]*";
		keyword = "[$]?[a-zA-Z_][a-zA-Z_0-9]*";

		this->self = lex::token_def<>('\n') | '\r' | '(' | ')' | ' ';
		this->self += uuid36 | real | integer | id | keyword;
	}

	lex::token_def<std::string> uuid36, id, keyword;
	lex::token_def<int> integer;
	lex::token_def<flint::lexer::Real> real;
};

template<typename TIterator>
struct Grammar : qi::grammar<TIterator, Expr()> {

	template<typename TTokenDef>
	Grammar(TTokenDef const &td)
	: Grammar::base_type(expr)
	{
		expr %= (compound | td.real | td.integer | td.id | td.keyword);

		compound %= '(' >> (expr % ' ') >> ')';
	}

	qi::rule<TIterator, Expr()> expr;
	qi::rule<TIterator, Compound()> compound;
};

class Line {
public:
	Line(const Line &) = delete;
	Line &operator=(const Line &) = delete;

	Line(const std::string &name, const Expr &expr)
		: name_(name),
		  expr_(expr)
	{
	}

	const string &name() const {return name_;}

	size_t CollectDependencies(const std::unordered_map<string, size_t> &candidates, std::unordered_set<size_t> *dependencies) {
		boost::apply_visitor(DependencyCollector(name_, candidates, dependencies), expr_);
		return dependencies->size();
	}

	std::string GetMath() const {
		std::ostringstream oss;
		boost::apply_visitor(Printer(&oss), expr_);
		return oss.str();
	}

private:
	std::string name_;
	Expr expr_;
};

class LineVector {
public:
	LineVector(const LineVector &) = delete;
	LineVector &operator=(const LineVector &) = delete;

	LineVector() {}

	size_t GetSize() const {
		return lines_.size();
	}

	void Add(const std::string &name, const Expr &expr) {
		std::unique_ptr<Line> line(new Line(name, expr));
		lines_.push_back(std::move(line));
	}

	bool CalculateLevels(const boost::uuids::uuid &uuid, int *levels) {
		size_t n = lines_.size();
		std::unordered_map<string, size_t> nm;
		for (size_t i=0;i<n;i++) {
			auto p = nm.insert(std::make_pair(lines_[i]->name(), i));
			if (!p.second) {
				cerr << "more than one entries for " << p.first->first << endl;
				return false;
			}
			levels[i] = -1;
		}
		std::unique_ptr<std::unordered_set<size_t>[]> dependencies(new std::unordered_set<size_t>[n]);
		size_t total = 0;
		for (size_t i=0;i<n;i++) {
			auto &line = lines_[i];
			if (line->CollectDependencies(nm, dependencies.get()+i) == 0) {
				levels[i] = 0;
				total++;
			}
		}
		if (total == 0) {
			// we have nothing to do if there is no level 0
			return true;
		}
		int level = 1;
		while (total < n) {
			bool found = false;
			for (size_t i=0;i<n;i++) {
				if (levels[i] >= 0) continue;
				if (std::all_of(dependencies[i].begin(), dependencies[i].end(),
								[&levels, level](size_t k){return 0 <= levels[k] && levels[k] < level;})) {
					levels[i] = level;
					total++;
					found = true;
				}
			}
			if (!found) {
				cerr << "failed to calculate level in "
					 << uuid
					 << ':'
					 << endl;
				for (size_t i=0;i<n;i++) {
					if (levels[i] < 0)
						cerr << ' ' << lines_[i]->name()
							 << ": "
							 << lines_[i]->GetMath()
							 << endl;
				}
				return false;
			}
			level++;
		}
		return true;
	}

	const Line &at(size_t m) const {
		return *lines_.at(m);
	}

private:
	std::vector<std::unique_ptr<Line> > lines_;
};

class IndexAndLevel {
public:
	IndexAndLevel(size_t index, int level) : index_(index), level_(level) {}

	size_t index() const {return index_;}

	bool operator<(const IndexAndLevel &other) const {
		return level_ < other.level_;
	}

private:
	size_t index_;
	int level_;
};

typedef std::unordered_map<boost::uuids::uuid,
						   LineVector,
						   boost::hash<boost::uuids::uuid> > UuidMap;

/*
 * This class creates and keeps both tokens and grammar objects which
 * construction is expensive in terms of performance.
 */
class Parser {
public:
	typedef const char *base_iterator_type;
	typedef lex::lexertl::token<base_iterator_type> token_type;
	typedef lex::lexertl::lexer<token_type> lexer_type;
	typedef Lexer<lexer_type> RealLexer;
	typedef Grammar<RealLexer::iterator_type> RealGrammar;

	explicit Parser(UuidMap *um)
		: tokens_()
		, grammar_(tokens_)
		, um_(um)
	{
	}

	int Parse(const boost::uuids::uuid &uuid, const char *name, const char *math) {
		base_iterator_type it = math;
		base_iterator_type eit = math + std::strlen(math);
		Expr expr;
		bool r = lex::tokenize_and_parse(it, eit, tokens_, grammar_, expr);
		if (!r || it != eit) {
			cerr << "failed to parse: " << *it << endl;
			return 1;
		}
		(*um_)[uuid].Add(name, expr);
		return 0;
	}

private:
	RealLexer tokens_;
	RealGrammar grammar_;
	UuidMap *um_;
};

int Process(void *data, int argc, char **argv, char **names)
{
	(void)names;
	assert(argc == 3);
	Parser *parser = static_cast<Parser *>(data);
	assert(argv[0]);
	boost::uuids::uuid u;
	memcpy(&u, argv[0], u.size());
	return parser->Parse(u, argv[1], argv[2]);
}

class Inserter : db::StatementDriver {
public:
	explicit Inserter(sqlite3 *db)
		: db::StatementDriver(db, "INSERT INTO sorts VALUES (?, ?, ?)")
	{
	}

	bool Insert(const boost::uuids::uuid &uuid, const char *name, const char *math) {
		int e;
		e = sqlite3_bind_blob(stmt(), 1, &uuid, uuid.size(), SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind uuid: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 2, name, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind name: " << e << endl;
			return false;
		}
		e = sqlite3_bind_text(stmt(), 3, math, -1, SQLITE_STATIC);
		if (e != SQLITE_OK) {
			cerr << "failed to bind math: " << e << endl;
			return false;
		}
		e = sqlite3_step(stmt());
		if (e != SQLITE_DONE) {
			cerr << "failed to step: " << e << endl;
			return false;
		}
		sqlite3_reset(stmt());
		return true;
	}
};

}

bool Sort(sqlite3 *db)
{
	UuidMap um;
	{
		Parser parser(&um);
		char *em;
		int e;
		e = sqlite3_exec(db, "SELECT * FROM asts", Process, &parser, &em);
		if (e != SQLITE_OK) {
			cerr << "failed to exec: " << e
				 << ": " << em << endl;
			sqlite3_free(em);
			return false;
		}
	}

	if (!BeginTransaction(db))
		return false;
	if (!CreateTable(db, "sorts", "(uuid BLOB, name TEXT, math TEXT)"))
		return false;

	Inserter inserter(db);
	for (UuidMap::iterator umit=um.begin();umit!=um.end();++umit) {
		size_t n = umit->second.GetSize();
		std::unique_ptr<int[]> arr(new int[n]);
		if (!umit->second.CalculateLevels(umit->first, arr.get())) {
			return false;
		}
		vector<IndexAndLevel> v;
		for (size_t k=0;k<n;k++) {
			v.push_back(IndexAndLevel(k, arr[k]));
		}
		std::stable_sort(v.begin(), v.end());
		for (vector<IndexAndLevel>::const_iterator vit=v.begin();vit!=v.end();++vit) {
			size_t m = vit->index();
			const Line &line(umit->second.at(m));
			std::string math = line.GetMath();
			if (!inserter.Insert(umit->first,
								 line.name().c_str(),
								 math.c_str()))
				return false;
		}
	}
	return CommitTransaction(db);
}

}
}
}
<|endoftext|>


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

#include "lcds.h"
#include "bitop.h"

#include <util/delay.h>
#include <avr/pgmspace.h>

avr_cpp_lib::LCDS::LCDS(OutputPin rs, OutputPin e, OutputPin d4, OutputPin d5, OutputPin d6, OutputPin d7)
	: rs(rs), e(e), d4(d4), d5(d5), d6(d6), d7(d7) {
	d7.clear();
	d6.clear();
	d5.set();
	d4.set();
	rs.clear();

	// one (8 bit mode)
	enableToggle();

	// two (8 bit mode)
	enableToggle();

	// three (4 bit mode)
	d4.clear();
	enableToggle();

	// dual line, 4 bit mode
	command(0b00101000);

	// turn display on, cursor off
	command(DISPLAY_ON);

	// clear display
	command(CLEAR);
}

void avr_cpp_lib::LCDS::enableToggle() {
	e.set();
	_delay_ms(1);
	e.clear();
	_delay_ms(1);
}

void avr_cpp_lib::LCDS::command(uint8_t c) {
	rs.clear();
	send(c);
	_delay_ms(5);
}

void avr_cpp_lib::LCDS::character(uint8_t c) {
	rs.set();
	send(c);
}

void avr_cpp_lib::LCDS::send(uint8_t c) {
	if (BITSET(c, 7)) {
		d7.set();
	} else {
		d7.clear();
	}
	if (BITSET(c, 6)) {
		d6.set();
	} else {
		d6.clear();
	}
	if (BITSET(c, 5)) {
		d5.set();
	} else {
		d5.clear();
	}
	if (BITSET(c, 4)) {
		d4.set();
	} else {
		d4.clear();
	}
	enableToggle();
	if (BITSET(c, 3)) {
		d7.set();
	} else {
		d7.clear();
	}
	if (BITSET(c, 2)) {
		d6.set();
	} else {
		d6.clear();
	}
	if (BITSET(c, 1)) {
		d5.set();
	} else {
		d5.clear();
	}
	if (BITSET(c, 0)) {
		d4.set();
	} else {
		d4.clear();
	}
	enableToggle();
}

void avr_cpp_lib::LCDS::gotoXY(uint8_t x, uint8_t y) {
	uint8_t tmp;
	switch (y) {
	case 0:
		tmp = x;
		break;
	case 1:
		tmp = 0x40 + x;
		break;
	case 2:
		tmp = 0x14 + x;
		break;
	default:
		tmp = 0x54 + x;
	}
	command(1<<7 | tmp);
}

void avr_cpp_lib::LCDS::write(uint32_t i, uint8_t l, uint8_t m) {
	char buf[l + 1];
	buf[l] = '\0';
	for (; l > 0; l--) {
		uint8_t c = i % m;
		if (c < 10) {
			buf[l-1] = 0x30 + c;
		} else {
			buf[l-1] = 0x41 + c - 10;
		}
		i = i / m;
	}
	write(buf);
}

void avr_cpp_lib::LCDS::write(const char * s) {
	while (*s != '\0') {
		character(*s);
		s++;
	}
}

void avr_cpp_lib::LCDS::writeFlash(const char * s) {
	uint8_t c = pgm_read_byte(s);
	while (c != '\0') {
		character(c);
		s++;
		c = pgm_read_byte(s);
	}
}
<commit_msg>Totally changed timings<commit_after>/* File: lcds.cpp
 * Synchronous lcd hd44780 interface.
 */
/* Copyright (c) 2012-2013 Domen Ipavec (domen.ipavec@z-v.si)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation files
 * (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "lcds.h"
#include "bitop.h"

#ifndef F_CPU
	#define F_CPU 8000000UL  // 8 MHz
#endif

#include <util/delay.h>
#include <avr/pgmspace.h>

avr_cpp_lib::LCDS::LCDS(OutputPin rs, OutputPin e, OutputPin d4, OutputPin d5, OutputPin d6, OutputPin d7)
	: rs(rs), e(e), d4(d4), d5(d5), d6(d6), d7(d7) {
	d7.clear();
	d6.clear();
	d5.set();
	d4.set();
	rs.clear();

	// one (8 bit mode)
	enableToggle();

	// two (8 bit mode)
	enableToggle();

	// three (4 bit mode)
	d4.clear();
	enableToggle();

	// dual line, 4 bit mode
	command(0b00101000);

	// turn display on, cursor off
	command(DISPLAY_ON);

	// clear display
	command(CLEAR);
}

void avr_cpp_lib::LCDS::enableToggle() {
	e.set();
	_delay_us(1);
	e.clear();
	_delay_us(1);
}

void avr_cpp_lib::LCDS::command(uint8_t c) {
	rs.clear();
	send(c);
	_delay_ms(2);
}

void avr_cpp_lib::LCDS::character(uint8_t c) {
	rs.set();
	send(c);
}

void avr_cpp_lib::LCDS::send(uint8_t c) {
	if (BITSET(c, 7)) {
		d7.set();
	} else {
		d7.clear();
	}
	if (BITSET(c, 6)) {
		d6.set();
	} else {
		d6.clear();
	}
	if (BITSET(c, 5)) {
		d5.set();
	} else {
		d5.clear();
	}
	if (BITSET(c, 4)) {
		d4.set();
	} else {
		d4.clear();
	}
	enableToggle();
	if (BITSET(c, 3)) {
		d7.set();
	} else {
		d7.clear();
	}
	if (BITSET(c, 2)) {
		d6.set();
	} else {
		d6.clear();
	}
	if (BITSET(c, 1)) {
		d5.set();
	} else {
		d5.clear();
	}
	if (BITSET(c, 0)) {
		d4.set();
	} else {
		d4.clear();
	}
	enableToggle();
}

void avr_cpp_lib::LCDS::gotoXY(uint8_t x, uint8_t y) {
	uint8_t tmp;
	switch (y) {
	case 0:
		tmp = x;
		break;
	case 1:
		tmp = 0x40 + x;
		break;
	case 2:
		tmp = 0x14 + x;
		break;
	default:
		tmp = 0x54 + x;
	}
	command(1<<7 | tmp);
}

void avr_cpp_lib::LCDS::write(uint32_t i, uint8_t l, uint8_t m) {
	char buf[l + 1];
	buf[l] = '\0';
	for (; l > 0; l--) {
		uint8_t c = i % m;
		if (c < 10) {
			buf[l-1] = 0x30 + c;
		} else {
			buf[l-1] = 0x41 + c - 10;
		}
		i = i / m;
	}
	write(buf);
}

void avr_cpp_lib::LCDS::write(const char * s) {
	while (*s != '\0') {
		character(*s);
		s++;
	}
}

void avr_cpp_lib::LCDS::writeFlash(const char * s) {
	uint8_t c = pgm_read_byte(s);
	while (c != '\0') {
		character(c);
		s++;
		c = pgm_read_byte(s);
	}
}
<|endoftext|>


<commit_before>#include <smartref/smartref.h>

REFLECTABLE(foo);

namespace tests {

using smartref::using_;

//! These tests check for existence of the foo member-function.
namespace test_existence {

template<typename T>
constexpr auto has_foo(int) -> decltype(std::declval<T>().foo(), bool{}) {return true;}
template<typename T>
constexpr auto has_foo(...) {return false;}

struct Empty {};

struct NonConst
{
  void foo() {}
};

struct Const
{
  void foo() const {}
};

struct Mixed
{
  void foo() {}
  void foo() const {}
};

////////////////////////////////
// non-const member functions //
////////////////////////////////

static_assert(!has_foo<Empty>(0),
              "TEST FAILED: Empty seems to have a foo() member-function!");

static_assert(!has_foo<using_<Empty>>(0),
              "TEST FAILED: using_<Empty> seems to have a foo() member-function!");

static_assert(has_foo<NonConst>(0),
              "TEST FAILED: NonConst doesn't seem to have a foo() member-function!");

static_assert(has_foo<using_<NonConst>>(0),
              "TEST FAILED: using_<NonConst> doesn't seem to have a foo() member-function!");

////////////////////////////
// const member functions //
////////////////////////////

static_assert(!has_foo<const Empty>(0),
              "TEST FAILED: const Empty seems to have a foo() member-function!");

static_assert(!has_foo<const using_<Empty>>(0),
              "TEST FAILED: const using_<Empty> seems to have a foo() member-function!");

static_assert(!has_foo<const NonConst>(0),
              "TEST FAILED: const NonConst seems to have a foo() const member-function!");

static_assert(!has_foo<const using_<NonConst>>(0),
              "TEST FAILED: const using_<NonConst> seem to have a foo() const member-function!");

} // namespace test_existence
} // namespace tests
<commit_msg>Added Mixed tests for non-const objects.<commit_after>#include <smartref/smartref.h>

REFLECTABLE(foo);

namespace tests {

using smartref::using_;

//! These tests check for existence of the foo member-function.
namespace test_existence {

template<typename T>
constexpr auto has_foo(int) -> decltype(std::declval<T>().foo(), bool{}) {return true;}
template<typename T>
constexpr auto has_foo(...) {return false;}

struct Empty {};

struct NonConst
{
  void foo() {}
};

struct Const
{
  void foo() const {}
};

struct Mixed
{
  void foo() {}
  void foo() const {}
};

////////////////////////////////
// non-const member functions //
////////////////////////////////

static_assert(!has_foo<Empty>(0),
              "TEST FAILED: Empty seems to have a foo() member-function!");

static_assert(!has_foo<using_<Empty>>(0),
              "TEST FAILED: using_<Empty> seems to have a foo() member-function!");

static_assert(has_foo<NonConst>(0),
              "TEST FAILED: NonConst doesn't seem to have a foo() member-function!");

static_assert(has_foo<using_<NonConst>>(0),
              "TEST FAILED: using_<NonConst> doesn't seem to have a foo() member-function!");

static_assert(has_foo<Mixed>(0),
              "TEST FAILED: Mixed doesn't seem to have a foo() member-function!");

static_assert(has_foo<using_<Mixed>>(0),
              "TEST FAILED: using_<Mixed> doesn't seem to have a foo() member-function!");

////////////////////////////
// const member functions //
////////////////////////////

static_assert(!has_foo<const Empty>(0),
              "TEST FAILED: const Empty seems to have a foo() member-function!");

static_assert(!has_foo<const using_<Empty>>(0),
              "TEST FAILED: const using_<Empty> seems to have a foo() member-function!");

static_assert(!has_foo<const NonConst>(0),
              "TEST FAILED: const NonConst seems to have a foo() const member-function!");

static_assert(!has_foo<const using_<NonConst>>(0),
              "TEST FAILED: const using_<NonConst> seem to have a foo() const member-function!");

} // namespace test_existence
} // namespace tests
<|endoftext|>


<commit_before>#include <glib.h>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QDebug>
#include <QList>
#include <QMessageBox>

#include "utils/utils.h"
#include "seafile-applet.h"
#include "ccnet-init.h"
#include "ui/init-seafile-dialog.h"

#if defined(Q_OS_WIN32)
#include "utils/registry.h"
#include <shlobj.h>
#include <shlwapi.h>
#endif

#include "configurator.h"

namespace {

#if defined(Q_OS_WIN32)

const char *kVirtualDriveGUID = "F817C393-A76E-435E-B6B1-485844BC9C2E";
const char *kMyComputerNamespacePath =
    "Software\\Microsoft\\Windows\\CurrentVersion"
    "\\Explorer\\MyComputer\\Namespace";

const char* const kPreconfigureDirectory = "PreconfigureDirectory";
QString getPreconfigureDirectory()
{
    RegElement reg(HKEY_CURRENT_USER, "SOFTWARE\\Seafile", kPreconfigureDirectory, "");
    if (!reg.exists()) {
        return QString();
    }
    reg.read();
    return reg.stringValue();
}
#endif

} // namespace

Configurator::Configurator()
    : ccnet_dir_(defaultCcnetDir()),
      first_use_(false)
{
}

void Configurator::checkInit()
{
    if (needInitConfig()) {
        // first time use
        initConfig();
    } else {
        validateExistingConfig();
    }
}

bool Configurator::needInitConfig()
{
    if (QDir(ccnet_dir_).exists()) {
        return false;
    }

    return true;
}

void Configurator::initConfig()
{
    initCcnet();
    initSeafile();
}

void Configurator::initCcnet()
{
    QString path = QDir::toNativeSeparators(ccnet_dir_);
    if (create_ccnet_config(path.toUtf8().data()) < 0) {
        seafApplet->errorAndExit(tr("Error when creating ccnet configuration"));
    }

    first_use_ = true;
}

void Configurator::initSeafile()
{
#if defined(Q_OS_WIN32)
    QString preconfigure_dir = getPreconfigureDirectory();
    if (!preconfigure_dir.isEmpty()) {
        QDir dir(preconfigure_dir);
        if (!dir.mkpath(".") ||
            !dir.mkpath("Seafile/.seafile-data")) {
            qWarning("[Configurator] unable to create preconfigure directory \"%s\"", preconfigure_dir.toUtf8().data());
            qWarning("[Configurator] exiting from an unrecovable error.");
            QMessageBox::warning(NULL, getBrand(),
                                 tr("Unable to create preconfigure directory \"%1\"").arg(preconfigure_dir.toUtf8().data()),
                                 QMessageBox::Ok);
            exit(1);
            return;
        }
        first_use_ = true;

        QString seafile_dir = dir.absoluteFilePath("Seafile/.seafile-data");
        onSeafileDirSet(seafile_dir);
        return;
    }
#endif
    InitSeafileDialog dialog;
    connect(&dialog, SIGNAL(seafileDirSet(const QString&)),
            this, SLOT(onSeafileDirSet(const QString&)));

    if (dialog.exec() != QDialog::Accepted) {
        exit(1);
        return;
    }

    first_use_ = true;
}

void Configurator::onSeafileDirSet(const QString& path)
{
    // Write seafile dir to <ccnet dir>/seafile.ini
    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));

    if (!seafile_ini.open(QIODevice::WriteOnly)) {
        return;
    }

    seafile_ini.write(path.toUtf8().data());

    seafile_dir_ = path;

    QDir d(path);

    d.cdUp();
    worktree_ = d.absolutePath();

    setSeafileDirAttributes();
}

void Configurator::setSeafileDirAttributes()
{
#if defined(Q_OS_WIN32)
    std::wstring seafdir = seafile_dir_.toStdWString();

    // Make seafile-data folder hidden
    SetFileAttributesW (seafdir.c_str(),
                        FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);

    // Set seafdir folder icon.
    SetFileAttributesW (worktree_.toStdWString().c_str(), FILE_ATTRIBUTE_SYSTEM);
    QString desktop_ini_path = QDir(worktree_).filePath("Desktop.ini");
    QFile desktop_ini(desktop_ini_path);

    if (!desktop_ini.open(QIODevice::WriteOnly |  QIODevice::Text)) {
        return;
    }

    QString icon_path = QDir(QCoreApplication::applicationDirPath()).filePath("seafdir.ico");

    QTextStream out(&desktop_ini);
    out << "[.ShellClassInfo]\n";
    out << QString("IconFile=%1\n").arg(icon_path);
    out << "IconIndex=0\n";

    // Make the "Desktop.ini" file hidden.
    SetFileAttributesW (desktop_ini_path.toStdWString().c_str(),
                        FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
#endif
}

void Configurator::validateExistingConfig()
{
    QFile ccnet_conf(QDir(ccnet_dir_).filePath("ccnet.conf"));
    if (!ccnet_conf.exists()) {
        initConfig();
        return;
    }

    if (readSeafileIni(&seafile_dir_) < 0 || !QDir(seafile_dir_).exists()) {
        initSeafile();
        return;
    }

    QDir d(seafile_dir_);
#if !defined(Q_OS_WIN32)
    QString old_client_wt = d.filePath("../seafile/");
    if (QFile(old_client_wt).exists()) {
        // old client
        worktree_ = QFileInfo(old_client_wt).absoluteFilePath();
        return;
    }
#endif

    d.cdUp();
    worktree_ = d.absolutePath();
}

int Configurator::readSeafileIni(QString *content)
{
    // First try SEAFILE_DATA_DIR
    const char *env = g_getenv("SEAFILE_DATA_DIR");
    if (env) {
        *content = QString::fromUtf8(env);
        return 0;
    }

    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
    if (!seafile_ini.exists()) {
        return -1;
    }

    if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
        seafApplet->errorAndExit(tr("failed to read %1").arg(seafile_ini.fileName()));
    }

    QTextStream input(&seafile_ini);
    input.setCodec("UTF-8");

    if (input.atEnd()) {
        return -1;
    }

    *content = input.readLine();

    return 0;
}

int Configurator::setVirtualDrive(const QString& path, const QString& name)
{
    printf ("Configurator::setVirtualDrive is called\n");
#if defined(Q_OS_WIN32)
    QString clsid_path = QString("Software\\Classes\\CLSID\\{%1}").arg(kVirtualDriveGUID);

    QList<RegElement> list;

    /*
      See http://msdn.microsoft.com/en-us/library/ms997573.aspx

        HKEY_CLASSES_ROOT\CLSID\Classes\CLSID\{GUID}
        - DefaultIcon = "c:/Program Files/Seafile/bin/seafile-appelet.exe", 0
        - InProcServer32 = "%SystemRoot%\system32\shdocvw.dll"
          - ThreadingModel = "Apartment"
        - Instance
          - CLSID = {0AFACED1-E828-11D1-9187-B532F1E9575D}
          - InitPropertyBag
            -Target(REG_SZ) = D:\Seafile
        - ShellFolder
          - Attributes=0xXXXXX
          - PinToNameSpaceTree=""
          - wantsFORPARSING=""
    */

    HKEY root = HKEY_CURRENT_USER;

    list.append(RegElement(root, clsid_path, "", name));

    list.append(RegElement(root, clsid_path,
                           "InfoTip", tr("%1 Default Library").arg(getBrand())));

    list.append(RegElement(root, clsid_path + "\\DefaultIcon",
                           "", QCoreApplication::applicationFilePath(), true));

    list.append(RegElement(root, clsid_path + "\\InProcServer32",
                           "", "shdocvw.dll", true));

    list.append(RegElement(root, clsid_path + "\\InProcServer32",
                           "ThreadingModel", "Apartment"));

    list.append(RegElement(root, clsid_path + "\\Instance",
                           "CLSID", "{0AFACED1-E828-11D1-9187-B532F1E9575D}"));

    list.append(RegElement(root, clsid_path + "\\Instance\\InitPropertyBag",
                           "Target", QDir::toNativeSeparators(path)));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "Attributes",
                           SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "PinToNameSpaceTree", ""));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "wantsFORPARSING", ""));

    // HKEY_CURRENT_USESR\Software\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\Namespace
    // - {GUID}

    list.append(RegElement(root, kMyComputerNamespacePath + QString("\\{%1}").arg(kVirtualDriveGUID),
                           "", ""));

    for (int i = 0; i < list.size(); i++) {
        RegElement& reg = list[i];
        if (reg.add() < 0) {
            return -1;
        }
    }
#endif
    return 0;
}

void Configurator::removeVirtualDrive()
{
#if defined(Q_OS_WIN32)
    HKEY root = HKEY_CURRENT_USER;
    QString parent, subkey;

    parent = QString("Software\\Classes\\CLSID");
    subkey = QString("{%1}").arg(kVirtualDriveGUID);
    RegElement::removeRegKey(root, parent, subkey);

    parent = kMyComputerNamespacePath;
    subkey = QString("{%1}").arg(kVirtualDriveGUID);
    RegElement::removeRegKey(root, parent, subkey);
#endif
}

void Configurator::installCustomUrlHandler()
{
#if defined(Q_OS_WIN32)
    QList<RegElement> list;
    HKEY root = HKEY_CURRENT_USER;

    QString exe = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());

    QString cmd = QString("\"%1\" -f ").arg(exe) + " \"%1\"";

    QString classes_seafile = "Software\\Classes\\seafile";

    list.append(RegElement(root, classes_seafile,
                           "", "URL:seafile Protocol"));

    list.append(RegElement(root, classes_seafile,
                           "URL Protocol", ""));

    list.append(RegElement(root, classes_seafile + "\\shell",
                           "", ""));

    list.append(RegElement(root, classes_seafile + "\\shell\\open",
                           "", ""));

    list.append(RegElement(root, classes_seafile + "\\shell\\open\\command",
                           "", cmd));
    for (int i = 0; i < list.size(); i++) {
        RegElement& reg = list[i];
        reg.add();
    }
#endif
}

<commit_msg>Use HKLM for PreconfigureDirectory entry<commit_after>#include <glib.h>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QTextStream>
#include <QDebug>
#include <QList>
#include <QMessageBox>

#include "utils/utils.h"
#include "seafile-applet.h"
#include "ccnet-init.h"
#include "ui/init-seafile-dialog.h"

#if defined(Q_OS_WIN32)
#include "utils/registry.h"
#include <shlobj.h>
#include <shlwapi.h>
#endif

#include "configurator.h"

namespace {

#if defined(Q_OS_WIN32)

const char *kVirtualDriveGUID = "F817C393-A76E-435E-B6B1-485844BC9C2E";
const char *kMyComputerNamespacePath =
    "Software\\Microsoft\\Windows\\CurrentVersion"
    "\\Explorer\\MyComputer\\Namespace";

const char* const kPreconfigureDirectory = "PreconfigureDirectory";
QString getPreconfigureDirectory()
{
    RegElement reg(HKEY_LOCAL_MACHINE, "SOFTWARE\\Seafile", kPreconfigureDirectory, "");
    if (!reg.exists()) {
        return QString();
    }
    reg.read();
    return reg.stringValue();
}
#endif

} // namespace

Configurator::Configurator()
    : ccnet_dir_(defaultCcnetDir()),
      first_use_(false)
{
}

void Configurator::checkInit()
{
    if (needInitConfig()) {
        // first time use
        initConfig();
    } else {
        validateExistingConfig();
    }
}

bool Configurator::needInitConfig()
{
    if (QDir(ccnet_dir_).exists()) {
        return false;
    }

    return true;
}

void Configurator::initConfig()
{
    initCcnet();
    initSeafile();
}

void Configurator::initCcnet()
{
    QString path = QDir::toNativeSeparators(ccnet_dir_);
    if (create_ccnet_config(path.toUtf8().data()) < 0) {
        seafApplet->errorAndExit(tr("Error when creating ccnet configuration"));
    }

    first_use_ = true;
}

void Configurator::initSeafile()
{
#if defined(Q_OS_WIN32)
    QString preconfigure_dir = getPreconfigureDirectory();
    if (!preconfigure_dir.isEmpty()) {
        QDir dir(preconfigure_dir);
        if (!dir.mkpath(".") ||
            !dir.mkpath("Seafile/.seafile-data")) {
            qWarning("[Configurator] unable to create preconfigure directory \"%s\"", preconfigure_dir.toUtf8().data());
            qWarning("[Configurator] exiting from an unrecovable error.");
            QMessageBox::warning(NULL, getBrand(),
                                 tr("Unable to create preconfigure directory \"%1\"").arg(preconfigure_dir.toUtf8().data()),
                                 QMessageBox::Ok);
            exit(1);
            return;
        }
        first_use_ = true;

        QString seafile_dir = dir.absoluteFilePath("Seafile/.seafile-data");
        onSeafileDirSet(seafile_dir);
        return;
    }
#endif
    InitSeafileDialog dialog;
    connect(&dialog, SIGNAL(seafileDirSet(const QString&)),
            this, SLOT(onSeafileDirSet(const QString&)));

    if (dialog.exec() != QDialog::Accepted) {
        exit(1);
        return;
    }

    first_use_ = true;
}

void Configurator::onSeafileDirSet(const QString& path)
{
    // Write seafile dir to <ccnet dir>/seafile.ini
    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));

    if (!seafile_ini.open(QIODevice::WriteOnly)) {
        return;
    }

    seafile_ini.write(path.toUtf8().data());

    seafile_dir_ = path;

    QDir d(path);

    d.cdUp();
    worktree_ = d.absolutePath();

    setSeafileDirAttributes();
}

void Configurator::setSeafileDirAttributes()
{
#if defined(Q_OS_WIN32)
    std::wstring seafdir = seafile_dir_.toStdWString();

    // Make seafile-data folder hidden
    SetFileAttributesW (seafdir.c_str(),
                        FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);

    // Set seafdir folder icon.
    SetFileAttributesW (worktree_.toStdWString().c_str(), FILE_ATTRIBUTE_SYSTEM);
    QString desktop_ini_path = QDir(worktree_).filePath("Desktop.ini");
    QFile desktop_ini(desktop_ini_path);

    if (!desktop_ini.open(QIODevice::WriteOnly |  QIODevice::Text)) {
        return;
    }

    QString icon_path = QDir(QCoreApplication::applicationDirPath()).filePath("seafdir.ico");

    QTextStream out(&desktop_ini);
    out << "[.ShellClassInfo]\n";
    out << QString("IconFile=%1\n").arg(icon_path);
    out << "IconIndex=0\n";

    // Make the "Desktop.ini" file hidden.
    SetFileAttributesW (desktop_ini_path.toStdWString().c_str(),
                        FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
#endif
}

void Configurator::validateExistingConfig()
{
    QFile ccnet_conf(QDir(ccnet_dir_).filePath("ccnet.conf"));
    if (!ccnet_conf.exists()) {
        initConfig();
        return;
    }

    if (readSeafileIni(&seafile_dir_) < 0 || !QDir(seafile_dir_).exists()) {
        initSeafile();
        return;
    }

    QDir d(seafile_dir_);
#if !defined(Q_OS_WIN32)
    QString old_client_wt = d.filePath("../seafile/");
    if (QFile(old_client_wt).exists()) {
        // old client
        worktree_ = QFileInfo(old_client_wt).absoluteFilePath();
        return;
    }
#endif

    d.cdUp();
    worktree_ = d.absolutePath();
}

int Configurator::readSeafileIni(QString *content)
{
    // First try SEAFILE_DATA_DIR
    const char *env = g_getenv("SEAFILE_DATA_DIR");
    if (env) {
        *content = QString::fromUtf8(env);
        return 0;
    }

    QFile seafile_ini(QDir(ccnet_dir_).filePath("seafile.ini"));
    if (!seafile_ini.exists()) {
        return -1;
    }

    if (!seafile_ini.open(QIODevice::ReadOnly | QIODevice::Text)) {
        seafApplet->errorAndExit(tr("failed to read %1").arg(seafile_ini.fileName()));
    }

    QTextStream input(&seafile_ini);
    input.setCodec("UTF-8");

    if (input.atEnd()) {
        return -1;
    }

    *content = input.readLine();

    return 0;
}

int Configurator::setVirtualDrive(const QString& path, const QString& name)
{
    printf ("Configurator::setVirtualDrive is called\n");
#if defined(Q_OS_WIN32)
    QString clsid_path = QString("Software\\Classes\\CLSID\\{%1}").arg(kVirtualDriveGUID);

    QList<RegElement> list;

    /*
      See http://msdn.microsoft.com/en-us/library/ms997573.aspx

        HKEY_CLASSES_ROOT\CLSID\Classes\CLSID\{GUID}
        - DefaultIcon = "c:/Program Files/Seafile/bin/seafile-appelet.exe", 0
        - InProcServer32 = "%SystemRoot%\system32\shdocvw.dll"
          - ThreadingModel = "Apartment"
        - Instance
          - CLSID = {0AFACED1-E828-11D1-9187-B532F1E9575D}
          - InitPropertyBag
            -Target(REG_SZ) = D:\Seafile
        - ShellFolder
          - Attributes=0xXXXXX
          - PinToNameSpaceTree=""
          - wantsFORPARSING=""
    */

    HKEY root = HKEY_CURRENT_USER;

    list.append(RegElement(root, clsid_path, "", name));

    list.append(RegElement(root, clsid_path,
                           "InfoTip", tr("%1 Default Library").arg(getBrand())));

    list.append(RegElement(root, clsid_path + "\\DefaultIcon",
                           "", QCoreApplication::applicationFilePath(), true));

    list.append(RegElement(root, clsid_path + "\\InProcServer32",
                           "", "shdocvw.dll", true));

    list.append(RegElement(root, clsid_path + "\\InProcServer32",
                           "ThreadingModel", "Apartment"));

    list.append(RegElement(root, clsid_path + "\\Instance",
                           "CLSID", "{0AFACED1-E828-11D1-9187-B532F1E9575D}"));

    list.append(RegElement(root, clsid_path + "\\Instance\\InitPropertyBag",
                           "Target", QDir::toNativeSeparators(path)));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "Attributes",
                           SFGAO_FOLDER | SFGAO_FILESYSTEM | SFGAO_HASSUBFOLDER));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "PinToNameSpaceTree", ""));

    list.append(RegElement(root, clsid_path + "\\ShellFolder",
                           "wantsFORPARSING", ""));

    // HKEY_CURRENT_USESR\Software\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\Namespace
    // - {GUID}

    list.append(RegElement(root, kMyComputerNamespacePath + QString("\\{%1}").arg(kVirtualDriveGUID),
                           "", ""));

    for (int i = 0; i < list.size(); i++) {
        RegElement& reg = list[i];
        if (reg.add() < 0) {
            return -1;
        }
    }
#endif
    return 0;
}

void Configurator::removeVirtualDrive()
{
#if defined(Q_OS_WIN32)
    HKEY root = HKEY_CURRENT_USER;
    QString parent, subkey;

    parent = QString("Software\\Classes\\CLSID");
    subkey = QString("{%1}").arg(kVirtualDriveGUID);
    RegElement::removeRegKey(root, parent, subkey);

    parent = kMyComputerNamespacePath;
    subkey = QString("{%1}").arg(kVirtualDriveGUID);
    RegElement::removeRegKey(root, parent, subkey);
#endif
}

void Configurator::installCustomUrlHandler()
{
#if defined(Q_OS_WIN32)
    QList<RegElement> list;
    HKEY root = HKEY_CURRENT_USER;

    QString exe = QDir::toNativeSeparators(QCoreApplication::applicationFilePath());

    QString cmd = QString("\"%1\" -f ").arg(exe) + " \"%1\"";

    QString classes_seafile = "Software\\Classes\\seafile";

    list.append(RegElement(root, classes_seafile,
                           "", "URL:seafile Protocol"));

    list.append(RegElement(root, classes_seafile,
                           "URL Protocol", ""));

    list.append(RegElement(root, classes_seafile + "\\shell",
                           "", ""));

    list.append(RegElement(root, classes_seafile + "\\shell\\open",
                           "", ""));

    list.append(RegElement(root, classes_seafile + "\\shell\\open\\command",
                           "", cmd));
    for (int i = 0; i < list.size(); i++) {
        RegElement& reg = list[i];
        reg.add();
    }
#endif
}

<|endoftext|>


<commit_before>//
// Copyright (c) 2011 Kim Walisch, <kim.walisch@gmail.com>.
// All rights reserved.
//
// This file is part of primesieve.
// Homepage: http://primesieve.googlecode.com
//
// 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.

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP).
 * @see   http://primesieve.googlecode.com
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../soe/ParallelPrimeSieve.h"
#include "../soe/defs.h"
#include "../expr/ExpressionParser.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include <iomanip> /* std::setw(int) */

namespace {
  enum {
    OPTION_ERROR,
    OPTION_HELP,
    OPTION_TEST,
    OPTION_VERSION,
    START_SIEVING
  };
  std::vector<uint64_t> numbers; /* start and stop number for sieving */
  uint32_t sieveSize     = 0;    /* sieve size in kilobytes */
  uint32_t preSieve      = defs::PRIMESIEVE_PRESIEVE_LIMIT;
  uint32_t flags         = 0;    /* settings */
  bool quietMode         = false;
  bool showParserResults = false;
  int threads            = ParallelPrimeSieve::USE_IDEAL_NUM_THREADS;
  int maxThreads         = ParallelPrimeSieve::getMaxThreads();
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..."                                              << std::endl
            << "Use the segmented sieve of Eratosthenes to generate the prime numbers and"             << std::endl
            << "prime k-tuplets in the interval [START, STOP] < 2^64"                                  << std::endl
                                                                                << std::endl
            << "Options:"                                                                              << std::endl
                                                                                << std::endl
            << "  -c<N+>        Count prime numbers and/or prime k-tuplets, 1 <= N <= 7"               << std::endl
            << "                e.g. -c1 count prime numbers (DEFAULT)"                                << std::endl
            << "                     -c23 count twin primes and prime triplets"                        << std::endl
            << "  -o<OFFSET>    Sieve the interval [START, START+OFFSET]"                              << std::endl
            << "  -p<N>         Print prime numbers or prime k-tuplets, 1 <= N <= 7"                   << std::endl
            << "                e.g. -p1 print prime numbers"                                          << std::endl
            << "                     -p5 print prime quintuplets"                                      << std::endl
            << "  -q            Quiet mode, print less output"                                         << std::endl
            << "  -r<PRE-SIEVE> Pre-sieve multiples of small primes <= PRE-SIEVE to speed up"          << std::endl
            << "                the sieve of Eratosthenes, 13 <= PRE-SIEVE <= 23"                      << std::endl
            << "  -s<SIZE>      Set the sieve size in kilobytes, 1 <= SIZE <= 8192"                    << std::endl
            << "                Set SIZE to your CPU's L1/L2 cache size for best performance"          << std::endl
            << "  -t<THREADS>   Set the number of threads for sieving, 1 <= THREADS <= " << maxThreads << std::endl
            << "                Primes are not generated in order if THREADS >= 2"                     << std::endl
            << "  -test         Run various sieving tests and exit"                                    << std::endl
            << "  -v            Print version and license information and exit"                        << std::endl
                                                                                << std::endl
            << "Examples:"                                                                             << std::endl
                                                                                << std::endl
            << "  primesieve 2 1000 -p1    print the prime numbers up to 1000"                         << std::endl
            << "  primesieve 2 1E11 -s32   count the prime numbers up to 10^11 using a"                << std::endl
            << "                           sieve size of 32 KB"                                        << std::endl;
}

void version() {
  std::cout << "primesieve 3.1, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "This software is licensed under the New BSD License. See the LICENSE file" << std::endl
            << "for more information." << std::endl;
}

bool isDigits(const std::string &str) {
  const std::string digits("0123456789");
  if (str.size() == 0)
    return false;
  return str.find_first_not_of(digits) == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
int processOptions(std::size_t argc, char* argv[]) {
  if (argc < 2 || argc > 20)
    return OPTION_HELP;

  std::string testOption("est");
  std::string arg;
  ExpressionParser<uint64_t> parser;
  uint64_t tmp = 0;

  // process the START and STOP numbers
  for (std::size_t i = 1; i < 3 && i < argc; i++) {
    if (parser.eval(argv[i])) {
      numbers.push_back(parser.getResult());
      if (!isDigits(argv[i]))
        showParserResults = true;
    }
  }
  // process the options ([OPTION]...)
  for (std::size_t i = numbers.size() + 1; i < argc; i++) {
    if (*argv[i] != '-' && *argv[i] != '/')
      return OPTION_HELP;
    argv[i]++;
    switch (*argv[i]++) {
      case 'c': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                tmp = parser.getResult();
                do {
                  if (tmp % 10 < 1 || tmp % 10 > 7)
                    return OPTION_HELP;
                  flags |= ParallelPrimeSieve::COUNT_PRIMES << (tmp % 10 - 1);
                  tmp /= 10;
                } while (tmp > 0);
                break;
      case 'o': parser.eval(argv[i]);
                if (!parser.isSuccess() || numbers.size() == 0)
                  return OPTION_HELP;
                tmp = numbers[0] + parser.getResult();
                numbers.push_back(tmp);
                break;
      case 'p': parser.eval(argv[i]);
                if (!parser.isSuccess() || parser.getResult() < 1 || parser.getResult() > 7)
                  return OPTION_HELP;
                tmp = parser.getResult() - 1;
                flags |= ParallelPrimeSieve::PRINT_PRIMES << tmp;
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 'r': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                preSieve = static_cast<uint32_t> (parser.getResult());
                break;
      case 's': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                sieveSize = static_cast<uint32_t> (parser.getResult());
                break;
      case 't': arg = argv[i];
                if (arg.compare(testOption) == 0)
                  return OPTION_TEST;
                parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': return OPTION_VERSION;
      default : return OPTION_HELP;
    }
  }
  return (numbers.size() == 2) ? START_SIEVING : OPTION_HELP;
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  switch(processOptions(argc, argv)) {
    case OPTION_ERROR:              return 1;
    case OPTION_HELP:    help();    return 0;
    case OPTION_VERSION: version(); return 0;
    case OPTION_TEST:    test();    return 0;
    case START_SIEVING:  break;
  }
  // use left alignment with std::setw
  std::cout << std::left;
  // print parser results
  if (!quietMode && showParserResults)
    std::cout << std::setw(10) << "START" << " = " << numbers[0] << std::endl
              << std::setw(10) << "STOP"  << " = " << numbers[1] << std::endl;
  try {
    ParallelPrimeSieve pps;

    // set default settings
    if ((flags & pps.COUNT_FLAGS) == 0 && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.COUNT_PRIMES;
    if (!quietMode && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.PRINT_STATUS;
    if (sieveSize == 0)
      sieveSize = (numbers[1] < static_cast<uint64_t> (1E14))
          ? L1_DCACHE_SIZE : L2_CACHE_SIZE;

    pps.setStartNumber(numbers[0]);
    pps.setStopNumber(numbers[1]);
    pps.setSieveSize(sieveSize);
    pps.setPreSieveLimit(preSieve);
    pps.setFlags(flags);
    pps.setNumThreads(threads);

    if (!quietMode)
      std::cout << std::setw(10) << "Sieve size" << " = " << pps.getSieveSize() << " kilobytes" << std::endl
                << std::setw(10) << "Threads" << " = " << pps.getNumThreads() << std::endl;

    // start sieving primes
    pps.sieve();
    if ((flags & pps.PRINT_STATUS) || (
        (flags & pps.PRINT_FLAGS) &&
        (flags & pps.COUNT_FLAGS)))
      std::cout << std::endl;

    const std::string primes[7] = {
        "Prime numbers",
        "Twin primes",
        "Prime triplets",
        "Prime quadruplets",
        "Prime quintuplets",
        "Prime sextuplets",
        "Prime septuplets"};

    // get max string size
    std::size_t size = (quietMode) ? 0 : 12;
    for (int i = 0; i < 7; i++)
      if ((flags & (pps.COUNT_PRIMES << i)) && size < primes[i].size())
        size = primes[i].size();
    // print prime count results and time elapsed
    int width = static_cast<int> (size);
    for (uint32_t i = 0; i < 7; i++)
      if (flags & (pps.COUNT_PRIMES << i))
        std::cout << std::setw(width) << primes[i] << " : " << pps.getCounts(i) << std::endl;
    if (!quietMode)
      std::cout << std::setw(width) << "Time elapsed" << " : " << pps.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    return 1;
  }
  return 0;
}
<commit_msg>updated for primesieve 3.1<commit_after>//
// Copyright (c) 2011 Kim Walisch, <kim.walisch@gmail.com>.
// All rights reserved.
//
// This file is part of primesieve.
// Homepage: http://primesieve.googlecode.com
//
// 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.

/**
 * @file  main.cpp
 * @brief Command-line version of primesieve, multi-threaded (OpenMP).
 * @see   http://primesieve.googlecode.com
 *
 * primesieve is a highly optimized implementation of the sieve of
 * Eratosthenes that generates prime numbers and prime k-tuplets (twin
 * primes, prime triplets, ...) up to 2^64 maximum.
 */

#include "../soe/ParallelPrimeSieve.h"
#include "../soe/defs.h"
#include "../expr/ExpressionParser.h"

/// declared in test.cpp
void test();

#include <stdint.h>
#include <exception>
#include <iostream>
#include <string>
#include <vector>
#include <iomanip> /* std::setw(int) */

namespace {
  enum {
    OPTION_ERROR,
    OPTION_HELP,
    OPTION_TEST,
    OPTION_VERSION,
    START_SIEVING
  };
  std::vector<uint64_t> numbers; /* start and stop number for sieving */
  uint32_t sieveSize     = 0;    /* sieve size in kilobytes */
  uint32_t preSieve      = defs::PRIMESIEVE_PRESIEVE_LIMIT;
  uint32_t flags         = 0;    /* settings */
  bool quietMode         = false;
  bool showParserResults = false;
  int threads            = ParallelPrimeSieve::USE_IDEAL_NUM_THREADS;
  int maxThreads         = ParallelPrimeSieve::getMaxThreads();
}

void help() {
  std::cout << "Usage: primesieve START STOP [OPTION]..."                                              << std::endl
            << "Use the segmented sieve of Eratosthenes to generate the prime numbers and/or"          << std::endl
            << "prime k-tuplets in the interval [START, STOP] < 2^64"                                  << std::endl
                                                                                << std::endl
            << "Options:"                                                                              << std::endl
                                                                                << std::endl
            << "  -c<N+>        Count prime numbers and/or prime k-tuplets, 1 <= N <= 7"               << std::endl
            << "                e.g. -c1 count prime numbers (DEFAULT)"                                << std::endl
            << "                     -c23 count twin primes and prime triplets"                        << std::endl
            << "  -o<OFFSET>    Sieve the interval [START, START+OFFSET]"                              << std::endl
            << "  -p<N>         Print prime numbers or prime k-tuplets, 1 <= N <= 7"                   << std::endl
            << "                e.g. -p1 print prime numbers"                                          << std::endl
            << "                     -p5 print prime quintuplets"                                      << std::endl
            << "  -q            Quiet mode, print less output"                                         << std::endl
            << "  -r<PRE-SIEVE> Pre-sieve multiples of small primes <= PRE-SIEVE to speed up"          << std::endl
            << "                the sieve of Eratosthenes, 13 <= PRE-SIEVE <= 23"                      << std::endl
            << "  -s<SIZE>      Set the sieve size in kilobytes, 1 <= SIZE <= 8192"                    << std::endl
            << "                Set SIZE to your CPU's L1/L2 cache size for best performance"          << std::endl
            << "  -t<THREADS>   Set the number of threads for sieving, 1 <= THREADS <= " << maxThreads << std::endl
            << "                Primes are not generated in order if THREADS >= 2"                     << std::endl
            << "  -test         Run various sieving tests and exit"                                    << std::endl
            << "  -v            Print version and license information and exit"                        << std::endl
                                                                                << std::endl
            << "Examples:"                                                                             << std::endl
                                                                                << std::endl
            << "Print the prime numbers up to 1000:"                                                   << std::endl
            << "> primesieve 2 1000 -p1"                                                               << std::endl
                                                                                << std::endl
            << "Count the twin primes and prime triplets in the interval [1E10, 1E10+2^32]:"           << std::endl
            << "> primesieve 1E10 -o2**32 -c23"                                                        << std::endl;
}

void version() {
  std::cout << "primesieve 3.1, <http://primesieve.googlecode.com>" << std::endl
            << "Copyright (C) 2011 Kim Walisch" << std::endl
            << "This software is licensed under the New BSD License. See the LICENSE file" << std::endl
            << "for more information." << std::endl;
}

bool isDigits(const std::string &str) {
  const std::string digits("0123456789");
  if (str.size() == 0)
    return false;
  return str.find_first_not_of(digits) == std::string::npos;
}

/**
 * Process the command-line options.
 * @see help(void)
 */
int processOptions(std::size_t argc, char* argv[]) {
  if (argc < 2 || argc > 20)
    return OPTION_HELP;

  std::string testOption("est");
  std::string arg;
  ExpressionParser<uint64_t> parser;
  uint64_t tmp = 0;

  // process the START and STOP numbers
  for (std::size_t i = 1; i < 3 && i < argc; i++) {
    if (parser.eval(argv[i])) {
      numbers.push_back(parser.getResult());
      if (!isDigits(argv[i]))
        showParserResults = true;
    }
  }
  // process the options ([OPTION]...)
  for (std::size_t i = numbers.size() + 1; i < argc; i++) {
    if (*argv[i] != '-' && *argv[i] != '/')
      return OPTION_HELP;
    argv[i]++;
    switch (*argv[i]++) {
      case 'c': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                tmp = parser.getResult();
                do {
                  if (tmp % 10 < 1 || tmp % 10 > 7)
                    return OPTION_HELP;
                  flags |= ParallelPrimeSieve::COUNT_PRIMES << (tmp % 10 - 1);
                  tmp /= 10;
                } while (tmp > 0);
                break;
      case 'o': parser.eval(argv[i]);
                if (!parser.isSuccess() || numbers.size() == 0)
                  return OPTION_HELP;
                tmp = numbers[0] + parser.getResult();
                numbers.push_back(tmp);
                break;
      case 'p': parser.eval(argv[i]);
                if (!parser.isSuccess() || parser.getResult() < 1 || parser.getResult() > 7)
                  return OPTION_HELP;
                tmp = parser.getResult() - 1;
                flags |= ParallelPrimeSieve::PRINT_PRIMES << tmp;
                quietMode = true;
                break;
      case 'q': quietMode = true;
                break;
      case 'r': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                preSieve = static_cast<uint32_t> (parser.getResult());
                break;
      case 's': parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                sieveSize = static_cast<uint32_t> (parser.getResult());
                break;
      case 't': arg = argv[i];
                if (arg.compare(testOption) == 0)
                  return OPTION_TEST;
                parser.eval(argv[i]);
                if (!parser.isSuccess())
                  return OPTION_HELP;
                threads = static_cast<int> (parser.getResult());
                break;
      case 'v': return OPTION_VERSION;
      default : return OPTION_HELP;
    }
  }
  return (numbers.size() == 2) ? START_SIEVING : OPTION_HELP;
}

/**
 * Process the command-line options and start sieving.
 */
int main(int argc, char* argv[]) {
  switch(processOptions(argc, argv)) {
    case OPTION_ERROR:              return 1;
    case OPTION_HELP:    help();    return 0;
    case OPTION_VERSION: version(); return 0;
    case OPTION_TEST:    test();    return 0;
    case START_SIEVING:  break;
  }
  // use left alignment with std::setw
  std::cout << std::left;
  // print parser results
  if (!quietMode && showParserResults)
    std::cout << std::setw(10) << "START" << " = " << numbers[0] << std::endl
              << std::setw(10) << "STOP"  << " = " << numbers[1] << std::endl;
  try {
    ParallelPrimeSieve pps;

    // set default settings
    if ((flags & pps.COUNT_FLAGS) == 0 && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.COUNT_PRIMES;
    if (!quietMode && (flags & pps.PRINT_FLAGS) == 0)
      flags |= pps.PRINT_STATUS;
    if (sieveSize == 0)
      sieveSize = (numbers[1] < static_cast<uint64_t> (1E14))
          ? L1_DCACHE_SIZE : L2_CACHE_SIZE;

    pps.setStartNumber(numbers[0]);
    pps.setStopNumber(numbers[1]);
    pps.setSieveSize(sieveSize);
    pps.setPreSieveLimit(preSieve);
    pps.setFlags(flags);
    pps.setNumThreads(threads);

    if (!quietMode)
      std::cout << std::setw(10) << "Sieve size" << " = " << pps.getSieveSize() << " kilobytes" << std::endl
                << std::setw(10) << "Threads" << " = " << pps.getNumThreads() << std::endl;

    // start sieving primes
    pps.sieve();
    if ((flags & pps.PRINT_STATUS) || (
        (flags & pps.PRINT_FLAGS) &&
        (flags & pps.COUNT_FLAGS)))
      std::cout << std::endl;

    const std::string primes[7] = {
        "Prime numbers",
        "Twin primes",
        "Prime triplets",
        "Prime quadruplets",
        "Prime quintuplets",
        "Prime sextuplets",
        "Prime septuplets"};

    // get max string size
    std::size_t size = (quietMode) ? 0 : 12;
    for (int i = 0; i < 7; i++)
      if ((flags & (pps.COUNT_PRIMES << i)) && size < primes[i].size())
        size = primes[i].size();
    // print prime count results and time elapsed
    int width = static_cast<int> (size);
    for (uint32_t i = 0; i < 7; i++)
      if (flags & (pps.COUNT_PRIMES << i))
        std::cout << std::setw(width) << primes[i] << " : " << pps.getCounts(i) << std::endl;
    if (!quietMode)
      std::cout << std::setw(width) << "Time elapsed" << " : " << pps.getTimeElapsed() << " sec" << std::endl;
  }
  catch (std::exception& e) {
    std::cerr << "Error: " << e.what() << std::endl
              << "Try `primesieve -help' for more information." << std::endl;
    return 1;
  }
  return 0;
}
<|endoftext|>