<commit_before>//===--- Immediate.cpp - the swift immediate mode -------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the implementation of the swift interpreter, which takes a
// source file and JITs it.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-immediate"
#include "swift/Immediate/Immediate.h"
#include "ImmediateImpl.h"

#include "swift/Subsystems.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Module.h"
#include "swift/Frontend/Frontend.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Support/Path.h"

#include <dlfcn.h>

using namespace swift;
using namespace swift::immediate;

static bool loadRuntimeLib(StringRef sharedLibName, StringRef runtimeLibPath) {
  // FIXME: Need error-checking.
  llvm::SmallString<128> Path = runtimeLibPath;
  llvm::sys::path::append(Path, sharedLibName);
  return dlopen(Path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
}

bool swift::immediate::loadSwiftRuntime(StringRef runtimeLibPath) {
  return loadRuntimeLib("libswiftCore" LTDL_SHLIB_EXT, runtimeLibPath);
}

static bool tryLoadLibrary(LinkLibrary linkLib,
                           SearchPathOptions searchPathOpts) {
  llvm::SmallString<128> path = linkLib.getName();

  // If we have an absolute or relative path, just try to load it now.
  if (llvm::sys::path::has_parent_path(path.str())) {
    return dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
  }

  bool success = false;
  switch (linkLib.getKind()) {
  case LibraryKind::Library: {
    llvm::SmallString<32> stem;
    if (llvm::sys::path::has_extension(path.str())) {
      stem = std::move(path);
    } else {
      // FIXME: Try the appropriate extension for the current platform?
      stem = "lib";
      stem += path;
      stem += LTDL_SHLIB_EXT;
    }

    // Try user-provided library search paths first.
    for (auto &libDir : searchPathOpts.LibrarySearchPaths) {
      path = libDir;
      llvm::sys::path::append(path, stem.str());
      success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
      if (success)
        break;
    }

    // Let dlopen determine the best search paths.
    if (!success)
      success = dlopen(stem.c_str(), RTLD_LAZY | RTLD_GLOBAL);

    // If that fails, try our runtime library path.
    if (!success)
      success = loadRuntimeLib(stem, searchPathOpts.RuntimeLibraryPath);
    break;
  }
  case LibraryKind::Framework: {
    // If we have a framework, mangle the name to point to the framework
    // binary.
    llvm::SmallString<64> frameworkPart{std::move(path)};
    frameworkPart += ".framework";
    llvm::sys::path::append(frameworkPart, linkLib.getName());

    // Try user-provided framework search paths first; frameworks contain
    // binaries as well as modules.
    for (auto &frameworkDir : searchPathOpts.FrameworkSearchPaths) {
      path = frameworkDir;
      llvm::sys::path::append(path, frameworkPart.str());
      success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
      if (success)
        break;
    }

    // If that fails, let dlopen search for system frameworks.
    if (!success)
      success = dlopen(frameworkPart.c_str(), RTLD_LAZY | RTLD_GLOBAL);
    break;
  }
  }

  return success;
}

bool swift::immediate::tryLoadLibraries(ArrayRef<LinkLibrary> LinkLibraries,
                                        SearchPathOptions SearchPathOpts,
                                        DiagnosticEngine &Diags) {
  SmallVector<bool, 4> LoadedLibraries;
  LoadedLibraries.append(LinkLibraries.size(), false);

  // Libraries are not sorted in the topological order of dependencies, and we
  // don't know the dependencies in advance.  Try to load all libraries until
  // we stop making progress.
  bool HadProgress;
  do {
    HadProgress = false;
    for (unsigned i = 0; i != LinkLibraries.size(); ++i) {
      if (!LoadedLibraries[i] &&
          tryLoadLibrary(LinkLibraries[i], SearchPathOpts)) {
        LoadedLibraries[i] = true;
        HadProgress = true;
      }
    }
  } while (HadProgress);

  return std::all_of(LoadedLibraries.begin(), LoadedLibraries.end(),
                     [](bool Value) { return Value; });
}

static void linkerDiagnosticHandlerNoCtx(const llvm::DiagnosticInfo &DI) {
  if (DI.getSeverity() != llvm::DS_Error)
    return;

  std::string MsgStorage;
  {
    llvm::raw_string_ostream Stream(MsgStorage);
    llvm::DiagnosticPrinterRawOStream DP(Stream);
    DI.print(DP);
  }
  llvm::errs() << "Error linking swift modules\n";
  llvm::errs() << MsgStorage << "\n";
}

static void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI,
                                    void *Context) {
  // This assert self documents our precondition that Context is always
  // nullptr. It seems that parts of LLVM are using the flexibility of having a
  // context. We don't really care about this.
  assert(Context == nullptr && "We assume Context is always a nullptr");

  return linkerDiagnosticHandlerNoCtx(DI);
}

bool swift::immediate::linkLLVMModules(llvm::Module *Module,
                                       std::unique_ptr<llvm::Module> SubModule
                            // TODO: reactivate the linker mode if it is
                            // supported in llvm again. Otherwise remove the
                            // commented code completely.
                            /*, llvm::Linker::LinkerMode LinkerMode */)
{
  llvm::LLVMContext &Ctx = SubModule->getContext();
  auto OldHandler = Ctx.getDiagnosticHandler();
  void *OldDiagnosticContext = Ctx.getDiagnosticContext();
  Ctx.setDiagnosticHandler(linkerDiagnosticHandler, nullptr);
                              // TODO: reactivate the linker mode if it is
                              // supported in llvm again. Otherwise remove the
                              // commented code completely.
  bool Failed = llvm::Linker::linkModules(*Module, std::move(SubModule),
                                          linkerDiagnosticHandlerNoCtx
                                          /*, LinkerMode*/);
  Ctx.setDiagnosticHandler(OldHandler, OldDiagnosticContext);

  return !Failed;
}

bool swift::immediate::IRGenImportedModules(
    CompilerInstance &CI,
    llvm::Module &Module,
    llvm::SmallPtrSet<swift::Module *, 8> &ImportedModules,
    SmallVectorImpl<llvm::Function*> &InitFns,
    IRGenOptions &IRGenOpts,
    const SILOptions &SILOpts) {
  swift::Module *M = CI.getMainModule();

  // Perform autolinking.
  SmallVector<LinkLibrary, 4> AllLinkLibraries(IRGenOpts.LinkLibraries);
  auto addLinkLibrary = [&](LinkLibrary linkLib) {
    AllLinkLibraries.push_back(linkLib);
  };

  M->forAllVisibleModules({}, /*includePrivateTopLevel=*/true,
                          [&](Module::ImportedModule import) {
    import.second->collectLinkLibraries(addLinkLibrary);
  });

  // Hack to handle thunks eagerly synthesized by the Clang importer.
  swift::Module *prev = nullptr;
  for (auto external : CI.getASTContext().ExternalDefinitions) {
    swift::Module *next = external->getModuleContext();
    if (next == prev)
      continue;
    next->collectLinkLibraries(addLinkLibrary);
    prev = next;
  }

  tryLoadLibraries(AllLinkLibraries, CI.getASTContext().SearchPathOpts,
                   CI.getDiags());

  ImportedModules.insert(M);
  if (!CI.hasSourceImport())
    return false;

  // IRGen the modules this module depends on. This is only really necessary
  // for imported source, but that's a very convenient thing to do in -i mode.
  // FIXME: Crawling all loaded modules is a hack.
  // FIXME: And re-doing SILGen, SIL-linking, SIL diagnostics, and IRGen is
  // expensive, because it's not properly being limited to new things right now.
  bool hadError = false;
  for (auto &entry : CI.getASTContext().LoadedModules) {
    swift::Module *import = entry.second;
    if (!ImportedModules.insert(import).second)
      continue;

    std::unique_ptr<SILModule> SILMod = performSILGeneration(import,
                                                             CI.getSILOptions());
    performSILLinking(SILMod.get());
    if (runSILDiagnosticPasses(*SILMod)) {
      hadError = true;
      break;
    }

    // FIXME: We shouldn't need to use the global context here, but
    // something is persisting across calls to performIRGeneration.
    auto SubModule = performIRGeneration(IRGenOpts, import, SILMod.get(),
                                         import->getName().str(),
                                         llvm::getGlobalContext());

    if (CI.getASTContext().hadError()) {
      hadError = true;
      break;
    }

    if (!linkLLVMModules(&Module, std::move(SubModule)
                         // TODO: reactivate the linker mode if it is
                         // supported in llvm again. Otherwise remove the
                         // commented code completely.
                         /*, llvm::Linker::DestroySource */)) {
      hadError = true;
      break;
    }

    // FIXME: This is an ugly hack; need to figure out how this should
    // actually work.
    SmallVector<char, 20> NameBuf;
    StringRef InitFnName = (import->getName().str() + ".init").toStringRef(NameBuf);
    llvm::Function *InitFn = Module.getFunction(InitFnName);
    if (InitFn)
      InitFns.push_back(InitFn);
  }

  return hadError;
}

int swift::RunImmediately(CompilerInstance &CI, const ProcessCmdLine &CmdLine,
                          IRGenOptions &IRGenOpts, const SILOptions &SILOpts) {
  ASTContext &Context = CI.getASTContext();

  // IRGen the main module.
  auto *swiftModule = CI.getMainModule();
  // FIXME: We shouldn't need to use the global context here, but
  // something is persisting across calls to performIRGeneration.
  auto ModuleOwner = performIRGeneration(
      IRGenOpts, swiftModule, CI.getSILModule(), swiftModule->getName().str(),
      llvm::getGlobalContext());
  auto *Module = ModuleOwner.get();

  if (Context.hadError())
    return -1;

  SmallVector<llvm::Function*, 8> InitFns;
  llvm::SmallPtrSet<swift::Module *, 8> ImportedModules;
  if (IRGenImportedModules(CI, *Module, ImportedModules, InitFns,
                           IRGenOpts, SILOpts))
    return -1;

  llvm::PassManagerBuilder PMBuilder;
  PMBuilder.OptLevel = 2;
  PMBuilder.Inliner = llvm::createFunctionInliningPass(200);

  if (!loadSwiftRuntime(Context.SearchPathOpts.RuntimeLibraryPath)) {
    CI.getDiags().diagnose(SourceLoc(),
                           diag::error_immediate_mode_missing_stdlib);
    return -1;
  }

  // Build the ExecutionEngine.
  llvm::EngineBuilder builder(std::move(ModuleOwner));
  std::string ErrorMsg;
  llvm::TargetOptions TargetOpt;
  std::string CPU;
  std::vector<std::string> Features;
  std::tie(TargetOpt, CPU, Features)
    = getIRTargetOptions(IRGenOpts, swiftModule->getASTContext());
  builder.setRelocationModel(llvm::Reloc::PIC_);
  builder.setTargetOptions(TargetOpt);
  builder.setMCPU(CPU);
  builder.setMAttrs(Features);
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  llvm::ExecutionEngine *EE = builder.create();
  if (!EE) {
    llvm::errs() << "Error loading JIT: " << ErrorMsg;
    return -1;
  }

  DEBUG(llvm::dbgs() << "Module to be executed:\n";
        Module->dump());

  EE->finalizeObject();

  // Run the generated program.
  for (auto InitFn : InitFns) {
    DEBUG(llvm::dbgs() << "Running initialization function "
            << InitFn->getName() << '\n');
    EE->runFunctionAsMain(InitFn, CmdLine, 0);
  }

  DEBUG(llvm::dbgs() << "Running static constructors\n");
  EE->runStaticConstructorsDestructors(false);
  DEBUG(llvm::dbgs() << "Running main\n");
  llvm::Function *EntryFn = Module->getFunction("main");
  return EE->runFunctionAsMain(EntryFn, CmdLine, 0);
}
<commit_msg>[upstream-update] llvm::Linker::linkModules no longer needs a NoCtx diagnostic handler. It always gets it from the llvm context.<commit_after>//===--- Immediate.cpp - the swift immediate mode -------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This is the implementation of the swift interpreter, which takes a
// source file and JITs it.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "swift-immediate"
#include "swift/Immediate/Immediate.h"
#include "ImmediateImpl.h"

