<commit_before>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2017 David Medina and Tim Warburton
 *
 * 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
 */

#include <algorithm>
#include <iomanip>
#include <sstream>

#include "occa/tools/args.hpp"
#include "occa/tools/string.hpp"
#include "occa/tools/lex.hpp"

namespace occa {
  namespace args {
    //---[ Printable ]------------------
    printable::printable() {}

    std::string printable::getName() const {
      return name;
    }

    void printable::printDescription(std::ostream &out,
                                     const int indent, const int width,
                                     const std::string &description_) {
      std::stringstream ss;

      // Print the description across multiple lines if needed
      const char *desc_c = &(description_[0]);
      while (*desc_c) {
        const char *start = desc_c;
        lex::skipToWhitespace(desc_c);
        const std::string word(start, desc_c - start);

        if ((int) (ss.str().size() + word.size()) >= width) {
          out << ss.str()
              << '\n' << std::string(indent, ' ');
          ss.str("");
        }
        ss << word;

        start = desc_c;
        lex::skipWhitespace(desc_c);
        const std::string space(start, desc_c - start);

        if ((int) (ss.str().size() + space.size()) >= width) {
          ss << std::string(width - ss.str().size(), ' ');
        } else {
          ss << space;
        }
      }
      if (ss.str().size()) {
        out << ss.str();
        ss.str("");
      }
      out << '\n';
    }

    //---[ Option ]---------------------
    option::option() {}

    option::option(const std::string &name_,
                   const std::string &description_,
                   const int args_,
                   const bool isRequired_) :
      shortname(0),
      args(args_),
      isRequired(isRequired_) {

      name = name_;
      description = description_;
    }

    option::option(const char shortname_,
                   const std::string &name_,
                   const std::string &description_,
                   const int args_,
                   const bool isRequired_) :
      shortname(shortname_),
      args(args_),
      isRequired(isRequired_) {

      name = name_;
      description = description_;
    }

    std::string option::getName() const {
      std::string ret;
      if (shortname) {
        ret += '-';
        ret += shortname;
        ret += ", --";
        ret += name;
      } else {
        ret += "    --";
        ret += name;
      }
      return ret;
    }

    bool operator < (const option &l, const option &r) {
      const char leftSN = l.shortname ? l.shortname : l.name[0];
      const char rightSN = r.shortname ? r.shortname : r.name[0];
      if (leftSN != rightSN) {
        return leftSN < rightSN;
      }
      if (l.shortname || r.shortname) {
        return l.shortname;
      }
      return l.name < r.name;
    }

    std::ostream& operator << (std::ostream &out, const option &opt) {
      if (opt.shortname) {
        out << '-' << opt.shortname << '/';
      }
      out << "--" << opt.name;
      return out;
    }

    longOption::longOption() {}

    longOption::longOption(const option &opt) {
      shortname = opt.shortname;
      name = opt.name;
      description = opt.description;
      args = opt.args;
      isRequired = opt.isRequired;
    }

    std::string longOption::getName() const {
      return name;
    }

    //---[ Parser ]---------------------
    parser::parser() {}

    option* parser::getShortOption(const std::string &opt) {
      if (opt.size() != 1) {
        return NULL;
      }
      const char optChar = opt[0];
      const int optCount = (int) options.size();
      for (int i = 0; i < optCount; ++i) {
        if (options[i].shortname == optChar) {
          return &(options[i]);
        }
      }
      return NULL;
    }

    option* parser::getOption(const std::string &opt) {
      const int optCount = (int) options.size();
      for (int i = 0; i < optCount; ++i) {
        if (options[i].name == opt) {
          return &(options[i]);
        }
      }
      return NULL;
    }

    parser& parser::withDescription(const std::string &description_) {
      description = description_;
      return *this;
    }

    bool parser::hasOptionalArg() {
      const int argumentCount = (int) arguments.size();
      return (argumentCount &&
              !arguments[argumentCount - 1].isRequired);
    }

    parser& parser::addArgument(const std::string &name_,
                                const std::string &description_,
                                const bool isRequired_) {

      OCCA_ERROR("Cannot add " << arguments[arguments.size() - 1]
                 << ", an optional argument has already been added\n",
                 !hasOptionalArg());

      arguments.push_back(option(name_, description_,
                                 0, isRequired_));

      return *this;
    }

    parser& parser::addRepetitiveArgument(const std::string &name_,
                                          const std::string &description_,
                                          const bool isRequired_) {

      addArgument(name_, description_, isRequired_);
      hasRepetitiveArg = true;

      return *this;
    }

    parser& parser::addOption(const std::string &name_,
                              const std::string &description_,
                              const int args,
                              const bool isRequired_) {

      options.push_back(option(name_, description_,
                               args, isRequired_));
      return *this;
    }

    parser& parser::addOption(const char shortname_,
                              const std::string &name_,
                              const std::string &description_,
                              const int args,
                           const bool isRequired_) {

      options.push_back(option(shortname_, name_, description_,
                               args, isRequired_));
      return *this;
    }

    strVector_t parser::makeArgs(const int argc, const char **argv) {
      strVector_t args;
      for (int i = 0; i < argc; ++i) {
        args.push_back(argv[i]);
      }
      return args;
    }

    occa::json parser::parse(const int argc, const char **argv) {
      return parse(makeArgs(argc, argv));
    }

    occa::json parser::parse(const strVector_t &args) {
      occa::json parsedInfo(json::object_);
      const int argc = (int) args.size();

      occa::json &jOrder = parsedInfo["order"].asArray();
      occa::json &jOptions = parsedInfo["options"].asObject();
      occa::json &jArguments = parsedInfo["arguments"].asArray();

      option *opt = NULL;
      occa::json *optArgs = &jArguments;
      bool readingOpts = true;

      for (int i = 1; i < argc; ++i) {
        const std::string &arg_i = args[i];
        bool gotOpt = false;

        if (readingOpts) {
          if (startsWith(arg_i, "--")) {
            opt = getOption(arg_i.substr(2));
            gotOpt = true;
          } else if (startsWith(arg_i, "-")) {
            opt = getShortOption(arg_i.substr(1));
            gotOpt = true;
          } else {
            const int optArgCount = (int) optArgs->array().size();
            if (opt && opt->args <= optArgCount) {
              opt = NULL;
              optArgs = &jArguments;
            }
            *optArgs += arg_i;
          }
        } else {
          jArguments += arg_i;
        }

        readingOpts = !jArguments.array().size();

        if (gotOpt) {
          if (((arg_i == "-h")     && !getShortOption("h")) ||
              ((arg_i == "--help") && !getShortOption("help"))) {

            printUsage(args[0]);
            ::exit(0);
          }

          if (opt == NULL) {
            std::cerr << "Unknown option: " << arg_i << '\n';
            printUsage(args[0], std::cerr);
            ::exit(1);
          }

          jOrder += opt->name;

          // --foo a b       = [[a b]]
          // --foo a --foo b = [[a], [b]]
          json &argArrays = jOptions[opt->name].asArray();
          argArrays += json(json::array_);
          jsonArray_t &argArray = argArrays.array();
          optArgs = &(argArray[argArray.size() - 1]);
        }
      }

      // Make sure required options were passed
      for (int i = 0; i < (int) options.size(); ++i) {
        option &opt_i = options[i];
        const bool hasOption = jOptions.has(opt_i.name);

        if (hasOption) {
          jsonArray_t optArgs_i = jOptions[opt_i.name].array();
          for (int j = 0; j < (int) optArgs_i.size(); ++j) {
            if (opt_i.args != (int) optArgs_i[j].array().size()) {
              std::cerr << "Option " << opt_i << " is required and missing\n";
              printUsage(args[0], std::cerr);
              ::exit(1);
            }
          }
        } else if (opt_i.isRequired) {
          std::cerr << "Option " << opt_i << " is required and missing\n";
          printUsage(args[0], std::cerr);
          ::exit(1);
        }
      }

      const int argCount = (int) jArguments.array().size();
      const int reqArgCount = (int) arguments.size() - hasOptionalArg();

      if (argCount < reqArgCount) {
        std::cerr << "Incorrect number of arguments\n";
        printUsage(args[0], std::cerr);
        ::exit(1);
      }

      return parsedInfo;
    }

    void parser::printUsage(const std::string &program,
                            std::ostream &out) {

      out << "\nUsage: " << program;

      if (options.size()) {
        out << " [OPTIONS]";
      }

      const int argumentCount = (int) arguments.size();
      for (int i = 0; i < argumentCount; ++i) {
        option &argument = arguments[i];
        const bool repeats = hasRepetitiveArg && (i == (argumentCount - 1));
        if (argument.isRequired) {
          out << ' ' << argument.name;
        } else if (!repeats) {
          out << " [" << argument.name << ']';
        }

        if (repeats) {
          out << " [" << argument.name << "...]";
        }
      }
      out << "\n\n";
      if (description.size()) {
        printable::printDescription(out,
                                    0, MAX_NAME_COLUMN_WIDTH + MAX_DESC_COLUMN_WIDTH,
                                    description);
      } else {
        out << '\n';
      }
      out << '\n';

      printRequired(out);

      std::sort(options.begin(), options.end());
      printable::printEntries("Arguments", arguments, out);
      printable::printEntries("Options", options, out);
    }

    void parser::printRequired(std::ostream &out) {}

    //---[ Command ]--------------------
    command::command() {}

    command& command::withName(const std::string &name_) {
      name = name_;
      return *this;
    }

    command& command::withCallback(callback_t callback_) {
      callback = callback_;
      return *this;
    }

    int command::getCommandIdx(const std::string &name_) const {
      const int commandCount = (int) commands.size();
      for (int i = 0; i < commandCount; ++i) {
        const command &comm = commands[i];
        if (comm.name == name_) {
          return i;
        }
      }
      return -1;
    }

    const command* command::getCommand(const std::string &name_) const {
      const int idx = getCommandIdx(name_);
      return idx < 0 ? NULL : &commands[idx];
    }

    command* command::getCommand(const std::string &name_) {
      const int idx = getCommandIdx(name_);
      return idx < 0 ? NULL : &commands[idx];
    }

    void command::fillProgram(std::string &program) {
      if (runParent) {
        runParent->fillProgram(program);
      } else {
        program = runArgs[0];
      }

      if (name.size()) {
        program += ' ';
        program += name;
      }
    }

    void command::printUsage(std::ostream &out) {
      printUsage("", out);
    }

    void command::printUsage(const std::string &program,
                             std::ostream &out) {
      std::string newProgram;
      fillProgram(newProgram);

      parser::printUsage(newProgram, out);
    }

    void command::printRequired(std::ostream &out) {
      std::sort(commands.begin(), commands.end());
      printable::printEntries("Commands", commands, out);
    }

