<commit_before>// cb_info allows to parse and manipulate MCell's cellblender output files
//
// (C) <NAME>, 2015
// Licenses under a BSD license, see LICENSE file for details

#include <cassert>
#include <exception>
#include <getopt.h>
#include <iostream>
#include <string>

#include "cb_info.hpp"

// forward declaration of static funcs
static void usage(); 
static CmdlOpts parse_cmdline(int argc, char** argv);
static void print_positions(const SpecMap& specs, const CmdlOpts& cmdlOpts);

int main(int argc, char** argv) {

  if (argc <= 1) {
    usage();
    return EXIT_FAILURE;
  }
  auto cmdl = parse_cmdline(argc, argv);
  if (cmdl.files.size() == 0) {
    std::cerr << "***** ERROR: No MCell viz files specified to operate on\n\n";
    usage();
    return EXIT_FAILURE;
  }

  for (const auto& fileName : cmdl.files) {
    SpecMap specs;
    try {
      specs = parse_cb(fileName);
    } catch (std::exception& e) {
      std::cerr << "Failed to parse CellBlender file " << fileName << ": "
                << e.what() << std::endl;
      return EXIT_FAILURE;
    }

    if (cmdl.info) {
      for (const auto& s : specs) {
        std::cout << s.first << "  " << s.second.pos.size() 
          << "  " << (s.second.isVolMol ? "VOL" : "SURF") << "\n";
      }
    }

    if (cmdl.listMolPos) {
      print_positions(specs, cmdl);
    }
  }

  return EXIT_SUCCESS;
}

// parse_cb does the actual work of parsing the cellblender input file
SpecMap parse_cb(const std::string& fileName) {
  std::ifstream file(fileName);
  if (file.fail()) {
    throw std::runtime_error("failed to open");
  }

  SpecMap specs;
  uint32_t version;
  read_val(file, version);

  while (file) {
    unsigned char nameLength;
    read_val(file, nameLength);

    Species spec;
    char specName[nameLength + 1];
    for (int i = 0; i < nameLength; ++i) {
      read_val(file, specName[i]);
    }
    specName[nameLength] = '\0';

    unsigned char type;
    read_val(file, type);
    spec.isVolMol = (type == 0) ? true : false;
    // FIXME: currently we support only volume molecules
    // this check can go away once surface mols are supported
    if (!spec.isVolMol) {
      throw std::runtime_error("surface mols are not currently supported");
    }

    uint32_t numMols;
    read_val(file, numMols);
    spec.pos.reserve(numMols);
    assert(numMols % 3 == 0);
    for (int i = 0; i < numMols / 3; i++) {
      Vec3 v;
      read_val(file, v.x);
      read_val(file, v.y);
      read_val(file, v.z);
      spec.pos.emplace_back(std::move(v));
    }
    specs[specName] = std::move(spec);

    // check if we're done
    if (file.peek() == EOF) {
      break;
    }
  }

  return specs;
}

// print_positions prints the position info of the requested molecules
void print_positions(const SpecMap& specs, const CmdlOpts& cmdl) {
  if (cmdl.spec != "" && specs.find(cmdl.spec) != specs.end()) {
    for (const auto& v : specs.at(cmdl.spec).pos) {
      std::cout << v << "\n";
    }
  }
  if (cmdl.spec == "") {
    for (const auto& s : specs) {
      if (cmdl.addSeparator) {
        std::cout << "--- " << s.first << "\n";
      }
      for (const auto& v : s.second.pos) {
        std::cout << v << "\n";
      }
    }
  }
}

// usage prints a quick usage info
void usage() {
  std::cout
      << "cb_info v0.1    (C) 2015 <NAME>\n\n"
      << "usage: cb_info [options] <file1> <file2> ....\n\n"
      << "Options:"
      << "\n"
      << "\t-i, --species_info       print names of species and number of\n"
      << "\t                         available molecules\n"
      << "\t-p, --print_mol_positions <species type>\n"
      << "\t                         print the (x,y,z) positions of all\n"
      << "\t                         molecules of species type\n"
      << "\t-o, --print_mol_orientations <species type>\n"
      << "\t                         print the orientations of all\n"
      << "\t                         molecules of species type\n"
      << "\t                         (empty string \"\" implies all species)\n"
      << "\t-s, --add_separator      add separator between species in "
         "printout\n"
      << "\t-n, --species_name       name of species to print\n" 
      << "\t-h, --help               this help message\n" << std::endl;
}


// longOptions provides the parameters used for command line parsing
static struct option long_options[] = {
    {"species_info", no_argument, NULL, 'i'},
    {"print_mol_positions", no_argument, NULL, 'p'},
    {"print_mol_orientations", no_argument, NULL, 'o'},
    {"add_separator", no_argument, NULL, 's'},
    {"species_name", required_argument, NULL, 'n'},
    {"help", no_argument, NULL, 'h'}};