#include "swift/Subsystems.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/DiagnosticsFrontend.h"
#include "swift/AST/IRGenOptions.h"
#include "swift/AST/Module.h"
#include "swift/Frontend/Frontend.h"
#include "swift/SILOptimizer/PassManager/Passes.h"
#include "swift/Basic/LLVM.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/ExecutionEngine/MCJIT.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Linker/Linker.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Support/Path.h"

#include <dlfcn.h>

using namespace swift;
using namespace swift::immediate;

static bool loadRuntimeLib(StringRef sharedLibName, StringRef runtimeLibPath) {
  // FIXME: Need error-checking.
  llvm::SmallString<128> Path = runtimeLibPath;
  llvm::sys::path::append(Path, sharedLibName);
  return dlopen(Path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
}

bool swift::immediate::loadSwiftRuntime(StringRef runtimeLibPath) {
  return loadRuntimeLib("libswiftCore" LTDL_SHLIB_EXT, runtimeLibPath);
}

static bool tryLoadLibrary(LinkLibrary linkLib,
                           SearchPathOptions searchPathOpts) {
  llvm::SmallString<128> path = linkLib.getName();

  // If we have an absolute or relative path, just try to load it now.
  if (llvm::sys::path::has_parent_path(path.str())) {
    return dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
  }

  bool success = false;
  switch (linkLib.getKind()) {
  case LibraryKind::Library: {
    llvm::SmallString<32> stem;
    if (llvm::sys::path::has_extension(path.str())) {
      stem = std::move(path);
    } else {
      // FIXME: Try the appropriate extension for the current platform?
      stem = "lib";
      stem += path;
      stem += LTDL_SHLIB_EXT;
    }

    // Try user-provided library search paths first.
    for (auto &libDir : searchPathOpts.LibrarySearchPaths) {
      path = libDir;
      llvm::sys::path::append(path, stem.str());
      success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
      if (success)
        break;
    }

    // Let dlopen determine the best search paths.
    if (!success)
      success = dlopen(stem.c_str(), RTLD_LAZY | RTLD_GLOBAL);

    // If that fails, try our runtime library path.
    if (!success)
      success = loadRuntimeLib(stem, searchPathOpts.RuntimeLibraryPath);
    break;
  }
  case LibraryKind::Framework: {
    // If we have a framework, mangle the name to point to the framework
    // binary.
    llvm::SmallString<64> frameworkPart{std::move(path)};
    frameworkPart += ".framework";
    llvm::sys::path::append(frameworkPart, linkLib.getName());

    // Try user-provided framework search paths first; frameworks contain
    // binaries as well as modules.
    for (auto &frameworkDir : searchPathOpts.FrameworkSearchPaths) {
      path = frameworkDir;
      llvm::sys::path::append(path, frameworkPart.str());
      success = dlopen(path.c_str(), RTLD_LAZY | RTLD_GLOBAL);
      if (success)
        break;
    }

    // If that fails, let dlopen search for system frameworks.
    if (!success)
      success = dlopen(frameworkPart.c_str(), RTLD_LAZY | RTLD_GLOBAL);
    break;
  }
  }

  return success;
}

bool swift::immediate::tryLoadLibraries(ArrayRef<LinkLibrary> LinkLibraries,
                                        SearchPathOptions SearchPathOpts,
                                        DiagnosticEngine &Diags) {
  SmallVector<bool, 4> LoadedLibraries;
  LoadedLibraries.append(LinkLibraries.size(), false);

  // Libraries are not sorted in the topological order of dependencies, and we
  // don't know the dependencies in advance.  Try to load all libraries until
  // we stop making progress.
  bool HadProgress;
  do {
    HadProgress = false;
    for (unsigned i = 0; i != LinkLibraries.size(); ++i) {
      if (!LoadedLibraries[i] &&
          tryLoadLibrary(LinkLibraries[i], SearchPathOpts)) {
        LoadedLibraries[i] = true;
        HadProgress = true;
      }
    }
  } while (HadProgress);

  return std::all_of(LoadedLibraries.begin(), LoadedLibraries.end(),
                     [](bool Value) { return Value; });
}

static void linkerDiagnosticHandlerNoCtx(const llvm::DiagnosticInfo &DI) {
  if (DI.getSeverity() != llvm::DS_Error)
    return;

  std::string MsgStorage;
  {
    llvm::raw_string_ostream Stream(MsgStorage);
    llvm::DiagnosticPrinterRawOStream DP(Stream);
    DI.print(DP);
  }
  llvm::errs() << "Error linking swift modules\n";
  llvm::errs() << MsgStorage << "\n";
}

static void linkerDiagnosticHandler(const llvm::DiagnosticInfo &DI,
                                    void *Context) {
  // This assert self documents our precondition that Context is always
  // nullptr. It seems that parts of LLVM are using the flexibility of having a
  // context. We don't really care about this.
  assert(Context == nullptr && "We assume Context is always a nullptr");

  return linkerDiagnosticHandlerNoCtx(DI);
}

bool swift::immediate::linkLLVMModules(llvm::Module *Module,
                                       std::unique_ptr<llvm::Module> SubModule
                            // TODO: reactivate the linker mode if it is
                            // supported in llvm again. Otherwise remove the
                            // commented code completely.
                            /*, llvm::Linker::LinkerMode LinkerMode */)
{
  llvm::LLVMContext &Ctx = SubModule->getContext();
  auto OldHandler = Ctx.getDiagnosticHandler();
  void *OldDiagnosticContext = Ctx.getDiagnosticContext();
  Ctx.setDiagnosticHandler(linkerDiagnosticHandler, nullptr);
  bool Failed = llvm::Linker::linkModules(*Module, std::move(SubModule));
  Ctx.setDiagnosticHandler(OldHandler, OldDiagnosticContext);

  return !Failed;
}

bool swift::immediate::IRGenImportedModules(
    CompilerInstance &CI,
    llvm::Module &Module,
    llvm::SmallPtrSet<swift::Module *, 8> &ImportedModules,
    SmallVectorImpl<llvm::Function*> &InitFns,
    IRGenOptions &IRGenOpts,
    const SILOptions &SILOpts) {
  swift::Module *M = CI.getMainModule();

  // Perform autolinking.
  SmallVector<LinkLibrary, 4> AllLinkLibraries(IRGenOpts.LinkLibraries);
  auto addLinkLibrary = [&](LinkLibrary linkLib) {
    AllLinkLibraries.push_back(linkLib);
  };

  M->forAllVisibleModules({}, /*includePrivateTopLevel=*/true,
                          [&](Module::ImportedModule import) {
    import.second->collectLinkLibraries(addLinkLibrary);
  });

  // Hack to handle thunks eagerly synthesized by the Clang importer.
  swift::Module *prev = nullptr;
  for (auto external : CI.getASTContext().ExternalDefinitions) {
    swift::Module *next = external->getModuleContext();
    if (next == prev)
      continue;
    next->collectLinkLibraries(addLinkLibrary);
    prev = next;
  }

  tryLoadLibraries(AllLinkLibraries, CI.getASTContext().SearchPathOpts,
                   CI.getDiags());

  ImportedModules.insert(M);
  if (!CI.hasSourceImport())
    return false;

  // IRGen the modules this module depends on. This is only really necessary
  // for imported source, but that's a very convenient thing to do in -i mode.
  // FIXME: Crawling all loaded modules is a hack.
  // FIXME: And re-doing SILGen, SIL-linking, SIL diagnostics, and IRGen is
  // expensive, because it's not properly being limited to new things right now.
  bool hadError = false;
  for (auto &entry : CI.getASTContext().LoadedModules) {
    swift::Module *import = entry.second;
    if (!ImportedModules.insert(import).second)
      continue;

    std::unique_ptr<SILModule> SILMod = performSILGeneration(import,
                                                             CI.getSILOptions());
    performSILLinking(SILMod.get());
    if (runSILDiagnosticPasses(*SILMod)) {
      hadError = true;
      break;
    }

    // FIXME: We shouldn't need to use the global context here, but
    // something is persisting across calls to performIRGeneration.
    auto SubModule = performIRGeneration(IRGenOpts, import, SILMod.get(),
                                         import->getName().str(),
                                         llvm::getGlobalContext());

    if (CI.getASTContext().hadError()) {
      hadError = true;
      break;
    }

    if (!linkLLVMModules(&Module, std::move(SubModule)
                         // TODO: reactivate the linker mode if it is
                         // supported in llvm again. Otherwise remove the
                         // commented code completely.
                         /*, llvm::Linker::DestroySource */)) {
      hadError = true;
      break;
    }

    // FIXME: This is an ugly hack; need to figure out how this should
    // actually work.
    SmallVector<char, 20> NameBuf;
    StringRef InitFnName = (import->getName().str() + ".init").toStringRef(NameBuf);
    llvm::Function *InitFn = Module.getFunction(InitFnName);
    if (InitFn)
      InitFns.push_back(InitFn);
  }

  return hadError;
}

int swift::RunImmediately(CompilerInstance &CI, const ProcessCmdLine &CmdLine,
                          IRGenOptions &IRGenOpts, const SILOptions &SILOpts) {
  ASTContext &Context = CI.getASTContext();

  // IRGen the main module.
  auto *swiftModule = CI.getMainModule();
  // FIXME: We shouldn't need to use the global context here, but
  // something is persisting across calls to performIRGeneration.
  auto ModuleOwner = performIRGeneration(
      IRGenOpts, swiftModule, CI.getSILModule(), swiftModule->getName().str(),
      llvm::getGlobalContext());
  auto *Module = ModuleOwner.get();

  if (Context.hadError())
    return -1;

  SmallVector<llvm::Function*, 8> InitFns;
  llvm::SmallPtrSet<swift::Module *, 8> ImportedModules;
  if (IRGenImportedModules(CI, *Module, ImportedModules, InitFns,
                           IRGenOpts, SILOpts))
    return -1;

  llvm::PassManagerBuilder PMBuilder;
  PMBuilder.OptLevel = 2;
  PMBuilder.Inliner = llvm::createFunctionInliningPass(200);

  if (!loadSwiftRuntime(Context.SearchPathOpts.RuntimeLibraryPath)) {
    CI.getDiags().diagnose(SourceLoc(),
                           diag::error_immediate_mode_missing_stdlib);
    return -1;
  }

  // Build the ExecutionEngine.
  llvm::EngineBuilder builder(std::move(ModuleOwner));
  std::string ErrorMsg;
  llvm::TargetOptions TargetOpt;
  std::string CPU;
  std::vector<std::string> Features;
  std::tie(TargetOpt, CPU, Features)
    = getIRTargetOptions(IRGenOpts, swiftModule->getASTContext());
  builder.setRelocationModel(llvm::Reloc::PIC_);
  builder.setTargetOptions(TargetOpt);
  builder.setMCPU(CPU);
  builder.setMAttrs(Features);
  builder.setErrorStr(&ErrorMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  llvm::ExecutionEngine *EE = builder.create();
  if (!EE) {
    llvm::errs() << "Error loading JIT: " << ErrorMsg;
    return -1;
  }

  DEBUG(llvm::dbgs() << "Module to be executed:\n";
        Module->dump());

  EE->finalizeObject();

  // Run the generated program.
  for (auto InitFn : InitFns) {
    DEBUG(llvm::dbgs() << "Running initialization function "
            << InitFn->getName() << '\n');
    EE->runFunctionAsMain(InitFn, CmdLine, 0);
  }

  DEBUG(llvm::dbgs() << "Running static constructors\n");
  EE->runStaticConstructorsDestructors(false);
  DEBUG(llvm::dbgs() << "Running main\n");
  llvm::Function *EntryFn = Module->getFunction("main");
  return EE->runFunctionAsMain(EntryFn, CmdLine, 0);
}
<|endoftext|>


<commit_before>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786 )
#endif

#include "common.h"

// interface header
#include "WorldFileObject.h"

// system headers
#include <string.h>
#include <iostream>
#include <vector>

WorldFileObject::WorldFileObject()
{
  name = "";
}

bool WorldFileObject::read(const char *cmd, std::istream& input)
{
  if (strcasecmp(cmd, "name") == 0) {
    input >> name;
    return true;
  }
  return false;
}

void WorldFileObject::writeToWorld(WorldInfo*) const
{
  std::cout << "ERROR: writeToWorld() called improperly" << std::endl;
  return;
}

void WorldFileObject::writeToManager() const
{
  std::cout << "ERROR: writeToManager() called improperly" << std::endl;
  return;
}

void WorldFileObject::writeToGroupDef(GroupDefinition*) const
{
  std::cout << "ERROR: writeToGroupDef() called improperly" << std::endl;
  return;
}

/** delete all of the world file objects from a vector list
 */

void emptyWorldFileObjectList(std::vector<WorldFileObject*>& wlist)
{
  const int n = wlist.size();
  for (int i = 0; i < n; ++i) {
    delete wlist[i];
  }
  wlist.clear();
}

// Local variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>undo removal of <string> include<commit_after>/* bzflag
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning( 4: 4786 )
#endif

#include "common.h"

// interface header
#include "WorldFileObject.h"

// system headers
#include <string>
#include <string.h>
#include <iostream>
#include <vector>

WorldFileObject::WorldFileObject()
{
  name = "";
}

bool WorldFileObject::read(const char *cmd, std::istream& input)
{
  if (strcasecmp(cmd, "name") == 0) {
    input >> name;
    return true;
  }
  return false;
}

void WorldFileObject::writeToWorld(WorldInfo*) const
{
  std::cout << "ERROR: writeToWorld() called improperly" << std::endl;
  return;
}

void WorldFileObject::writeToManager() const
{
  std::cout << "ERROR: writeToManager() called improperly" << std::endl;
  return;
}

void WorldFileObject::writeToGroupDef(GroupDefinition*) const
{
  std::cout << "ERROR: writeToGroupDef() called improperly" << std::endl;
  return;
}

/** delete all of the world file objects from a vector list
 */

void emptyWorldFileObjectList(std::vector<WorldFileObject*>& wlist)
{
  const int n = wlist.size();
  for (int i = 0; i < n; ++i) {
    delete wlist[i];
  }
  wlist.clear();
}

// Local variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>#include <algorithm>
#include <cstring>
#include <limits>
#include <memory>

#include <android/log.h>

#include <boost/format.hpp>
#include <boost/utility.hpp>

#include <tbb/blocked_range2d.h>
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_init.h>

#include "body_parts_recognizer.h"
#include "rgbd_image.h"
#include "sources.h"
#include "stopwatch.h"

const Depth BACKGROUND_DEPTH = std::numeric_limits<Depth>::max();

struct DepthImage
{
private:

  unsigned width, height;
  std::vector<Depth> depths;

public:

  DepthImage(const RGBDImage & image)
    : width(image.width), height(image.height), depths(width * height)
  {
    for (std::size_t i = 0; i < depths.size(); ++i)
      depths[i] = image.pixels[i].d == 0 ? BACKGROUND_DEPTH : image.pixels[i].d; // we consider 0 to be invalid depth
  }

  void
  applyThreshold(int threshold)
  {
    Depth min_depth = *std::min_element(depths.begin (), depths.end ());

    for (std::size_t i = 0; i < depths.size (); ++i)
      depths[i] = depths[i] <= min_depth + threshold ? depths[i] : BACKGROUND_DEPTH;
  }

  Depth
  getDepth(int x, int y) const
  {
    if (x < 0 || x >= int (width) || y < 0 || y >= int (height))
      return BACKGROUND_DEPTH;

    return depths[x + width * y];
  }

  unsigned getWidth() const { return width; }
  unsigned getHeight() const { return height; }
};

struct DecisionTreeCPU
{
  tbb::task_scheduler_init tbb_init;

  struct Offsets
  {
    boost::int16_t du1, dv1, du2, dv2;
  };

  struct Node
  {
    Offsets offsets;
    boost::int16_t threshold;
  };

  boost::uint16_t depth;
  std::vector<Node> nodes;
  std::vector<Label> leaves;

  DecisionTreeCPU(const char * data)
  {
    std::memcpy (&depth, data, sizeof depth);
    data += sizeof depth;

    nodes.resize ((1 << depth) - 1);
    std::memcpy (&nodes.front (), data, nodes.size () * sizeof (Node));
    data += nodes.size () * sizeof (Node);

    leaves.resize (1 << depth);
    std::memcpy (&leaves.front (), data, leaves.size () * sizeof (Label));
    data += leaves.size () * sizeof (Label);
  }

  Label
  walk(const DepthImage & image, int x, int y) const
  {
    unsigned nid = 0;
    Depth d0 = image.getDepth(x, y);
    float scale = 1000.0f / d0;

    for(int node_depth = 0; node_depth < depth; ++node_depth)
    {
      const Node & node = nodes[nid];

      Depth d1 = image.getDepth (x + node.offsets.du1 * scale, y + node.offsets.dv1 * scale);
      Depth d2 = image.getDepth (x + node.offsets.du2 * scale, y + node.offsets.dv2 * scale);

      int feature = int (d1) - int (d2);

      if (feature > node.threshold)
        nid = nid * 2 + 2;
      else
        nid = nid * 2 + 1;
    }

    return leaves[nid - nodes.size()];
  }

  struct WalkHelper
  {
  private:
    const DecisionTreeCPU & tree;
    const DepthImage & image;
    std::vector<Label> & labels;

  public:
    WalkHelper(const DecisionTreeCPU & tree, const DepthImage & image, std::vector<Label> & labels)
      : tree(tree), image(image), labels(labels)
    {
    }

    void
    operator () (const tbb::blocked_range2d<unsigned> & range) const
    {
      for (unsigned y = range.rows().begin(); y < range.rows().end(); ++y)
        for (unsigned x = range.cols().begin(); x < range.cols().end(); ++x)
          labels[x + y * image.getWidth()] = image.getDepth(x, y) == BACKGROUND_DEPTH ?
                Labels::Background : tree.walk(image, x, y);
    }
  };

  void
  eval(const DepthImage & image, std::vector<Label> & labels) const
  {
    tbb::parallel_for(
          tbb::blocked_range2d<unsigned>(0, image.getHeight(), 0, image.getWidth()),
          WalkHelper(*this, image, labels)
    );
  }
};

int maxElementNoTie(int num, unsigned * elements)
{
  int max_element = 0;
  unsigned max = elements[max_element];

  for (int i = 1; i < num; ++i)
  {
    unsigned val = elements[i];
    if (max < val) { max_element = i; max = val; }
    else if (max == val) { max_element = -1; }
  }

  return max_element;
}

struct ConsensusHelper
{
private:
  const std::vector<std::vector<Label> > & multi_labels;
  std::vector<Label> & labels;
  const DepthImage & depth_image;

public:
  ConsensusHelper(
      const std::vector<std::vector<Label> > & multi_labels,
      std::vector<Label> & labels,
      const DepthImage & depth_image
  )
    : multi_labels(multi_labels), labels(labels), depth_image(depth_image)
  {
  }

  void operator ()(const tbb::blocked_range2d<unsigned> & range) const
  {
    for (unsigned y = range.rows().begin(); y < range.rows().end(); ++y)
      for (unsigned x = range.cols().begin(); x < range.cols().end(); ++x)
      {
        std::size_t i = x + y * depth_image.getWidth();

        bool background = true;
        for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
          if (multi_labels[ti][i] != Labels::Background) background = false;

        if (background)
        {
          labels[i] = Labels::Background;
          continue;
        }

        unsigned bins[Labels::NUM_LABELS] = { 0 };

        for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
          ++bins[multi_labels[ti][i]];

        int consensus = maxElementNoTie(Labels::NUM_LABELS, bins);

        if (consensus == -1)
        {
          std::fill (bins, bins + Labels::NUM_LABELS, 0);
          Depth d = depth_image.getDepth (x, y);

          for (int off_x = -1; off_x <= 1; ++off_x)
            for (int off_y = -1; off_y <= 1; ++off_y)
            {
              Depth off_d = depth_image.getDepth (x + off_x, y + off_y);

              if (std::abs (d - off_d) < 50)
                for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
                  ++bins[multi_labels[ti][i]];
            }

          labels[i] = std::max_element (bins, bins + Labels::NUM_LABELS) - bins;
        }
        else
        {
          labels[i] = consensus;
        }
      }
  }
};

BodyPartsRecognizer::BodyPartsRecognizer(std::size_t num_trees, const char * trees[])
{
  this->trees.resize(num_trees);

  for (std::size_t i = 0; i < num_trees; ++i)
    this->trees[i].reset(new Tree(trees[i]));

#if GPU_CONSENSUS
  this->consensus_finder.reset(new ConsensusFinderGPU(num_trees));
#endif
}

void
BodyPartsRecognizer::recognize(const RGBDImage & image, std::vector<Label> & labels)
{
  labels.clear ();
  labels.resize (image.width * image.height);

  DepthImage depth_image (image);

  Stopwatch watch_threshold;

  depth_image.applyThreshold (500);

  __android_log_print(ANDROID_LOG_INFO, "BPR", "Thresholding: %d ms", watch_threshold.elapsedMs());

  std::vector<std::vector<Label> > multi_labels (trees.size ());

  for (std::size_t ti = 0; ti < trees.size (); ++ti)
  {
    Stopwatch watch_evaluation;

    multi_labels[ti].resize (labels.size ());
    trees[ti]->eval (depth_image, multi_labels[ti]);

    __android_log_print(ANDROID_LOG_INFO, "BPR", "Evaluating tree %d: %d ms", ti, watch_evaluation.elapsedMs());
  }

  Stopwatch watch_consensus;

#if GPU_CONSENSUS
  consensus_finder->run(image.width, image.height, multi_labels, labels);
#else
  tbb::parallel_for(
        tbb::blocked_range2d<unsigned>(0, depth_image.getHeight(), 0, depth_image.getWidth()),
        ConsensusHelper(multi_labels, labels, depth_image)
  );
#endif

  __android_log_print(ANDROID_LOG_INFO, "BPR", "Finding consensus: %d ms", watch_consensus.elapsedMs());
}
<commit_msg>Removed another remnant of the GPU implementation.<commit_after>#include <algorithm>
#include <cstring>
#include <limits>
#include <memory>

#include <android/log.h>

#include <boost/format.hpp>
#include <boost/utility.hpp>

#include <tbb/blocked_range2d.h>
#include <tbb/parallel_for.h>
#include <tbb/task_scheduler_init.h>

#include "body_parts_recognizer.h"
#include "rgbd_image.h"
#include "sources.h"
#include "stopwatch.h"

const Depth BACKGROUND_DEPTH = std::numeric_limits<Depth>::max();

struct DepthImage
{
private:

  unsigned width, height;
  std::vector<Depth> depths;

public:

  DepthImage(const RGBDImage & image)
    : width(image.width), height(image.height), depths(width * height)
  {
    for (std::size_t i = 0; i < depths.size(); ++i)
      depths[i] = image.pixels[i].d == 0 ? BACKGROUND_DEPTH : image.pixels[i].d; // we consider 0 to be invalid depth
  }

  void
  applyThreshold(int threshold)
  {
    Depth min_depth = *std::min_element(depths.begin (), depths.end ());

    for (std::size_t i = 0; i < depths.size (); ++i)
      depths[i] = depths[i] <= min_depth + threshold ? depths[i] : BACKGROUND_DEPTH;
  }

  Depth
  getDepth(int x, int y) const
  {
    if (x < 0 || x >= int (width) || y < 0 || y >= int (height))
      return BACKGROUND_DEPTH;

    return depths[x + width * y];
  }

  unsigned getWidth() const { return width; }
  unsigned getHeight() const { return height; }
};

struct DecisionTreeCPU
{
  tbb::task_scheduler_init tbb_init;

  struct Offsets
  {
    boost::int16_t du1, dv1, du2, dv2;
  };

  struct Node
  {
    Offsets offsets;
    boost::int16_t threshold;
  };

  boost::uint16_t depth;
  std::vector<Node> nodes;
  std::vector<Label> leaves;

  DecisionTreeCPU(const char * data)
  {
    std::memcpy (&depth, data, sizeof depth);
    data += sizeof depth;

    nodes.resize ((1 << depth) - 1);
    std::memcpy (&nodes.front (), data, nodes.size () * sizeof (Node));
    data += nodes.size () * sizeof (Node);

    leaves.resize (1 << depth);
    std::memcpy (&leaves.front (), data, leaves.size () * sizeof (Label));
    data += leaves.size () * sizeof (Label);
  }

  Label
  walk(const DepthImage & image, int x, int y) const
  {
    unsigned nid = 0;
    Depth d0 = image.getDepth(x, y);
    float scale = 1000.0f / d0;

    for(int node_depth = 0; node_depth < depth; ++node_depth)
    {
      const Node & node = nodes[nid];

      Depth d1 = image.getDepth (x + node.offsets.du1 * scale, y + node.offsets.dv1 * scale);
      Depth d2 = image.getDepth (x + node.offsets.du2 * scale, y + node.offsets.dv2 * scale);

      int feature = int (d1) - int (d2);

      if (feature > node.threshold)
        nid = nid * 2 + 2;
      else
        nid = nid * 2 + 1;
    }

    return leaves[nid - nodes.size()];
  }

  struct WalkHelper
  {
  private:
    const DecisionTreeCPU & tree;
    const DepthImage & image;
    std::vector<Label> & labels;

  public:
    WalkHelper(const DecisionTreeCPU & tree, const DepthImage & image, std::vector<Label> & labels)
      : tree(tree), image(image), labels(labels)
    {
    }

    void
    operator () (const tbb::blocked_range2d<unsigned> & range) const
    {
      for (unsigned y = range.rows().begin(); y < range.rows().end(); ++y)
        for (unsigned x = range.cols().begin(); x < range.cols().end(); ++x)
          labels[x + y * image.getWidth()] = image.getDepth(x, y) == BACKGROUND_DEPTH ?
                Labels::Background : tree.walk(image, x, y);
    }
  };

  void
  eval(const DepthImage & image, std::vector<Label> & labels) const
  {
    tbb::parallel_for(
          tbb::blocked_range2d<unsigned>(0, image.getHeight(), 0, image.getWidth()),
          WalkHelper(*this, image, labels)
    );
  }
};

int maxElementNoTie(int num, unsigned * elements)
{
  int max_element = 0;
  unsigned max = elements[max_element];

  for (int i = 1; i < num; ++i)
  {
    unsigned val = elements[i];
    if (max < val) { max_element = i; max = val; }
    else if (max == val) { max_element = -1; }
  }

  return max_element;
}

struct ConsensusHelper
{
private:
  const std::vector<std::vector<Label> > & multi_labels;
  std::vector<Label> & labels;
  const DepthImage & depth_image;

public:
  ConsensusHelper(
      const std::vector<std::vector<Label> > & multi_labels,
      std::vector<Label> & labels,
      const DepthImage & depth_image
  )
    : multi_labels(multi_labels), labels(labels), depth_image(depth_image)
  {
  }

  void operator ()(const tbb::blocked_range2d<unsigned> & range) const
  {
    for (unsigned y = range.rows().begin(); y < range.rows().end(); ++y)
      for (unsigned x = range.cols().begin(); x < range.cols().end(); ++x)
      {
        std::size_t i = x + y * depth_image.getWidth();

        bool background = true;
        for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
          if (multi_labels[ti][i] != Labels::Background) background = false;

        if (background)
        {
          labels[i] = Labels::Background;
          continue;
        }

        unsigned bins[Labels::NUM_LABELS] = { 0 };

        for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
          ++bins[multi_labels[ti][i]];

        int consensus = maxElementNoTie(Labels::NUM_LABELS, bins);

        if (consensus == -1)
        {
          std::fill (bins, bins + Labels::NUM_LABELS, 0);
          Depth d = depth_image.getDepth (x, y);

          for (int off_x = -1; off_x <= 1; ++off_x)
            for (int off_y = -1; off_y <= 1; ++off_y)
            {
              Depth off_d = depth_image.getDepth (x + off_x, y + off_y);

              if (std::abs (d - off_d) < 50)
                for (std::size_t ti = 0; ti < multi_labels.size (); ++ti)
                  ++bins[multi_labels[ti][i]];
            }

          labels[i] = std::max_element (bins, bins + Labels::NUM_LABELS) - bins;
        }
        else
        {
          labels[i] = consensus;
        }
      }
  }
};

BodyPartsRecognizer::BodyPartsRecognizer(std::size_t num_trees, const char * trees[])
{
  this->trees.resize(num_trees);

  for (std::size_t i = 0; i < num_trees; ++i)
    this->trees[i].reset(new Tree(trees[i]));

#if GPU_CONSENSUS
  this->consensus_finder.reset(new ConsensusFinderGPU(num_trees));
#endif
}

void
BodyPartsRecognizer::recognize(const RGBDImage & image, std::vector<Label> & labels)
{
  labels.clear ();
  labels.resize (image.width * image.height);

  DepthImage depth_image (image);

  Stopwatch watch_threshold;

  depth_image.applyThreshold (500);

  __android_log_print(ANDROID_LOG_INFO, "BPR", "Thresholding: %d ms", watch_threshold.elapsedMs());

  std::vector<std::vector<Label> > multi_labels (trees.size ());

  for (std::size_t ti = 0; ti < trees.size (); ++ti)
  {
    Stopwatch watch_evaluation;

    multi_labels[ti].resize (labels.size ());
    trees[ti]->eval (depth_image, multi_labels[ti]);

    __android_log_print(ANDROID_LOG_INFO, "BPR", "Evaluating tree %d: %d ms", ti, watch_evaluation.elapsedMs());
  }

  Stopwatch watch_consensus;

  tbb::parallel_for(
        tbb::blocked_range2d<unsigned>(0, depth_image.getHeight(), 0, depth_image.getWidth()),
        ConsensusHelper(multi_labels, labels, depth_image)
  );

  __android_log_print(ANDROID_LOG_INFO, "BPR", "Finding consensus: %d ms", watch_consensus.elapsedMs());
}
<|endoftext|>


<commit_before>#include "json.h"

using namespace std;

// Value

JsonValue * JsonValue::fromString(string message){
    int i = 0;
    return JsonValue::fromString(message, i);
}

JsonValue * JsonValue::fromString(string message, int &i){
    while(i < message.length()){
        i += skip_whitespace(message, i);
        switch(message[i]){
            case '{':
                return JsonDict::fromString(message, i);
                break;
            case '[':
                return JsonList::fromString(message, i);
                break;
            case '"':
                return JsonString::fromString(message, i);
                break;
            case 't':
            case 'f':
                return JsonBool::fromString(message, i);
            case 'n':
                return JsonNull::fromString(message, i);
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return JsonInt::fromString(message, i);
                break;
            default:
                throw PARSE_ERROR("unknwown value", i);
        }
    }
    throw PARSE_ERROR("no value found", i);
}

// String

JsonString::JsonString(string val){
    replace_all(val, "\\\\", '\\');
    replace_all(val, "\\\"", '"');
    replace_all(val, "\\t", '\t');
    replace_all(val, "\\n", '\n');
    replace_all(val, "\\r", '\r');
    replace_all(val, "\\b", '\b');
    replace_all(val, "\\f", '\f');
    // TODO : replace \u four-hex-digits
    value = val;
}

JsonString::operator string() const{
    return value;
}

JsonString * JsonString::fromString(string message, int &i){
    i++;
    int start = i;
    while(i < message.length()){
        switch(message[i]){
        case '\\':
            i++;
            break;
        case '"':
            string s = message.substr(start, i - start);
            i++;
            return new JsonString(s);
        }
    i++;
    }
    throw PARSE_ERROR("No \" ending string", i);
}

string JsonString::toString(){
    string infos = "\"" + this->value + "\"";
    return infos;
}

// Dict

JsonDict * JsonDict::fromString(string message, int &i){
    i++;
    JsonDict * r = new JsonDict();
    i += skip_whitespace(message, i);

    if(message[i] == '}'){
        i++;
        return r;
    }

    while(1){
        JsonString * key = NULL;
        JsonValue * value = NULL;

        i += skip_whitespace(message, i);
        key = JsonString::fromString(message, i);
        string key_str = *key;
        delete key;
        i += skip_whitespace(message, i);
        i += skip_colon(message, i);
        i += skip_whitespace(message, i);
        value = JsonValue::fromString(message, i);
        r->add(key_str, value);

        i += skip_whitespace(message, i);
        if(message[i] == ','){
            i++;
        }
        else if(message[i] == '}'){
            i++;
            return r;
        }
        else{
            throw PARSE_ERROR("expected } or , found '" + string(1, message[i]) + "'", i);
        }
    }
}

string JsonDict::toString(){
    string infos = "{";
    for (map<string, JsonValue *>::iterator index = this->dict.begin() ; index != this->dict.end() ; ++index ){
        infos += "\"" + ((string) index->first) + "\"" + " : ";
        infos += index->second->toString();
        infos += ", ";
    }
    infos = infos.substr(0, infos.size()-2) + "}";
    return infos;
}

void JsonDict::add(string key, JsonValue * value){
    dict[key] = value;
}

size_t JsonDict::size(){
    return dict.size();
}

JsonValue * JsonDict::operator[](const string &str){
    // TODO : Should make a copy ?
    return this->dict[str];
}

// List

JsonList * JsonList::fromString(string message, int &i){
    i++;
    JsonList * r = new JsonList();
    i += skip_whitespace(message, i);

    if(message[i] == ']') {
        i++;
        return r;
    }

    while(1){
        JsonValue * value = NULL;

        i += skip_whitespace(message, i);
        value = JsonValue::fromString(message, i);
        r->add(value);

        i += skip_whitespace(message, i);

        switch(message[i]){
            case ',':
                i++;
                break;
            case ']':
                i++;
                return r;
                break;
            default:
                throw PARSE_ERROR("expected ] or , found " + string(1, message[i]), i);
        }
    }
}

string JsonList::toString(){
    string infos = "[";
    int index = 0;
    while (index < this->content.size()){
        infos += this->content[index]->toString();
        index++;
        infos+=", ";
    }

    infos = infos.substr(0, infos.size() - 2) + "]";
    return infos;
}

void JsonList::add(JsonValue * value){
    content.push_back(value);
}

size_t JsonList::size(){
    return content.size();
}

JsonValue * JsonList::operator[](const int &i){
    return content.at(i);
}

// Int

JsonInt::JsonInt(int val){
    value = val;
}

JsonInt * JsonInt::fromString(string message, int &i){
    JsonInt * r = new JsonInt();
    bool end = false;
    int start = i;
    while(!end){
        switch(message[i]){
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                i++;
                break;
            default:
                end = true;
                break;
        }
    }
    r->setValue(message.substr(start, i));
    return r;
}

string JsonInt::toString(){
    return (string) *this;
}

int JsonInt::getValue(){
    return value;
}

void JsonInt::setValue(int val){
    value = val;
}

void JsonInt::setValue(string val){
    value = stoi(val);
}

JsonInt::operator string() const{
    return to_string(value);
}

JsonInt::operator int() const{
    return value;
}

// Null

string JsonNull::toString(){
    return "null";
}

JsonNull * JsonNull::fromString(string message, int &i){
    if(message.substr(0,4) != "null"){
        throw PARSE_ERROR("expected null", i);
    }
    i += 4;
    return new JsonNull();
}

bool JsonNull::operator ==(const int * i){
    return i == 0;
}

// Bool

JsonBool::JsonBool(bool val){
    value = val;
}

JsonBool * JsonBool::fromString(string message, int &i){
    JsonBool * r = NULL;
    if(message[0] == 't'){
        if(message.substr(0,4) != "true"){
            throw PARSE_ERROR("expected true", i);
        }
        r = new JsonBool(true);
        i += 4;
    }
    else {
        if(message.substr(0,5) != "false"){
            throw PARSE_ERROR("expected false", i);
        }
        r = new JsonBool(false);
        i += 5;
    }

    return r;
}

string JsonBool::toString(){
    if(value){
        return "true";
    }
    else {
        return "false";
    }
}

bool JsonBool::operator ==(const bool i){
    return value == i;
}

JsonBool::operator bool() const{
    return value;
}
<commit_msg>More verbose ParseError<commit_after>#include "json.h"

using namespace std;

// Value

JsonValue * JsonValue::fromString(string message){
    int i = 0;
    return JsonValue::fromString(message, i);
}

JsonValue * JsonValue::fromString(string message, int &i){
    while(i < message.length()){
        i += skip_whitespace(message, i);
        switch(message[i]){
            case '{':
                return JsonDict::fromString(message, i);
                break;
            case '[':
                return JsonList::fromString(message, i);
                break;
            case '"':
                return JsonString::fromString(message, i);
                break;
            case 't':
            case 'f':
                return JsonBool::fromString(message, i);
            case 'n':
                return JsonNull::fromString(message, i);
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return JsonInt::fromString(message, i);
                break;
            default:
                throw PARSE_ERROR("unknwown value. Got '" + string(1, message[i]) + "'", i);
        }
    }
    throw PARSE_ERROR("no value found", i);
}

// String

JsonString::JsonString(string val){
    replace_all(val, "\\\\", '\\');
    replace_all(val, "\\\"", '"');
    replace_all(val, "\\t", '\t');
    replace_all(val, "\\n", '\n');
    replace_all(val, "\\r", '\r');
    replace_all(val, "\\b", '\b');
    replace_all(val, "\\f", '\f');
    // TODO : replace \u four-hex-digits
    value = val;
}

JsonString::operator string() const{
    return value;
}

JsonString * JsonString::fromString(string message, int &i){
    i++;
    int start = i;
    while(i < message.length()){
        switch(message[i]){
        case '\\':
            i++;
            break;
        case '"':
            string s = message.substr(start, i - start);
            i++;
            return new JsonString(s);
        }
    i++;
    }
    throw PARSE_ERROR("No \" ending string", i);
}

string JsonString::toString(){
    string infos = "\"" + this->value + "\"";
    return infos;
}

// Dict

JsonDict * JsonDict::fromString(string message, int &i){
    i++;
    JsonDict * r = new JsonDict();
    i += skip_whitespace(message, i);

    if(message[i] == '}'){
        i++;
        return r;
    }

    while(1){
        JsonString * key = NULL;
        JsonValue * value = NULL;

        i += skip_whitespace(message, i);
        key = JsonString::fromString(message, i);
        string key_str = *key;
        delete key;
        i += skip_whitespace(message, i);
        i += skip_colon(message, i);
        i += skip_whitespace(message, i);
        value = JsonValue::fromString(message, i);
        r->add(key_str, value);

        i += skip_whitespace(message, i);
        if(message[i] == ','){
            i++;
        }
        else if(message[i] == '}'){
            i++;
            return r;
        }
        else{
            throw PARSE_ERROR("expected } or , found '" + string(1, message[i]) + "'", i);
        }
    }
}

string JsonDict::toString(){
    string infos = "{";
    for (map<string, JsonValue *>::iterator index = this->dict.begin() ; index != this->dict.end() ; ++index ){
        infos += "\"" + ((string) index->first) + "\"" + " : ";
        infos += index->second->toString();
        infos += ", ";
    }
    infos = infos.substr(0, infos.size()-2) + "}";
    return infos;
}

void JsonDict::add(string key, JsonValue * value){
    dict[key] = value;
}

size_t JsonDict::size(){
    return dict.size();
}

JsonValue * JsonDict::operator[](const string &str){
    // TODO : Should make a copy ?
    return this->dict[str];
}

// List

JsonList * JsonList::fromString(string message, int &i){
    i++;
    JsonList * r = new JsonList();
    i += skip_whitespace(message, i);

    if(message[i] == ']') {
        i++;
        return r;
    }

    while(1){
        JsonValue * value = NULL;

        i += skip_whitespace(message, i);
        value = JsonValue::fromString(message, i);
        r->add(value);

        i += skip_whitespace(message, i);

        switch(message[i]){
            case ',':
                i++;
                break;
            case ']':
                i++;
                return r;
                break;
            default:
                throw PARSE_ERROR("expected ] or , found " + string(1, message[i]), i);
        }
    }
}

string JsonList::toString(){
    string infos = "[";
    int index = 0;
    while (index < this->content.size()){
        infos += this->content[index]->toString();
        index++;
        infos+=", ";
    }

    infos = infos.substr(0, infos.size() - 2) + "]";
    return infos;
}

void JsonList::add(JsonValue * value){
    content.push_back(value);
}

size_t JsonList::size(){
    return content.size();
}

JsonValue * JsonList::operator[](const int &i){
    return content.at(i);
}

// Int

JsonInt::JsonInt(int val){
    value = val;
}

JsonInt * JsonInt::fromString(string message, int &i){
    JsonInt * r = new JsonInt();
    bool end = false;
    int start = i;
    while(!end){
        switch(message[i]){
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                i++;
                break;
            default:
                end = true;
                break;
        }
    }
    r->setValue(message.substr(start, i));
    return r;
}

string JsonInt::toString(){
    return (string) *this;
}

int JsonInt::getValue(){
    return value;
}

void JsonInt::setValue(int val){
    value = val;
}

void JsonInt::setValue(string val){
    value = stoi(val);
}

JsonInt::operator string() const{
    return to_string(value);
}

JsonInt::operator int() const{
    return value;
}

// Null

string JsonNull::toString(){
    return "null";
}

JsonNull * JsonNull::fromString(string message, int &i){
    if(message.substr(0,4) != "null"){
        throw PARSE_ERROR("expected null, got '" + message.substr(0,4) + "'", i);
    }
    i += 4;
    return new JsonNull();
}

bool JsonNull::operator ==(const int * i){
    return i == 0;
}

// Bool

JsonBool::JsonBool(bool val){
    value = val;
}

JsonBool * JsonBool::fromString(string message, int &i){
    JsonBool * r = NULL;
    if(message[0] == 't'){
        if(message.substr(0,4) != "true"){
            throw PARSE_ERROR("expected true, got '" + message.substr(0,4) + "'", i);
        }
        r = new JsonBool(true);
        i += 4;
    }
    else {
        if(message.substr(0,5) != "false"){
            throw PARSE_ERROR("expected false, got '" + message.substr(0,5) + "'", i);
        }
        r = new JsonBool(false);
        i += 5;
    }

    return r;
}

string JsonBool::toString(){
    if(value){
        return "true";
    }
    else {
        return "false";
    }
}

bool JsonBool::operator ==(const bool i){
    return value == i;
}

JsonBool::operator bool() const{
    return value;
}
<|endoftext|>


<commit_before><commit_msg>removed unused variables<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// See the corresponding header file for description of the functions in this
// file.

#include "chrome/installer/util/install_util.h"

#include <shellapi.h>
#include <shlobj.h>

#include <algorithm>

#include "base/file_util.h"
#include "base/logging.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/win_util.h"

#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/work_item_list.h"

bool InstallUtil::ExecuteExeAsAdmin(const std::wstring& exe,
                                    const std::wstring& params,
                                    DWORD* exit_code) {
  SHELLEXECUTEINFO info = {0};
  info.cbSize = sizeof(SHELLEXECUTEINFO);
  info.fMask = SEE_MASK_NOCLOSEPROCESS;
  info.lpVerb = L"runas";
  info.lpFile = exe.c_str();
  info.lpParameters = params.c_str();
  info.nShow = SW_SHOW;
  if (::ShellExecuteEx(&info) == FALSE)
    return false;

  ::WaitForSingleObject(info.hProcess, INFINITE);
  DWORD ret_val = 0;
  if (!::GetExitCodeProcess(info.hProcess, &ret_val))
    return false;

  if (exit_code)
    *exit_code = ret_val;
  return true;
}

std::wstring InstallUtil::GetChromeUninstallCmd(bool system_install) {
  HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  RegKey key(root, dist->GetUninstallRegPath().c_str());
  std::wstring uninstall_cmd;
  key.ReadValue(installer_util::kUninstallStringField, &uninstall_cmd);
  return uninstall_cmd;
}

installer::Version* InstallUtil::GetChromeVersion(bool system_install) {
  RegKey key;
  std::wstring version_str;

  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  if (!key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ) ||
      !key.ReadValue(google_update::kRegVersionField, &version_str)) {
    LOG(INFO) << "No existing Chrome install found.";
    key.Close();
    return NULL;
  }
  key.Close();
  LOG(INFO) << "Existing Chrome version found " << version_str;
  return installer::Version::GetVersionFromString(version_str);
}