    command& command::requiresCommand() {
      commandIsRequired = true;
      return *this;
    }

    command& command::addCommand(const occa::args::command &command_) {
      commands.push_back(command_);
      return *this;
    }

    void command::run(const int argc, const char **argv) {
      run(makeArgs(argc, argv));
    }

    void command::run(const strVector_t &args,
                      command *parent) {
      runParent = parent;
      runArgs = args;

      const bool hasCommands = commands.size();

      if (hasCommands) {
        addArgument("COMMAND",
                    "Command to run",
                    commandIsRequired);
      }

      json info = parse(args);

      json &jArguments = info["arguments"];
      strVector_t inputArgs = jArguments.getArray<std::string>();

      const int commandArg = arguments.size() - 1;
      std::string commandName;
      command *comm = NULL;

      // Modify arguments and find command
      if (hasCommands &&
          inputArgs.size() &&
          commandArg < (int) inputArgs.size()) {

        // Remove command arguments
        jsonArray_t &jArgArray = jArguments.array();
        jArgArray = jsonArray_t(jArgArray.begin(),
                                jArgArray.begin() + commandArg + 1);

        // Extract command arguments
        inputArgs = strVector_t(inputArgs.begin() + commandArg,
                                inputArgs.end());

        commandName = inputArgs[0];
        comm = getCommand(commandName);
      }

      if (callback && !callback(*this,
                                info["order"].array(),
                                info["options"].object(),
                                info["arguments"].array())) {
        printUsage(std::cerr);
        ::exit(1);
      }

      if (comm) {
        comm->run(inputArgs, this);
      } else if (commandIsRequired) {
        std::cerr << "Unknown command: " << commandName << '\n';
        printUsage(std::cerr);
        ::exit(1);
      }
    }

    bool command::operator < (const command &comm) const {
      return name < comm.name;
    }
  }
}
<commit_msg>[Args] callback wasn't initialized as NULL<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014-2017 David Medina and Tim Warburton
 *
 * 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
 */

#include <algorithm>
#include <iomanip>
#include <sstream>

#include "occa/tools/args.hpp"
#include "occa/tools/string.hpp"
#include "occa/tools/lex.hpp"

namespace occa {
  namespace args {
    //---[ Printable ]------------------
    printable::printable() {}

    std::string printable::getName() const {
      return name;
    }

    void printable::printDescription(std::ostream &out,
                                     const int indent, const int width,
                                     const std::string &description_) {
      std::stringstream ss;

      // Print the description across multiple lines if needed
      const char *desc_c = &(description_[0]);
      while (*desc_c) {
        const char *start = desc_c;
        lex::skipToWhitespace(desc_c);
        const std::string word(start, desc_c - start);

        if ((int) (ss.str().size() + word.size()) >= width) {
          out << ss.str()
              << '\n' << std::string(indent, ' ');
          ss.str("");
        }
        ss << word;

        start = desc_c;
        lex::skipWhitespace(desc_c);
        const std::string space(start, desc_c - start);

        if ((int) (ss.str().size() + space.size()) >= width) {
          ss << std::string(width - ss.str().size(), ' ');
        } else {
          ss << space;
        }
      }
      if (ss.str().size()) {
        out << ss.str();
        ss.str("");
      }
      out << '\n';
    }

    //---[ Option ]---------------------
    option::option() {}

    option::option(const std::string &name_,
                   const std::string &description_,
                   const int args_,
                   const bool isRequired_) :
      shortname(0),
      args(args_),
      isRequired(isRequired_) {

      name = name_;
      description = description_;
    }

    option::option(const char shortname_,
                   const std::string &name_,
                   const std::string &description_,
                   const int args_,
                   const bool isRequired_) :
      shortname(shortname_),
      args(args_),
      isRequired(isRequired_) {

      name = name_;
      description = description_;
    }

    std::string option::getName() const {
      std::string ret;
      if (shortname) {
        ret += '-';
        ret += shortname;
        ret += ", --";
        ret += name;
      } else {
        ret += "    --";
        ret += name;
      }
      return ret;
    }

    bool operator < (const option &l, const option &r) {
      const char leftSN = l.shortname ? l.shortname : l.name[0];
      const char rightSN = r.shortname ? r.shortname : r.name[0];
      if (leftSN != rightSN) {
        return leftSN < rightSN;
      }
      if (l.shortname || r.shortname) {
        return l.shortname;
      }
      return l.name < r.name;
    }

    std::ostream& operator << (std::ostream &out, const option &opt) {
      if (opt.shortname) {
        out << '-' << opt.shortname << '/';
      }
      out << "--" << opt.name;
      return out;
    }

    longOption::longOption() {}

    longOption::longOption(const option &opt) {
      shortname = opt.shortname;
      name = opt.name;
      description = opt.description;
      args = opt.args;
      isRequired = opt.isRequired;
    }

    std::string longOption::getName() const {
      return name;
    }

    //---[ Parser ]---------------------
    parser::parser() {}

    option* parser::getShortOption(const std::string &opt) {
      if (opt.size() != 1) {
        return NULL;
      }
      const char optChar = opt[0];
      const int optCount = (int) options.size();
      for (int i = 0; i < optCount; ++i) {
        if (options[i].shortname == optChar) {
          return &(options[i]);
        }
      }
      return NULL;
    }

    option* parser::getOption(const std::string &opt) {
      const int optCount = (int) options.size();
      for (int i = 0; i < optCount; ++i) {
        if (options[i].name == opt) {
          return &(options[i]);
        }
      }
      return NULL;
    }

    parser& parser::withDescription(const std::string &description_) {
      description = description_;
      return *this;
    }

    bool parser::hasOptionalArg() {
      const int argumentCount = (int) arguments.size();
      return (argumentCount &&
              !arguments[argumentCount - 1].isRequired);
    }

    parser& parser::addArgument(const std::string &name_,
                                const std::string &description_,
                                const bool isRequired_) {

      OCCA_ERROR("Cannot add " << arguments[arguments.size() - 1]
                 << ", an optional argument has already been added\n",
                 !hasOptionalArg());

      arguments.push_back(option(name_, description_,
                                 0, isRequired_));

      return *this;
    }

    parser& parser::addRepetitiveArgument(const std::string &name_,
                                          const std::string &description_,
                                          const bool isRequired_) {

      addArgument(name_, description_, isRequired_);
      hasRepetitiveArg = true;

      return *this;
    }

    parser& parser::addOption(const std::string &name_,
                              const std::string &description_,
                              const int args,
                              const bool isRequired_) {

      options.push_back(option(name_, description_,
                               args, isRequired_));
      return *this;
    }

    parser& parser::addOption(const char shortname_,
                              const std::string &name_,
                              const std::string &description_,
                              const int args,
                           const bool isRequired_) {

      options.push_back(option(shortname_, name_, description_,
                               args, isRequired_));
      return *this;
    }

    strVector_t parser::makeArgs(const int argc, const char **argv) {
      strVector_t args;
      for (int i = 0; i < argc; ++i) {
        args.push_back(argv[i]);
      }
      return args;
    }

    occa::json parser::parse(const int argc, const char **argv) {
      return parse(makeArgs(argc, argv));
    }

    occa::json parser::parse(const strVector_t &args) {
      occa::json parsedInfo(json::object_);
      const int argc = (int) args.size();

      occa::json &jOrder = parsedInfo["order"].asArray();
      occa::json &jOptions = parsedInfo["options"].asObject();
      occa::json &jArguments = parsedInfo["arguments"].asArray();

      option *opt = NULL;
      occa::json *optArgs = &jArguments;
      bool readingOpts = true;

      for (int i = 1; i < argc; ++i) {
        const std::string &arg_i = args[i];
        bool gotOpt = false;

        if (readingOpts) {
          if (startsWith(arg_i, "--")) {
            opt = getOption(arg_i.substr(2));
            gotOpt = true;
          } else if (startsWith(arg_i, "-")) {
            opt = getShortOption(arg_i.substr(1));
            gotOpt = true;
          } else {
            const int optArgCount = (int) optArgs->array().size();
            if (opt && opt->args <= optArgCount) {
              opt = NULL;
              optArgs = &jArguments;
            }
            *optArgs += arg_i;
          }
        } else {
          jArguments += arg_i;
        }

        readingOpts = !jArguments.array().size();

        if (gotOpt) {
          if (((arg_i == "-h")     && !getShortOption("h")) ||
              ((arg_i == "--help") && !getShortOption("help"))) {

            printUsage(args[0]);
            ::exit(0);
          }

          if (opt == NULL) {
            std::cerr << "Unknown option: " << arg_i << '\n';
            printUsage(args[0], std::cerr);
            ::exit(1);
          }

          jOrder += opt->name;

          // --foo a b       = [[a b]]
          // --foo a --foo b = [[a], [b]]
          json &argArrays = jOptions[opt->name].asArray();
          argArrays += json(json::array_);
          jsonArray_t &argArray = argArrays.array();
          optArgs = &(argArray[argArray.size() - 1]);
        }
      }

      // Make sure required options were passed
      for (int i = 0; i < (int) options.size(); ++i) {
        option &opt_i = options[i];
        const bool hasOption = jOptions.has(opt_i.name);

        if (hasOption) {
          jsonArray_t optArgs_i = jOptions[opt_i.name].array();
          for (int j = 0; j < (int) optArgs_i.size(); ++j) {
            if (opt_i.args != (int) optArgs_i[j].array().size()) {
              std::cerr << "Option " << opt_i << " is required and missing\n";
              printUsage(args[0], std::cerr);
              ::exit(1);
            }
          }
        } else if (opt_i.isRequired) {
          std::cerr << "Option " << opt_i << " is required and missing\n";
          printUsage(args[0], std::cerr);
          ::exit(1);
        }
      }

      const int argCount = (int) jArguments.array().size();
      const int reqArgCount = (int) arguments.size() - hasOptionalArg();

      if (argCount < reqArgCount) {
        std::cerr << "Incorrect number of arguments\n";
        printUsage(args[0], std::cerr);
        ::exit(1);
      }

      return parsedInfo;
    }

    void parser::printUsage(const std::string &program,
                            std::ostream &out) {

      out << "\nUsage: " << program;

      if (options.size()) {
        out << " [OPTIONS]";
      }

      const int argumentCount = (int) arguments.size();
      for (int i = 0; i < argumentCount; ++i) {
        option &argument = arguments[i];
        const bool repeats = hasRepetitiveArg && (i == (argumentCount - 1));
        if (argument.isRequired) {
          out << ' ' << argument.name;
        } else if (!repeats) {
          out << " [" << argument.name << ']';
        }

        if (repeats) {
          out << " [" << argument.name << "...]";
        }
      }
      out << "\n\n";
      if (description.size()) {
        printable::printDescription(out,
                                    0, MAX_NAME_COLUMN_WIDTH + MAX_DESC_COLUMN_WIDTH,
                                    description);
      } else {
        out << '\n';
      }
      out << '\n';

      printRequired(out);

      std::sort(options.begin(), options.end());
      printable::printEntries("Arguments", arguments, out);
      printable::printEntries("Options", options, out);
    }