// parse_cmdline parses the user provided command line options and
// does some basic sanity checks on them
static CmdlOpts parse_cmdline(int argc, char** argv) {

  int c;
  CmdlOpts cmdlOpts;
  while ((c = getopt_long(argc, argv, "ins:polh", long_options, NULL)) != -1) {
    switch (c) {
      case 'i':
        cmdlOpts.info = true;
        break;

      case 'p':
        cmdlOpts.listMolPos = true;
        break;

      case 'o':
        cmdlOpts.listMolOrient = true;
        break;

      case 'n':
        cmdlOpts.spec = optarg;
        break;

      case 's':
        cmdlOpts.addSeparator = true;
        break;

      case 'h':<commit_msg>Fixed bug in command line parser.<commit_after>// cb_info allows to parse and manipulate MCell's cellblender output files
//
// (C) <NAME>, 2015
// Licenses under a BSD license, see LICENSE file for details

#include <cassert>
#include <exception>
#include <getopt.h>
#include <iostream>
#include <string>

#include "cb_info.hpp"

// forward declaration of static funcs
static void usage(); 
static CmdlOpts parse_cmdline(int argc, char** argv);
static void print_positions(const SpecMap& specs, const CmdlOpts& cmdlOpts);

int main(int argc, char** argv) {

  if (argc <= 1) {
    usage();
    return EXIT_FAILURE;
  }
  auto cmdl = parse_cmdline(argc, argv);
  if (cmdl.files.size() == 0) {
    std::cerr << "***** ERROR: No MCell viz files specified to operate on\n\n";
    usage();
    return EXIT_FAILURE;
  }

  for (const auto& fileName : cmdl.files) {
    SpecMap specs;
    try {
      specs = parse_cb(fileName);
    } catch (std::exception& e) {
      std::cerr << "Failed to parse CellBlender file " << fileName << ": "
                << e.what() << std::endl;
      return EXIT_FAILURE;
    }

    if (cmdl.info) {
      for (const auto& s : specs) {
        std::cout << s.first << "  " << s.second.pos.size() 
          << "  " << (s.second.isVolMol ? "VOL" : "SURF") << "\n";
      }
    }

    if (cmdl.listMolPos) {
      print_positions(specs, cmdl);
    }
  }

  return EXIT_SUCCESS;
}

// parse_cb does the actual work of parsing the cellblender input file
SpecMap parse_cb(const std::string& fileName) {
  std::ifstream file(fileName);
  if (file.fail()) {
    throw std::runtime_error("failed to open");
  }

  SpecMap specs;
  uint32_t version;
  read_val(file, version);

  while (file) {
    unsigned char nameLength;
    read_val(file, nameLength);

    Species spec;
    char specName[nameLength + 1];
    for (int i = 0; i < nameLength; ++i) {
      read_val(file, specName[i]);
    }
    specName[nameLength] = '\0';

    unsigned char type;
    read_val(file, type);
    spec.isVolMol = (type == 0) ? true : false;
    // FIXME: currently we support only volume molecules
    // this check can go away once surface mols are supported
    if (!spec.isVolMol) {
      throw std::runtime_error("surface mols are not currently supported");
    }

    uint32_t numMols;
    read_val(file, numMols);
    spec.pos.reserve(numMols);
    assert(numMols % 3 == 0);
    for (int i = 0; i < numMols / 3; i++) {
      Vec3 v;
      read_val(file, v.x);
      read_val(file, v.y);
      read_val(file, v.z);
      spec.pos.emplace_back(std::move(v));
    }
    specs[specName] = std::move(spec);

    // check if we're done
    if (file.peek() == EOF) {
      break;
    }
  }

  return specs;
}

// print_positions prints the position info of the requested molecules
void print_positions(const SpecMap& specs, const CmdlOpts& cmdl) {
  if (cmdl.spec != "" && specs.find(cmdl.spec) != specs.end()) {
    for (const auto& v : specs.at(cmdl.spec).pos) {
      std::cout << v << "\n";
    }
  }
  if (cmdl.spec == "") {
    for (const auto& s : specs) {
      if (cmdl.addSeparator) {
        std::cout << "--- " << s.first << "\n";
      }
      for (const auto& v : s.second.pos) {
        std::cout << v << "\n";
      }
    }
  }
}

// usage prints a quick usage info
void usage() {
  std::cout
      << "cb_info v0.1    (C) 2015 <NAME>\n\n"
      << "usage: cb_info [options] <file1> <file2> ....\n\n"
      << "Options:"
      << "\n"
      << "\t-i, --species_info       print names of species and number of\n"
      << "\t                         available molecules\n"
      << "\t-p, --print_mol_positions <species type>\n"
      << "\t                         print the (x,y,z) positions of all\n"
      << "\t                         molecules of species type\n"
      << "\t-o, --print_mol_orientations <species type>\n"
      << "\t                         print the orientations of all\n"
      << "\t                         molecules of species type\n"
      << "\t                         (empty string \"\" implies all species)\n"
      << "\t-s, --add_separator      add separator between species in "
         "printout\n"
      << "\t-n, --species_name       name of species to print\n" 
      << "\t-h, --help               this help message\n" << std::endl;
}


// longOptions provides the parameters used for command line parsing
static struct option long_options[] = {
    {"species_info", no_argument, NULL, 'i'},
    {"print_mol_positions", no_argument, NULL, 'p'},
    {"print_mol_orientations", no_argument, NULL, 'o'},
    {"add_separator", no_argument, NULL, 's'},
    {"species_name", required_argument, NULL, 'n'},
    {"help", no_argument, NULL, 'h'}};

// parse_cmdline parses the user provided command line options and
// does some basic sanity checks on them
static CmdlOpts parse_cmdline(int argc, char** argv) {

  int c;
  CmdlOpts cmdlOpts;
  while ((c = getopt_long(argc, argv, "in:spolh", long_options, NULL)) != -1) {
    switch (c) {
      case 'i':
        cmdlOpts.info = true;
        break;

      case 'p':
        cmdlOpts.listMolPos = true;
        break;

      case 'o':
        cmdlOpts.listMolOrient = true;
        break;

      case 'n':
        cmdlOpts.spec = optarg;
        break;

      case 's':
        cmdlOpts.addSeparator = true;
        break;

      case 'h':
{'fraction_non_alphanumeric': 0.14892221180880974, 'fraction_numerical': 0.005248359887535145, 'mean_word_length': 2.2703034017775052, 'pattern_counts': {'":': 2, '<': 175, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7514760', 'n_tokens_mistral': 3711, 'n_tokens_neox': 3580, 'n_words': 1000}