bool InstallUtil::IsOSSupported() {
  int major, minor;
  win_util::WinVersion version = win_util::GetWinVersion();
  win_util::GetServicePackLevel(&major, &minor);

  // We do not support Win2K or older, or XP without service pack 1.
  LOG(INFO) << "Windows Version: " << version
            << ", Service Pack: " << major << "." << minor;
  if ((version > win_util::WINVERSION_XP) ||
      (version == win_util::WINVERSION_XP && major >= 1)) {
    return true;
  }
  return false;
}

void InstallUtil::WriteInstallerResult(bool system_install,
                                       installer_util::InstallStatus status,
                                       int string_resource_id,
                                       const std::wstring* const launch_cmd) {
  HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  std::wstring key = dist->GetStateKey();
  int installer_result = (dist->GetInstallReturnCode(status) == 0) ? 0 : 1;
  scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
  install_list->AddCreateRegKeyWorkItem(root, key);
  install_list->AddSetRegValueWorkItem(root, key, L"InstallerResult",
                                       installer_result, true);
  install_list->AddSetRegValueWorkItem(root, key, L"InstallerError",
                                       status, true);
  if (string_resource_id != 0) {
    std::wstring msg = installer_util::GetLocalizedString(string_resource_id);
    install_list->AddSetRegValueWorkItem(root, key, L"InstallerResultUIString",
                                         msg, true);
  }
  if (launch_cmd != NULL) {
    install_list->AddSetRegValueWorkItem(root, key,
                                         L"InstallerSuccessLaunchCmdLine",
                                         *launch_cmd, true);
  }
  if (!install_list->Do())
    LOG(ERROR) << "Failed to record installer error information in registry.";
}

bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) {
  wchar_t program_files_path[MAX_PATH] = {0};
  if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
                                SHGFP_TYPE_CURRENT, program_files_path))) {
    return !StartsWith(exe_path, program_files_path, false);
  } else {
    NOTREACHED();
  }
  return true;
}

bool InstallUtil::BuildDLLRegistrationList(const std::wstring& install_path,
                                           const wchar_t** const dll_names,
                                           int dll_names_count,
                                           bool do_register,
                                           WorkItemList* registration_list) {
  DCHECK(NULL != registration_list);
  bool success = true;
  for (int i = 0; i < dll_names_count; i++) {
    std::wstring dll_file_path(install_path);
    file_util::AppendToPath(&dll_file_path, dll_names[i]);
    success = registration_list->AddSelfRegWorkItem(dll_file_path,
        do_register) && success;
  }
  return (dll_names_count > 0) && success;
}
<commit_msg>Min XP Service Pack required is two not one.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// See the corresponding header file for description of the functions in this
// file.

#include "chrome/installer/util/install_util.h"

#include <shellapi.h>
#include <shlobj.h>

#include <algorithm>

#include "base/file_util.h"
#include "base/logging.h"
#include "base/registry.h"
#include "base/scoped_ptr.h"
#include "base/string_util.h"
#include "base/win_util.h"