    void parser::printRequired(std::ostream &out) {}

    //---[ Command ]--------------------
    command::command() :
      commandIsRequired(false),
      callback(NULL),
      runParent(NULL) {}

    command& command::withName(const std::string &name_) {
      name = name_;
      return *this;
    }

    command& command::withCallback(callback_t callback_) {
      callback = callback_;
      return *this;
    }

    int command::getCommandIdx(const std::string &name_) const {
      const int commandCount = (int) commands.size();
      for (int i = 0; i < commandCount; ++i) {
        const command &comm = commands[i];
        if (comm.name == name_) {
          return i;
        }
      }
      return -1;
    }

    const command* command::getCommand(const std::string &name_) const {
      const int idx = getCommandIdx(name_);
      return idx < 0 ? NULL : &commands[idx];
    }

    command* command::getCommand(const std::string &name_) {
      const int idx = getCommandIdx(name_);
      return idx < 0 ? NULL : &commands[idx];
    }

    void command::fillProgram(std::string &program) {
      if (runParent) {
        runParent->fillProgram(program);
      } else {
        program = runArgs[0];
      }

      if (name.size()) {
        program += ' ';
        program += name;
      }
    }

    void command::printUsage(std::ostream &out) {
      printUsage("", out);
    }

    void command::printUsage(const std::string &program,
                             std::ostream &out) {
      std::string newProgram;
      fillProgram(newProgram);

      parser::printUsage(newProgram, out);
    }

    void command::printRequired(std::ostream &out) {
      std::sort(commands.begin(), commands.end());
      printable::printEntries("Commands", commands, out);
    }

    command& command::requiresCommand() {
      commandIsRequired = true;
      return *this;
    }

    command& command::addCommand(const occa::args::command &command_) {
      commands.push_back(command_);
      return *this;
    }

    void command::run(const int argc, const char **argv) {
      run(makeArgs(argc, argv));
    }

    void command::run(const strVector_t &args,
                      command *parent) {
      runParent = parent;
      runArgs = args;

      const bool hasCommands = commands.size();

      if (hasCommands) {
        addArgument("COMMAND",
                    "Command to run",
                    commandIsRequired);
      }

      json info = parse(args);

      json &jArguments = info["arguments"];
      strVector_t inputArgs = jArguments.getArray<std::string>();

      const int commandArg = arguments.size() - 1;
      std::string commandName;
      command *comm = NULL;

      // Modify arguments and find command
      if (hasCommands &&
          inputArgs.size() &&
          commandArg < (int) inputArgs.size()) {

        // Remove command arguments
        jsonArray_t &jArgArray = jArguments.array();
        jArgArray = jsonArray_t(jArgArray.begin(),
                                jArgArray.begin() + commandArg + 1);

        // Extract command arguments
        inputArgs = strVector_t(inputArgs.begin() + commandArg,
                                inputArgs.end());

        commandName = inputArgs[0];
        comm = getCommand(commandName);
      }

      if (callback && !callback(*this,
                                info["order"].array(),
                                info["options"].object(),
                                info["arguments"].array())) {
        printUsage(std::cerr);
        ::exit(1);
      }

      if (comm) {
        comm->run(inputArgs, this);
      } else if (commandIsRequired) {
        std::cerr << "Unknown command: " << commandName << '\n';
        printUsage(std::cerr);
        ::exit(1);
      }
    }

    bool command::operator < (const command &comm) const {
      return name < comm.name;
    }
  }
}
<|endoftext|>


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

// Standard includes
#include <fstream>
#include <memory>

// VOTCA includes
#include <votca/tools/tokenizer.h>

// Local VOTCA includes
#include "votca/csg/cgengine.h"
#include "votca/csg/version.h"

namespace votca {
namespace csg {

using namespace std;

namespace po = boost::program_options;

CGEngine::CGEngine() = default;

/**
    \todo melts with different molecules
*/
std::unique_ptr<TopologyMap> CGEngine::CreateCGTopology(const Topology &in,
                                                        Topology &out) {
  const MoleculeContainer &mols = in.Molecules();
  auto m = std::make_unique<TopologyMap>(&in, &out);
  for (const auto &mol : mols) {
    if (IsIgnored(mol.getName())) {
      continue;
    }
    CGMoleculeDef *def = getMoleculeDef(mol.getName());
    if (!def) {
      cout << "--------------------------------------\n"
           << "WARNING: unknown molecule \"" << mol.getName() << "\" with id "
           << mol.getId() << " in topology" << endl
           << "molecule will not be mapped to CG representation\n"
           << "Check weather a mapping file for all molecule exists, was "
              "specified in --cg "
           << "separated by ; and the ident tag in xml-file matches the "
              "molecule name\n"
           << "--------------------------------------\n";
      continue;
    }
    Molecule *mcg = def->CreateMolecule(out);
    Map map = def->CreateMap(mol, *mcg);
    m->AddMoleculeMap(std::move(map));
  }
  out.RebuildExclusions();
  return std::move(m);
}

void CGEngine::LoadMoleculeType(const string &filename) {
  tools::Tokenizer tok(filename, ";");

  for (tools::Tokenizer::iterator iter = tok.begin(); iter != tok.end();
       ++iter) {
    auto def = std::make_unique<CGMoleculeDef>();
    string file = *iter;
    boost::trim(file);
    def->Load(file);
    _molecule_defs[def->getIdent()] = std::move(def);
  }
}

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

// Standard includes
#include <fstream>
#include <memory>

// VOTCA includes
#include <votca/tools/tokenizer.h>

// Local VOTCA includes
#include "votca/csg/cgengine.h"
#include "votca/csg/version.h"

namespace votca {
namespace csg {

using namespace std;

namespace po = boost::program_options;

CGEngine::CGEngine() = default;

/**
    \todo melts with different molecules
*/
std::unique_ptr<TopologyMap> CGEngine::CreateCGTopology(const Topology &in,
                                                        Topology &out) {
  const MoleculeContainer &mols = in.Molecules();
  auto m = std::make_unique<TopologyMap>(&in, &out);
  for (const auto &mol : mols) {
    if (IsIgnored(mol.getName())) {
      continue;
    }
    CGMoleculeDef *def = getMoleculeDef(mol.getName());
    if (!def) {
      cout << "--------------------------------------\n"
           << "WARNING: unknown molecule \"" << mol.getName() << "\" with id "
           << mol.getId() << " in topology" << endl
           << "molecule will not be mapped to CG representation\n"
           << "Check weather a mapping file for all molecule exists, was "
              "specified in --cg "
           << "separated by ; and the ident tag in xml-file matches the "
              "molecule name\n"
           << "--------------------------------------\n";
      continue;
    }
    Molecule *mcg = def->CreateMolecule(out);
    Map map = def->CreateMap(mol, *mcg);
    m->AddMoleculeMap(std::move(map));
  }
  out.RebuildExclusions();
  return m;
}

void CGEngine::LoadMoleculeType(const string &filename) {
  tools::Tokenizer tok(filename, ";");

  for (tools::Tokenizer::iterator iter = tok.begin(); iter != tok.end();
       ++iter) {
    auto def = std::make_unique<CGMoleculeDef>();
    string file = *iter;
    boost::trim(file);
    def->Load(file);
    _molecule_defs[def->getIdent()] = std::move(def);
  }
}

}  // namespace csg
}  // namespace votca
<|endoftext|>


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

#include <votca/csg/topology.h>
#include <votca/csg/interaction.h>
#include <votca/tools/rangeparser.h>
#include <stdexcept>

namespace votca { namespace csg {

Topology::~Topology()
{
    Cleanup();
    if(_bc)
        delete (_bc);
    _bc = NULL;
}

void Topology::Cleanup()
{
    // cleanup beads
    {
        BeadContainer::iterator i;
        for(i=_beads.begin();i<_beads.end();++i)
            delete *i;
        _beads.clear();
    }
    // cleanup molecules
    {
        MoleculeContainer::iterator i;
        for(i=_molecules.begin();i<_molecules.end();++i)
            delete *i;
        _molecules.clear();
    }
    // cleanup residues
    {
        ResidueContainer::iterator i;
        for(i=_residues.begin();i<_residues.end();++i)
            delete (*i);
        _residues.clear();
    }
    // cleanup interactions
    {
        InteractionContainer::iterator i;
        for(i=_interactions.begin();i<_interactions.end();++i)
            delete (*i);
        _interactions.clear();
    }
    // cleanup _bc object
    if(_bc)
        delete (_bc);
    _bc = new OpenBox();
}

/// \todo implement checking, only used in xml topology reader
void Topology::CreateMoleculesByRange(string name, int first, int nbeads, int nmolecules)
{
    Molecule *mol = CreateMolecule(name);
    int beadcount=0;
    int res_offset=0;

    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        while(--first > 0) continue;
	//This is not 100% correct, but let's assume for now that the resnr do increase
	if ( beadcount == 0 ) {
	    res_offset = (*bead)->getResnr();
	}
        stringstream bname;
	bname << (*bead)->getResnr() - res_offset + 1 << ":" << getResidue((*bead)->getResnr())->getName() << ":" << (*bead)->getName();
        mol->AddBead((*bead), bname.str());
        if(++beadcount == nbeads) {
            if(--nmolecules <= 0) break;
            mol = CreateMolecule(name);
            beadcount = 0;
        }
    }
}

/// \todo clean up CreateMoleculesByResidue!
void Topology::CreateMoleculesByResidue()
{
    // first create a molecule for each residue
    ResidueContainer::iterator res;
    for(res=_residues.begin(); res!=_residues.end(); ++res) {
        CreateMolecule((*res)->getName());
    }

    // add the beads to the corresponding molecules based on their resid
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        //MoleculeByIndex((*bead)->getResnr())->AddBead((*bead)->getId(), (*bead)->getName());

        MoleculeByIndex((*bead)->getResnr())->AddBead((*bead), string("1:TRI:") + (*bead)->getName());
    }

    /// \todo sort beads in molecules that all beads are stored in the same order. This is needed for the mapping!
}

void Topology::CreateOneBigMolecule(string name)
{
    Molecule *mi = CreateMolecule(name);

    BeadContainer::iterator bead;

    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        stringstream n("");
        n << (*bead)->getResnr() +1 << ":" <<  _residues[(*bead)->getResnr()]->getName() << ":" << (*bead)->getName();
        //cout << n.str() << endl;
        mi->AddBead((*bead), n.str());
    }
}

void Topology::Add(Topology *top)
{
    BeadContainer::iterator bead;
    ResidueContainer::iterator res;
    MoleculeContainer::iterator mol;

    int res0=ResidueCount();

    for(bead=top->_beads.begin(); bead!=top->_beads.end(); ++bead) {
        Bead *bi = *bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr()+res0, bi->getM(), bi->getQ());
    }

