<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <fstream>
#include <glob.h>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/* Returns the first path found matching '$venvDir/lib/python*\/site-packages' */
static const char* getPythonPath(const char* venvDir) {
  glob_t globResult;
  const char* globPattern = astr(venvDir, "/lib/python*/site-packages");
  glob(globPattern, 0, NULL, &globResult);
  const size_t count = globResult.gl_pathc;

  // No results found. Return "".

  // FIXME: This should report error (chpldoc is not properly built/installed),
  //        and stop processing...
  //        (thomasvandoren, 2015-03-10)
  char* result;
  if (count == 0) {
    result = (char*)"";
  // At least one result found, so return first.
  } else {
    result = globResult.gl_pathv[0];
  }
  globfree(&globResult);
  return result;
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.

  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");
  const char * pythonPath = getPythonPath(venvDir);

  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && ",
                              "export VIRTUAL_ENV=", venvDir, " && ",
                              "export PYTHONPATH=", pythonPath);

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<commit_msg>Correctly copy glob result into result char*.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <fstream>
#include <glob.h>
#include <iostream>
#include <iterator>
#include <sstream>
#include <sys/stat.h>
#include <sys/types.h>

#include "AstPrintDocs.h"
#include "AstToText.h"
#include "driver.h"
#include "expr.h"
#include "files.h"
#include "mysystem.h"
#include "passes.h"
#include "stmt.h"
#include "symbol.h"
#include "stringutil.h"

#include "docs.h"

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Open the directory to store the docs

    // This is the final location for the output format (e.g. the html files.).
    std::string docsOutputDir;
    if (strlen(fDocsFolder) > 0) {
      docsOutputDir = fDocsFolder;
    } else {
      docsOutputDir = astr(getCwd(), "/docs");
    }

    // Root of the sphinx project and generated rst files. If
    // --docs-save-sphinx is not specified, it will be a temp dir.
    std::string docsTempDir = "";
    std::string docsSphinxDir;
    if (strlen(fDocsSphinxDir) > 0) {
      docsSphinxDir = fDocsSphinxDir;
    } else {
      docsTempDir = makeTempDir("chpldoc-");
      docsSphinxDir = docsTempDir;
    }

    // The location of intermediate rst files.
    std::string docsRstDir;
    if (fDocsTextOnly) {
      // For text-only mode, the output and working location is the same.
      docsRstDir = docsOutputDir;
    } else {
      // For rst mode, the working location is somewhere inside the temp dir.
      docsRstDir = generateSphinxProject(docsSphinxDir);
    }

    // TODO: Check for errors here... (thomasvandoren, 2015-02-25)
    const int dirPerms = S_IRWXU | S_IRWXG | S_IRWXO;
    mkdir(docsRstDir.c_str(), dirPerms);
    mkdir(docsOutputDir.c_str(), dirPerms);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!mod->hasFlag(FLAG_NO_DOC) && !devOnlyModule(mod)) {
        if (isNotSubmodule(mod)) {
          std::ofstream *file = openFileFromMod(mod, docsRstDir);

          AstPrintDocs *docsVisitor = new AstPrintDocs(file);
          mod->accept(docsVisitor);
          delete docsVisitor;

          // Comment the above three lines and uncomment the following line to
          // get the old category based output (or alphabetical). Note that
          // this will be restored (hopefully soon)... (thomasvandoren, 2015-02-22)
          //
          // printModule(file, mod, 0);

          file->close();
        }
      }
    }

    if (!fDocsTextOnly) {
      generateSphinxOutput(docsSphinxDir, docsOutputDir);
    }

    if (docsTempDir.length() > 0) {
      deleteDir(docsTempDir.c_str());
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printFields(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      var->printDocs(file, tabs);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl, unsigned int tabs) {
  if (!cl->symbol->hasFlag(FLAG_NO_DOC) && ! cl->isUnion()) {
    cl->printDocs(file, tabs);

    printFields(file, cl, tabs + 1);

    // In rst mode, add an additional line break after the attributes and
    // before the next directive.
    if (!fDocsTextOnly) {
      *file << std::endl;
    }

    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      // We only want to print methods defined within the class under the
      // class header
      if (fn->isPrimaryMethod())
        fn->printDocs(file, tabs + 1);
    }
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->isPrimaryMethod());
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, unsigned int tabs) {
  if (!mod->hasFlag(FLAG_NO_DOC)) {
    mod->printDocs(file, tabs);

    Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
    if (fDocsAlphabetize)
      qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
    forv_Vec(VarSymbol, var, configs) {
      var->printDocs(file, tabs + 1);
    }

    Vec<VarSymbol*> variables = mod->getTopLevelVariables();
    if (fDocsAlphabetize)
      qsort(variables.v, variables.n, sizeof(variables.v[0]), compareNames);
    forv_Vec(VarSymbol, var, variables) {
      var->printDocs(file, tabs + 1);
    }
    Vec<FnSymbol*> fns = mod->getTopLevelFunctions(fDocsIncludeExterns);
    // If alphabetical option passed, fDocsAlphabetizes the output
    if (fDocsAlphabetize)
      qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

    forv_Vec(FnSymbol, fn, fns) {
      // TODO: Add flag to compiler to turn on doc dev only output

      // We want methods on classes that are defined at the module level to be
      // printed at the module level
      if (!devOnlyFunction(fn) || fn->isSecondaryMethod()) {
        fn->printDocs(file, tabs + 1);
      }
    }

    Vec<AggregateType*> classes = mod->getTopLevelClasses();
    if (fDocsAlphabetize)
      qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

    forv_Vec(AggregateType, cl, classes) {
      printClass(file, cl, tabs + 1);
    }

    Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
    if (fDocsAlphabetize)
      qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

    forv_Vec(ModuleSymbol, subMod, mods) {
      // TODO: Add flag to compiler to turn on doc dev only output
      if (!devOnlyModule(subMod)) {
        subMod->addPrefixToName(mod->docsName() + ".");
        printModule(file, subMod, tabs + 1);
      }
    }
  }
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}

/*
 * Create new sphinx project at given location and return path where .rst files
 * should be placed.
 */
std::string generateSphinxProject(std::string dirpath) {
  // Create the output dir under the docs output dir.
  const char * sphinxDir = dirpath.c_str();

  // Ensure output directory exists.
  const char * mkdirCmd = astr("mkdir -p ", sphinxDir);
  mysystem(mkdirCmd, "creating docs output dir");

  // Copy the sphinx template into the output dir.
  const char * sphinxTemplate = astr(CHPL_HOME, "/third-party/chpldoc-venv/chpldoc-sphinx-project/*");
  const char * cmd = astr("cp -r ", sphinxTemplate, " ", sphinxDir, "/");
  mysystem(cmd, "copying chpldoc sphinx template");

  const char * moddir = astr(sphinxDir, "/source/modules");
  return std::string(moddir);
}

/* Returns the first path found matching '$venvDir/lib/python*\/site-packages' */
static const char* getPythonPath(const char* venvDir) {
  glob_t globResult;
  const char* globPattern = astr(venvDir, "/lib/python*/site-packages");
  glob(globPattern, 0, NULL, &globResult);
  const size_t count = globResult.gl_pathc;

  // No results found. Return "".

  // FIXME: This should report error (chpldoc is not properly built/installed),
  //        and stop processing...
  //        (thomasvandoren, 2015-03-10)
  char* result;
  if (count == 0) {
    result = (char*)"";
  // At least one result found, so return first.
  } else {
    result = new char[strlen(globResult.gl_pathv[0])];
    strcpy(result, globResult.gl_pathv[0]);
  }
  globfree(&globResult);
  return result;
}

/*
 * Invoke sphinx-build using sphinxDir to find conf.py and rst sources, and
 * outputDir for generated html files.
 */
void generateSphinxOutput(std::string sphinxDir, std::string outputDir) {
  // Set the PATH and VIRTUAL_ENV variables in the environment. The values are
  // based on the install path in the third-party/chpldoc-venv/ dir.

  const char * venvDir = astr(
    CHPL_HOME, "/third-party/chpldoc-venv/install/",
    CHPL_TARGET_PLATFORM, "/chpldoc-virtualenv");
  const char * venvBinDir = astr(venvDir, "/bin");
  const char * sphinxBuild = astr(venvBinDir, "/sphinx-build");
  const char * pythonPath = getPythonPath(venvDir);

  const char * envVars = astr("export PATH=", venvBinDir, ":$PATH && ",
                              "export VIRTUAL_ENV=", venvDir, " && ",
                              "export PYTHONPATH=", pythonPath);

  // Run:
  //   $envVars &&
  //     sphinx-build -b html
  //     -d $sphinxDir/build/doctrees -W
  //     $sphinxDir/source $outputDir
  const char * cmdPrefix = astr(envVars, " && ");
  const char * cmd = astr(
    cmdPrefix,
    sphinxBuild, " -b html -d ",
    sphinxDir.c_str(), "/build/doctrees -W ",
    sphinxDir.c_str(), "/source ", outputDir.c_str());
  mysystem(cmd, "building html output from chpldoc sphinx project");
  printf("HTML files are at: %s\n", outputDir.c_str());
}

std::string filenameFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = mod->filename;

  if (mod->modTag == MOD_INTERNAL) {
    filename = "internal-modules/";
  } else if (mod ->modTag == MOD_STANDARD) {
    filename = "standard-modules/";
  } else {
    size_t location = filename.rfind("/");
    if (location != std::string::npos) {
      filename = filename.substr(0, location + 1);
    } else {
      filename = "";
    }
  }
  filename = docsWorkDir + "/" + filename;
  createDocsFileFolders(filename);

  // Creates files for each top level module.
  if (fDocsTextOnly) {
    filename = filename + mod->name + ".txt";
  } else {
    filename = filename + mod->name + ".rst";
  }

  return filename;
}