#include "chrome/installer/util/browser_distribution.h"
#include "chrome/installer/util/google_update_constants.h"
#include "chrome/installer/util/l10n_string_util.h"
#include "chrome/installer/util/work_item_list.h"

bool InstallUtil::ExecuteExeAsAdmin(const std::wstring& exe,
                                    const std::wstring& params,
                                    DWORD* exit_code) {
  SHELLEXECUTEINFO info = {0};
  info.cbSize = sizeof(SHELLEXECUTEINFO);
  info.fMask = SEE_MASK_NOCLOSEPROCESS;
  info.lpVerb = L"runas";
  info.lpFile = exe.c_str();
  info.lpParameters = params.c_str();
  info.nShow = SW_SHOW;
  if (::ShellExecuteEx(&info) == FALSE)
    return false;

  ::WaitForSingleObject(info.hProcess, INFINITE);
  DWORD ret_val = 0;
  if (!::GetExitCodeProcess(info.hProcess, &ret_val))
    return false;

  if (exit_code)
    *exit_code = ret_val;
  return true;
}

std::wstring InstallUtil::GetChromeUninstallCmd(bool system_install) {
  HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  RegKey key(root, dist->GetUninstallRegPath().c_str());
  std::wstring uninstall_cmd;
  key.ReadValue(installer_util::kUninstallStringField, &uninstall_cmd);
  return uninstall_cmd;
}