    for(res=top->_residues.begin();res!=top->_residues.end(); ++res) {
        CreateResidue((*res)->getName());
    }

    // \todo beadnames in molecules!!
    for(mol=top->_molecules.begin();mol!=top->_molecules.end(); ++mol) {
        Molecule *mi = CreateMolecule((*mol)->getName());
        for(int i=0; i<mi->BeadCount(); i++) {
            mi->AddBead(mi->getBead(i), "invalid");
        }
    }
}

void Topology::CopyTopologyData(Topology *top)
{
    BeadContainer::iterator it_bead;
    ResidueContainer::iterator it_res;
    MoleculeContainer::iterator it_mol;
    InteractionContainer::iterator it_ia;

    _bc->setBox(top->getBox());
    _time = top->_time;
    _step = top->_step;

    // cleanup old data
    Cleanup();

    // copy all residues
    for(it_res=top->_residues.begin();it_res!=top->_residues.end(); ++it_res) {
        CreateResidue((*it_res)->getName());
    }

    // create all beads
    for(it_bead=top->_beads.begin(); it_bead!=top->_beads.end(); ++it_bead) {
        Bead *bi = *it_bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        Bead *bn = CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr(), bi->getM(), bi->getQ());
        bn->setOptions(bi->Options());
    }

    // copy all molecules
    for(it_mol=top->_molecules.begin();it_mol!=top->_molecules.end(); ++it_mol) {
        Molecule *mi = CreateMolecule((*it_mol)->getName());
        for(int i=0; i<(*it_mol)->BeadCount(); i++) {
            int beadid = (*it_mol)->getBead(i)->getId();
            mi->AddBead(_beads[beadid], (*it_mol)->getBeadName(i));
        }
    }
    // TODO: copy interactions
    //for(it_ia=top->_interaction.begin();it_ia=top->_interactions.end();++it_ia) {

    //}
}

void Topology::RenameMolecules(string range, string name)
{
    RangeParser rp;
    RangeParser::iterator i;

    rp.Parse(range);
    for(i=rp.begin();i!=rp.end();++i) {
        if((unsigned int)*i > _molecules.size())
            throw runtime_error(string("RenameMolecules: num molecules smaller than"));
        getMolecule(*i-1)->setName(name);
    }
}

void Topology::RenameBeadType(string name, string newname)
{
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
      BeadType *type =  GetOrCreateBeadType((*bead)->getType()->getName());
      if (name.compare(type->getName()) == 0 ) {
	type->setName(newname);
      }
    }
}

void Topology::SetBeadTypeMass(string name, double value)
{
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
      if (name.compare((*bead)->getType()->getName()) == 0 ) {
	(*bead)->setM(value);
      }
    }

}

void Topology::CheckMoleculeNaming(void)
{
    map<string,int> nbeads;

    for(MoleculeContainer::iterator iter = _molecules.begin(); iter!=_molecules.end(); ++iter) {
        map<string,int>::iterator entry = nbeads.find((*iter)->getName());
        if(entry != nbeads.end()) {
            if(entry->second != (*iter)->BeadCount())
                throw runtime_error("There are molecules which have the same name but different number of bead "
                        "please check the section manual topology handling in the votca manual");
            continue;
        }
        nbeads[(*iter)->getName()] = (*iter)->BeadCount();
    }
}

void Topology::AddBondedInteraction(Interaction *ic)
{
    map<string,int>::iterator iter;
    iter = _interaction_groups.find(ic->getGroup());
    if(iter!=_interaction_groups.end())
        ic->setGroupId((*iter).second);
    else {
        int i= _interaction_groups.size();
        _interaction_groups[ic->getGroup()] = i;
        ic->setGroupId(i);
    }
    _interactions.push_back(ic);
    _interactions_by_group[ic->getGroup()].push_back(ic);
}

std::list<Interaction *> Topology::InteractionsInGroup(const string &group)
{
    map<string, list<Interaction*> >::iterator iter;
    iter = _interactions_by_group.find(group);
    if(iter == _interactions_by_group.end())
        return list<Interaction *>();
    return iter->second;
}

BeadType *Topology::GetOrCreateBeadType(string name)
{
    map<string, int>::iterator iter;

    iter = _beadtype_map.find(name);
    if(iter == _beadtype_map.end()) {
        BeadType *bt = new BeadType(this, _beadtypes.size(), name);
        _beadtypes.push_back(bt);
        _beadtype_map[name] = bt->getId();
        return bt;
    }
    else {
        return _beadtypes[(*iter).second];
    }
    return NULL;
}

vec Topology::BCShortestConnection(const vec &r_i, const vec &r_j) const
{
    return _bc->BCShortestConnection(r_i, r_j);
}

vec Topology::getDist(int bead1, int bead2) const
{
    return BCShortestConnection(
            getBead(bead1)->getPos(),
            getBead(bead2)->getPos());
}

double Topology::BoxVolume()
{
    return _bc->BoxVolume();
}

void Topology::RebuildExclusions()
{
    _exclusions.CreateExclusions(this);
}

BoundaryCondition::eBoxtype Topology::autoDetectBoxType(const matrix &box) {
    // set the box type to OpenBox in case "box" is the zero matrix,
    // to OrthorhombicBox in case "box" is a diagonal matrix,
    // or to TriclinicBox otherwise
    if(box.get(0,0)==0 && box.get(0,1)==0 && box.get(0,2)==0 &&
       box.get(1,0)==0 && box.get(1,1)==0 && box.get(1,2)==0 &&
       box.get(2,0)==0 && box.get(2,1)==0 && box.get(2,2)==0) {
        //cout << "box open\n";
        return BoundaryCondition::typeOpen;
    }
    else
    if(box.get(0,1)==0 && box.get(0,2)==0 &&
       box.get(1,0)==0 && box.get(1,2)==0 &&
       box.get(2,0)==0 && box.get(2,1)==0) {
        //cout << "box orth\n";
        return BoundaryCondition::typeOrthorhombic;
    }
    else {
        //cout << "box tric\n";
        return BoundaryCondition::typeTriclinic;
    }
    return BoundaryCondition::typeOpen;
}