std::ofstream* openFileFromMod(ModuleSymbol *mod, std::string docsWorkDir) {
  std::string filename = filenameFromMod(mod, docsWorkDir);
  return new std::ofstream(filename.c_str(), std::ios::out);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <map>
#include <iostream>
#include <fstream>
#include <iterator>
#include <sys/stat.h>
#include <sys/types.h>

#include "driver.h"
#include "passes.h"
#include "symbol.h"
#include "expr.h"
#include "stmt.h"
#include "docs.h"
#include "mysystem.h"

int NUMTABS = 0;

static std::map<std::string, std::string> outputMap;
// If we were using C++11 then this could be an unordered_map

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Create a map of structural names to their expected chpldoc output
    if (fDocsTextOnly) {
      outputMap["class"] = "Class: ";
      outputMap["record"] = "Record: ";
      outputMap["config"] = "config ";
    } else {
      outputMap["class"] = ".. class:: ";
      outputMap["record"] = ".. record:: ";
      outputMap["module"] = ".. module:: ";
      outputMap["module comment prefix"] = ":synopsis: ";
      outputMap["iter func"] = ".. iterfunction:: ";
      outputMap["iter method"] = ".. itermethod:: ";
      outputMap["func"] = ".. function:: ";
      outputMap["method"] = ".. method:: ";
      outputMap["config"] = ".. data:: ";
      outputMap["field"] = ".. attribute:: ";
    }

    // Open the directory to store the docs
    std::string folderName = (strlen(fDocsFolder) != 0) ? fDocsFolder : "docs";

    mkdir(folderName.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      if (!devOnlyModule(mod) || developer) {
        std::string filename = mod->filename;

        if (mod->modTag == MOD_INTERNAL) {
          filename = "internal-modules/";
        } else if (mod ->modTag == MOD_STANDARD) {
          filename = "standard-modules/";
        } else {
          size_t location = filename.rfind("/");
          if (location != std::string::npos) {
            filename = filename.substr(0, location + 1);
          } else {
            filename = "";
          }
        }
        filename = folderName + "/" + filename;
        createDocsFileFolders(filename);

        if (isNotSubmodule(mod)) {
          // Creates files for each top level module
          if (!fDocsTextOnly)
            filename = filename + mod->name + ".rst";
          else
            filename = filename + mod->name + ".txt";
          std::ofstream file(filename.c_str(), std::ios::out);
          if (!fDocsTextOnly) {
            file << ".. default-domain:: chpl" << std::endl << std::endl;
          }
          printModule(&file, mod, mod->name);
          file.close();
        }
      }
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printIntent(std::ofstream *file, IntentTag intent) {
  switch(intent) {
  case INTENT_IN:
    *file << "in "; break;
  case INTENT_INOUT:
    *file << "inout "; break;
  case INTENT_OUT:
    *file << "out "; break;
  case INTENT_CONST:
    *file << "const "; break;
  case INTENT_CONST_IN:
    *file << "const in "; break;
  case INTENT_CONST_REF:
    *file << "const ref "; break;
  case INTENT_REF:
    *file << "ref "; break;
  case INTENT_PARAM:
    *file << "param "; break;
  default:
    break;
  }
}

void printArg(std::ofstream *file, ArgSymbol *arg) {
  printIntent(file, arg->intent);
  if (arg->hasFlag(FLAG_TYPE_VARIABLE)) {
    *file << "type ";
    // Because type intents are handled differently during parsing
  }

  *file << arg->name;
  if (arg->typeExpr != NULL) {
    *file << ": ";
    arg->typeExpr->body.tail->prettyPrint(file);
  } else if (arg->type != NULL && arg->type != dtAny) {
    *file << ": " << arg->type->symbol->name;
  }
}

void printFields(std::ofstream *file, AggregateType *cl) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      if (!var->hasFlag(FLAG_SUPER_CLASS)) {
        printTabs(file);
        *file << outputMap["field"];
        // For rst, this will insert '.. attribute:: ' here
        // For plain text, nothing will be inserted
        printVarStart(file, var);
        Expr *expr;
        if (cl->isClass()) {
          expr = cl->defaultTypeConstructor->body->body.get(i);
        } else {
          expr = cl->defaultTypeConstructor->body->body.get(i+1);
        }
        if (CallExpr *list = toCallExpr(expr)) {
          if (CallExpr *end = toCallExpr(list->argList.tail)) {
            if (end->primitive != NULL) {
              *file << ": ";
              end->prettyPrint(file);
              // TODO: prettify type output
            } else if (SymExpr* sym = toSymExpr(end->argList.tail)) {
              *file << " = ";
              sym->prettyPrint(file);
            }
          }
        }

        *file << std::endl;
        printVarDocs(file, var);
      }
    }
  }
}