installer::Version* InstallUtil::GetChromeVersion(bool system_install) {
  RegKey key;
  std::wstring version_str;

  HKEY reg_root = (system_install) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  if (!key.Open(reg_root, dist->GetVersionKey().c_str(), KEY_READ) ||
      !key.ReadValue(google_update::kRegVersionField, &version_str)) {
    LOG(INFO) << "No existing Chrome install found.";
    key.Close();
    return NULL;
  }
  key.Close();
  LOG(INFO) << "Existing Chrome version found " << version_str;
  return installer::Version::GetVersionFromString(version_str);
}

bool InstallUtil::IsOSSupported() {
  int major, minor;
  win_util::WinVersion version = win_util::GetWinVersion();
  win_util::GetServicePackLevel(&major, &minor);

  // We do not support Win2K or older, or XP without service pack 2.
  LOG(INFO) << "Windows Version: " << version
            << ", Service Pack: " << major << "." << minor;
  if ((version > win_util::WINVERSION_XP) ||
      (version == win_util::WINVERSION_XP && major >= 2)) {
    return true;
  }
  return false;
}

void InstallUtil::WriteInstallerResult(bool system_install,
                                       installer_util::InstallStatus status,
                                       int string_resource_id,
                                       const std::wstring* const launch_cmd) {
  HKEY root = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
  std::wstring key = dist->GetStateKey();
  int installer_result = (dist->GetInstallReturnCode(status) == 0) ? 0 : 1;
  scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
  install_list->AddCreateRegKeyWorkItem(root, key);
  install_list->AddSetRegValueWorkItem(root, key, L"InstallerResult",
                                       installer_result, true);
  install_list->AddSetRegValueWorkItem(root, key, L"InstallerError",
                                       status, true);
  if (string_resource_id != 0) {
    std::wstring msg = installer_util::GetLocalizedString(string_resource_id);
    install_list->AddSetRegValueWorkItem(root, key, L"InstallerResultUIString",
                                         msg, true);
  }
  if (launch_cmd != NULL) {
    install_list->AddSetRegValueWorkItem(root, key,
                                         L"InstallerSuccessLaunchCmdLine",
                                         *launch_cmd, true);
  }
  if (!install_list->Do())
    LOG(ERROR) << "Failed to record installer error information in registry.";
}