double Topology::ShortestBoxSize()
{
    vec _box_a = getBox().getCol(0);
    vec _box_b = getBox().getCol(1);
    vec _box_c = getBox().getCol(2);

    // create plane normals
    vec _norm_a = _box_b ^ _box_c;
    vec _norm_b = _box_c ^ _box_a;
    vec _norm_c = _box_a ^ _box_b;

    _norm_a.normalize();
    _norm_b.normalize();
    _norm_c.normalize();

    double la = _box_a * _norm_a;
    double lb = _box_b * _norm_b;
    double lc = _box_c * _norm_c;

    return min(la, min(lb, lc));
}

}}
<commit_msg>Topology::SetBeadTypeMass: use wildcmp instead of simple compare (fixes issue 136)<commit_after>/*
 * Copyright 2009-2011 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/csg/topology.h>
#include <votca/csg/interaction.h>
#include <votca/tools/rangeparser.h>
#include <stdexcept>

namespace votca { namespace csg {

Topology::~Topology()
{
    Cleanup();
    if(_bc)
        delete (_bc);
    _bc = NULL;
}

void Topology::Cleanup()
{
    // cleanup beads
    {
        BeadContainer::iterator i;
        for(i=_beads.begin();i<_beads.end();++i)
            delete *i;
        _beads.clear();
    }
    // cleanup molecules
    {
        MoleculeContainer::iterator i;
        for(i=_molecules.begin();i<_molecules.end();++i)
            delete *i;
        _molecules.clear();
    }
    // cleanup residues
    {
        ResidueContainer::iterator i;
        for(i=_residues.begin();i<_residues.end();++i)
            delete (*i);
        _residues.clear();
    }
    // cleanup interactions
    {
        InteractionContainer::iterator i;
        for(i=_interactions.begin();i<_interactions.end();++i)
            delete (*i);
        _interactions.clear();
    }
    // cleanup _bc object
    if(_bc)
        delete (_bc);
    _bc = new OpenBox();
}

/// \todo implement checking, only used in xml topology reader
void Topology::CreateMoleculesByRange(string name, int first, int nbeads, int nmolecules)
{
    Molecule *mol = CreateMolecule(name);
    int beadcount=0;
    int res_offset=0;

    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        while(--first > 0) continue;
	//This is not 100% correct, but let's assume for now that the resnr do increase
	if ( beadcount == 0 ) {
	    res_offset = (*bead)->getResnr();
	}
        stringstream bname;
	bname << (*bead)->getResnr() - res_offset + 1 << ":" << getResidue((*bead)->getResnr())->getName() << ":" << (*bead)->getName();
        mol->AddBead((*bead), bname.str());
        if(++beadcount == nbeads) {
            if(--nmolecules <= 0) break;
            mol = CreateMolecule(name);
            beadcount = 0;
        }
    }
}

/// \todo clean up CreateMoleculesByResidue!
void Topology::CreateMoleculesByResidue()
{
    // first create a molecule for each residue
    ResidueContainer::iterator res;
    for(res=_residues.begin(); res!=_residues.end(); ++res) {
        CreateMolecule((*res)->getName());
    }

    // add the beads to the corresponding molecules based on their resid
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        //MoleculeByIndex((*bead)->getResnr())->AddBead((*bead)->getId(), (*bead)->getName());

        MoleculeByIndex((*bead)->getResnr())->AddBead((*bead), string("1:TRI:") + (*bead)->getName());
    }

    /// \todo sort beads in molecules that all beads are stored in the same order. This is needed for the mapping!
}

void Topology::CreateOneBigMolecule(string name)
{
    Molecule *mi = CreateMolecule(name);

    BeadContainer::iterator bead;

    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
        stringstream n("");
        n << (*bead)->getResnr() +1 << ":" <<  _residues[(*bead)->getResnr()]->getName() << ":" << (*bead)->getName();
        //cout << n.str() << endl;
        mi->AddBead((*bead), n.str());
    }
}

void Topology::Add(Topology *top)
{
    BeadContainer::iterator bead;
    ResidueContainer::iterator res;
    MoleculeContainer::iterator mol;

    int res0=ResidueCount();

    for(bead=top->_beads.begin(); bead!=top->_beads.end(); ++bead) {
        Bead *bi = *bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr()+res0, bi->getM(), bi->getQ());
    }

    for(res=top->_residues.begin();res!=top->_residues.end(); ++res) {
        CreateResidue((*res)->getName());
    }

    // \todo beadnames in molecules!!
    for(mol=top->_molecules.begin();mol!=top->_molecules.end(); ++mol) {
        Molecule *mi = CreateMolecule((*mol)->getName());
        for(int i=0; i<mi->BeadCount(); i++) {
            mi->AddBead(mi->getBead(i), "invalid");
        }
    }
}

void Topology::CopyTopologyData(Topology *top)
{
    BeadContainer::iterator it_bead;
    ResidueContainer::iterator it_res;
    MoleculeContainer::iterator it_mol;
    InteractionContainer::iterator it_ia;

    _bc->setBox(top->getBox());
    _time = top->_time;
    _step = top->_step;

    // cleanup old data
    Cleanup();

    // copy all residues
    for(it_res=top->_residues.begin();it_res!=top->_residues.end(); ++it_res) {
        CreateResidue((*it_res)->getName());
    }

    // create all beads
    for(it_bead=top->_beads.begin(); it_bead!=top->_beads.end(); ++it_bead) {
        Bead *bi = *it_bead;
        BeadType *type =  GetOrCreateBeadType(bi->getType()->getName());
        Bead *bn = CreateBead(bi->getSymmetry(), bi->getName(), type, bi->getResnr(), bi->getM(), bi->getQ());
        bn->setOptions(bi->Options());
    }

    // copy all molecules
    for(it_mol=top->_molecules.begin();it_mol!=top->_molecules.end(); ++it_mol) {
        Molecule *mi = CreateMolecule((*it_mol)->getName());
        for(int i=0; i<(*it_mol)->BeadCount(); i++) {
            int beadid = (*it_mol)->getBead(i)->getId();
            mi->AddBead(_beads[beadid], (*it_mol)->getBeadName(i));
        }
    }
    // TODO: copy interactions
    //for(it_ia=top->_interaction.begin();it_ia=top->_interactions.end();++it_ia) {

    //}
}

void Topology::RenameMolecules(string range, string name)
{
    RangeParser rp;
    RangeParser::iterator i;

    rp.Parse(range);
    for(i=rp.begin();i!=rp.end();++i) {
        if((unsigned int)*i > _molecules.size())
            throw runtime_error(string("RenameMolecules: num molecules smaller than"));
        getMolecule(*i-1)->setName(name);
    }
}

void Topology::RenameBeadType(string name, string newname)
{
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
      BeadType *type =  GetOrCreateBeadType((*bead)->getType()->getName());
      if (name.compare(type->getName()) == 0 ) {
	type->setName(newname);
      }
    }
}

void Topology::SetBeadTypeMass(string name, double value)
{
    BeadContainer::iterator bead;
    for(bead=_beads.begin(); bead!=_beads.end(); ++bead) {
      if (wildcmp(name.c_str(),(*bead)->getType()->getName().c_str())) {
	(*bead)->setM(value);
      }
    }

}

void Topology::CheckMoleculeNaming(void)
{
    map<string,int> nbeads;

    for(MoleculeContainer::iterator iter = _molecules.begin(); iter!=_molecules.end(); ++iter) {
        map<string,int>::iterator entry = nbeads.find((*iter)->getName());
        if(entry != nbeads.end()) {
            if(entry->second != (*iter)->BeadCount())
                throw runtime_error("There are molecules which have the same name but different number of bead "
                        "please check the section manual topology handling in the votca manual");
            continue;
        }
        nbeads[(*iter)->getName()] = (*iter)->BeadCount();
    }
}

void Topology::AddBondedInteraction(Interaction *ic)
{
    map<string,int>::iterator iter;
    iter = _interaction_groups.find(ic->getGroup());
    if(iter!=_interaction_groups.end())
        ic->setGroupId((*iter).second);
    else {
        int i= _interaction_groups.size();
        _interaction_groups[ic->getGroup()] = i;
        ic->setGroupId(i);
    }
    _interactions.push_back(ic);
    _interactions_by_group[ic->getGroup()].push_back(ic);
}

std::list<Interaction *> Topology::InteractionsInGroup(const string &group)
{
    map<string, list<Interaction*> >::iterator iter;
    iter = _interactions_by_group.find(group);
    if(iter == _interactions_by_group.end())
        return list<Interaction *>();
    return iter->second;
}

BeadType *Topology::GetOrCreateBeadType(string name)
{
    map<string, int>::iterator iter;

    iter = _beadtype_map.find(name);
    if(iter == _beadtype_map.end()) {
        BeadType *bt = new BeadType(this, _beadtypes.size(), name);
        _beadtypes.push_back(bt);
        _beadtype_map[name] = bt->getId();
        return bt;
    }
    else {
        return _beadtypes[(*iter).second];
    }
    return NULL;
}

vec Topology::BCShortestConnection(const vec &r_i, const vec &r_j) const
{
    return _bc->BCShortestConnection(r_i, r_j);
}

vec Topology::getDist(int bead1, int bead2) const
{
    return BCShortestConnection(
            getBead(bead1)->getPos(),
            getBead(bead2)->getPos());
}

double Topology::BoxVolume()
{
    return _bc->BoxVolume();
}

void Topology::RebuildExclusions()
{
    _exclusions.CreateExclusions(this);
}

BoundaryCondition::eBoxtype Topology::autoDetectBoxType(const matrix &box) {
    // set the box type to OpenBox in case "box" is the zero matrix,
    // to OrthorhombicBox in case "box" is a diagonal matrix,
    // or to TriclinicBox otherwise
    if(box.get(0,0)==0 && box.get(0,1)==0 && box.get(0,2)==0 &&
       box.get(1,0)==0 && box.get(1,1)==0 && box.get(1,2)==0 &&
       box.get(2,0)==0 && box.get(2,1)==0 && box.get(2,2)==0) {
        //cout << "box open\n";
        return BoundaryCondition::typeOpen;
    }
    else
    if(box.get(0,1)==0 && box.get(0,2)==0 &&
       box.get(1,0)==0 && box.get(1,2)==0 &&
       box.get(2,0)==0 && box.get(2,1)==0) {
        //cout << "box orth\n";
        return BoundaryCondition::typeOrthorhombic;
    }
    else {
        //cout << "box tric\n";
        return BoundaryCondition::typeTriclinic;
    }
    return BoundaryCondition::typeOpen;
}

double Topology::ShortestBoxSize()
{
    vec _box_a = getBox().getCol(0);
    vec _box_b = getBox().getCol(1);
    vec _box_c = getBox().getCol(2);

    // create plane normals
    vec _norm_a = _box_b ^ _box_c;
    vec _norm_b = _box_c ^ _box_a;
    vec _norm_c = _box_a ^ _box_b;

    _norm_a.normalize();
    _norm_b.normalize();
    _norm_c.normalize();

    double la = _box_a * _norm_a;
    double lb = _box_b * _norm_b;
    double lc = _box_c * _norm_c;

    return min(la, min(lb, lc));
}

}}
<|endoftext|>


<commit_before>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string>
#include <cstring>
#include <iostream>
#include <vector>

//Include available regex headers
#ifdef HAVE_PRCRE_H
#include <pcre.h>
#endif
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif

#include "regex.hxx"

//Determine support level.
//First check for specific requests from the configuration.
#if defined(FORCE_REGEX_PCRE16)
#  if defined(HAVE_PCRE_H) && defined(PCRE_SUPPORTS_16_BIT)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE16
#  elif !defined(HAVE_PCRE_H)
#    error Configuration forces REGEX_PCRE16, but you do not have PCRE
#  else
#    error Configuration forces REGEX_PCRE16, but 16-bit not supported
#  endif
#elif defined(FORCE_REGEX_PCRE8)
#  if defined(HAVE_PCRE_H)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE8
#  else
#    error Configuration forces REGEX_PCRE8, but you do not have PCRE
#  endif
#elif defined(FORCE_REGEX_POSIX)
#  if defined(HAVE_REGEX_H)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_POSIX
#  else
#    error Configuration forces REGEX_POSIX, but your system does not have it
#  endif
#elif defined(FORCE_REGEX_NONE)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_NONE
//Not forced, determine automatically
#elif defined(HAVE_PCRE_H) && defined(PCRE_SUPPORTS_16_BIT)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE16
#elif defined(HAVE_PCRE_H)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE8
#elif defined(HAVE_REGEX_H)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_POSIX
#else
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_NONE
#endif

using namespace std;

namespace tglng {
  const unsigned regexLevel = TGLNG_REGEX_LEVEL;
#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_NONE
  const wstring regexLevelName(L"NONE");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  const wstring regexLevelName(L"POSIX");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE8
  const wstring regexLevelName(L"PCRE8");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE16
  const wstring regexLevelName(L"PCRE16");
#endif

  //Functions to convert natvie wstrings to the type needed by the backend.
#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE16
  typedef vector<PCRE_UCHAR16> rstring;
  static void convertString(rstring& dst, const wstring& src) {
    dst.resize(src.size()+1);
    for (unsigned i = 0; i < src.size(); ++i)
      if (src[i] <= 0xFFFF)
        dst[i] = src[i];
      else
        dst[i] = 0x001A;

    dst[src.size()] = 0;
  }
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE8 || \
      TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  typedef vector<char> rstring;
  static void convertString(rstring& dst, const wstring& src) {
    dst.resize(src.size()+1);
    for (unsigned i = 0; i < src.size(); ++i)
      if (src[i] <= 0xFF)
        dst[i] = (src[i] & 0xFF);
      else
        dst[i] = 0x1A;
    dst[src.size()] = 0;
  }
#endif

#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_NONE
  //Null implementation; always fails at everything
  Regex::Regex(const wstring&, const wstring&)
  : data(*(RegexData*)NULL) {}
  Regex::~Regex() {}
  Regex::operator bool() const { return false; }
  void Regex::showWhy() const {
    wcerr << L"regular expressions not supported in this build." << endl;
  }
  void Regex::input(const wstring&) {}
  bool Regex::match() { return false; }
  unsigned Regex::groupCount() const { return 0; }
  void Regex::group(wstring&, unsigned) const {}
  void Regex::tail(wstring&) const {}
#endif /* NONE */