void inheritance(Vec<AggregateType*> *list, AggregateType *cl) {
  forv_Vec(Type, t, cl->dispatchParents) {
    if (AggregateType* c = toAggregateType(t)) {
      list->add_exclusive(c);
      inheritance(list, c);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl) {
  if (! cl->isUnion()) {
    printTabs(file);

    // TODO: for rst, change convert to '.. class:: ' and '.. record:: '
    if (cl->isClass()) {
      *file << outputMap["class"];
    } else if (cl->isRecord()) {
      *file << outputMap["record"];
    }

    NUMTABS++;
    *file << cl->symbol->name << std::endl;
    if (cl->doc != NULL) {
      printTabs(file);
      *file << cl->doc << std::endl;
    }
    printFields(file, cl);
    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      printFunction(file, fn, true);
    }

    Vec<AggregateType*> list;
    inheritance(&list, cl);

    if (fDocsAlphabetize)
      qsort(list.v, list.n, sizeof(list.v[0]), compareClasses);

    forv_Vec(AggregateType, c, list) {
      printTabs(file);
      *file << "inherited from " << c->symbol->name;
      *file << std::endl;
      NUMTABS++;
      printFields(file, c);

      forv_Vec(FnSymbol, fn, c->methods) {
        printFunction(file, fn, true);

      }
      NUMTABS--;
      *file << std::endl;
    }
    NUMTABS--;
  }
}

void printVarStart(std::ofstream *file, VarSymbol *var) {
  // TODO: I need to get this to print type fields as type fields instead of
  // vars.
  if (var->isConstant())
    *file << "const ";
  else if (var->isParameter())
    *file << "param ";
  else
    *file << "var ";

  *file << var->name;
}

void printVarType(std::ofstream *file, VarSymbol *var) {
  if (var->defPoint->exprType != NULL) {
    *file << ": ";
    var->defPoint->exprType->prettyPrint(file);
    // TODO: Make type output prettier
  }
  *file << std::endl;
}

void printVarDocs(std::ofstream *file, VarSymbol *var) {
  // TODO: Do we want to parse the output here to make it indent nicely?
  NUMTABS++;
  if (var->doc != NULL) {
    printTabs(file);
    *file << var->doc;
    *file << std::endl;
  }
  NUMTABS--;
}

void printTabs(std::ofstream *file) {
  for (int i = 1; i <= NUMTABS; i++) {
    *file << "   ";
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->hasFlag(FLAG_METHOD));
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, std::string name) {
  printTabs(file);
  *file << "Module: " << name << std::endl;
  if (!fDocsTextOnly) {
    int length = strlen("Module: ") + strlen(name.c_str());
    for (int i = 0; i < length; i++) {
      *file << "=";
    }
    *file << std::endl;
    // Make the length of this equal to "Module: " + name.length
  }
  NUMTABS++;
  if (mod->doc != NULL) {
    printTabs(file);
    *file << mod->doc << std::endl;
  }
  if(!fDocsTextOnly) {
    NUMTABS--;
    *file << outputMap["module"] << name << std::endl;
    NUMTABS++;
    if (mod->doc != NULL) {
      printTabs(file);
      *file << outputMap["module comment prefix"];
      *file << mod->doc << std::endl;
      *file << std::endl;
    }
  }

  Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
  if (fDocsAlphabetize)
    qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
  forv_Vec(VarSymbol, var, configs) {
    printTabs(file);
    *file << outputMap["config"];
    printVarStart(file, var);
    printVarType(file, var);
    printVarDocs(file, var);
  }

  Vec<FnSymbol*> fns = mod->getTopLevelFunctions(true);
  // If alphabetical option passed, fDocsAlphabetizes the output
  if (fDocsAlphabetize)
    qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

  forv_Vec(FnSymbol, fn, fns) {
    if (!devOnlyFunction(fn) || developer) {
      printFunction(file, fn, false);
    }
  }

  Vec<AggregateType*> classes = mod->getTopLevelClasses();
  if (fDocsAlphabetize)
    qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

  forv_Vec(AggregateType, cl, classes) {
    printClass(file, cl);
  }

  Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
  if (fDocsAlphabetize)
    qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

  forv_Vec(ModuleSymbol, md, mods) {
    if (!devOnlyModule(md) || developer)
      printModule(file, md, name + "." +  md->name);
  }
  NUMTABS--;
}

void printFunction(std::ofstream *file, FnSymbol *fn, bool method) {
  printTabs(file);
  NUMTABS++;
  bool iterator = fn->hasFlag(FLAG_ITERATOR_FN);
  if (method) {
    if (iterator) {
      *file << outputMap["iter method"];
    } else {
      *file << outputMap["method"];
    }
  } else {
    if (iterator) {
      *file << outputMap["iter func"];
    } else {
      *file << outputMap["func"];
    }
  }
  if (fn->hasFlag(FLAG_INLINE)) {
    *file << "inline ";
  } else if (fn->hasFlag(FLAG_EXPORT)) {
    *file << "export ";
  } else if (fn->hasFlag(FLAG_EXTERN)) {
    *file << "extern ";
  }

  if (iterator) {
    *file << "iter ";
  } else {
    *file << "proc ";
  }

  *file << fn->name << "(";
  if (fn->numFormals() > 0) {
    if (!developer && strcmp(fn->getFormal(1)->name, "_mt") == 0) {
      for (int i = 3; i < fn->numFormals(); i++) {
        ArgSymbol *cur = fn->getFormal(i);
        printArg(file, cur);
        *file << ", ";
      }
      if (fn->numFormals() != 2) {
        ArgSymbol *cur = fn->getFormal(fn->numFormals());
        printArg(file, cur);
      }
    } else {
      for (int i = 1; i < fn->numFormals(); i++) {
        ArgSymbol *cur = fn->getFormal(i);
        printArg(file, cur);
        *file << ", ";
      }
      ArgSymbol *cur = fn->getFormal(fn->numFormals());
      printArg(file, cur);
    }
  }
  *file << ")";
  switch (fn->retTag) {
  case RET_REF:
    *file << " ref"; break;
  case RET_PARAM:
    *file << " param"; break;
  case RET_TYPE:
    *file << " type"; break;
  default: break;
  }
  if (fn->retExprType != NULL) {
    *file << ": ";
    fn->retExprType->body.tail->prettyPrint(file);
    // TODO: better type output
  }
  *file << std::endl;

  if (fn->doc != NULL) {
    printTabs(file);
    *file << fn->doc << std::endl;
  }
  *file << std::endl;
  NUMTABS--;
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}
<commit_msg>Alter indentation for rst mode.<commit_after>/*
 * Copyright 2004-2015 Cray Inc.
 * Other additional copyright holders may be indicated within.
 *
 * The entirety of this work is 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 <map>
#include <iostream>
#include <fstream>
#include <iterator>
#include <sys/stat.h>
#include <sys/types.h>

#include "driver.h"
#include "passes.h"
#include "symbol.h"
#include "expr.h"
#include "stmt.h"
#include "docs.h"
#include "mysystem.h"

int NUMTABS = 0;

static std::map<std::string, std::string> outputMap;
// If we were using C++11 then this could be an unordered_map

static int compareNames(const void* v1, const void* v2) {
  Symbol* s1 = *(Symbol* const *)v1;
  Symbol* s2 = *(Symbol* const *)v2;
  return strcmp(s1->name, s2->name);
}

static int compareClasses(const void *v1, const void* v2) {
  Type *t1 = *(Type* const *)v1;
  Type *t2 = *(Type* const *)v2;
  return strcmp(t1->symbol->name, t2->symbol->name);
}

void docs(void) {

  if (fDocs) {
    // Create a map of structural names to their expected chpldoc output
    if (fDocsTextOnly) {
      outputMap["class"] = "Class: ";
      outputMap["record"] = "Record: ";
      outputMap["config"] = "config ";
    } else {
      outputMap["class"] = ".. class:: ";
      outputMap["record"] = ".. record:: ";
      outputMap["module"] = ".. module:: ";
      outputMap["module comment prefix"] = ":synopsis: ";
      outputMap["iter func"] = ".. iterfunction:: ";
      outputMap["iter method"] = ".. itermethod:: ";
      outputMap["func"] = ".. function:: ";
      outputMap["method"] = ".. method:: ";
      outputMap["config"] = ".. data:: ";
      outputMap["field"] = ".. attribute:: ";
    }

    // Open the directory to store the docs
    std::string folderName = (strlen(fDocsFolder) != 0) ? fDocsFolder : "docs";

    mkdir(folderName.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);

    forv_Vec(ModuleSymbol, mod, gModuleSymbols) {
      if (!devOnlyModule(mod) || developer) {
        std::string filename = mod->filename;

        if (mod->modTag == MOD_INTERNAL) {
          filename = "internal-modules/";
        } else if (mod ->modTag == MOD_STANDARD) {
          filename = "standard-modules/";
        } else {
          size_t location = filename.rfind("/");
          if (location != std::string::npos) {
            filename = filename.substr(0, location + 1);
          } else {
            filename = "";
          }
        }
        filename = folderName + "/" + filename;
        createDocsFileFolders(filename);

        if (isNotSubmodule(mod)) {
          // Creates files for each top level module
          if (!fDocsTextOnly)
            filename = filename + mod->name + ".rst";
          else
            filename = filename + mod->name + ".txt";
          std::ofstream file(filename.c_str(), std::ios::out);
          if (!fDocsTextOnly) {
            file << ".. default-domain:: chpl" << std::endl << std::endl;
          }
          printModule(&file, mod, mod->name);
          file.close();
        }
      }
    }
  }
}

bool isNotSubmodule(ModuleSymbol *mod) {
  return (mod->defPoint == NULL ||
          mod->defPoint->parentSymbol == NULL ||
          mod->defPoint->parentSymbol->name == NULL ||
          strcmp("chpl__Program", mod->defPoint->parentSymbol->name) == 0 ||
          strcmp("_root", mod->defPoint->parentSymbol->name) == 0);
}

void printIntent(std::ofstream *file, IntentTag intent) {
  switch(intent) {
  case INTENT_IN:
    *file << "in "; break;
  case INTENT_INOUT:
    *file << "inout "; break;
  case INTENT_OUT:
    *file << "out "; break;
  case INTENT_CONST:
    *file << "const "; break;
  case INTENT_CONST_IN:
    *file << "const in "; break;
  case INTENT_CONST_REF:
    *file << "const ref "; break;
  case INTENT_REF:
    *file << "ref "; break;
  case INTENT_PARAM:
    *file << "param "; break;
  default:
    break;
  }
}

void printArg(std::ofstream *file, ArgSymbol *arg) {
  printIntent(file, arg->intent);
  if (arg->hasFlag(FLAG_TYPE_VARIABLE)) {
    *file << "type ";
    // Because type intents are handled differently during parsing
  }

  *file << arg->name;
  if (arg->typeExpr != NULL) {
    *file << ": ";
    arg->typeExpr->body.tail->prettyPrint(file);
  } else if (arg->type != NULL && arg->type != dtAny) {
    *file << ": " << arg->type->symbol->name;
  }
}

void printFields(std::ofstream *file, AggregateType *cl) {
  for (int i = 1; i <= cl->fields.length; i++) {
    if (VarSymbol *var = toVarSymbol(((DefExpr *)cl->fields.get(i))->sym)) {
      if (!var->hasFlag(FLAG_SUPER_CLASS)) {
        printTabs(file);
        *file << outputMap["field"];
        // For rst, this will insert '.. attribute:: ' here
        // For plain text, nothing will be inserted
        printVarStart(file, var);
        Expr *expr;
        if (cl->isClass()) {
          expr = cl->defaultTypeConstructor->body->body.get(i);
        } else {
          expr = cl->defaultTypeConstructor->body->body.get(i+1);
        }
        if (CallExpr *list = toCallExpr(expr)) {
          if (CallExpr *end = toCallExpr(list->argList.tail)) {
            if (end->primitive != NULL) {
              *file << ": ";
              end->prettyPrint(file);
              // TODO: prettify type output
            } else if (SymExpr* sym = toSymExpr(end->argList.tail)) {
              *file << " = ";
              sym->prettyPrint(file);
            }
          }
        }

        *file << std::endl;
        printVarDocs(file, var);
      }
    }
  }
}

void inheritance(Vec<AggregateType*> *list, AggregateType *cl) {
  forv_Vec(Type, t, cl->dispatchParents) {
    if (AggregateType* c = toAggregateType(t)) {
      list->add_exclusive(c);
      inheritance(list, c);
    }
  }
}

void printClass(std::ofstream *file, AggregateType *cl) {
  if (! cl->isUnion()) {
    printTabs(file);

    // TODO: for rst, change convert to '.. class:: ' and '.. record:: '
    if (cl->isClass()) {
      *file << outputMap["class"];
    } else if (cl->isRecord()) {
      *file << outputMap["record"];
    }

    NUMTABS++;
    *file << cl->symbol->name << std::endl;
    if (cl->doc != NULL) {
      printTabs(file);
      *file << cl->doc << std::endl;
    }
    printFields(file, cl);
    // If alphabetical option passed, alphabetizes the output
    if (fDocsAlphabetize)
      qsort(cl->methods.v, cl->methods.n, sizeof(cl->methods.v[0]),
        compareNames);

    forv_Vec(FnSymbol, fn, cl->methods){
      printFunction(file, fn, true);
    }

    Vec<AggregateType*> list;
    inheritance(&list, cl);

    if (fDocsAlphabetize)
      qsort(list.v, list.n, sizeof(list.v[0]), compareClasses);

    forv_Vec(AggregateType, c, list) {
      printTabs(file);
      *file << "inherited from " << c->symbol->name;
      *file << std::endl;
      NUMTABS++;
      printFields(file, c);

      forv_Vec(FnSymbol, fn, c->methods) {
        printFunction(file, fn, true);

      }
      NUMTABS--;
      *file << std::endl;
    }
    NUMTABS--;
  }
}

void printVarStart(std::ofstream *file, VarSymbol *var) {
  // TODO: I need to get this to print type fields as type fields instead of
  // vars.
  if (var->isConstant())
    *file << "const ";
  else if (var->isParameter())
    *file << "param ";
  else
    *file << "var ";

  *file << var->name;
}

void printVarType(std::ofstream *file, VarSymbol *var) {
  if (var->defPoint->exprType != NULL) {
    *file << ": ";
    var->defPoint->exprType->prettyPrint(file);
    // TODO: Make type output prettier
  }
  *file << std::endl;
}

void printVarDocs(std::ofstream *file, VarSymbol *var) {
  // TODO: Do we want to parse the output here to make it indent nicely?
  NUMTABS++;
  if (var->doc != NULL) {
    printTabs(file);
    *file << var->doc;
    *file << std::endl;
  }
  NUMTABS--;
}

void printTabs(std::ofstream *file) {
  for (int i = 1; i <= NUMTABS; i++) {
    *file << "   ";
  }
}

// Returns true if the provided fn is a module initializer, class constructor,
// type constructor, or module copy of a class method.  These functions are
// only printed in developer mode.  Is not applicable to printing class
// functions.
bool devOnlyFunction(FnSymbol *fn) {
  return (fn->hasFlag(FLAG_MODULE_INIT) || fn->hasFlag(FLAG_TYPE_CONSTRUCTOR)
          || fn->hasFlag(FLAG_CONSTRUCTOR) || fn->hasFlag(FLAG_METHOD));
}

// Returns true if the provide module is one of the internal or standard
// modules. It is our opinion that these should only automatically be printed
// out if the user is in developer mode.
bool devOnlyModule(ModuleSymbol *mod) {
  return mod->modTag == MOD_INTERNAL || mod->modTag == MOD_STANDARD;
}

void printModule(std::ofstream *file, ModuleSymbol *mod, std::string name) {
  printTabs(file);
  *file << "Module: " << name << std::endl;
  if (!fDocsTextOnly) {
    int length = strlen("Module: ") + strlen(name.c_str());
    for (int i = 0; i < length; i++) {
      *file << "=";
    }
    *file << std::endl;
    // Make the length of this equal to "Module: " + name.length
  }
  NUMTABS++;
  if (mod->doc != NULL) {
    printTabs(file);
    *file << mod->doc << std::endl;
  }
  if(!fDocsTextOnly) {
    NUMTABS--;
    *file << outputMap["module"] << name << std::endl;
    if (mod->doc != NULL) {
      printTabs(file);
      *file << outputMap["module comment prefix"];
      *file << mod->doc << std::endl;
      *file << std::endl;
    }
  }

  Vec<VarSymbol*> configs = mod->getTopLevelConfigVars();
  if (fDocsAlphabetize)
    qsort(configs.v, configs.n, sizeof(configs.v[0]), compareNames);
  forv_Vec(VarSymbol, var, configs) {
    printTabs(file);
    *file << outputMap["config"];
    printVarStart(file, var);
    printVarType(file, var);
    printVarDocs(file, var);
  }

  Vec<FnSymbol*> fns = mod->getTopLevelFunctions(true);
  // If alphabetical option passed, fDocsAlphabetizes the output
  if (fDocsAlphabetize)
    qsort(fns.v, fns.n, sizeof(fns.v[0]), compareNames);

  forv_Vec(FnSymbol, fn, fns) {
    if (!devOnlyFunction(fn) || developer) {
      printFunction(file, fn, false);
    }
  }

  Vec<AggregateType*> classes = mod->getTopLevelClasses();
  if (fDocsAlphabetize)
    qsort(classes.v, classes.n, sizeof(classes.v[0]), compareClasses);

  forv_Vec(AggregateType, cl, classes) {
    printClass(file, cl);
  }

  Vec<ModuleSymbol*> mods = mod->getTopLevelModules();
  if (fDocsAlphabetize)
    qsort(mods.v, mods.n, sizeof(mods.v[0]), compareNames);

  forv_Vec(ModuleSymbol, md, mods) {
    if (!devOnlyModule(md) || developer)
      printModule(file, md, name + "." +  md->name);
  }
  if (fDocsTextOnly)
    NUMTABS--;
}

void printFunction(std::ofstream *file, FnSymbol *fn, bool method) {
  printTabs(file);
  NUMTABS++;
  bool iterator = fn->hasFlag(FLAG_ITERATOR_FN);
  if (method) {
    if (iterator) {
      *file << outputMap["iter method"];
    } else {
      *file << outputMap["method"];
    }
  } else {
    if (iterator) {
      *file << outputMap["iter func"];
    } else {
      *file << outputMap["func"];
    }
  }
  if (fn->hasFlag(FLAG_INLINE)) {
    *file << "inline ";
  } else if (fn->hasFlag(FLAG_EXPORT)) {
    *file << "export ";
  } else if (fn->hasFlag(FLAG_EXTERN)) {
    *file << "extern ";
  }

  if (iterator) {
    *file << "iter ";
  } else {
    *file << "proc ";
  }

  *file << fn->name << "(";
  if (fn->numFormals() > 0) {
    if (!developer && strcmp(fn->getFormal(1)->name, "_mt") == 0) {
      for (int i = 3; i < fn->numFormals(); i++) {
        ArgSymbol *cur = fn->getFormal(i);
        printArg(file, cur);
        *file << ", ";
      }
      if (fn->numFormals() != 2) {
        ArgSymbol *cur = fn->getFormal(fn->numFormals());
        printArg(file, cur);
      }
    } else {
      for (int i = 1; i < fn->numFormals(); i++) {
        ArgSymbol *cur = fn->getFormal(i);
        printArg(file, cur);
        *file << ", ";
      }
      ArgSymbol *cur = fn->getFormal(fn->numFormals());
      printArg(file, cur);
    }
  }
  *file << ")";
  switch (fn->retTag) {
  case RET_REF:
    *file << " ref"; break;
  case RET_PARAM:
    *file << " param"; break;
  case RET_TYPE:
    *file << " type"; break;
  default: break;
  }
  if (fn->retExprType != NULL) {
    *file << ": ";
    fn->retExprType->body.tail->prettyPrint(file);
    // TODO: better type output
  }
  *file << std::endl;

  if (fn->doc != NULL) {
    printTabs(file);
    *file << fn->doc << std::endl;
  }
  *file << std::endl;
  NUMTABS--;
}

void createDocsFileFolders(std::string filename) {
  size_t dirCutoff = filename.find("/");
  size_t total = 0;
  while (dirCutoff != std::string::npos) {
    // Creates each subdirectory within the new documentation directory
    dirCutoff += total;
    std::string shorter = filename.substr(dirCutoff+1);
    std::string otherHalf = filename.substr(0, dirCutoff);
    mkdir(otherHalf.c_str(), S_IWUSR|S_IRUSR|S_IXUSR);
    total = dirCutoff + 1;
    dirCutoff = shorter.find("/");
  }
}
<|endoftext|>


<commit_before>#pragma once

#include "base/internal/message.hpp"
#include "base/macros.hpp"

#include <exception>
#include <string>

class RootException : public std::exception
{
public:
  RootException(char const * what, std::string const & msg);

  virtual ~RootException() noexcept = default;

  std::string const & Msg() const { return m_msg; }

  // std::exception overrides:
  char const * what() const noexcept override { return m_whatWithAscii.c_str(); }

private:
  std::string m_whatWithAscii;
  std::string m_msg;
};

#define DECLARE_EXCEPTION(exception_name, base_exception) \
  class exception_name : public base_exception \
  { \
  public: \
    exception_name(char const * what, std::string const & msg) : base_exception(what, msg) {} \
  }

// TODO: Use SRC_LOGGING macro.
#define MYTHROW(exception_name, msg) throw exception_name( \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::base::Message msg)

#define MYTHROW1(exception_name, param1, msg) throw exception_name(param1, \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::base::Message msg)
<commit_msg>[base] All kinds of exceptions catcher.<commit_after>#pragma once

#include "base/internal/message.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"

#include <exception>
#include <string>

class RootException : public std::exception
{
public:
  RootException(char const * what, std::string const & msg);

  virtual ~RootException() noexcept = default;

  std::string const & Msg() const { return m_msg; }

  // std::exception overrides:
  char const * what() const noexcept override { return m_whatWithAscii.c_str(); }

private:
  std::string m_whatWithAscii;
  std::string m_msg;
};

template <typename Fn, typename... Args>
std::result_of_t<Fn && (Args && ...)> ExceptionCatcher(std::string const & comment, Fn && fn,
                                                       Args &&... args) noexcept
{
  try
  {
    return std::forward<Fn>(fn)(std::forward<Args>(args)...);
  }
  catch (RootException const & ex)
  {
    LOG(LWARNING, ("RootException.", comment, ex.Msg(), ex.what()));
  }
  catch (std::exception const & ex)
  {
    LOG(LWARNING, ("std::exception.", comment, ex.what()));
  }
  catch (...)
  {
    LOG(LWARNING, ("Unknown exception.", comment));
  }
  return {};
}

#define DECLARE_EXCEPTION(exception_name, base_exception) \
  class exception_name : public base_exception \
  { \
  public: \
    exception_name(char const * what, std::string const & msg) : base_exception(what, msg) {} \
  }

// TODO: Use SRC_LOGGING macro.
#define MYTHROW(exception_name, msg) throw exception_name( \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::base::Message msg)

#define MYTHROW1(exception_name, param1, msg) throw exception_name(param1, \
  #exception_name " " __FILE__ ":" TO_STRING(__LINE__), ::base::Message msg)
<|endoftext|>


<commit_before>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void matrixRedux(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols);

  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
  VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
  Scalar s(0), p(1), minc(ei_real(m1.coeff(0))), maxc(ei_real(m1.coeff(0)));
  for(int j = 0; j < cols; j++)
  for(int i = 0; i < rows; i++)
  {
    s += m1(i,j);
    p *= m1(i,j);
    minc = std::min(ei_real(minc), ei_real(m1(i,j)));
    maxc = std::max(ei_real(maxc), ei_real(m1(i,j)));
  }
  const Scalar mean = s/Scalar(RealScalar(rows*cols));

  VERIFY_IS_APPROX(m1.sum(), s);
  VERIFY_IS_APPROX(m1.mean(), mean);
  VERIFY_IS_APPROX(m1.prod(), p);
  VERIFY_IS_APPROX(m1.real().minCoeff(), ei_real(minc));
  VERIFY_IS_APPROX(m1.real().maxCoeff(), ei_real(maxc));

  // test slice vectorization assuming assign is ok
  Index r0 = ei_random<Index>(0,rows-1);
  Index c0 = ei_random<Index>(0,cols-1);
  Index r1 = ei_random<Index>(r0+1,rows)-r0;
  Index c1 = ei_random<Index>(c0+1,cols)-c0;
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).prod(), m1.block(r0,c0,r1,c1).eval().prod());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());
}

template<typename VectorType> void vectorRedux(const VectorType& w)
{
  typedef typename VectorType::Index Index;
  typedef typename VectorType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  Index size = w.size();

  VectorType v = VectorType::Random(size);
  for(int i = 1; i < size; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(0))), maxc(ei_real(v.coeff(0)));
    for(int j = 0; j < i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_APPROX(s, v.head(i).sum());
    VERIFY_IS_APPROX(p, v.head(i).prod());
    VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
  }

  for(int i = 0; i < size-1; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(i))), maxc(ei_real(v.coeff(i)));
    for(int j = i; j < size; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_APPROX(s, v.tail(size-i).sum());
    VERIFY_IS_APPROX(p, v.tail(size-i).prod());
    VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
  }

  for(int i = 0; i < size/2; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(i))), maxc(ei_real(v.coeff(i)));
    for(int j = i; j < size-i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_APPROX(s, v.segment(i, size-2*i).sum());
    VERIFY_IS_APPROX(p, v.segment(i, size-2*i).prod());
    VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
  }
}

void test_redux()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
    CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
    CALL_SUBTEST_2( matrixRedux(Array2f()) );
    CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
    CALL_SUBTEST_3( matrixRedux(Array4d()) );
    CALL_SUBTEST_4( matrixRedux(MatrixXcf(3, 3)) );
    CALL_SUBTEST_4( matrixRedux(ArrayXXcf(3, 3)) );
    CALL_SUBTEST_5( matrixRedux(MatrixXd(8, 12)) );
    CALL_SUBTEST_5( matrixRedux(ArrayXXd(8, 12)) );
    CALL_SUBTEST_6( matrixRedux(MatrixXi(8, 12)) );
    CALL_SUBTEST_6( matrixRedux(ArrayXXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_7( vectorRedux(Vector4f()) );
    CALL_SUBTEST_7( vectorRedux(Array4f()) );
    CALL_SUBTEST_5( vectorRedux(VectorXd(10)) );
    CALL_SUBTEST_5( vectorRedux(ArrayXd(10)) );
    CALL_SUBTEST_8( vectorRedux(VectorXf(33)) );
    CALL_SUBTEST_8( vectorRedux(ArrayXf(33)) );
  }
}
<commit_msg>Relaxed precision test.<commit_after>// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#include "main.h"

template<typename MatrixType> void matrixRedux(const MatrixType& m)
{
  typedef typename MatrixType::Index Index;
  typedef typename MatrixType::Scalar Scalar;
  typedef typename MatrixType::RealScalar RealScalar;

  Index rows = m.rows();
  Index cols = m.cols();

  MatrixType m1 = MatrixType::Random(rows, cols);

  VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows, cols).sum(), Scalar(1));
  VERIFY_IS_APPROX(MatrixType::Ones(rows, cols).sum(), Scalar(float(rows*cols))); // the float() here to shut up excessive MSVC warning about int->complex conversion being lossy
  Scalar s(0), p(1), minc(ei_real(m1.coeff(0))), maxc(ei_real(m1.coeff(0)));
  for(int j = 0; j < cols; j++)
  for(int i = 0; i < rows; i++)
  {
    s += m1(i,j);
    p *= m1(i,j);
    minc = std::min(ei_real(minc), ei_real(m1(i,j)));
    maxc = std::max(ei_real(maxc), ei_real(m1(i,j)));
  }
  const Scalar mean = s/Scalar(RealScalar(rows*cols));

  VERIFY_IS_APPROX(m1.sum(), s);
  VERIFY_IS_APPROX(m1.mean(), mean);
  VERIFY_IS_APPROX(m1.prod(), p);
  VERIFY_IS_APPROX(m1.real().minCoeff(), ei_real(minc));
  VERIFY_IS_APPROX(m1.real().maxCoeff(), ei_real(maxc));

  // test slice vectorization assuming assign is ok
  Index r0 = ei_random<Index>(0,rows-1);
  Index c0 = ei_random<Index>(0,cols-1);
  Index r1 = ei_random<Index>(r0+1,rows)-r0;
  Index c1 = ei_random<Index>(c0+1,cols)-c0;
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).sum(), m1.block(r0,c0,r1,c1).eval().sum());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).mean(), m1.block(r0,c0,r1,c1).eval().mean());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).prod(), m1.block(r0,c0,r1,c1).eval().prod());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().minCoeff(), m1.block(r0,c0,r1,c1).real().eval().minCoeff());
  VERIFY_IS_APPROX(m1.block(r0,c0,r1,c1).real().maxCoeff(), m1.block(r0,c0,r1,c1).real().eval().maxCoeff());
}

template<typename VectorType> void vectorRedux(const VectorType& w)
{
  typedef typename VectorType::Index Index;
  typedef typename VectorType::Scalar Scalar;
  typedef typename NumTraits<Scalar>::Real RealScalar;
  Index size = w.size();

  VectorType v = VectorType::Random(size);
  for(int i = 1; i < size; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(0))), maxc(ei_real(v.coeff(0)));
    for(int j = 0; j < i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_APPROX(s, v.head(i).sum());
    VERIFY_IS_APPROX(p, v.head(i).prod());
    VERIFY_IS_APPROX(minc, v.real().head(i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().head(i).maxCoeff());
  }

  for(int i = 0; i < size-1; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(i))), maxc(ei_real(v.coeff(i)));
    for(int j = i; j < size; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_MUCH_SMALLER_THAN(ei_abs(s - v.tail(size-i).sum()), Scalar(1));
    VERIFY_IS_APPROX(p, v.tail(size-i).prod());
    VERIFY_IS_APPROX(minc, v.real().tail(size-i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().tail(size-i).maxCoeff());
  }

  for(int i = 0; i < size/2; i++)
  {
    Scalar s(0), p(1);
    RealScalar minc(ei_real(v.coeff(i))), maxc(ei_real(v.coeff(i)));
    for(int j = i; j < size-i; j++)
    {
      s += v[j];
      p *= v[j];
      minc = std::min(minc, ei_real(v[j]));
      maxc = std::max(maxc, ei_real(v[j]));
    }
    VERIFY_IS_APPROX(s, v.segment(i, size-2*i).sum());
    VERIFY_IS_APPROX(p, v.segment(i, size-2*i).prod());
    VERIFY_IS_APPROX(minc, v.real().segment(i, size-2*i).minCoeff());
    VERIFY_IS_APPROX(maxc, v.real().segment(i, size-2*i).maxCoeff());
  }
}

void test_redux()
{
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_1( matrixRedux(Matrix<float, 1, 1>()) );
    CALL_SUBTEST_1( matrixRedux(Array<float, 1, 1>()) );
    CALL_SUBTEST_2( matrixRedux(Matrix2f()) );
    CALL_SUBTEST_2( matrixRedux(Array2f()) );
    CALL_SUBTEST_3( matrixRedux(Matrix4d()) );
    CALL_SUBTEST_3( matrixRedux(Array4d()) );
    CALL_SUBTEST_4( matrixRedux(MatrixXcf(3, 3)) );
    CALL_SUBTEST_4( matrixRedux(ArrayXXcf(3, 3)) );
    CALL_SUBTEST_5( matrixRedux(MatrixXd(8, 12)) );
    CALL_SUBTEST_5( matrixRedux(ArrayXXd(8, 12)) );
    CALL_SUBTEST_6( matrixRedux(MatrixXi(8, 12)) );
    CALL_SUBTEST_6( matrixRedux(ArrayXXi(8, 12)) );
  }
  for(int i = 0; i < g_repeat; i++) {
    CALL_SUBTEST_7( vectorRedux(Vector4f()) );
    CALL_SUBTEST_7( vectorRedux(Array4f()) );
    CALL_SUBTEST_5( vectorRedux(VectorXd(10)) );
    CALL_SUBTEST_5( vectorRedux(ArrayXd(10)) );
    CALL_SUBTEST_8( vectorRedux(VectorXf(33)) );
    CALL_SUBTEST_8( vectorRedux(ArrayXf(33)) );
  }
}
<|endoftext|>


<commit_before>#include "Path.hpp"

std::string Path::extractFileName(std::string const& path)
{
	auto lastSlashPos = path.find_last_of("\\/");
	auto lastDotPos = path.find_last_of(".");

	if (lastSlashPos == std::string::npos)
	{
		lastSlashPos = 0u;
	}
	else
	{
		lastSlashPos += 1;
	}
	if (lastDotPos == std::string::npos)
	{
		lastDotPos = path.size();
	}

	auto const extractSize = lastDotPos - lastSlashPos;

	return path.substr(lastSlashPos, extractSize);
}

std::string Path::extractFileNameWithExtension(std::string const& path)
{
	auto lastSlashPos = path.find_last_of("\\/");

	if (lastSlashPos == std::string::npos)
	{
		lastSlashPos = 0u;
	}
	else
	{
		lastSlashPos += 1;
	}
	return path.substr(lastSlashPos);
}

std::string Path::extractExtension(std::string const& path)
{
	auto lastDotPos = path.find_last_of(".");

	if (lastDotPos != std::string::npos)
	{
		lastDotPos += 1;
	}
	return path.substr(lastDotPos);
}
<commit_msg>[Recorder]: fixed crash when the file selected does not have extension.<commit_after>#include "Path.hpp"

#include <iostream>

std::string Path::extractFileName(std::string const& path)
{
	auto lastSlashPos = path.find_last_of("\\/");
	auto lastDotPos = path.find_last_of(".");

	if (lastSlashPos == std::string::npos)
	{
		lastSlashPos = 0u;
	}
	else
	{
		lastSlashPos += 1;
	}
	if (lastDotPos == std::string::npos)
	{
		lastDotPos = path.size();
	}

	auto const extractSize = lastDotPos - lastSlashPos;

	return path.substr(lastSlashPos, extractSize);
}

std::string Path::extractFileNameWithExtension(std::string const& path)
{
	auto lastSlashPos = path.find_last_of("\\/");

	if (lastSlashPos == std::string::npos)
	{
		lastSlashPos = 0u;
	}
	else
	{
		lastSlashPos += 1;
	}
	return path.substr(lastSlashPos);
}

std::string Path::extractExtension(std::string const& path)
{
	auto lastDotPos = path.find_last_of(".");

	if (lastDotPos != std::string::npos)
	{
		lastDotPos += 1;
	}
	else
	{
		lastDotPos = path.size();
	}
	return path.substr(lastDotPos);
}
<|endoftext|>


<commit_before>#include <Complex_t.hpp>
#include <catch.hpp>

SCENARIO("def constructor")
{
	Complex_t complex;
	REQUIRE(complex.a_() == 0);
	REQUIRE(complex.b_() == 0);
}

SCENARIO("param constructor")
{
	Complex_t complex(1, 2);
	REQUIRE(complex.a_() == 1);
	REQUIRE(complex.b_() == 2);
}

SCENARIO("copy constructor")
{
	Complex_t complex(1, 2);
	Complex_t copy(complex);
	REQUIRE(copy.a_() == 1);
	REQUIRE(copy.b_() == 2);
}

SCENARIO("operator *")
{
	Complex_t c1(3, 2);
	Complex_t c2(5, 4);
	Complex_t c3(15, 8);
	REQUIRE((c1*c2) == c3);
}

SCENARIO("operator /")
{
	Complex_t c1(4, 5);
	Complex_t c2(4, 5);
	Complex_t c3(1, 0);
	REQUIRE((c1 / c2) == c3);
}

SCENARIO("operator +=")
{
	Complex_t c1(11, 1);
	Complex_t c2(8, 3);
	Complex_t c3(19, 4);
	REQUIRE((c1 += c2) == c3);
}

SCENARIO("operator -=")
{
	Complex_t c1(6, 10);
	Complex_t c2(3, 6);
	Complex_t c3(3, 4);
	REQUIRE((c1 -= c2) == c3);
}

SCENARIO("operator *=")
{
	Complex_t c1(7, 6);
	Complex_t c2(5, 4);
	Complex_t c3(11, 58);
	REQUIRE((c1 *= c2) == c3);
}

SCENARIO("operator /=")
{
	Complex_t c1(2, 1);
	Complex_t c2(2, 1);
	Complex_t c3(1, 0);
	REQUIRE((c1 /= c2) == c3);
}

SCENARIO("operator =")
{
	Complex_t c1(5, 7);
	Complex_t c2 = c1;
	REQUIRE(c2 == c1);
}

SCENARIO("operator ==")
{
	Complex_t c1(2, 5);
	Complex_t c2(2, 5);
	REQUIRE(c1 == c2);
}
<commit_msg>Update init.cpp<commit_after>#include <Complex_t.hpp>
#include <catch.hpp>
SCENARIO("def constructor")
{
	Complex_t complex;
	REQUIRE(complex.a_() == 0);
	REQUIRE(complex.b_() == 0);
}

SCENARIO("param constructor")
{
	Complex_t complex(1, 2);
	REQUIRE(complex.a_() == 1);
	REQUIRE(complex.b_() == 2);
}

SCENARIO("copy constructor")
{
	Complex_t complex(1, 2);
	Complex_t copy(complex);
	REQUIRE(copy.a_() == 1);
	REQUIRE(copy.b_() == 2);
}

SCENARIO("operator *")
{
	Complex_t c1(3, 2);
	Complex_t c2(5, 4);
	Complex_t c3(15, 8);
	REQUIRE((c1*c2) == c3);
}

SCENARIO("operator /")
{
	Complex_t c1(4, 5);
	Complex_t c2(4, 5);
	Complex_t c3(1, 0);
	REQUIRE((c1 / c2) == c3);
}

SCENARIO("operator +=")
{
	Complex_t c1(11, 1);
	Complex_t c2(8, 3);
	Complex_t c3(19, 4);
	REQUIRE((c1 += c2) == c3);
}

SCENARIO("operator -=")
{
	Complex_t c1(6, 10);
	Complex_t c2(3, 6);
	Complex_t c3(3, 4);
	REQUIRE((c1 -= c2) == c3);
}

SCENARIO("operator *=")
{
	Complex_t c1(7, 6);
	Complex_t c2(5, 4);
	Complex_t c3(11, 58);
	REQUIRE((c1 *= c2) == c3);
}

SCENARIO("operator /=")
{
	Complex_t c1(2, 1);
	Complex_t c2(2, 1);
	Complex_t c3(1, 0);
	REQUIRE((c1 /= c2) == c3);
}

SCENARIO("operator =")
{
	Complex_t c1(5, 7);
	Complex_t c2 = c1;
	REQUIRE(c2 == c1);
}

SCENARIO("operator ==")
{
	Complex_t c1(2, 5);
	Complex_t c2(2, 5);
	REQUIRE(c1 == c2);
}
<|endoftext|>


<commit_before>#include <bst.h>
#include <catch.hpp>

SCENARIO ("init", "[init]")
{
  BST<int> test;
  REQUIRE(test.root_() == nullptr);
  REQUIRE(test.get_count() == 0);
}
SCENARIO("insert node", "[ins]")
{
  BST<int> test;
  test.insert_node(7);
  REQUIRE(test.get_count() == 1);
  REQUIRE(test.find_node(7, test.root_())->_key == 7);
}
SCENARIO("find node", "[find]")
{
  BST<int> test;
  test.insert_node(2);
  REQUIRE(test.find_node(2, test.root_()) != nullptr);
  REQUIRE(test.find_node(2, test.root_())->_key == 2);
}
SCENARIO("get root", "[root]")
{
  BST<int> test;
  test.insert_node(4);
  REQUIRE(test.root_() != 0);
}
SCENARIO ("reading/writing", "[init]")
{
  BST<int> test1;
  test1.insert_node(1);
  test1.insert_node(2);
  test1.writing("file1.txt");
  BST<int> test2;
  test2.reading("file2.txt");
  REQUIRE(test2.find_node(1, test2.root_())!= nullptr);
  REQUIRE(test2.find_node(2, test2.root_())!= nullptr);
  REQUIRE(test1.get_count() == test2.get_count());
}
SCENARIO("delete", "[del]")
{
  BST<int> test;
  test.insert_node(6);
  test.insert_node(7);
  test.insert_node(8);
  test.delete_val(6);
  test.delete_val(8);
  REQUIRE(test.find_node(8, test.root_())== nullptr);
  REQUIRE(test.find_node(7, test.root_())== test.root_());
  REQUIRE(test.root_() != nullptr);
  REQUIRE(test.get_count() == 1);
}
<commit_msg>Create init.cpp<commit_after>#include <bst.h>
#include <catch.hpp>

SCENARIO ("init", "[init]")
{
  BST<int> test;
  REQUIRE(test.root_() == nullptr);
  REQUIRE(test.get_count() == 0);
}
SCENARIO("insert node", "[ins]")
{
  BST<int> test;
  test.insert_node(7);
  REQUIRE(test.get_count() == 1);
  REQUIRE(test.find_node(7, test.root_())->_key == 7);
}
SCENARIO("find node", "[find]")
{
  BST<int> test;
  test.insert_node(2);
  REQUIRE(test.find_node(2, test.root_()) != nullptr);
  REQUIRE(test.find_node(2, test.root_())->_key == 2);
}
SCENARIO("get root", "[root]")
{
  BST<int> test;
  test.insert_node(4);
  REQUIRE(test.root_() != 0);
}
SCENARIO ("reading/writing", "[r/wr]")
{
  BST<int> test1;
  test1.insert_node(1);
  test1.insert_node(2);
  test1.writing("file.txt");
  BST<int> test2;
  test2.reading("file.txt");
  REQUIRE(test2.find_node(1, test2.root_())!= nullptr);
  REQUIRE(test2.find_node(2, test2.root_())!= nullptr);
  REQUIRE(test1.get_count() == test2.get_count());
}
SCENARIO("delete", "[del]")
{
  BST<int> test;
  test.insert_node(6);
  test.insert_node(7);
  test.insert_node(8);
  test.delete_val(6);
  test.delete_val(8);
  REQUIRE(test.find_node(8, test.root_())== nullptr);
  REQUIRE(test.find_node(7, test.root_())== test.root_());
  REQUIRE(test.root_() != nullptr);
  REQUIRE(test.get_count() == 1);
}
<|endoftext|>


<commit_before>#include <matrix.hpp>
#include <catch.hpp>

SCENARIO("copy constructor")

{

	Matrix matrix;

	Matrix copy(matrix);

	REQUIRE(copy.strings() == 2);

	REQUIRE(copy.columns() == 2);

}

SCENARIO("operator +")

{
	Matrix matrix (2, 2);

	Matrix matrix2 (2, 2);

	Matrix matrix3 (2, 2);
	std::ifstream("matrix.txt") >> matrix 1;
	std::ifstream("matrix2.txt") >> matrix 2;
	std::ifstream("sum.txt") >> matrix 3;

	REQUIRE(matrix1 + matrix2 == matrix3);

}

SCENARIO("operator *")

{

	Matrix matrix (2,2);
	Matrix matrix2 (2,2);
	Matrix matrix3 (2,2);
	std::ifstream("matrix.txt") >> matrix 1;
	std::ifstream("matrix2.txt") >> matrix 2;
	std::ifstream("multi.txt") >> matrix 3;

	REQUIRE(matrix1 * matrix2 == matrix3);

}

SCENARIO("operator =")

{

	Matrix matrix (2,2);

	Matrix matrix2 = matrix;

	REQUIRE(matrix == matrix2);

}

SCENARIO("operator ==")
{

	Matrix matrix (2,2);

	Matrix matrix2 (2,2);

	REQUIRE(matrix == matrix2);

}

<commit_msg>Update init.cpp<commit_after>#include <matrix.hpp>
#include <catch.hpp>

SCENARIO("copy constructor")

{

	Matrix matrix;

	Matrix copy(matrix);

	REQUIRE(copy.strings() == 2);

	REQUIRE(copy.columns() == 2);

}

SCENARIO("operator +")

{
	Matrix matrix (2, 2);

	Matrix matrix2 (2, 2);

	Matrix matrix3 (2, 2);
	std::istream("matrix.txt") >> matrix 1;
	std::istream("matrix2.txt") >> matrix 2;
	std::istream("sum.txt") >> matrix 3;

	REQUIRE(matrix1 + matrix2 == matrix3);

}

SCENARIO("operator *")

{

	Matrix matrix (2,2);
	Matrix matrix2 (2,2);
	Matrix matrix3 (2,2);
	std::istream("matrix.txt") >> matrix 1;
	std::istream("matrix2.txt") >> matrix 2;
	std::istream("multi.txt") >> matrix 3;

	REQUIRE(matrix1 * matrix2 == matrix3);

}

SCENARIO("operator =")

{

	Matrix matrix (2,2);

	Matrix matrix2 = matrix;

	REQUIRE(matrix == matrix2);

}

SCENARIO("operator ==")
{

	Matrix matrix (2,2);

	Matrix matrix2 (2,2);

	REQUIRE(matrix == matrix2);

}

<|endoftext|>


<commit_before>#include <binary_search_tree.hpp>
#include <catch.hpp>

SCENARIO("default constructor")
{
	BinarySearchTree<int> bst;
	REQUIRE(bst.root() == nullptr);
}

SCENARIO("insertElement")
{
	BinarySearchTree<int> bst;
	bst.insert(7);
	REQUIRE(bst.value_() == 7);
	REQUIRE(bst.leftNode_() == nullptr);
	REQUIRE(bst.rightNode_() == nullptr);
}

SCENARIO("findElement")
{
	BinarySearchTree<int> bst;
	bst.insert(7);
	REQUIRE(bst.isFound(7) == 1);
}

SCENARIO("infile")
{
	BinarySearchTree<int> bst;
	bst.infile("file.txt");
	REQUIRE(bst.count_(bst.root()) == 0);
}

SCENARIO("count_")
{
	BinarySearchTree<int> bst;
	int count = 0;
	bst.insert(7);
	count = bst.count_(bst.root ());
	REQUIRE(count == 1);
}
<commit_msg>Update init.cpp<commit_after>#include <binary_search_tree.hpp>
#include <catch.hpp>

SCENARIO("default constructor")
{
	BinarySearchTree<int> bst;
	REQUIRE(bst.root() == nullptr);
}

SCENARIO("insertElement")
{
	BinarySearchTree<int> bst;
	bst.insert(7);
	REQUIRE(bst.value_() == 7);
	REQUIRE(bst.leftNode_() == nullptr);
	REQUIRE(bst.rightNode_() == nullptr);
}

SCENARIO("findElement")
{
	BinarySearchTree<int> bst;
	bst.insert(7);
	REQUIRE(bst.isFound(7) == 1);
}

SCENARIO("infile")
{
	BinarySearchTree<int> bst;
	bst.infile("file.txt");
	REQUIRE(bst.count_(bst.root()) == 0);
}

SCENARIO("count_")
{
	BinarySearchTree<int> bst;
	int count = 0;
	bst.insert(7);
	count = bst.count_(bst.root ());
	REQUIRE(count == 1);
}

SCENARIO("deleteNode")
{
	BinarySearchTree<int> bst;
	int size1, size2, size3, size4;
	tree.insert(5);
	tree.insert(3);
	tree.insert(2);
	tree.insert(4);
	tree.insert(7);
	tree.insert(6);
	tree.insert(8);
	size1 = bst.count_(bst.root ());
	tree.deleteNode(8);
	size2 = bst.count_(bst.root ());
	tree.deleteNode(7);
	size3 = bst.count_(bst.root ());
	tree.deleteNode(3);
	size4 = bst.count_(bst.root ());
	REQUIRE(size1 == 7);
	REQUIRE(size2 == 6);
	REQUIRE(size3 == 5);
	REQUIRE(size4 == 4);
}
<|endoftext|>


<commit_before>#include <BST.hpp>
#include <catch.hpp>
#include <fstream>

SCENARIO ("init", "[init]")

{

  Tree<int> test;

  REQUIRE(test.getroot() == nullptr);
  REQUIRE(test.getcount() == 0);

}

SCENARIO("insert", "[init]")

{

  Tree<int> test;

  test.add(10);

  REQUIRE(test.find_node(5, test.getroot()) == true);

}

SCENARIO("find_node", "[init]")

{

  Tree<int> test;

  test.add(10);

  REQUIRE(test.find_node(10, test.getroot()) != nullptr);

  REQUIRE(test.find_node(10, test.getroot()) == true);

}

SCENARIO("get root", "[init]")

{

  Tree<int> test;

  test.add(10);

  REQUIRE(test.getcount() == 1);

  REQUIRE(test.getroot() != 0);

}

SCENARIO ("read/write", "[init]")

{

    Tree<int> test1;
    test1.read("File1.txt");
    bool isCatched = false;

  try
    {
      test1.write("File2.txt");
    }

    catch(bool isCatched)
    {
      isCatched = true;
      throw std::logic_error ("Error.");
    }

  REQUIRE(isCatched == false);

  Tree<int> test2;

  test2.read("File2.txt");

  REQUIRE(test1.getcount() == test2.getcount());

}

SCENARIO("deleteX")

{

  Tree<int> test;

  test.add(1);

  test.add(2);

  test.add(3);

  test.del(1);

  test.del(2);

  REQUIRE(test.find_node(1, test.getroot())== false);
  REQUIRE(test.find_node(2, test.getroot())== false);

  REQUIRE(test.find_node(3, test.getroot())== true);

  REQUIRE(test.getcount() == 1);

}

<commit_msg>Update init.cpp<commit_after>#include <BST.hpp>
#include <catch.hpp>
#include <fstream>

SCENARIO ("init", "[init]")

{

  BST<int> test;

  REQUIRE(test.getroot() == nullptr);
  REQUIRE(test.getcount() == 0);

}

SCENARIO("insert", "[init]")

{

  BST<int> test;

  test.add(10);

  REQUIRE(test.find_node(5, test.getroot()) == true);

}

SCENARIO("find_node", "[init]")

{

  BST<int> test;

  test.add(10);

  REQUIRE(test.find_node(10, test.getroot()) != nullptr);

  REQUIRE(test.find_node(10, test.getroot()) == true);

}

SCENARIO("get root", "[init]")

{

  BST<int> test;

  test.add(10);

  REQUIRE(test.getcount() == 1);

  REQUIRE(test.getroot() != 0);

}

SCENARIO ("read/write", "[init]")

{

    BST<int> test1;
    test1.read("File1.txt");
    bool isCatched = false;

  try
    {
      test1.write("File2.txt");
    }

    catch(bool isCatched)
    {
      isCatched = true;
      throw std::logic_error ("Error.");
    }

  REQUIRE(isCatched == false);

  BST<int> test2;

  test2.read("File2.txt");

  REQUIRE(test1.getcount() == test2.getcount());

}

SCENARIO("deleteX")

{

  BST<int> test;

  test.add(1);

  test.add(2);

  test.add(3);

  test.del(1);

  test.del(2);

  REQUIRE(test.find_node(1, test.getroot())== false);
  REQUIRE(test.find_node(2, test.getroot())== false);

  REQUIRE(test.find_node(3, test.getroot())== true);

  REQUIRE(test.getcount() == 1);

}

<|endoftext|>


<commit_before>#include <complex_t.hpp>
#include <catch.hpp>

SCENARIO("default constructor") {
	complex_t complex;
	REQUIRE(complex.real_() == 0);
	REQUIRE(complex.imaginary_() == 0);
}

SCENARIO("constructor with params") {
	complex_t complex(1, 2);
	REQUIRE(complex.real_() == 1);
	REQUIRE(complex.imaginary_() == 2);
}

SCENARIO("copy constructor") {
	complex_t complex(1, 2);
	complex_t copy(complex);
	REQUIRE(copy.real_() == 1);
	REQUIRE(copy.imaginary_() == 2);
}

SCENARIO("operator *") {
	complex_t c1(7, 6);
	complex_t c2(5, 4);
	complex_t c3(11, 58);
	REQUIRE((c1*c2)==c3);
}

SCENARIO("operator /") {
	complex_t c1(7, 6);
	complex_t c2(7, 6);
	complex_t c3(1, 0);
	REQUIRE((c1/c2)==c3);
}

SCENARIO("operator +=") {
	complex_t c1(13, 1);
	complex_t c2(7, 6);
	complex_t c3(20, 7);
	REQUIRE((c1+=c2)==c3);
}

SCENARIO("operator -=") {
	complex_t c1(13, 10);
	complex_t c2(7, 6);
	complex_t c3(6, 4);
	REQUIRE((c1-=c2)==c3);
}

SCENARIO("operator *=") {
	complex_t c1(7, 6);
	complex_t c2(5, 4);
	complex_t c3(11, 58);
	REQUIRE((c1*=c2)==c3);
}

SCENARIO("operator /=") {
	complex_t c1(7, 6);
	complex_t c2(7, 6);
	complex_t c3(1, 0);
	REQUIRE((c1/=c2)==c3);
}

SCENARIO("operator =") {
	complex_t c1(7, 6);
	complex_t c2=c1;
	REQUIRE(c2==c1);
}

SCENARIO("operator ==") {
	complex_t c1(7, 6);
	complex_t c2(7, 6);
	REQUIRE(c1==c2);
}
<commit_msg>Update init.cpp<commit_after>#include <binary_search_tree.hpp>
#include <catch.hpp>

SCENARIO("default constructor") {
	Node<int> node;
	REQUIRE(node.root() == nullptr);
	REQUIRE(complex.count() == 0);
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * XPLC - Cross-Platform Lightweight Components
 * Copyright (C) 2000, Pierre Phaneuf
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <stdio.h>
#include "test.h"

int main(int argc, char* argv[]) {
  printf("%s: ", argv[0]);

  if(test())
    printf("pass\n");
  else
    printf("FAIL\n");

  return 0;
}

<commit_msg>Small modification in the output of the testing main(), to allow for test code that generates output.<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 *
 * XPLC - Cross-Platform Lightweight Components
 * Copyright (C) 2000, Pierre Phaneuf
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public License
 * as published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-1307, USA.
 */

#include <stdio.h>
#include "test.h"

int main(int argc, char* argv[]) {
  if(test())
    printf("%s passed\n", argv[0]);
  else
    printf("%s FAILED\n", argv[0]);

  return 0;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <err.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#if defined(__APPLE__)
#	include <OpenGL/gl.h>
#	include <GLUT/glut.h>
#else
#	include <GL/gl.h>
#	include <GL/glut.h>
#endif

#include <vector>
#include <map>

#include <glosm/geomath.h>

#include <glosm/Math.hh>

#include <glosm/SphericalProjection.hh>
#include <glosm/MercatorProjection.hh>
#include <glosm/PreloadedXmlDatasource.hh>
#include <glosm/DefaultGeometryGenerator.hh>
#include <glosm/FirstPersonViewer.hh>
#include <glosm/GeometryLayer.hh>

/* as glut has no OO concept and no feature like setUserData,
 * please forgive me using global variables pointing to
 * stack data for now */
FirstPersonViewer viewer;
GeometryLayer* layer_p = NULL;

int screenw = 1;
int screenh = 1;
int movementflags = 0;
float speed = 200.0f;
int lockheight = 0;

struct timeval prevtime, curtime, fpstime;
int nframes = 0;

/* stuff that may eb changed with args */
Projection proj = MercatorProjection();
int tilelevel = -1;

void Display(void) {
	/* update scene */
	gettimeofday(&curtime, NULL);
	float dt = (float)(curtime.tv_sec - prevtime.tv_sec) + (float)(curtime.tv_usec - prevtime.tv_usec)/1000000.0f;

	/* render frame */
	glClearColor(0.5, 0.5, 0.5, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (layer_p) {
		if (tilelevel >= 0) {
			int radius = 5000000;
			layer_p->RequestVisible(BBoxi(viewer.GetPos(MercatorProjection()) - Vector2i(radius, radius), viewer.GetPos(MercatorProjection()) + Vector2i(radius, radius)), 0);
			layer_p->GarbageCollect();
		}
		layer_p->Render(viewer);
	}

	glFlush();
	glutSwapBuffers();

	/* movement */
	if (movementflags) {
		float myspeed = speed;
		float height = viewer.MutablePos().z / GEOM_UNITSINMETER;

		/* don't scale down under 100 meters */
		if (height > 100.0)
			myspeed *= height / 100.0;

		viewer.Move(movementflags, myspeed, dt);
	}
	if (lockheight != 0)
		viewer.MutablePos().z = lockheight;

	/* update FPS */
	float fpst = (float)(curtime.tv_sec - fpstime.tv_sec) + (float)(curtime.tv_usec - fpstime.tv_usec)/1000000.0f;

	if (fpst > 10.0) {
		fprintf(stderr, "FPS: %.3f\n", (float)nframes/fpst);
		fpstime = curtime;
		nframes = 0;
	}

	prevtime = curtime;
	nframes++;

	/* frame limiter */
	usleep(10000);
}

void Reshape(int w, int h) {
	if (w <= 0)
		w = 1;
	if (h <= 0)
		h = 1;

	screenw = w;
	screenh = h;

	float wanted_fov = 70.0f/180.0f*M_PI;
	float wanted_aspect = 4.0f/3.0f;

	float fov, aspect;

	if ((float)w/(float)h > wanted_aspect) { // wider than wanted
		fov = wanted_fov;
	} else { // narrower than wanted
		float wanted_h = (float)w/wanted_aspect;
		fov = 2.0f*atanf((float)h / wanted_h * tanf(wanted_fov/2.0f));
	}
	fov = wanted_fov;
	aspect = (float)w/(float)h;

	glViewport(0, 0, w, h);

	viewer.SetFov(fov);
	viewer.SetAspect(aspect);

	glutWarpPointer(screenw/2, screenh/2);
}

void Mouse(int x, int y) {
	int dx = x - screenw/2;
	int dy = y - screenh/2;

	float YawDelta = (float)dx / 500.0;
	float PitchDelta = -(float)dy / 500.0;

	viewer.HardRotate(YawDelta, PitchDelta);

	if (dx != 0 || dy != 0)
		glutWarpPointer(screenw/2, screenh/2);
}

void SpecialDown(int key, int, int) {
	switch (key) {
	case GLUT_KEY_UP: movementflags |= FirstPersonViewer::FORWARD; break;
	case GLUT_KEY_DOWN: movementflags |= FirstPersonViewer::BACKWARD; break;
	case GLUT_KEY_LEFT: movementflags |= FirstPersonViewer::LEFT; break;
	case GLUT_KEY_RIGHT: movementflags |= FirstPersonViewer::RIGHT; break;
	default:
		break;
	}
}

void SpecialUp(int key, int, int) {
	switch (key) {
	case GLUT_KEY_UP: movementflags &= ~FirstPersonViewer::FORWARD; break;
	case GLUT_KEY_DOWN: movementflags &= ~FirstPersonViewer::BACKWARD; break;
	case GLUT_KEY_LEFT: movementflags &= ~FirstPersonViewer::LEFT; break;
	case GLUT_KEY_RIGHT: movementflags &= ~FirstPersonViewer::RIGHT; break;
	default:
		break;
	}
}

void KeyDown(unsigned char key, int, int) {
	switch (key) {
	case 27: case 'q': exit(0); break;
	case 'w': movementflags |= FirstPersonViewer::FORWARD; break;
	case 's': movementflags |= FirstPersonViewer::BACKWARD; break;
	case 'a': movementflags |= FirstPersonViewer::LEFT; break;
	case 'd': movementflags |= FirstPersonViewer::RIGHT; break;
	case 'c': movementflags |= FirstPersonViewer::LOWER; break;
	case ' ': movementflags |= FirstPersonViewer::HIGHER; break;
	case 'l': lockheight = (lockheight == 0 ? viewer.MutablePos().z : 0); break;
	case 'h': lockheight = (lockheight == 0 ? 1750 : 0); break;
	case '+': speed *= 5.0f; break;
	case '-': speed /= 5.0f; break;
	default:
		break;
	}
}

void KeyUp(unsigned char key, int, int) {
	switch (key) {
	case 'w': movementflags &= ~FirstPersonViewer::FORWARD; break;
	case 's': movementflags &= ~FirstPersonViewer::BACKWARD; break;
	case 'a': movementflags &= ~FirstPersonViewer::LEFT; break;
	case 'd': movementflags &= ~FirstPersonViewer::RIGHT; break;
	case 'c': movementflags &= ~FirstPersonViewer::LOWER; break;
	case ' ': movementflags &= ~FirstPersonViewer::HIGHER; break;
	default:
		break;
	}
}

void usage(const char* progname) {
	fprintf(stderr, "Usage: %s [-s] file.osm\n", progname);
	exit(1);
}

int real_main(int argc, char** argv) {
	glutInit(&argc, argv);

	/* argument parsing */
	int c;
	const char* progname = argv[0];
	while ((c = getopt(argc, argv, "st:")) != -1) {
		switch (c) {
		case 's': proj = SphericalProjection(); break;
		case 't': tilelevel = strtol(optarg, NULL, 10); break;
		default:
			usage(progname);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage(progname);

	/* load data */
	fprintf(stderr, "Loading...\n");
	PreloadedXmlDatasource osm_datasource;
	gettimeofday(&prevtime, NULL);
	osm_datasource.Load(argv[0]);
	gettimeofday(&curtime, NULL);
	fprintf(stderr, "Loaded XML in %.3f seconds\n", (float)(curtime.tv_sec - prevtime.tv_sec) + (float)(curtime.tv_usec - prevtime.tv_usec)/1000000.0f);
	prevtime = curtime;
	fpstime = curtime;

	/* glut init */
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
	glutInitWindowSize(800, 600);
	glutCreateWindow("glosm viewer");

	glutIgnoreKeyRepeat(1);
	glutSetCursor(GLUT_CURSOR_NONE);

	glutDisplayFunc(Display);
	glutIdleFunc(Display);
	glutReshapeFunc(Reshape);
	glutPassiveMotionFunc(Mouse);
	glutKeyboardFunc(KeyDown);
	glutKeyboardUpFunc(KeyUp);
	glutSpecialFunc(SpecialDown);
	glutSpecialUpFunc(SpecialUp);

	/* glosm init */
	DefaultGeometryGenerator geometry_generator(osm_datasource);
	GeometryLayer layer(proj, geometry_generator);
	if (tilelevel >= 0)
		layer.SetTargetLevel(tilelevel);
	else
		layer.RequestVisible(geometry_generator.GetBBox(), TileManager::EXPLICIT);
	layer_p = &layer;

	int height = fabs((float)geometry_generator.GetBBox().top - (float)geometry_generator.GetBBox().bottom) / GEOM_LONSPAN * WGS84_EARTH_EQ_LENGTH * GEOM_UNITSINMETER / 10.0;
	viewer.SetPos(Vector3i(geometry_generator.GetCenter(), height));

	/* main loop */
	/* note that this never returns and objects created above
	 * are never properly destroyed; should dump GLUT ASAP */
	glutMainLoop();

	return 0;
}

int main(int argc, char** argv) {
	try {
		return real_main(argc, argv);
	} catch (std::exception &e) {
		fprintf(stderr, "Exception: %s\n", e.what());
	} catch (...) {
		fprintf(stderr, "Unknown exception\n");
	}

	return 1;
}
<commit_msg>Initialize viewer looking 45° down to avoid user confusion<commit_after>/*
 * Copyright (C) 2010-2011 Dmitry Marakasov
 *
 * This file is part of glosm.
 *
 * glosm is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * glosm is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with glosm.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <err.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

#if defined(__APPLE__)
#	include <OpenGL/gl.h>
#	include <GLUT/glut.h>
#else
#	include <GL/gl.h>
#	include <GL/glut.h>
#endif

#include <vector>
#include <map>

#include <glosm/geomath.h>

#include <glosm/Math.hh>

#include <glosm/SphericalProjection.hh>
#include <glosm/MercatorProjection.hh>
#include <glosm/PreloadedXmlDatasource.hh>
#include <glosm/DefaultGeometryGenerator.hh>
#include <glosm/FirstPersonViewer.hh>
#include <glosm/GeometryLayer.hh>

/* as glut has no OO concept and no feature like setUserData,
 * please forgive me using global variables pointing to
 * stack data for now */
FirstPersonViewer viewer;
GeometryLayer* layer_p = NULL;

int screenw = 1;
int screenh = 1;
int movementflags = 0;
float speed = 200.0f;
int lockheight = 0;

struct timeval prevtime, curtime, fpstime;
int nframes = 0;

/* stuff that may eb changed with args */
Projection proj = MercatorProjection();
int tilelevel = -1;

void Display(void) {
	/* update scene */
	gettimeofday(&curtime, NULL);
	float dt = (float)(curtime.tv_sec - prevtime.tv_sec) + (float)(curtime.tv_usec - prevtime.tv_usec)/1000000.0f;

	/* render frame */
	glClearColor(0.5, 0.5, 0.5, 0.0);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	if (layer_p) {
		if (tilelevel >= 0) {
			int radius = 5000000;
			layer_p->RequestVisible(BBoxi(viewer.GetPos(MercatorProjection()) - Vector2i(radius, radius), viewer.GetPos(MercatorProjection()) + Vector2i(radius, radius)), 0);
			layer_p->GarbageCollect();
		}
		layer_p->Render(viewer);
	}

	glFlush();
	glutSwapBuffers();

	/* movement */
	if (movementflags) {
		float myspeed = speed;
		float height = viewer.MutablePos().z / GEOM_UNITSINMETER;

		/* don't scale down under 100 meters */
		if (height > 100.0)
			myspeed *= height / 100.0;

		viewer.Move(movementflags, myspeed, dt);
	}
	if (lockheight != 0)
		viewer.MutablePos().z = lockheight;

	/* update FPS */
	float fpst = (float)(curtime.tv_sec - fpstime.tv_sec) + (float)(curtime.tv_usec - fpstime.tv_usec)/1000000.0f;

	if (fpst > 10.0) {
		fprintf(stderr, "FPS: %.3f\n", (float)nframes/fpst);
		fpstime = curtime;
		nframes = 0;
	}

	prevtime = curtime;
	nframes++;

	/* frame limiter */
	usleep(10000);
}

void Reshape(int w, int h) {
	if (w <= 0)
		w = 1;
	if (h <= 0)
		h = 1;

	screenw = w;
	screenh = h;

	float wanted_fov = 70.0f/180.0f*M_PI;
	float wanted_aspect = 4.0f/3.0f;

	float fov, aspect;

	if ((float)w/(float)h > wanted_aspect) { // wider than wanted
		fov = wanted_fov;
	} else { // narrower than wanted
		float wanted_h = (float)w/wanted_aspect;
		fov = 2.0f*atanf((float)h / wanted_h * tanf(wanted_fov/2.0f));
	}
	fov = wanted_fov;
	aspect = (float)w/(float)h;

	glViewport(0, 0, w, h);

	viewer.SetFov(fov);
	viewer.SetAspect(aspect);

	glutWarpPointer(screenw/2, screenh/2);
}

void Mouse(int x, int y) {
	int dx = x - screenw/2;
	int dy = y - screenh/2;

	float YawDelta = (float)dx / 500.0;
	float PitchDelta = -(float)dy / 500.0;

	viewer.HardRotate(YawDelta, PitchDelta);

	if (dx != 0 || dy != 0)
		glutWarpPointer(screenw/2, screenh/2);
}

void SpecialDown(int key, int, int) {
	switch (key) {
	case GLUT_KEY_UP: movementflags |= FirstPersonViewer::FORWARD; break;
	case GLUT_KEY_DOWN: movementflags |= FirstPersonViewer::BACKWARD; break;
	case GLUT_KEY_LEFT: movementflags |= FirstPersonViewer::LEFT; break;
	case GLUT_KEY_RIGHT: movementflags |= FirstPersonViewer::RIGHT; break;
	default:
		break;
	}
}

void SpecialUp(int key, int, int) {
	switch (key) {
	case GLUT_KEY_UP: movementflags &= ~FirstPersonViewer::FORWARD; break;
	case GLUT_KEY_DOWN: movementflags &= ~FirstPersonViewer::BACKWARD; break;
	case GLUT_KEY_LEFT: movementflags &= ~FirstPersonViewer::LEFT; break;
	case GLUT_KEY_RIGHT: movementflags &= ~FirstPersonViewer::RIGHT; break;
	default:
		break;
	}
}

void KeyDown(unsigned char key, int, int) {
	switch (key) {
	case 27: case 'q': exit(0); break;
	case 'w': movementflags |= FirstPersonViewer::FORWARD; break;
	case 's': movementflags |= FirstPersonViewer::BACKWARD; break;
	case 'a': movementflags |= FirstPersonViewer::LEFT; break;
	case 'd': movementflags |= FirstPersonViewer::RIGHT; break;
	case 'c': movementflags |= FirstPersonViewer::LOWER; break;
	case ' ': movementflags |= FirstPersonViewer::HIGHER; break;
	case 'l': lockheight = (lockheight == 0 ? viewer.MutablePos().z : 0); break;
	case 'h': lockheight = (lockheight == 0 ? 1750 : 0); break;
	case '+': speed *= 5.0f; break;
	case '-': speed /= 5.0f; break;
	default:
		break;
	}
}

void KeyUp(unsigned char key, int, int) {
	switch (key) {
	case 'w': movementflags &= ~FirstPersonViewer::FORWARD; break;
	case 's': movementflags &= ~FirstPersonViewer::BACKWARD; break;
	case 'a': movementflags &= ~FirstPersonViewer::LEFT; break;
	case 'd': movementflags &= ~FirstPersonViewer::RIGHT; break;
	case 'c': movementflags &= ~FirstPersonViewer::LOWER; break;
	case ' ': movementflags &= ~FirstPersonViewer::HIGHER; break;
	default:
		break;
	}
}

void usage(const char* progname) {
	fprintf(stderr, "Usage: %s [-s] file.osm\n", progname);
	exit(1);
}

int real_main(int argc, char** argv) {
	glutInit(&argc, argv);

	/* argument parsing */
	int c;
	const char* progname = argv[0];
	while ((c = getopt(argc, argv, "st:")) != -1) {
		switch (c) {
		case 's': proj = SphericalProjection(); break;
		case 't': tilelevel = strtol(optarg, NULL, 10); break;
		default:
			usage(progname);
		}
	}

	argc -= optind;
	argv += optind;

	if (argc != 1)
		usage(progname);

	/* load data */
	fprintf(stderr, "Loading...\n");
	PreloadedXmlDatasource osm_datasource;
	gettimeofday(&prevtime, NULL);
	osm_datasource.Load(argv[0]);
	gettimeofday(&curtime, NULL);
	fprintf(stderr, "Loaded XML in %.3f seconds\n", (float)(curtime.tv_sec - prevtime.tv_sec) + (float)(curtime.tv_usec - prevtime.tv_usec)/1000000.0f);
	prevtime = curtime;
	fpstime = curtime;

	/* glut init */
	glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA | GLUT_MULTISAMPLE);
	glutInitWindowSize(800, 600);
	glutCreateWindow("glosm viewer");

	glutIgnoreKeyRepeat(1);
	glutSetCursor(GLUT_CURSOR_NONE);

	glutDisplayFunc(Display);
	glutIdleFunc(Display);
	glutReshapeFunc(Reshape);
	glutPassiveMotionFunc(Mouse);
	glutKeyboardFunc(KeyDown);
	glutKeyboardUpFunc(KeyUp);
	glutSpecialFunc(SpecialDown);
	glutSpecialUpFunc(SpecialUp);

	/* glosm init */
	DefaultGeometryGenerator geometry_generator(osm_datasource);
	GeometryLayer layer(proj, geometry_generator);
	if (tilelevel >= 0)
		layer.SetTargetLevel(tilelevel);
	else
		layer.RequestVisible(geometry_generator.GetBBox(), TileManager::EXPLICIT);
	layer_p = &layer;

	int height = fabs((float)geometry_generator.GetBBox().top - (float)geometry_generator.GetBBox().bottom) / GEOM_LONSPAN * WGS84_EARTH_EQ_LENGTH * GEOM_UNITSINMETER / 10.0;
	viewer.SetPos(Vector3i(geometry_generator.GetCenter(), height));
	viewer.HardRotate(0, -M_PI_4);

	/* main loop */
	/* note that this never returns and objects created above
	 * are never properly destroyed; should dump GLUT ASAP */
	glutMainLoop();

	return 0;
}

int main(int argc, char** argv) {
	try {
		return real_main(argc, argv);
	} catch (std::exception &e) {
		fprintf(stderr, "Exception: %s\n", e.what());
	} catch (...) {
		fprintf(stderr, "Unknown exception\n");
	}

	return 1;
}
<|endoftext|>