bool InstallUtil::IsPerUserInstall(const wchar_t* const exe_path) {
  wchar_t program_files_path[MAX_PATH] = {0};
  if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL,
                                SHGFP_TYPE_CURRENT, program_files_path))) {
    return !StartsWith(exe_path, program_files_path, false);
  } else {
    NOTREACHED();
  }
  return true;
}

bool InstallUtil::BuildDLLRegistrationList(const std::wstring& install_path,
                                           const wchar_t** const dll_names,
                                           int dll_names_count,
                                           bool do_register,
                                           WorkItemList* registration_list) {
  DCHECK(NULL != registration_list);
  bool success = true;
  for (int i = 0; i < dll_names_count; i++) {
    std::wstring dll_file_path(install_path);
    file_util::AppendToPath(&dll_file_path, dll_names[i]);
    success = registration_list->AddSelfRegWorkItem(dll_file_path,
        do_register) && success;
  }
  return (dll_names_count > 0) && success;
}
<|endoftext|>


<commit_before>/*-
 * Copyright (c) 2009, Ascent Group.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of the Ascent Group nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <common/Database.h>
#include <psql/Schema.h>
#include <psql/Table.h>
#include <psql/Tools.h>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QVariant>

#include <QtDebug>

namespace DbObjects
{

namespace Psql
{

/*!
 * Constructor
 *
 * \param[in] ipName - Name of the given table
 * \param[in] ipSchema - Handle to schema containing this view
 */
Table::Table(QString ipName, const DbSchemaPtr &ipSchema)
    :DbTable(ipName, ipSchema)
{
    // load column definitions
//    loadData();
}

/*!
 * Destructor
 */
Table::~Table()
{

}

/*!
 * Load column definitions data
 *
 * \return true If data has been successfully loaded
 * \return false Otherwise
 */
bool
Table::loadData()
{
//    int *p = 0;
//    *p = 7;
    if (mIsLoaded) {
        return true;
    }

    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);
    QString qstr;

    /*! \todo Before creating a query we need to find out postgres version;
     *        Bersion check can help support different Postgres versions,
     *        especcialy when the system catalogs change in newer versions
     */
    Tools::Version version = Tools::version();

    /*! \todo version check */
    /*! \todo do version specific actions */

    // create query
    qstr = QString("SELECT "
                        "pga.attname, "
                        "pg_catalog.format_type(pga.atttypid, pga.atttypmod), "
                        "pga.attnotnull "
                    "FROM "
                        "pg_catalog.pg_attribute pga "
                    "WHERE "
                        "pga.attnum > 0 "
                        "AND NOT pga.attisdropped "
                        "AND pga.attrelid = ("
                        "SELECT pgc.oid FROM pg_catalog.pg_class pgc "
                        "LEFT JOIN pg_catalog.pg_namespace pgn ON pgn.oid = pgc.relnamespace "
                        "WHERE pgc.relname = '%1' and pgn.nspname = '%2'); ")
//          "AND pg_catalog.pg_table_is_visible(pgc.oid));")
        .arg(mName)
        .arg(mSchema->name());

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::loadData> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();
        return false;
    }

    // if query result is empty
    if (!query.first()) {
        return false;
    }

    // for each retrieved row
    do {
        /* temporary debug output */
#if DEBUG_TRACE
        qDebug() << query.value(0).toString();
        qDebug() << query.value(1).toString();
        qDebug() << query.value(2).toString();
#endif

        // create column definition
        struct ColumnDefinition cDef;

        // populate column definition
        cDef.name = query.value(0).toString();
        cDef.type = query.value(1).toString();
        cDef.isNullable = !query.value(2).toBool();
        cDef.isPrimaryKey = checkPrimaryKey(cDef.name);
        cDef.isForeignKey = checkForeignKey(cDef.name, cDef.foreignSchemaName, cDef.foreignTableName, cDef.foreignFieldNames);
        cDef.isUnique = checkUnique(cDef.name);

        /* temporary debug output */
#if DEBUG_TRACE
        qDebug() << "NAME: " << cDef.name;
        qDebug() << "isPrimaryKey: " << cDef.isPrimaryKey;
        qDebug() << "isForeignKey: " << cDef.isForeignKey;
        qDebug() << "isUnique: " << cDef.isUnique;
        qDebug() << "FKEY_SCHEMA: " << cDef.foreignSchemaName;
        qDebug() << "FKEY_TABLE: " << cDef.foreignTableName;
#endif

        // add column definition
        mColumnDefs.push_back(cDef);
    } while (query.next());

    // clear result from previous query
    query.clear();

    // try to find parents if they exist
    qstr = QString("SELECT "
//                       "childns.nspname AS child_schema, "
//                       "child.relname AS child_name, "
                       "parentns.nspname AS parent_schema, "
                       "parent.relname AS parent_name "
                   "FROM "
                       "pg_catalog.pg_inherits i, "
                       "pg_catalog.pg_class child, "
                       "pg_catalog.pg_class parent, "
                       "pg_catalog.pg_namespace childns, "
                       "pg_catalog.pg_namespace parentns "
                   "WHERE "
                       "i.inhrelid = child.oid AND "
                       "i.inhparent = parent.oid AND "
                       "childns.oid = child.relnamespace AND "
                       "parentns.oid = parent.relnamespace AND "
                       "childns.nspname = '%1' AND "
                       "child.relname = '%2';")
        .arg(mSchema.name())
        .arg(mName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::loadData> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();
        return false;
    }

    // if query result is empty
    if (query.first()) {

        do {
            DbSchemaPtr schema = Common::Database::instance()->findSchema(query.value(0).toString());
            // devtime assert
            Q_ASSERT(0 != schema.get());

            DbTablePtr table = schema->findTable(query.value(1).toString());
            // devtime assert
            Q_ASSERT(0 != table.get());

            // store handle to parent table
            mParentTables.push_back(table);

            qDebug() << "Psql::Table::loadData> Parent table: " << table.name();
        } while (query.next());
    }

    return DbTable::loadData();
}

/*!
 * Checks if column is a primary key for the given table
 *
 * \param[in] ipColumnName - Name of the column
 *
 * \return true If the column is primary key
 * \return false Otherwise
 */
bool
Table::checkPrimaryKey(const QString &ipColumnName) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                        "pgc.relname, "
                        "pga.attname "
                    "FROM "
                        "pg_class pgc, "
                        "pg_attribute pga, "
                        "pg_index pgi, "
                        "pg_namespace pgn "
                    "WHERE "
                        "pgc.oid = pga.attrelid "
                        "AND pgc.oid = pgi.indrelid "
                        "AND pgi.indkey[0] = pga.attnum "
                        "AND pgi.indisprimary = 't' "
                        "AND pgn.oid = pgc.relnamespace "
                        "AND pgn.nspname = '%1' "
                        "AND pgc.relname = '%2' "
                        "AND pga.attname = '%3';")
                .arg(mSchema->name())
                .arg(mName)
                .arg(ipColumnName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::checkPrimaryKey> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    // primary constraint definition found
    return query.first();
}

/*!
 * Checks if ipColumnName is a foreign key for ipTableName
 *
 * \param[in] ipColumnName - Name of the column
 * \param[out] opForeignSchemaName - Name of the schema that contains the reference table
 * \param[out] opForeignTableName - Name of the table references by this column
 * \param[out] opForeignFieldsNames - Names of fields references by this column
 *
 * \return true If the column is a foreign key
 * \return false Otherwise
 */
bool
Table::checkForeignKey(const QString &ipColumnName,
               QString &opForeignSchemaName,
               QString &opForeignTableName,
               QStringList &opForeignFieldsNames) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                                "p1.relname, "
                                "a1.attname, "
                                "pgn2.nspname AS foreign_schema, "
                                "p2.relname AS reltable, "
                                "a2.attname AS ref_field "
                            "FROM "
                                "pg_constraint c, "
                                "pg_class p1, "
                                "pg_class p2, "
                                "pg_attribute a1, "
                                "pg_attribute a2, "
                                "pg_namespace pgn1, "
                                "pg_namespace pgn2 "
                            "WHERE "
                                "c.contype = 'f' "
                                "AND c.confrelid > 0 "
                                "AND c.conrelid = p1.oid "
                                "AND c.confrelid = p2.oid "
                                "AND c.conrelid = a1.attrelid "
                                "AND a1.attnum = ANY (c.conkey) "
                                "AND c.confrelid = a2.attrelid "
                                "AND a2.attnum = ANY (c.confkey) "
                                "AND p2.relnamespace = pgn2.oid "
                                "AND pgn1.oid = p1.relnamespace "
                                "AND pgn1.nspname = '%1' "
                                "AND p1.relname = '%2' "
                                "AND a1.attname = '%3';")
        .arg(mSchema->name())
        .arg(mName)
        .arg(ipColumnName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::checkForeignKey> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    bool flag = false;
    qint32 colId;

    // if query result is empty
    if (!query.first()) {
    return flag;
    }

    // if we are here then the result is not empty
    flag = true;

    // this needs to be don only once for all fields
    colId = query.record().indexOf("reltable");
    opForeignTableName = query.value(colId).toString();

    colId = query.record().indexOf("foreign_schema");
    opForeignSchemaName = query.value(colId).toString();

    // fields themselves
    do {
        colId = query.record().indexOf("ref_field");
        opForeignFieldsNames.push_back(query.value(colId).toString());
    } while (query.next());

    // foreign key constraint definition found
    return flag;
}

/*!
 * Checks if ipColumnName is unique for ipTableName
 *
 * \param[in] ipColumnName - Name of the column
 *
 * \return true If the column has unique constraint
 * \return false Otherwise
 */
bool
Table::checkUnique(const QString &ipColumnName) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                                "pgc.relname, "
                                "pga.attname, "
                "pgc.relnamespace "
                            "FROM "
                                "pg_constraint constr, "
                                "pg_class pgc, "
                                "pg_attribute pga, "
                                "pg_namespace pgn "
                            "WHERE "
                                "pga.attnum = ANY (constr.conkey) "
                                "AND constr.contype = 'u' "
                                "AND constr.conrelid = pgc.oid "
                                "AND constr.conrelid = pga.attrelid "
                                "AND pgn.oid = pgc.relnamespace "
                                "AND pgn.nspname = '%1' "
                                "AND pgc.relname = '%2' "
                                "AND pga.attname = '%3';")
        .arg(mSchema->name())
        .arg(mName)
        .arg(ipColumnName);