#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  //POSIX.1-2001 implementation
  struct RegexData {
    regex_t rx;
    int status; //0=OK, others=error
    rstring input;
    wstring rawInput;
    unsigned inputOffset, headBegin, headEnd;
    string why;
    regmatch_t matches[10];
  };

  Regex::Regex(const wstring& pattern, const wstring& options)
  : data(*new RegexData)
  {
    rstring rpattern;
    convertString(rpattern, pattern);

    int flags = REG_EXTENDED;
    //Parse options
    for (unsigned i = 0; i < options.size(); ++i)
      switch (options[i]) {
      case L'i':
        flags |= REG_ICASE;
        break;

      case L'l':
        flags |= REG_NEWLINE;
        break;
      }

    data.status = regcomp(&data.rx, &rpattern[0], flags);
    if (data.status) {
      //Save error message
      data.why.resize(regerror(data.status, &data.rx, NULL, 0));
      regerror(data.status, &data.rx, &data.why[0], data.why.size());
    }
  }

  Regex::~Regex() {
    if (data.status == 0)
      regfree(&data.rx);
    delete &data;
  }

  Regex::operator bool() const {
    return !data.status;
  }

  void Regex::showWhy() const {
    wcerr << "POSIX extended regular expression: "
          << &data.why[0] << endl;
  }

  void Regex::input(const std::wstring& str) {
    convertString(data.input, str);
    data.inputOffset = 0;
    data.rawInput = str;
  }

  bool Regex::match() {
    data.status = regexec(&data.rx, &data.input[data.inputOffset],
                          sizeof(data.matches)/sizeof(data.matches[0]),
                          data.matches, 0);
    if (data.status) {
      //Failed for some reason
      data.why.resize(regerror(data.status, &data.rx, NULL, 0));
      regerror(data.status, &data.rx, &data.why[0], data.why.size());
      //Free the pattern now, since the destructor won't think it exists
      regfree(&data.rx);
      return false;
    }

    //Matched if the zeroth group is not -1
    if (-1 != data.matches[0].rm_eo) {
      //Update offsets
      data.headBegin = data.inputOffset;
      data.headEnd = data.matches[0].rm_so;
      data.inputOffset = data.matches[0].rm_eo;
    }
    return -1 != data.matches[0].rm_eo;
  }

  unsigned Regex::groupCount() const {
    unsigned cnt = 0;
    while (cnt < sizeof(data.matches)/sizeof(data.matches[0]) &&
           -1 != data.matches[cnt].rm_so)
      ++cnt;
    return cnt;
  }

  void Regex::group(wstring& out, unsigned ix) const {
    out.assign(data.rawInput, data.matches[ix].rm_so,
               data.matches[ix].rm_eo - data.matches[ix].rm_so);
  }

  void Regex::tail(wstring& out) const {
    out.assign(data.rawInput, data.inputOffset,
               data.rawInput.size() - data.inputOffset);
  }

  void Regex::head(wstring& out) const {
    out.assign(data.rawInput, data.headBegin,
               data.headEnd - data.headBegin);
  }
#endif /* POSIX */
}
<commit_msg>POSIX regex wrapper now handles failed matches correctly.<commit_after>#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <string>
#include <cstring>
#include <iostream>
#include <vector>

//Include available regex headers
#ifdef HAVE_PRCRE_H
#include <pcre.h>
#endif
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif

#include "regex.hxx"

//Determine support level.
//First check for specific requests from the configuration.
#if defined(FORCE_REGEX_PCRE16)
#  if defined(HAVE_PCRE_H) && defined(PCRE_SUPPORTS_16_BIT)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE16
#  elif !defined(HAVE_PCRE_H)
#    error Configuration forces REGEX_PCRE16, but you do not have PCRE
#  else
#    error Configuration forces REGEX_PCRE16, but 16-bit not supported
#  endif
#elif defined(FORCE_REGEX_PCRE8)
#  if defined(HAVE_PCRE_H)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE8
#  else
#    error Configuration forces REGEX_PCRE8, but you do not have PCRE
#  endif
#elif defined(FORCE_REGEX_POSIX)
#  if defined(HAVE_REGEX_H)
#    define TGLNG_REGEX_LEVEL TGLNG_REGEX_POSIX
#  else
#    error Configuration forces REGEX_POSIX, but your system does not have it
#  endif
#elif defined(FORCE_REGEX_NONE)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_NONE
//Not forced, determine automatically
#elif defined(HAVE_PCRE_H) && defined(PCRE_SUPPORTS_16_BIT)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE16
#elif defined(HAVE_PCRE_H)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_PCRE8
#elif defined(HAVE_REGEX_H)
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_POSIX
#else
#  define TGLNG_REGEX_LEVEL TGLNG_REGEX_NONE
#endif

using namespace std;

namespace tglng {
  const unsigned regexLevel = TGLNG_REGEX_LEVEL;
#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_NONE
  const wstring regexLevelName(L"NONE");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  const wstring regexLevelName(L"POSIX");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE8
  const wstring regexLevelName(L"PCRE8");
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE16
  const wstring regexLevelName(L"PCRE16");
#endif

  //Functions to convert natvie wstrings to the type needed by the backend.
#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE16
  typedef vector<PCRE_UCHAR16> rstring;
  static void convertString(rstring& dst, const wstring& src) {
    dst.resize(src.size()+1);
    for (unsigned i = 0; i < src.size(); ++i)
      if (src[i] <= 0xFFFF)
        dst[i] = src[i];
      else
        dst[i] = 0x001A;

    dst[src.size()] = 0;
  }
#elif TGLNG_REGEX_LEVEL == TGLNG_REGEX_PCRE8 || \
      TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  typedef vector<char> rstring;
  static void convertString(rstring& dst, const wstring& src) {
    dst.resize(src.size()+1);
    for (unsigned i = 0; i < src.size(); ++i)
      if (src[i] <= 0xFF)
        dst[i] = (src[i] & 0xFF);
      else
        dst[i] = 0x1A;
    dst[src.size()] = 0;
  }
#endif

#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_NONE
  //Null implementation; always fails at everything
  Regex::Regex(const wstring&, const wstring&)
  : data(*(RegexData*)NULL) {}
  Regex::~Regex() {}
  Regex::operator bool() const { return false; }
  void Regex::showWhy() const {
    wcerr << L"regular expressions not supported in this build." << endl;
  }
  void Regex::input(const wstring&) {}
  bool Regex::match() { return false; }
  unsigned Regex::groupCount() const { return 0; }
  void Regex::group(wstring&, unsigned) const {}
  void Regex::tail(wstring&) const {}
#endif /* NONE */

#if TGLNG_REGEX_LEVEL == TGLNG_REGEX_POSIX
  //POSIX.1-2001 implementation
  struct RegexData {
    regex_t rx;
    int status; //0=OK, others=error
    rstring input;
    wstring rawInput;
    unsigned inputOffset, headBegin, headEnd;
    string why;
    regmatch_t matches[10];
  };

  Regex::Regex(const wstring& pattern, const wstring& options)
  : data(*new RegexData)
  {
    rstring rpattern;
    convertString(rpattern, pattern);

    int flags = REG_EXTENDED;
    //Parse options
    for (unsigned i = 0; i < options.size(); ++i)
      switch (options[i]) {
      case L'i':
        flags |= REG_ICASE;
        break;

      case L'l':
        flags |= REG_NEWLINE;
        break;
      }

    data.status = regcomp(&data.rx, &rpattern[0], flags);
    if (data.status) {
      //Save error message
      data.why.resize(regerror(data.status, &data.rx, NULL, 0));
      regerror(data.status, &data.rx, &data.why[0], data.why.size());
    }
  }

  Regex::~Regex() {
    if (data.status == 0)
      regfree(&data.rx);
    delete &data;
  }

  Regex::operator bool() const {
    return !data.status;
  }

  void Regex::showWhy() const {
    wcerr << "POSIX extended regular expression: "
          << &data.why[0] << endl;
  }

  void Regex::input(const std::wstring& str) {
    convertString(data.input, str);
    data.inputOffset = 0;
    data.rawInput = str;
  }

  bool Regex::match() {
    data.status = regexec(&data.rx, &data.input[data.inputOffset],
                          sizeof(data.matches)/sizeof(data.matches[0]),
                          data.matches, 0);
    if (data.status == REG_NOMATCH) {
      //Transform to a more uniform result
      //(Nothing went wrong, no error should be returned, in theory)
      data.status = 0;
      memset(data.matches, -1, sizeof(data.matches));
    }
    if (data.status) {
      //Failed for some reason
      data.why.resize(regerror(data.status, &data.rx, NULL, 0));
      regerror(data.status, &data.rx, &data.why[0], data.why.size());
      //Free the pattern now, since the destructor won't think it exists
      regfree(&data.rx);
      return false;
    }

    //Matched if the zeroth group is not -1
    if (-1 != data.matches[0].rm_eo) {
      //Update offsets
      data.headBegin = data.inputOffset;
      data.headEnd = data.matches[0].rm_so;
      data.inputOffset = data.matches[0].rm_eo;
    }
    return -1 != data.matches[0].rm_eo;
  }

  unsigned Regex::groupCount() const {
    unsigned cnt = 0;
    while (cnt < sizeof(data.matches)/sizeof(data.matches[0]) &&
           -1 != data.matches[cnt].rm_so)
      ++cnt;
    return cnt;
  }

  void Regex::group(wstring& out, unsigned ix) const {
    out.assign(data.rawInput, data.matches[ix].rm_so,
               data.matches[ix].rm_eo - data.matches[ix].rm_so);
  }

  void Regex::tail(wstring& out) const {
    out.assign(data.rawInput, data.inputOffset,
               data.rawInput.size() - data.inputOffset);
  }

  void Regex::head(wstring& out) const {
    out.assign(data.rawInput, data.headBegin,
               data.headEnd - data.headBegin);
  }
#endif /* POSIX */
}
<|endoftext|>


<commit_before>/* Copyright (c) 2010-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QtSql>
#include <QCoreApplication>
#include <QMetaObject>
#include <TSqlObject>
#include <TSqlQuery>
#include <TSystemGlobal>

const QByteArray LockRevision("lock_revision");
const QByteArray CreatedAt("created_at");
const QByteArray UpdatedAt("updated_at");
const QByteArray ModifiedAt("modified_at");

/*!
  \class TSqlObject
  \brief The TSqlObject class is the base class of ORM objects.
  \sa TSqlORMapper
*/

/*!
  Constructor.
 */
TSqlObject::TSqlObject()
    : TModelObject(), QSqlRecord(), sqlError()
{ }

/*!
  Copy constructor.
 */
TSqlObject::TSqlObject(const TSqlObject &other)
    : TModelObject(), QSqlRecord(*static_cast<const QSqlRecord *>(&other)),
      sqlError(other.sqlError)
{ }

/*!
  Assignment operator.
*/
TSqlObject &TSqlObject::operator=(const TSqlObject &other)
{
    QSqlRecord::operator=(*static_cast<const QSqlRecord *>(&other));
    sqlError = other.sqlError;
    return *this;
}

/*!
  Returns the table name, which is generated from the class name.
*/
QString TSqlObject::tableName() const
{
    QString tblName;
    QString clsname(metaObject()->className());

    for (int i = 0; i < clsname.length(); ++i) {
        if (i > 0 && clsname[i].isUpper()) {
            tblName += '_';
        }
        tblName += clsname[i].toLower();
    }
    tblName.remove(QRegExp("_object$"));
    return tblName;
}

/*!
  \fn virtual int TSqlObject::primaryKeyIndex() const
  Returns the position of the primary key field on the table.
  This is a virtual function.
*/

/*!
  \fn virtual int TSqlObject::autoValueIndex() const
  Returns the position of the auto-generated value field on
  the table. This is a virtual function.
*/

/*!
  \fn virtual int TSqlObject::databaseId() const
  Returns the database ID.
*/

/*!
  \fn bool TSqlObject::isNull() const
  Returns true if there is no database record associated with the
  object; otherwise returns false.
*/

/*!
  \fn bool TSqlObject::isNew() const
  Returns true if it is a new object, otherwise returns false.
  Equivalent to isNull().
*/

/*!
  \fn QSqlError TSqlObject::error() const
  Returns a QSqlError object which contains information about
  the last error that occurred on the database.
*/

/*!
  Sets the \a record. This function is for internal use only.
*/
void TSqlObject::setRecord(const QSqlRecord &record, const QSqlError &error)
{
    QSqlRecord::operator=(record);
    syncToObject();
    sqlError = error;
}

/*!
  Inserts new record into the database, based on the current properties
  of the object.
*/
bool TSqlObject::create()
{
    // Sets the values of 'created_at', 'updated_at' or 'modified_at' properties
    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (prop == CreatedAt || prop == UpdatedAt || prop == ModifiedAt) {
            setProperty(propName, QDateTime::currentDateTime());
        } else if (prop == LockRevision) {
            // Sets the default value of 'revision' property
            setProperty(propName, 1);  // 1 : default value
        } else {
            // do nothing
        }
    }

    syncToSqlRecord();

    QString autoValName;
    QSqlRecord record = *this;
    if (autoValueIndex() >= 0) {
        autoValName = field(autoValueIndex()).name();
        record.remove(autoValueIndex()); // not insert the value of auto-value field
    }

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString ins = database.driver()->sqlStatement(QSqlDriver::InsertStatement, tableName(), record, false);
    if (ins.isEmpty()) {
        sqlError = QSqlError(QLatin1String("No fields to insert"),
                             QString(), QSqlError::StatementError);
        tWarn("SQL statement error, no fields to insert");
        return false;
    }

    TSqlQuery query(database);
    bool ret = query.exec(ins);
    sqlError = query.lastError();
    if (ret) {
        // Gets the last inserted value of auto-value field
        if (autoValueIndex() >= 0) {
            QVariant lastid = query.lastInsertId();
            if (lastid.isValid()) {
                QObject::setProperty(autoValName.toLatin1().constData(), lastid);
            }
        }
    }
    return ret;
}

/*!
  Updates the corresponding record with the properties of the object.
*/
bool TSqlObject::update()
{
    if (isNew()) {
        sqlError = QSqlError(QLatin1String("No record to update"),
                             QString(), QSqlError::UnknownError);
        tWarn("Unable to update the '%s' object. Create it before!", metaObject()->className());
        return false;
    }

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString where(" WHERE ");

    // Updates the value of 'updated_at' or 'modified_at' property
    bool updflag = false;
    int revIndex = -1;

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (!updflag && (prop == UpdatedAt || prop == ModifiedAt)) {
            setProperty(propName, QDateTime::currentDateTime());
            updflag = true;

        } else if (revIndex < 0 && prop == LockRevision) {
            bool ok;
            int oldRevision = property(propName).toInt(&ok);

            if (!ok || oldRevision <= 0) {
                sqlError = QSqlError(QLatin1String("Unable to convert the 'revision' property to an int"),
                                     QString(), QSqlError::UnknownError);
                tError("Unable to convert the 'revision' property to an int, %s", qPrintable(objectName()));
                return false;
            }

            setProperty(propName, oldRevision + 1);
            revIndex = i;

            where.append(QLatin1String(propName));
            where.append("=").append(TSqlQuery::formatValue(oldRevision, database));
            where.append(" AND ");
        } else {
            // continue
        }
    }

    QString upd;   // UPDATE Statement
    upd.reserve(255);
    upd.append(QLatin1String("UPDATE ")).append(tableName()).append(QLatin1String(" SET "));

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QVariant newval = QObject::property(propName);
        QVariant recval = QSqlRecord::value(QLatin1String(propName));
        if (recval.isValid() && recval != newval) {
            upd.append(QLatin1String(propName));
            upd.append(QLatin1Char('='));
            upd.append(TSqlQuery::formatValue(newval, database));
            upd.append(QLatin1String(", "));
        }
    }

    if (!upd.endsWith(QLatin1String(", "))) {
        tSystemDebug("SQL UPDATE: Same values as that of the record. No need to update.");
        return true;
    }

    upd.chop(2);
    syncToSqlRecord();

    const char *pkName = metaObject()->property(metaObject()->propertyOffset() + primaryKeyIndex()).name();
    if (primaryKeyIndex() < 0 || !pkName) {
        QString msg = QString("Not found the primary key for table ") + tableName();
        sqlError = QSqlError(msg, QString(), QSqlError::StatementError);
        tError("%s", qPrintable(msg));
        return false;
    }
    where.append(QLatin1String(pkName));
    where.append("=").append(TSqlQuery::formatValue(property(pkName), database));
    upd.append(where);

    TSqlQuery query(database);
    bool ret = query.exec(upd);
    sqlError = query.lastError();
    if (ret) {
        // Optimistic lock check
        if (revIndex >= 0 && query.numRowsAffected() != 1) {
            QString msg = QString("Row was updated or deleted from table ") + tableName() + QLatin1String(" by another transaction");
            sqlError = QSqlError(msg, QString(), QSqlError::UnknownError);
            throw SqlException(msg, __FILE__, __LINE__);
        }
    }
    return ret;
}

/*!
  Deletes the record with this primary key from the database.
*/
bool TSqlObject::remove()
{
    syncToSqlRecord();

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString del = database.driver()->sqlStatement(QSqlDriver::DeleteStatement, tableName(), *static_cast<QSqlRecord *>(this), false);
    if (del.isEmpty()) {
        sqlError = QSqlError(QLatin1String("Unable to delete row"),
                             QString(), QSqlError::StatementError);
        return false;
    }

    del.append(" WHERE ");
    int revIndex = -1;

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (prop == LockRevision) {
            bool ok;
            int revision = property(propName).toInt(&ok);

            if (!ok || revision <= 0) {
                sqlError = QSqlError(QLatin1String("Unable to convert the 'revision' property to an int"),
                                     QString(), QSqlError::UnknownError);
                tError("Unable to convert the 'revision' property to an int, %s", qPrintable(objectName()));
                return false;
            }

            del.append(QLatin1String(propName));
            del.append("=").append(TSqlQuery::formatValue(revision, database));
            del.append(" AND ");

            revIndex = i;
            break;
        }
    }

    const char *pkName = metaObject()->property(metaObject()->propertyOffset() + primaryKeyIndex()).name();
    if (primaryKeyIndex() < 0 || !pkName) {
        QString msg = QString("Not found the primary key for table ") + tableName();
        sqlError = QSqlError(msg, QString(), QSqlError::StatementError);
        tError("%s", qPrintable(msg));
        return false;
    }
    del.append(QLatin1String(pkName));
    del.append("=").append(TSqlQuery::formatValue(property(pkName), database));

    TSqlQuery query(database);
    bool ret = query.exec(del);
    sqlError = query.lastError();
    if (ret) {
        // Optimistic lock check
        if (query.numRowsAffected() != 1) {
            if (revIndex >= 0) {
                QString msg = QString("Row was updated or deleted from table ") + tableName() + QLatin1String(" by another transaction");
                sqlError = QSqlError(msg, QString(), QSqlError::UnknownError);
                throw SqlException(msg, __FILE__, __LINE__);
            }
            tWarn("Row was deleted by another transaction, %s", qPrintable(tableName()));
        }
        clear();
    }
    return ret;
}

/*!
  Reloads the values of  the record onto the properties.
 */
bool TSqlObject::reload()
{
    if (isEmpty()) {
        return false;
    }
    syncToObject();
    return true;
}

/*!
  Returns true if the values of the properties differ with the record on the
  database; otherwise returns false.
 */
bool TSqlObject::isModified() const
{
    if (isNew())
        return false;

    for (int i = 0; i < QSqlRecord::count(); ++i) {
        QString name = field(i).name();
        int index = metaObject()->indexOfProperty(name.toLatin1().constData());
        if (index >= 0) {
            if (value(name) != property(name.toLatin1().constData())) {
                return true;
            }
        }
    }
    return false;
}

/*!
  Synchronizes the internal record data to the properties of the object.
  This function is for internal use only.
*/
void TSqlObject::syncToObject()
{
    int offset = metaObject()->propertyOffset();
    for (int i = 0; i < QSqlRecord::count(); ++i) {
        QString propertyName = field(i).name();
        QByteArray name = propertyName.toLatin1();
        int index = metaObject()->indexOfProperty(name.constData());
        if (index >= offset) {
            QObject::setProperty(name.constData(), value(propertyName));
        }
    }
}

/*!
  Synchronizes the properties to the internal record data.
  This function is for internal use only.
*/
void TSqlObject::syncToSqlRecord()
{
    QSqlRecord::operator=(Tf::currentSqlDatabase(databaseId()).record(tableName()));
    const QMetaObject *metaObj = metaObject();
    for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
        const char *propName = metaObj->property(i).name();
        int idx = indexOf(propName);
        if (idx >= 0) {
            QSqlRecord::setValue(idx, QObject::property(propName));
        } else {
            tWarn("invalid name: %s", propName);
        }
    }
}
<commit_msg>modified error messages.<commit_after>/* Copyright (c) 2010-2013, AOYAMA Kazuharu
 * All rights reserved.
 *
 * This software may be used and distributed according to the terms of
 * the New BSD License, which is incorporated herein by reference.
 */

#include <QtSql>
#include <QCoreApplication>
#include <QMetaObject>
#include <TSqlObject>
#include <TSqlQuery>
#include <TSystemGlobal>

const QByteArray LockRevision("lock_revision");
const QByteArray CreatedAt("created_at");
const QByteArray UpdatedAt("updated_at");
const QByteArray ModifiedAt("modified_at");

/*!
  \class TSqlObject
  \brief The TSqlObject class is the base class of ORM objects.
  \sa TSqlORMapper
*/

/*!
  Constructor.
 */
TSqlObject::TSqlObject()
    : TModelObject(), QSqlRecord(), sqlError()
{ }

/*!
  Copy constructor.
 */
TSqlObject::TSqlObject(const TSqlObject &other)
    : TModelObject(), QSqlRecord(*static_cast<const QSqlRecord *>(&other)),
      sqlError(other.sqlError)
{ }