#if DEBUG_QUERY
    qDebug() << "Psql::Table::checkUnique> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    // unique constraint definition found
    return query.first();
}

} // namespace Psql

} // namespace DbObjects

<commit_msg>* Merged 'lyuts_feature_table_inheritance' branch. Added ordering by inheritance sequence   number.<commit_after>/*-
 * Copyright (c) 2009, Ascent Group.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of the Ascent Group nor the names of its contributors
 *       may be used to endorse or promote products derived from this software
 *       without specific prior written permission.
 *
 *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <common/Database.h>
#include <psql/Schema.h>
#include <psql/Table.h>
#include <psql/Tools.h>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QVariant>

#include <QtDebug>

namespace DbObjects
{

namespace Psql
{

/*!
 * Constructor
 *
 * \param[in] ipName - Name of the given table
 * \param[in] ipSchema - Handle to schema containing this view
 */
Table::Table(QString ipName, const DbSchemaPtr &ipSchema)
    :DbTable(ipName, ipSchema)
{
    // load column definitions
//    loadData();
}

/*!
 * Destructor
 */
Table::~Table()
{

}

/*!
 * Load column definitions data
 *
 * \return true If data has been successfully loaded
 * \return false Otherwise
 */
bool
Table::loadData()
{
//    int *p = 0;
//    *p = 7;
    if (mIsLoaded) {
        return true;
    }

    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);
    QString qstr;

    /*! \todo Before creating a query we need to find out postgres version;
     *        Bersion check can help support different Postgres versions,
     *        especcialy when the system catalogs change in newer versions
     */
    Tools::Version version = Tools::version();

    /*! \todo version check */
    /*! \todo do version specific actions */

    // create query
    qstr = QString("SELECT "
                        "pga.attname, "
                        "pg_catalog.format_type(pga.atttypid, pga.atttypmod), "
                        "pga.attnotnull "
                    "FROM "
                        "pg_catalog.pg_attribute pga "
                    "WHERE "
                        "pga.attnum > 0 "
                        "AND NOT pga.attisdropped "
                        "AND pga.attrelid = ("
                        "SELECT pgc.oid FROM pg_catalog.pg_class pgc "
                        "LEFT JOIN pg_catalog.pg_namespace pgn ON pgn.oid = pgc.relnamespace "
                        "WHERE pgc.relname = '%1' and pgn.nspname = '%2'); ")
//          "AND pg_catalog.pg_table_is_visible(pgc.oid));")
        .arg(mName)
        .arg(mSchema->name());

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::loadData> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();
        return false;
    }

    // if query result is empty
    if (!query.first()) {
        return false;
    }

    // for each retrieved row
    do {
        /* temporary debug output */
#if DEBUG_TRACE
        qDebug() << query.value(0).toString();
        qDebug() << query.value(1).toString();
        qDebug() << query.value(2).toString();
#endif

        // create column definition
        struct ColumnDefinition cDef;

        // populate column definition
        cDef.name = query.value(0).toString();
        cDef.type = query.value(1).toString();
        cDef.isNullable = !query.value(2).toBool();
        cDef.isPrimaryKey = checkPrimaryKey(cDef.name);
        cDef.isForeignKey = checkForeignKey(cDef.name, cDef.foreignSchemaName, cDef.foreignTableName, cDef.foreignFieldNames);
        cDef.isUnique = checkUnique(cDef.name);

        /* temporary debug output */
#if DEBUG_TRACE
        qDebug() << "NAME: " << cDef.name;
        qDebug() << "isPrimaryKey: " << cDef.isPrimaryKey;
        qDebug() << "isForeignKey: " << cDef.isForeignKey;
        qDebug() << "isUnique: " << cDef.isUnique;
        qDebug() << "FKEY_SCHEMA: " << cDef.foreignSchemaName;
        qDebug() << "FKEY_TABLE: " << cDef.foreignTableName;
#endif

        // add column definition
        mColumnDefs.push_back(cDef);
    } while (query.next());

    // clear result from previous query
    query.clear();

    // try to find parents if they exist
    qstr = QString("SELECT "
//                       "childns.nspname AS child_schema, "
//                       "child.relname AS child_name, "
                       "parentns.nspname AS parent_schema, "
                       "parent.relname AS parent_name "
                   "FROM "
                       "pg_catalog.pg_inherits i, "
                       "pg_catalog.pg_class child, "
                       "pg_catalog.pg_class parent, "
                       "pg_catalog.pg_namespace childns, "
                       "pg_catalog.pg_namespace parentns "
                   "WHERE "
                       "i.inhrelid = child.oid AND "
                       "i.inhparent = parent.oid AND "
                       "childns.oid = child.relnamespace AND "
                       "parentns.oid = parent.relnamespace AND "
                       "childns.nspname = '%1' AND "
                       "child.relname = '%2' "
                   "ORDER BY i.inhseqno;")
        .arg(mSchema.name())
        .arg(mName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::loadData> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();
        return false;
    }

    // if query result is empty
    if (query.first()) {

        do {
            DbSchemaPtr schema = Common::Database::instance()->findSchema(query.value(0).toString());
            // devtime assert
            Q_ASSERT(0 != schema.get());

            DbTablePtr table = schema->findTable(query.value(1).toString());
            // devtime assert
            Q_ASSERT(0 != table.get());

            // store handle to parent table
            mParentTables.push_back(table);

            qDebug() << "Psql::Table::loadData> Parent table: " << table.name();
        } while (query.next());
    }

    return DbTable::loadData();
}

/*!
 * Checks if column is a primary key for the given table
 *
 * \param[in] ipColumnName - Name of the column
 *
 * \return true If the column is primary key
 * \return false Otherwise
 */
bool
Table::checkPrimaryKey(const QString &ipColumnName) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                        "pgc.relname, "
                        "pga.attname "
                    "FROM "
                        "pg_class pgc, "
                        "pg_attribute pga, "
                        "pg_index pgi, "
                        "pg_namespace pgn "
                    "WHERE "
                        "pgc.oid = pga.attrelid "
                        "AND pgc.oid = pgi.indrelid "
                        "AND pgi.indkey[0] = pga.attnum "
                        "AND pgi.indisprimary = 't' "
                        "AND pgn.oid = pgc.relnamespace "
                        "AND pgn.nspname = '%1' "
                        "AND pgc.relname = '%2' "
                        "AND pga.attname = '%3';")
                .arg(mSchema->name())
                .arg(mName)
                .arg(ipColumnName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::checkPrimaryKey> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    // primary constraint definition found
    return query.first();
}

/*!
 * Checks if ipColumnName is a foreign key for ipTableName
 *
 * \param[in] ipColumnName - Name of the column
 * \param[out] opForeignSchemaName - Name of the schema that contains the reference table
 * \param[out] opForeignTableName - Name of the table references by this column
 * \param[out] opForeignFieldsNames - Names of fields references by this column
 *
 * \return true If the column is a foreign key
 * \return false Otherwise
 */
bool
Table::checkForeignKey(const QString &ipColumnName,
               QString &opForeignSchemaName,
               QString &opForeignTableName,
               QStringList &opForeignFieldsNames) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                                "p1.relname, "
                                "a1.attname, "
                                "pgn2.nspname AS foreign_schema, "
                                "p2.relname AS reltable, "
                                "a2.attname AS ref_field "
                            "FROM "
                                "pg_constraint c, "
                                "pg_class p1, "
                                "pg_class p2, "
                                "pg_attribute a1, "
                                "pg_attribute a2, "
                                "pg_namespace pgn1, "
                                "pg_namespace pgn2 "
                            "WHERE "
                                "c.contype = 'f' "
                                "AND c.confrelid > 0 "
                                "AND c.conrelid = p1.oid "
                                "AND c.confrelid = p2.oid "
                                "AND c.conrelid = a1.attrelid "
                                "AND a1.attnum = ANY (c.conkey) "
                                "AND c.confrelid = a2.attrelid "
                                "AND a2.attnum = ANY (c.confkey) "
                                "AND p2.relnamespace = pgn2.oid "
                                "AND pgn1.oid = p1.relnamespace "
                                "AND pgn1.nspname = '%1' "
                                "AND p1.relname = '%2' "
                                "AND a1.attname = '%3';")
        .arg(mSchema->name())
        .arg(mName)
        .arg(ipColumnName);

#ifdef DEBUG_QUERY
    qDebug() << "Psql::Table::checkForeignKey> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    bool flag = false;
    qint32 colId;

    // if query result is empty
    if (!query.first()) {
    return flag;
    }

    // if we are here then the result is not empty
    flag = true;

    // this needs to be don only once for all fields
    colId = query.record().indexOf("reltable");
    opForeignTableName = query.value(colId).toString();

    colId = query.record().indexOf("foreign_schema");
    opForeignSchemaName = query.value(colId).toString();

    // fields themselves
    do {
        colId = query.record().indexOf("ref_field");
        opForeignFieldsNames.push_back(query.value(colId).toString());
    } while (query.next());

    // foreign key constraint definition found
    return flag;
}

/*!
 * Checks if ipColumnName is unique for ipTableName
 *
 * \param[in] ipColumnName - Name of the column
 *
 * \return true If the column has unique constraint
 * \return false Otherwise
 */
bool
Table::checkUnique(const QString &ipColumnName) const
{
    QSqlDatabase db = QSqlDatabase::database("mainConnect");
    QSqlQuery query(db);

    // create query
    QString qstr = QString("SELECT "
                                "pgc.relname, "
                                "pga.attname, "
                "pgc.relnamespace "
                            "FROM "
                                "pg_constraint constr, "
                                "pg_class pgc, "
                                "pg_attribute pga, "
                                "pg_namespace pgn "
                            "WHERE "
                                "pga.attnum = ANY (constr.conkey) "
                                "AND constr.contype = 'u' "
                                "AND constr.conrelid = pgc.oid "
                                "AND constr.conrelid = pga.attrelid "
                                "AND pgn.oid = pgc.relnamespace "
                                "AND pgn.nspname = '%1' "
                                "AND pgc.relname = '%2' "
                                "AND pga.attname = '%3';")
        .arg(mSchema->name())
        .arg(mName)
        .arg(ipColumnName);

#if DEBUG_QUERY
    qDebug() << "Psql::Table::checkUnique> " << qstr;
#endif

    // if query execution failed
    if (!query.exec(qstr)) {
        qDebug() << query.lastError().text();

        return false;
    }

    // unique constraint definition found
    return query.first();
}

} // namespace Psql

} // namespace DbObjects

<|endoftext|>