/*!
  Assignment operator.
*/
TSqlObject &TSqlObject::operator=(const TSqlObject &other)
{
    QSqlRecord::operator=(*static_cast<const QSqlRecord *>(&other));
    sqlError = other.sqlError;
    return *this;
}

/*!
  Returns the table name, which is generated from the class name.
*/
QString TSqlObject::tableName() const
{
    QString tblName;
    QString clsname(metaObject()->className());

    for (int i = 0; i < clsname.length(); ++i) {
        if (i > 0 && clsname[i].isUpper()) {
            tblName += '_';
        }
        tblName += clsname[i].toLower();
    }
    tblName.remove(QRegExp("_object$"));
    return tblName;
}

/*!
  \fn virtual int TSqlObject::primaryKeyIndex() const
  Returns the position of the primary key field on the table.
  This is a virtual function.
*/

/*!
  \fn virtual int TSqlObject::autoValueIndex() const
  Returns the position of the auto-generated value field on
  the table. This is a virtual function.
*/

/*!
  \fn virtual int TSqlObject::databaseId() const
  Returns the database ID.
*/

/*!
  \fn bool TSqlObject::isNull() const
  Returns true if there is no database record associated with the
  object; otherwise returns false.
*/

/*!
  \fn bool TSqlObject::isNew() const
  Returns true if it is a new object, otherwise returns false.
  Equivalent to isNull().
*/

/*!
  \fn QSqlError TSqlObject::error() const
  Returns a QSqlError object which contains information about
  the last error that occurred on the database.
*/

/*!
  Sets the \a record. This function is for internal use only.
*/
void TSqlObject::setRecord(const QSqlRecord &record, const QSqlError &error)
{
    QSqlRecord::operator=(record);
    syncToObject();
    sqlError = error;
}

/*!
  Inserts new record into the database, based on the current properties
  of the object.
*/
bool TSqlObject::create()
{
    // Sets the values of 'created_at', 'updated_at' or 'modified_at' properties
    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (prop == CreatedAt || prop == UpdatedAt || prop == ModifiedAt) {
            setProperty(propName, QDateTime::currentDateTime());
        } else if (prop == LockRevision) {
            // Sets the default value of 'revision' property
            setProperty(propName, 1);  // 1 : default value
        } else {
            // do nothing
        }
    }

    syncToSqlRecord();

    QString autoValName;
    QSqlRecord record = *this;
    if (autoValueIndex() >= 0) {
        autoValName = field(autoValueIndex()).name();
        record.remove(autoValueIndex()); // not insert the value of auto-value field
    }

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString ins = database.driver()->sqlStatement(QSqlDriver::InsertStatement, tableName(), record, false);
    if (ins.isEmpty()) {
        sqlError = QSqlError(QLatin1String("No fields to insert"),
                             QString(), QSqlError::StatementError);
        tWarn("SQL statement error, no fields to insert");
        return false;
    }

    TSqlQuery query(database);
    bool ret = query.exec(ins);
    sqlError = query.lastError();
    if (ret) {
        // Gets the last inserted value of auto-value field
        if (autoValueIndex() >= 0) {
            QVariant lastid = query.lastInsertId();
            if (lastid.isValid()) {
                QObject::setProperty(autoValName.toLatin1().constData(), lastid);
            }
        }
    }
    return ret;
}

/*!
  Updates the corresponding record with the properties of the object.
*/
bool TSqlObject::update()
{
    if (isNew()) {
        sqlError = QSqlError(QLatin1String("No record to update"),
                             QString(), QSqlError::UnknownError);
        tWarn("Unable to update the '%s' object. Create it before!", metaObject()->className());
        return false;
    }

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString where(" WHERE ");

    // Updates the value of 'updated_at' or 'modified_at' property
    bool updflag = false;
    int revIndex = -1;

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (!updflag && (prop == UpdatedAt || prop == ModifiedAt)) {
            setProperty(propName, QDateTime::currentDateTime());
            updflag = true;

        } else if (revIndex < 0 && prop == LockRevision) {
            bool ok;
            int oldRevision = property(propName).toInt(&ok);

            if (!ok || oldRevision <= 0) {
                sqlError = QSqlError(QLatin1String("Unable to convert the 'revision' property to an int"),
                                     QString(), QSqlError::UnknownError);
                tError("Unable to convert the 'revision' property to an int, %s", qPrintable(objectName()));
                return false;
            }

            setProperty(propName, oldRevision + 1);
            revIndex = i;

            where.append(QLatin1String(propName));
            where.append("=").append(TSqlQuery::formatValue(oldRevision, database));
            where.append(" AND ");
        } else {
            // continue
        }
    }

    QString upd;   // UPDATE Statement
    upd.reserve(255);
    upd.append(QLatin1String("UPDATE ")).append(tableName()).append(QLatin1String(" SET "));

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QVariant newval = QObject::property(propName);
        QVariant recval = QSqlRecord::value(QLatin1String(propName));
        if (recval.isValid() && recval != newval) {
            upd.append(QLatin1String(propName));
            upd.append(QLatin1Char('='));
            upd.append(TSqlQuery::formatValue(newval, database));
            upd.append(QLatin1String(", "));
        }
    }

    if (!upd.endsWith(QLatin1String(", "))) {
        tSystemDebug("SQL UPDATE: Same values as that of the record. No need to update.");
        return true;
    }

    upd.chop(2);
    syncToSqlRecord();

    const char *pkName = metaObject()->property(metaObject()->propertyOffset() + primaryKeyIndex()).name();
    if (primaryKeyIndex() < 0 || !pkName) {
        QString msg = QString("Primary key not found for table ") + tableName() + QLatin1String(". Create a primary key!");
        sqlError = QSqlError(msg, QString(), QSqlError::StatementError);
        tError("%s", qPrintable(msg));
        return false;
    }
    where.append(QLatin1String(pkName));
    where.append("=").append(TSqlQuery::formatValue(property(pkName), database));
    upd.append(where);

    TSqlQuery query(database);
    bool ret = query.exec(upd);
    sqlError = query.lastError();
    if (ret) {
        // Optimistic lock check
        if (revIndex >= 0 && query.numRowsAffected() != 1) {
            QString msg = QString("Row was updated or deleted from table ") + tableName() + QLatin1String(" by another transaction");
            sqlError = QSqlError(msg, QString(), QSqlError::UnknownError);
            throw SqlException(msg, __FILE__, __LINE__);
        }
    }
    return ret;
}

/*!
  Deletes the record with this primary key from the database.
*/
bool TSqlObject::remove()
{
    syncToSqlRecord();

    QSqlDatabase &database = Tf::currentSqlDatabase(databaseId());
    QString del = database.driver()->sqlStatement(QSqlDriver::DeleteStatement, tableName(), *static_cast<QSqlRecord *>(this), false);
    if (del.isEmpty()) {
        sqlError = QSqlError(QLatin1String("Unable to delete row"),
                             QString(), QSqlError::StatementError);
        return false;
    }

    del.append(" WHERE ");
    int revIndex = -1;

    for (int i = metaObject()->propertyOffset(); i < metaObject()->propertyCount(); ++i) {
        const char *propName = metaObject()->property(i).name();
        QByteArray prop = QByteArray(propName).toLower();

        if (prop == LockRevision) {
            bool ok;
            int revision = property(propName).toInt(&ok);

            if (!ok || revision <= 0) {
                sqlError = QSqlError(QLatin1String("Unable to convert the 'revision' property to an int"),
                                     QString(), QSqlError::UnknownError);
                tError("Unable to convert the 'revision' property to an int, %s", qPrintable(objectName()));
                return false;
            }

            del.append(QLatin1String(propName));
            del.append("=").append(TSqlQuery::formatValue(revision, database));
            del.append(" AND ");

            revIndex = i;
            break;
        }
    }

    const char *pkName = metaObject()->property(metaObject()->propertyOffset() + primaryKeyIndex()).name();
    if (primaryKeyIndex() < 0 || !pkName) {
        QString msg = QString("Primary key not found for table ") + tableName() + QLatin1String(". Create a primary key!");
        sqlError = QSqlError(msg, QString(), QSqlError::StatementError);
        tError("%s", qPrintable(msg));
        return false;
    }
    del.append(QLatin1String(pkName));
    del.append("=").append(TSqlQuery::formatValue(property(pkName), database));

    TSqlQuery query(database);
    bool ret = query.exec(del);
    sqlError = query.lastError();
    if (ret) {
        // Optimistic lock check
        if (query.numRowsAffected() != 1) {
            if (revIndex >= 0) {
                QString msg = QString("Row was updated or deleted from table ") + tableName() + QLatin1String(" by another transaction");
                sqlError = QSqlError(msg, QString(), QSqlError::UnknownError);
                throw SqlException(msg, __FILE__, __LINE__);
            }
            tWarn("Row was deleted by another transaction, %s", qPrintable(tableName()));
        }
        clear();
    }
    return ret;
}

/*!
  Reloads the values of  the record onto the properties.
 */
bool TSqlObject::reload()
{
    if (isEmpty()) {
        return false;
    }
    syncToObject();
    return true;
}

/*!
  Returns true if the values of the properties differ with the record on the
  database; otherwise returns false.
 */
bool TSqlObject::isModified() const
{
    if (isNew())
        return false;

    for (int i = 0; i < QSqlRecord::count(); ++i) {
        QString name = field(i).name();
        int index = metaObject()->indexOfProperty(name.toLatin1().constData());
        if (index >= 0) {
            if (value(name) != property(name.toLatin1().constData())) {
                return true;
            }
        }
    }
    return false;
}

/*!
  Synchronizes the internal record data to the properties of the object.
  This function is for internal use only.
*/
void TSqlObject::syncToObject()
{
    int offset = metaObject()->propertyOffset();
    for (int i = 0; i < QSqlRecord::count(); ++i) {
        QString propertyName = field(i).name();
        QByteArray name = propertyName.toLatin1();
        int index = metaObject()->indexOfProperty(name.constData());
        if (index >= offset) {
            QObject::setProperty(name.constData(), value(propertyName));
        }
    }
}

/*!
  Synchronizes the properties to the internal record data.
  This function is for internal use only.
*/
void TSqlObject::syncToSqlRecord()
{
    QSqlRecord::operator=(Tf::currentSqlDatabase(databaseId()).record(tableName()));
    const QMetaObject *metaObj = metaObject();
    for (int i = metaObj->propertyOffset(); i < metaObj->propertyCount(); ++i) {
        const char *propName = metaObj->property(i).name();
        int idx = indexOf(propName);
        if (idx >= 0) {
            QSqlRecord::setValue(idx, QObject::property(propName));
        } else {
            tWarn("invalid name: %s", propName);
        }
    }
}
<|endoftext|>