<commit_before>#ifndef HEADERLIB_HDR_CORE_MATCH_HPP
#define HEADERLIB_HDR_CORE_MATCH_HPP
/*
 * match.hpp
 *
 *  Created on: 22.02.2017
 *      Author: Andreas Molzer
 */
#include "hdr/core/std.hpp"
#include "hdr/types/maybe.hpp"

/** Limited (!!!) core matching, as a monad.
 *    match var [>>= (with template selector function)]*
 *  Essentially works as a monad M with M::return == match which constructs
 *  an 'Unmatched' type. with constructs a bindable function returning this type.
 *  Binding F to a Matched T will skip the application of F while binding to
 *  an unmatched will do it. This works like Maybe but instead Nothing/Matched
 *  carries an additional result type and Maybe/Unmatched is very much the same.
 *
 *  Limitations of core matching:
 *  Each placeholder can only be used once in a template, this is not (!) checked
 *  for. If you need this functionality, use advanced matching based on sets
 *  instead (uniqueness check needs set mechanics for performance).
 *  [WIP]
 *  Templates are declared like the type they are supposed to match but using
 *  Placholders instead of the true type parameters. Should the type definition
 *  depends on its parameters, a special form is provided (can't be constructed).
 *  This feature is not currently implemented.
 */
namespace hdr::match {

using ::hdr::std::Apply;
using ::hdr::std::Const;
using ::hdr::std::True;
using ::hdr::std::False;
using ::hdr::std::TemplateFunction;
using ::hdr::std::TypeFunction;
using ::hdr::std::Void;
using ::hdr::std::apply;
using ::hdr::std::compose;
using ::hdr::std::id;
using ::hdr::std::fconst;
using ::hdr::std::ignore;
using ::hdr::std::flip;
using ::hdr::std::when_else;
using ::hdr::monad::MonadFromBind;

/// Type definition of Unmatched
template<typename Var>
struct Unmatched;
using unmatched = TemplateFunction<Unmatched>;
/// Type definition of Matched
template<typename Var>
struct Matched;
using matched   = TemplateFunction<Matched>;

namespace {
  template<typename U, typename M, typename V> struct _matching;
  template<typename U, typename M, typename V>
  struct _matching<U, M, Unmatched<V>> {
    using type = Apply<U, V>;
  };
  template<typename U, typename M, typename V>
  struct _matching<U, M, Matched<V>> {
    using type = Apply<M, V>;
  };
}
/// (a -> c) -> (b -> c) -> (Matching a b) -> c
using matching    = TypeFunction<_matching>;
using isUnmatched = Apply<matching, Const<True>,  Const<False>>;
using isMatched   = Apply<matching, Const<False>, Const<True>>;

/** Left side matched will always propagate, left side unmatched dominates
 *  right side unmatched.
 *    (Matching a b) -> (Matching a b) -> (Matching a b)
 *  This is a non-abelian function, beware
 */
using matchAdd    = Apply<matching, ignore, Apply<compose, fconst, matched>>;

using fromUnmatched = Apply<matching, id, Void>;
using fromMatched   = Apply<matching, Void, id>;

namespace {
  template<typename M>
  struct _bind;
  template<typename V>
  struct _bind<Matched<V>> {
    using type = Const<Matched<V>>;
  };
  template<typename V>
  struct _bind<Unmatched<V>> {
    using resultf = Apply<flip, apply, V>;
    using type    = Apply<compose, Apply<matchAdd, Unmatched<V>>, resultf>;
  };
}

using return_      = unmatched;
using bind         = TypeFunction<_bind>;
using MatchingType = MonadFromBind<return_, bind>;
using fmap         = MatchingType::fmap;
using kleisli      = MatchingType::kleisli;
using join         = MatchingType::join;

/// A placeholder with a given type as its identifier
template<typename Key>
struct Placeholder { using type = Key; };
/// A placeholder matching anything
struct PlaceholderAny;
using _ = PlaceholderAny;

namespace {
  using ::hdr::maybe::Just;
  using ::hdr::maybe::Nothing;
  using ::hdr::maybe::fromJust;
  using ::hdr::maybe::maybe;
  using maybefmap = ::hdr::maybe::fmap;
  /** We don't want to use set/map/list since we are in core :(
   *  This might change in the future, when I get, I might inline maybe here
   *  Anyways, this implements flat map, so don't go too wild with placeholder
   *  count and we don't check anything.
   */
  template<typename _Key, typename _Val> struct KVPair;
  template<typename ... KVs> struct KVList;

  template<typename K, typename L> struct Join;
  using _join = TypeFunction<Join>;
  template<typename ... KVs, typename ... KLs>
  struct Join<KVList<KVs...>, KVList<KLs...>> {
    using type = KVList<KVs..., KLs...>;
  };

  template<typename List, typename Name> struct Get;
  using _get_maybe  = TypeFunction<Get>;
  template<typename Name>
  struct Get<KVList<>, Name> {
    using type = Nothing;
  };
  template<typename Name, typename Value, typename ... Rest>
  struct Get<KVList<KVPair<Name, Value>, Rest...>, Name> {
    using type = Just<Value>;
  };
  template<typename Name, typename First, typename ... Rest>
  struct Get<KVList<First, Rest...>, Name> {
    using type = typename Get<KVList<Rest...>, Name>::type;
  };
  using _get       = Apply<compose, Apply<compose, fromJust>, _get_maybe>;

  template<typename ... KVs> struct KVList {
    using get = Apply<_get, KVList<KVs...>>;
  };

  template<typename... Args> struct Flatten;
  template<>           struct Flatten<>  { using type = KVList<>; };
  template<typename K> struct Flatten<K> { using type = K; };
  template<typename K, typename ... R> struct Flatten<K, R...> {
    template<typename Ma, typename Mb>
    struct MaybeJoin {
      using mjoin = Apply<compose, Apply<compose, ::hdr::maybe::return_>, _join>;
      using first = Apply<maybe, Const<Nothing>, mjoin, Ma>;
      using type  = Apply<::hdr::maybe::bind, Mb, first>;
    };
    using T       = typename Flatten<R...>::type;
    using type    = Apply<TypeFunction<MaybeJoin>, K, T>;
  };

  /** Tries to deconstruct a type into the placeholders given into the template.
   *    Template -> Argument -> Maybe TemplateVars
   */
  template<typename Template, typename Actual>
  struct Decompose {
    template<typename T, typename S> struct IsSame { using type = False; };
    template<typename T> struct IsSame<T, T>       { using type = True;  };
    using type = Apply<when_else, typename IsSame<Template, Actual>::type, Just<KVList<>>, Nothing>;
  };
  using _decompose = TypeFunction<Decompose>;
  template<typename PKey, typename A>
  struct Decompose<Placeholder<PKey>, A> {
    using type = Just<KVList<KVPair<PKey, A>>>;
  };
  template<typename A>
  struct Decompose<PlaceholderAny, A> {
    using type = Just<KVList<>>;
  };
  template<template<typename...> typename A, typename ... TArgs, typename ... Args>
  struct Decompose<A<TArgs...>, A<Args...>> {
    using type = typename Flatten<Apply<_decompose, TArgs, Args>...>::type;
  };

  /** Constructs a WithClause
   *    Template -> (TemplateVars -> Bool) -> (TemplateVars -> B) -> A -> Maybe B
   */
  template<typename Template, typename Selector, typename Function>
  struct _with {
    using maybe_decomp = Apply<_decompose, Template>;                     // (A -> Maybe TemplateVars)
    using boolifier    = Apply<maybefmap, Selector>;                      // (Maybe TemplateVars -> Maybe Bool)
    using get_result   = Apply<maybefmap, Function>;                      // (Maybe TemplateVars -> Maybe B)
    template<typename B>
    using _selector    = Apply<when_else, B, get_result, Const<Nothing>>;
    using selector     = TemplateFunction<_selector>;                    // (Bool -> (Maybe TemplateVars -> Maybe B))
    using select_after = Apply<flip, selector>;                          // (Maybe TemplateVars -> Bool -> Maybe B)
    template<typename MTV>
    using _result_func = Apply<::hdr::maybe::bind, Apply<boolifier, MTV>, Apply<select_after, MTV>>;
    using result_func  = TemplateFunction<_result_func>;                 // (Maybe TemplateVars -> Maybe B)
    using maybe_result = Apply<compose, result_func, maybe_decomp>;      // (A -> Maybe B)
    template<typename A>
    using match_result = Apply<maybe, Unmatched<A>, matched, Apply<maybe_result, A>>;
    using type         = TemplateFunction<match_result>;                 // (A -> Match V)
  };
}
/** Constructor function for With
 *    Template -> (TemplateVars -> Bool) -> (TemplateVars -> B) -> A -> Match B
 */
using with_if   = TypeFunction<_with>;
template<typename Template, typename Selector, typename Function>
using WithIf    = Apply<with_if, Template, Selector, Function>;
///   Template -> (TemplateVars -> B) -> A -> Match B
using with      = Apply<flip, with_if, Const<True>>;
template<typename Template, typename Function>
using With      = Apply<with, Template, Function>;
/// Template -> V -> Maybe TemplateVars
using decompose = _decompose;
/** Supply the name used in the placeholder then the template vars. Error when
 *  there is no such keyword in the TemplatVars. The argument order makes it
 *  easier to use it for maybe::bind or in lambdas (as the name should be defined
 *  ad-hoc and known to the programmer).
 *    Name -> TemplateVars -> V
 *  If you already know the TemplateVars, you can also use `TemplateVars::get`, type
 *    Name -> V
 */
using get       = Apply<flip, _get>;

namespace {
  template<typename ... W> struct _match_body;
  template<> struct _match_body<> {
    using combined_function = unmatched;
  };
  template<typename V> struct _match_body<V> {
    using combined_function = V;
  };
  template<typename V, typename ... W> struct _match_body<V, W...> {
    using recursor = typename _match_body<W...>::combined_function;
    using combined_function = Apply<kleisli, V, recursor>;
  };
  template<typename ... W>
  using _bindable_matches = typename _match_body<W...>::combined_function;
}

/** Convenience non-type version for matching, syntactic sugar for folding
 *  multiple with statements with ::hdr::match::kleisli, then binding it to
 *  Unmatched V and finally unpacking. Will fail if it didn't match
 *    V -> [with-clause]* -> W
 */
template<typename V, typename ... W>
using Match = Apply<fromMatched, Apply<bind, Unmatched<V>, _bindable_matches<W...>>>;

}
#endif //HEADERLIB_HDR_MATCH_HPP
<commit_msg>Deferred value matching<commit_after>#ifndef HEADERLIB_HDR_CORE_MATCH_HPP
#define HEADERLIB_HDR_CORE_MATCH_HPP
/*
 * match.hpp
 *
 *  Created on: 22.02.2017
 *      Author: Andreas Molzer
 */
#include "hdr/core/std.hpp"
#include "hdr/types/maybe.hpp"

/** Limited (!!!) core matching, as a monad.
 *    match var [>>= (with template selector function)]*
 *  Essentially works as a monad M with M::return == match which constructs
 *  an 'Unmatched' type. with constructs a bindable function returning this type.
 *  Binding F to a Matched T will skip the application of F while binding to
 *  an unmatched will do it. This works like Maybe but instead Nothing/Matched
 *  carries an additional result type and Maybe/Unmatched is very much the same.
 *
 *  Limitations of core matching:
 *  Each placeholder can only be used once in a template, this is not (!) checked
 *  for. If you need this functionality, use advanced matching based on sets
 *  instead (uniqueness check needs set mechanics for performance).
 *  [WIP]
 *  Templates are declared like the type they are supposed to match but using
 *  Placholders instead of the true type parameters. Should the type definition
 *  depends on its parameters, a special form is provided (can't be constructed).
 *  This feature is not currently implemented.
 */
namespace hdr::match {

using ::hdr::std::Apply;
using ::hdr::std::Const;
using ::hdr::std::True;
using ::hdr::std::False;
using ::hdr::std::TemplateFunction;
using ::hdr::std::TypeFunction;
using ::hdr::std::Void;
using ::hdr::std::apply;
using ::hdr::std::compose;
using ::hdr::std::id;
using ::hdr::std::fconst;
using ::hdr::std::ignore;
using ::hdr::std::flip;
using ::hdr::std::when_else;
using ::hdr::monad::MonadFromBind;

/// Type definition of Unmatched
template<typename Var>
struct Unmatched;
using unmatched = TemplateFunction<Unmatched>;
/// Type definition of Matched
template<typename Var>
struct Matched;
using matched   = TemplateFunction<Matched>;

namespace {
  template<typename U, typename M, typename V> struct _matching;
  template<typename U, typename M, typename V>
  struct _matching<U, M, Unmatched<V>> {
    using type = Apply<U, V>;
  };
  template<typename U, typename M, typename V>
  struct _matching<U, M, Matched<V>> {
    using type = Apply<M, V>;
  };
}
/// (a -> c) -> (b -> c) -> (Matching a b) -> c
using matching    = TypeFunction<_matching>;
using isUnmatched = Apply<matching, Const<True>,  Const<False>>;
using isMatched   = Apply<matching, Const<False>, Const<True>>;

/** Left side matched will always propagate, left side unmatched dominates
 *  right side unmatched.
 *    (Matching a b) -> (Matching a b) -> (Matching a b)
 *  This is a non-abelian function, beware
 */
using matchAdd    = Apply<matching, ignore, Apply<compose, fconst, matched>>;

using fromUnmatched = Apply<matching, id, Void>;
using fromMatched   = Apply<matching, Void, id>;

namespace {
  template<typename M>
  struct _bind;
  template<typename V>
  struct _bind<Matched<V>> {
    using type = Const<Matched<V>>;
  };
  template<typename V>
  struct _bind<Unmatched<V>> {
    using resultf = Apply<flip, apply, V>;
    using type    = Apply<compose, Apply<matchAdd, Unmatched<V>>, resultf>;
  };
}

using return_      = unmatched;
using bind         = TypeFunction<_bind>;
using MatchingType = MonadFromBind<return_, bind>;
using fmap         = MatchingType::fmap;
using kleisli      = MatchingType::kleisli;
using join         = MatchingType::join;

/// A placeholder with a given type as its identifier
template<typename Key>
struct Placeholder;
/// A placeholder matching anything
struct PlaceholderAny;
using _ = PlaceholderAny;

namespace {
  using ::hdr::maybe::Just;
  using ::hdr::maybe::Nothing;
  using ::hdr::maybe::fromJust;
  using ::hdr::maybe::maybe;
  using maybefmap = ::hdr::maybe::fmap;
  /** We don't want to use set/map/list since we are in core :(
   *  This might change in the future, when I get, I might inline maybe here
   *  Anyways, this implements flat map, so don't go too wild with placeholder
   *  count and we don't check anything.
   */
  template<typename _Key, typename _Val> struct KVPair;
  template<typename ... KVs> struct KVList;

  template<typename K, typename L> struct Join;
  using _join = TypeFunction<Join>;
  template<typename ... KVs, typename ... KLs>
  struct Join<KVList<KVs...>, KVList<KLs...>> {
    using type = KVList<KVs..., KLs...>;
  };

  template<typename List, typename Name> struct Get;
  using _get_maybe  = TypeFunction<Get>;
  template<typename Name>
  struct Get<KVList<>, Name> {
    using type = Nothing;
  };
  template<typename Name, typename Value, typename ... Rest>
  struct Get<KVList<KVPair<Name, Value>, Rest...>, Name> {
    using type = Just<Value>;
  };
  template<typename Name, typename First, typename ... Rest>
  struct Get<KVList<First, Rest...>, Name> {
    using type = typename Get<KVList<Rest...>, Name>::type;
  };
  using _get       = Apply<compose, Apply<compose, fromJust>, _get_maybe>;

  template<typename ... KVs> struct KVList {
    using get = Apply<_get, KVList<KVs...>>;
  };

  template<typename... Args> struct Flatten;
  template<>           struct Flatten<>  { using type = KVList<>; };
  template<typename K> struct Flatten<K> { using type = K; };
  template<typename K, typename ... R> struct Flatten<K, R...> {
    template<typename Ma, typename Mb>
    struct MaybeJoin {
      using mjoin = Apply<compose, Apply<compose, ::hdr::maybe::return_>, _join>;
      using first = Apply<maybe, Const<Nothing>, mjoin, Ma>;
      using type  = Apply<::hdr::maybe::bind, Mb, first>;
    };
    using T       = typename Flatten<R...>::type;
    using type    = Apply<TypeFunction<MaybeJoin>, K, T>;
  };

  /** Tries to deconstruct a type into the placeholders given into the template.
   *    Template -> Argument -> Maybe TemplateVars
   */
  template<typename Template, typename Actual>
  struct Decompose {
    template<typename T, typename S> struct IsSame { using type = False; };
    template<typename T> struct IsSame<T, T>       { using type = True;  };
    using type = Apply<when_else, typename IsSame<Template, Actual>::type, Just<KVList<>>, Nothing>;
  };
  using _decompose = TypeFunction<Decompose>;
  template<typename PKey, typename A>
  struct Decompose<Placeholder<PKey>, A> {
    using type = Just<KVList<KVPair<PKey, A>>>;
  };
  template<typename A>
  struct Decompose<PlaceholderAny, A> {
    using type = Just<KVList<>>;
  };
  template<template<typename...> typename A, typename ... TArgs, typename ... Args>
  struct Decompose<A<TArgs...>, A<Args...>> {
    using type = typename Flatten<Apply<_decompose, TArgs, Args>...>::type;
  };

  /** Constructs a WithClause
   *    Template -> (TemplateVars -> Bool) -> (TemplateVars -> B) -> A -> Maybe B
   */
  template<typename Template, typename Selector, typename Function>
  struct _with {
    using maybe_decomp = Apply<_decompose, Template>;                     // (A -> Maybe TemplateVars)
    using boolifier    = Apply<maybefmap, Selector>;                      // (Maybe TemplateVars -> Maybe Bool)
    using get_result   = Apply<maybefmap, Function>;                      // (Maybe TemplateVars -> Maybe B)
    template<typename B>
    using _selector    = Apply<when_else, B, get_result, Const<Nothing>>;
    using selector     = TemplateFunction<_selector>;                    // (Bool -> (Maybe TemplateVars -> Maybe B))
    using select_after = Apply<flip, selector>;                          // (Maybe TemplateVars -> Bool -> Maybe B)
    template<typename MTV>
    using _result_func = Apply<::hdr::maybe::bind, Apply<boolifier, MTV>, Apply<select_after, MTV>>;
    using result_func  = TemplateFunction<_result_func>;                 // (Maybe TemplateVars -> Maybe B)
    using maybe_result = Apply<compose, result_func, maybe_decomp>;      // (A -> Maybe B)
    template<typename A>
    using match_result = Apply<maybe, Unmatched<A>, matched, Apply<maybe_result, A>>;
    using type         = TemplateFunction<match_result>;                 // (A -> Match V)
  };
}
/** Constructor function for With
 *    Template -> (TemplateVars -> Bool) -> (TemplateVars -> B) -> A -> Match B
 */
using with_if   = TypeFunction<_with>;
template<typename Template, typename Selector, typename Function>
using WithIf    = Apply<with_if, Template, Selector, Function>;
///   Template -> (TemplateVars -> B) -> A -> Match B
using with      = Apply<flip, with_if, Const<True>>;
template<typename Template, typename Function>
using With      = Apply<with, Template, Function>;
/// Template -> V -> Maybe TemplateVars
using decompose = _decompose;
/** Supply the name used in the placeholder then the template vars. Error when
 *  there is no such keyword in the TemplatVars. The argument order makes it
 *  easier to use it for maybe::bind or in lambdas (as the name should be defined
 *  ad-hoc and known to the programmer).
 *    Name -> TemplateVars -> V
 *  If you already know the TemplateVars, you can also use `TemplateVars::get`, type
 *    Name -> V
 */
using get       = Apply<flip, _get>;

namespace {
  template<typename ... W> struct _match_body;
  template<> struct _match_body<> {
    using combined_function = unmatched;
  };
  template<typename V> struct _match_body<V> {
    using combined_function = V;
  };
  template<typename V, typename ... W> struct _match_body<V, W...> {
    using recursor = typename _match_body<W...>::combined_function;
    using combined_function = Apply<kleisli, V, recursor>;
  };
  template<typename ... W>
  using _bindable_matches = typename _match_body<W...>::combined_function;
}

/** Convenience non-type version for matching, syntactic sugar for folding
 *  multiple with statements with ::hdr::match::kleisli, then binding it to
 *  Unmatched V and finally unpacking. Will fail if it didn't match
 *    V -> [with-clause]* -> W
 */
template<typename V, typename ... W>
using Match = Apply<fromMatched, Apply<bind, Unmatched<V>, _bindable_matches<W...>>>;
/** 'Flipped' version of Match, deferring application of the argument
 *    [with-clause]* -> V -> W
 */
template<typename ... W>
using MatchClause = Apply<compose, fromMatched, _bindable_matches<W...>>;

}
#endif //HEADERLIB_HDR_MATCH_HPP
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id: b699d14f47fba93f2a13236bf24c6fd61f938363 $
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/StoredValueRef.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/FileSystem.h"

#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             StoredValueRef* result) {
    if (result)
      *result = StoredValueRef::invalidValue();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
      return expectedIndent;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->getInput();
    m_InputValidator->reset();
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(llvm::StringRef file, llvm::StringRef args,
                                  Interpreter::CompilationResult& compRes,
                                  StoredValueRef* result) {
    // Look for start of parameters:
    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairPathFile = file.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    Interpreter::CompilationResult interpRes = m_Interp.loadFile(file);
    if (interpRes == Interpreter::kSuccess) {
      std::string expression = pairFuncExt.first.str() + "(" + args.str() + ")";
      m_CurrentlyExecutingFile = file;
      bool topmost = !m_TopExecutingFile.data();
      if (topmost)
        m_TopExecutingFile = m_CurrentlyExecutingFile;

      interpRes = m_Interp.process(expression, result);

      m_CurrentlyExecutingFile = llvm::StringRef();
      if (topmost)
        m_TopExecutingFile = llvm::StringRef();
    }
    compRes = interpRes;
    return (interpRes != Interpreter::kFailure);
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                 StoredValueRef* result,
                                 bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magic);
        if (fileType != llvm::sys::fs::file_magic::unknown) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    std::string content(size, ' ');
    in.seekg(0);
    in.read(&content[0], size);

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      std::string::size_type replaced = posNonWS;
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              // More text (comments) are okay after the last '}', but
              // we can not easily find it to remove it (so we need to upgrade
              // this code to better handle the case with comments or
              // preprocessor code before and after the leading { and
              // trailing })
              content[replaced] = '{';
              // By putting the '{' back, we keep the code as consistent as
              // the user wrote it ... but we should still warn that we not
              // goint to treat this file an unamed macro.
              llvm::errs()
               << "Warning in cling::MetaProcessor: can not find the closing '}', "
               << llvm::sys::path::filename(filename)
               << " is not handled as an unamed script!\n";
            }
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    if (process(content.c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

} // end namespace cling
<commit_msg>Fix include.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id: b699d14f47fba93f2a13236bf24c6fd61f938363 $
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/MetaProcessor/MetaProcessor.h"

#include "Display.h"
#include "InputValidator.h"
#include "MetaParser.h"
#include "MetaSema.h"
#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/StoredValueRef.h"

#include "clang/Basic/FileManager.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Lex/Preprocessor.h"

#include "llvm/Support/Path.h"

#include <fstream>
#include <cstdlib>
#include <cctype>

using namespace clang;

namespace cling {

  MetaProcessor::MetaProcessor(Interpreter& interp, raw_ostream& outs)
    : m_Interp(interp), m_Outs(outs) {
    m_InputValidator.reset(new InputValidator());
    m_MetaParser.reset(new MetaParser(new MetaSema(interp, *this)));
  }

  MetaProcessor::~MetaProcessor() {}

  int MetaProcessor::process(const char* input_text,
                             Interpreter::CompilationResult& compRes,
                             StoredValueRef* result) {
    if (result)
      *result = StoredValueRef::invalidValue();
    compRes = Interpreter::kSuccess;
    int expectedIndent = m_InputValidator->getExpectedIndent();

    if (expectedIndent)
      compRes = Interpreter::kMoreInputExpected;
    if (!input_text || !input_text[0]) {
      // nullptr / empty string, nothing to do.
      return expectedIndent;
    }
    std::string input_line(input_text);
    if (input_line == "\n") { // just a blank line, nothing to do.
      return expectedIndent;
    }
    //  Check for and handle meta commands.
    m_MetaParser->enterNewInputLine(input_line);
    MetaSema::ActionResult actionResult = MetaSema::AR_Success;
    if (m_MetaParser->isMetaCommand(actionResult, result)) {

      if (m_MetaParser->isQuitRequested())
        return -1;

      if (actionResult != MetaSema::AR_Success)
        compRes = Interpreter::kFailure;
      return expectedIndent;
    }

    // Check if the current statement is now complete. If not, return to
    // prompt for more.
    if (m_InputValidator->validate(input_line) == InputValidator::kIncomplete) {
      compRes = Interpreter::kMoreInputExpected;
      return m_InputValidator->getExpectedIndent();
    }

    //  We have a complete statement, compile and execute it.
    std::string input = m_InputValidator->getInput();
    m_InputValidator->reset();
    // if (m_Options.RawInput)
    //   compResLocal = m_Interp.declare(input);
    // else
    compRes = m_Interp.process(input, result);

    return 0;
  }

  void MetaProcessor::cancelContinuation() const {
    m_InputValidator->reset();
  }

  int MetaProcessor::getExpectedIndent() const {
    return m_InputValidator->getExpectedIndent();
  }

  // Run a file: .x file[(args)]
  bool MetaProcessor::executeFile(llvm::StringRef file, llvm::StringRef args,
                                  Interpreter::CompilationResult& compRes,
                                  StoredValueRef* result) {
    // Look for start of parameters:
    typedef std::pair<llvm::StringRef,llvm::StringRef> StringRefPair;

    StringRefPair pairPathFile = file.rsplit('/');
    if (pairPathFile.second.empty()) {
       pairPathFile.second = pairPathFile.first;
    }
    StringRefPair pairFuncExt = pairPathFile.second.rsplit('.');

    Interpreter::CompilationResult interpRes = m_Interp.loadFile(file);
    if (interpRes == Interpreter::kSuccess) {
      std::string expression = pairFuncExt.first.str() + "(" + args.str() + ")";
      m_CurrentlyExecutingFile = file;
      bool topmost = !m_TopExecutingFile.data();
      if (topmost)
        m_TopExecutingFile = m_CurrentlyExecutingFile;

      interpRes = m_Interp.process(expression, result);

      m_CurrentlyExecutingFile = llvm::StringRef();
      if (topmost)
        m_TopExecutingFile = llvm::StringRef();
    }
    compRes = interpRes;
    return (interpRes != Interpreter::kFailure);
  }

  Interpreter::CompilationResult
  MetaProcessor::readInputFromFile(llvm::StringRef filename,
                                 StoredValueRef* result,
                                 bool ignoreOutmostBlock /*=false*/) {

    {
      // check that it's not binary:
      std::ifstream in(filename.str().c_str(), std::ios::in | std::ios::binary);
      char magic[1024] = {0};
      in.read(magic, sizeof(magic));
      size_t readMagic = in.gcount();
      if (readMagic >= 4) {
        llvm::sys::fs::file_magic fileType
          = llvm::sys::fs::identify_magic(magic);
        if (fileType != llvm::sys::fs::file_magic::unknown) {
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a binary file!\n";
          return Interpreter::kFailure;
        }
        unsigned printable = 0;
        for (size_t i = 0; i < readMagic; ++i)
          if (isprint(magic[i]))
            ++printable;
        if (10 * printable <  5 * readMagic) {
          // 50% printable for ASCII files should be a safe guess.
          llvm::errs() << "Error in cling::MetaProcessor: "
            "cannot read input from a (likely) binary file!\n" << printable;
          return Interpreter::kFailure;
        }
      }
    }

    std::ifstream in(filename.str().c_str());
    in.seekg(0, std::ios::end);
    size_t size = in.tellg();
    std::string content(size, ' ');
    in.seekg(0);
    in.read(&content[0], size);

    if (ignoreOutmostBlock && !content.empty()) {
      static const char whitespace[] = " \t\r\n";
      std::string::size_type posNonWS = content.find_first_not_of(whitespace);
      std::string::size_type replaced = posNonWS;
      if (posNonWS != std::string::npos) {
        if (content[posNonWS] == '{') {
          // hide the curly brace:
          content[posNonWS] = ' ';
          // and the matching closing '}'
          posNonWS = content.find_last_not_of(whitespace);
          if (posNonWS != std::string::npos) {
            if (content[posNonWS] == ';' && content[posNonWS-1] == '}') {
              content[posNonWS--] = ' '; // replace ';' and enter next if
            }
            if (content[posNonWS] == '}') {
              content[posNonWS] = ' '; // replace '}'
            } else {
              // More text (comments) are okay after the last '}', but
              // we can not easily find it to remove it (so we need to upgrade
              // this code to better handle the case with comments or
              // preprocessor code before and after the leading { and
              // trailing })
              content[replaced] = '{';
              // By putting the '{' back, we keep the code as consistent as
              // the user wrote it ... but we should still warn that we not
              // goint to treat this file an unamed macro.
              llvm::errs()
               << "Warning in cling::MetaProcessor: can not find the closing '}', "
               << llvm::sys::path::filename(filename)
               << " is not handled as an unamed script!\n";
            }
          } // find '}'
        } // have '{'
      } // have non-whitespace
    } // ignore outmost block

    std::string strFilename(filename.str());
    m_CurrentlyExecutingFile = strFilename;
    bool topmost = !m_TopExecutingFile.data();
    if (topmost)
      m_TopExecutingFile = m_CurrentlyExecutingFile;
    Interpreter::CompilationResult ret;
    if (process(content.c_str(), ret, result)) {
      // Input file has to be complete.
       llvm::errs()
          << "Error in cling::MetaProcessor: file "
          << llvm::sys::path::filename(filename)
          << " is incomplete (missing parenthesis or similar)!\n";
      ret = Interpreter::kFailure;
    }
    m_CurrentlyExecutingFile = llvm::StringRef();
    if (topmost)
      m_TopExecutingFile = llvm::StringRef();
    return ret;
  }

} // end namespace cling
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/UserInterface/UserInterface.h"

#include "cling/Interpreter/RuntimeException.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/PathV1.h"
#include "llvm/Config/config.h"

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif

#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif

namespace cling {
  UserInterface::UserInterface(Interpreter& interp) {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).
    static llvm::raw_fd_ostream m_MPOuts (STDOUT_FILENO, /*ShouldClose*/false);
    m_MetaProcessor.reset(new MetaProcessor(interp, m_MPOuts));
  }

  UserInterface::~UserInterface() {}

  void UserInterface::runInteractively(bool nologo /* = false */) {
    if (!nologo) {
      PrintLogo();
    }

    // History file is $HOME/.cling_history
    static const char* histfile = ".cling_history";
    llvm::sys::Path histfilePath = llvm::sys::Path::GetUserHomeDirectory();
    histfilePath.appendComponent(histfile);

    using namespace textinput;
    StreamReader* R = StreamReader::Create();
    TerminalDisplay* D = TerminalDisplay::Create();
    TextInput TI(*R, *D, histfilePath.c_str());

    TI.SetPrompt("[cling]$ ");
    std::string line;
    while (true) {
      try {
        m_MetaProcessor->getOuts().flush();
        TextInput::EReadResult RR = TI.ReadInput();
        TI.TakeInput(line);
        if (RR == TextInput::kRREOF) {
          break;
        }

        cling::Interpreter::CompilationResult compRes;
        int indent
          = m_MetaProcessor->process(line.c_str(), compRes, 0/*result*/);
        // Quit requested
        if (indent < 0)
          break;
        std::string Prompt = "[cling]";
        if (m_MetaProcessor->getInterpreter().isRawInputEnabled())
          Prompt.append("! ");
        else
          Prompt.append("$ ");

        if (indent > 0)
          // Continuation requested.
          Prompt.append('?' + std::string(indent * 3, ' '));

        TI.SetPrompt(Prompt.c_str());

      }
      catch(runtime::NullDerefException& e) {
        e.diagnose();
      }
      catch(runtime::InterpreterException& e) {
        llvm::errs() << e.what();
      }
      catch(...) {
        llvm::errs() << "Exception occurred. Recovering...\n";
      }
    }
  }

  void UserInterface::PrintLogo() {
    llvm::raw_ostream& outs = m_MetaProcessor->getOuts();
    outs << "\n";
    outs << "****************** CLING ******************" << "\n";
    outs << "* Type C++ code and press enter to run it *" << "\n";
    outs << "*             Type .q to exit             *" << "\n";
    outs << "*******************************************" << "\n";
  }
} // end namespace cling
<commit_msg>Install fatal error handler throwing an exception. Yes that is dangerous.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "cling/UserInterface/UserInterface.h"

#include "cling/Interpreter/RuntimeException.h"
#include "cling/Interpreter/StoredValueRef.h"
#include "cling/MetaProcessor/MetaProcessor.h"
#include "textinput/TextInput.h"
#include "textinput/StreamReader.h"
#include "textinput/TerminalDisplay.h"

#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/PathV1.h"
#include "llvm/Config/config.h"

// Fragment copied from LLVM's raw_ostream.cpp
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif

#if defined(_MSC_VER)
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#endif

namespace cling {
  class compilerException: public std::exception {
  public:
    compilerException(const std::string& reason): Reason(reason) {}
    ~compilerException() throw() {}
    virtual const char* what() const throw() { return Reason.c_str(); }
  private:
    std::string Reason;
  };
}

namespace {
  // Handle fatal llvm errors by throwing an exception..
  // Yes, throwing exceptions in error handlers is bad.
  // Doing nothing is pretty terrible, too.
  void exceptionErrorHandler(void * /*user_data*/,
                             const std::string& reason,
                             bool /*gen_crash_diag*/) {
    throw cling::compilerException(reason);
  }
}

namespace cling {
  UserInterface::UserInterface(Interpreter& interp) {
    // We need stream that doesn't close its file descriptor, thus we are not
    // using llvm::outs. Keeping file descriptor open we will be able to use
    // the results in pipes (Savannah #99234).
    static llvm::raw_fd_ostream m_MPOuts (STDOUT_FILENO, /*ShouldClose*/false);
    m_MetaProcessor.reset(new MetaProcessor(interp, m_MPOuts));
    llvm::install_fatal_error_handler(&exceptionErrorHandler);
  }

  UserInterface::~UserInterface() {}

  void UserInterface::runInteractively(bool nologo /* = false */) {
    if (!nologo) {
      PrintLogo();
    }

    // History file is $HOME/.cling_history
    static const char* histfile = ".cling_history";
    llvm::sys::Path histfilePath = llvm::sys::Path::GetUserHomeDirectory();
    histfilePath.appendComponent(histfile);

    using namespace textinput;
    StreamReader* R = StreamReader::Create();
    TerminalDisplay* D = TerminalDisplay::Create();
    TextInput TI(*R, *D, histfilePath.c_str());

    TI.SetPrompt("[cling]$ ");
    std::string line;
    while (true) {
      try {
        m_MetaProcessor->getOuts().flush();
        TextInput::EReadResult RR = TI.ReadInput();
        TI.TakeInput(line);
        if (RR == TextInput::kRREOF) {
          break;
        }

        cling::Interpreter::CompilationResult compRes;
        int indent
          = m_MetaProcessor->process(line.c_str(), compRes, 0/*result*/);
        // Quit requested
        if (indent < 0)
          break;
        std::string Prompt = "[cling]";
        if (m_MetaProcessor->getInterpreter().isRawInputEnabled())
          Prompt.append("! ");
        else
          Prompt.append("$ ");

        if (indent > 0)
          // Continuation requested.
          Prompt.append('?' + std::string(indent * 3, ' '));

        TI.SetPrompt(Prompt.c_str());

      }
      catch(runtime::NullDerefException& e) {
        e.diagnose();
      }
      catch(runtime::InterpreterException& e) {
        llvm::errs() << e.what();
      }
      catch(...) {
        llvm::errs() << "Exception occurred. Recovering...\n";
      }
    }
  }

  void UserInterface::PrintLogo() {
    llvm::raw_ostream& outs = m_MetaProcessor->getOuts();
    outs << "\n";
    outs << "****************** CLING ******************" << "\n";
    outs << "* Type C++ code and press enter to run it *" << "\n";
    outs << "*             Type .q to exit             *" << "\n";
    outs << "*******************************************" << "\n";
  }
} // end namespace cling
<|endoftext|>


<commit_before>/*
Copyright 2016 Peter Repukat - FlatspotSoftware

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "GloSC.h"

GloSC::GloSC(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	updateEntryList();
	updateTargetsToNewVersion();

}

void GloSC::updateEntryList()
{
	ui.lwInstances->clear();

	QDir dir(".\\");
	QStringList dirNames = dir.entryList(QDir::Dirs);

	for (auto &dirName : dirNames)
	{
		if (dirName != "." && dirName != ".." && dirName != "platforms")
			ui.lwInstances->addItem(dirName);
	}

}

void GloSC::writeIni(QString entryName)
{
	QSettings settings(entryName + "\\TargetConfig.ini", QSettings::IniFormat);

	settings.beginGroup("BaseConf");

	settings.setValue("bEnableOverlay", 0 + ui.cbOverlay->isChecked());
	settings.setValue("bEnableControllers", 0 + ui.cbControllers->isChecked());
	settings.setValue("bHookSteam", 1);

	settings.endGroup();

	settings.beginGroup("LaunchGame");

	settings.setValue("bLaunchGame", 0 + ui.cbLaunchGame->isChecked());
	if (ui.cbLaunchGame->isChecked())
	{
		settings.setValue("Path", ui.lePath->text());
		if (ui.lePath->text().contains("\\") || ui.lePath->text().contains("/"))
		{
			settings.setValue("Type", "Win32");
		} else {
			settings.setValue("Type", "UWP");
		}
	}

	settings.setValue("bCloseWhenDone", 0 + ui.cbCloseWhenDone->isChecked());

	settings.endGroup();

}

void GloSC::updateTargetsToNewVersion()
{
	//incredible lazy way to update to this next version but eh...
	for (int i = 0; i < ui.lwInstances->count(); i++)
	{
		on_lwInstances_currentRowChanged(i);
		QString name = ui.leName->text();

		QSettings settings(name + "\\TargetConfig.ini", QSettings::IniFormat);
		settings.beginGroup("BaseConf");
		bool newVersion = settings.value("bHookSteam").toBool();
		settings.endGroup();

		if (!newVersion)
			settings.endGroup();

		on_pbSave_clicked();
	}
}

void GloSC::on_pbSave_clicked()
{
	QString name = ui.leName->text();
	name.remove("\\");
	name.remove("/");
	name.remove(":");
	name.remove(".");

	QString temp = name;
	if (temp.remove(" ") == "")
		return;

	QDir dir(name);
	if (!dir.exists())
		dir.mkdir(".");

#ifdef NDEBUG
	QString fileNames[] = {
		"Qt5Core.dll",
		"Qt5Gui.dll",
		"Qt5Widgets.dll",
		"sfml-system-2.dll",
		"sfml-window-2.dll",
		"sfml-graphics-2.dll",
		"ViGEmUM.dll",
		"TargetConfig.ini" };
#else
	QString fileNames[] = {
		"Qt5Cored.dll",
		"Qt5Guid.dll",
		"Qt5Widgetsd.dll",
		"sfml-system-d-2.dll",
		"sfml-window-d-2.dll",
		"sfml-graphics-d-2.dll",
		"ViGEmUM.dll",
		"TargetConfig.ini"
};
#endif

	for (auto &fileName : fileNames)
	{
		QFile::copy(fileName, dir.path() + "\\" + fileName);
	}
	QDir platformdir(name + "\\platforms");
	if (!platformdir.exists())
		platformdir.mkdir(".");

	QFile::copy("platforms\\qwindows.dll", dir.path() + "\\" + "platforms\\qwindows.dll");
	QFile::copy("SteamTarget.exe", dir.path() + "\\" + name + ".exe");

	writeIni(name);

	updateEntryList();

}

void GloSC::on_pbDelete_clicked()
{
	QString name = ui.leName->text();
	name.remove("\\");
	name.remove("/");
	name.remove(":");
	name.remove(".");

	QString temp = name;
	if (temp.remove(" ") == "")
		return;

	QDir dir(name);
	if (dir.exists())
	{
		dir.removeRecursively();
	}
	updateEntryList();
}

void GloSC::on_pbAddToSteam_clicked()
{
	QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Valve\\Steam", QSettings::NativeFormat);
	QString steamPath = settings.value("SteamPath").toString();
	QString activeUser = settings.value("ActiveProcess/ActiveUser").toString();

	QFile shortcutsFile(steamPath + "/userdata/" + activeUser + "/config/shortcuts.vdf");

	if (!shortcutsFile.exists())
	{
		QMessageBox::information(this, "GloSC", "Couldn't detect Steam shortcuts file!", QMessageBox::Ok);
		return;
	}
	if (!shortcutsFile.open(QFile::ReadWrite))
	{
		QMessageBox::information(this, "GloSC", "Couldn't open Steam shortcuts file!", QMessageBox::Ok);
		return;
	}

	//just detect already present paths the easy way and hardcode the actual shortcut structure
	//will prob. come back to bite me, but for now it should be enough
	QByteArray shortcutsFileBytes = shortcutsFile.readAll();

	//get shortcutcount
	QByteArray temp = shortcutsFileBytes;
	temp.chop(9); //chop off last "tags"
	temp = temp.mid(temp.lastIndexOf("tags") + 8, temp.size() - 1);
	int shortcutCount = QString(temp).toInt();

	QString itemName;
	QString appDir = QDir::toNativeSeparators(QCoreApplication::applicationFilePath().mid(0, QCoreApplication::applicationFilePath().lastIndexOf("/")));
	for (int i = 0; i < ui.lwInstances->count(); i++)
	{
		itemName = ui.lwInstances->item(i)->text();
		if (!shortcutsFileBytes.contains(QString(appDir + "\\" + itemName + "\\" + itemName + ".exe").toStdString().c_str()))
		{
			shortcutsFileBytes.chop(2); //chop of end bytes
			shortcutCount++;

			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString::number(shortcutCount));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("appname");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(itemName);
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("exe");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString("\"" + appDir + "\\" + itemName + "\\" + itemName + ".exe\""));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("StartDir");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString("\"" + appDir + "\\" + itemName + "\\" + "\""));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("icon");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("ShortcutPath");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("IsHidden");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("AllowDesktopConfig");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("OpenVR");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append("tags");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x08');
			shortcutsFileBytes.append('\x08');

			//append chopped of bytes
			shortcutsFileBytes.append('\x08');
			shortcutsFileBytes.append('\x08');
		}
	}

	shortcutsFile.close();
	if (!shortcutsFile.open(QFile::ReadWrite | QIODevice::Truncate)) //damn qt is complicated...
	{
		QMessageBox::information(this, "GloSC", "Couldn't open Steam shortcuts file!", QMessageBox::Ok);
		return;
	}

	shortcutsFile.write(shortcutsFileBytes);

	shortcutsFile.close();
	QMessageBox::information(this, "GloSC", "Shortcuts were added! Restart Steam for changes to take effect!", QMessageBox::Ok);

}

void GloSC::on_pbSearchPath_clicked()
{
	QString filePath = QFileDialog::getOpenFileName(this, "Select Game", "", "*.exe");
	ui.lePath->setText(filePath);
}

void GloSC::on_pbUWP_clicked()
{
	QSettings *settings = new QSettings("HKEY_CLASSES_ROOT", QSettings::NativeFormat);

	QStringList childs = settings->childGroups();
	QStringList packages;

	for (auto& child : childs)
	{
		if (child.indexOf("AppX") == 0)
		{
			packages << child;
		}
	}

	delete settings;

	QList<UWPPair> pairs;

	QString AppName;
	QString AppUMId;

	QStringList AppNames;
	QStringList AppUMIds;

	for (auto &package : packages)
	{
		settings = new QSettings("HKEY_CLASSES_ROOT\\"+package, QSettings::NativeFormat);

		AppName = settings->value("Application/ApplicationName").toString();
		AppUMId = settings->value("Application/AppUserModelID").toString();
		if (!AppNames.contains(AppName) && !AppUMIds.contains(AppUMId) && AppUMId.size() > 0)
		{

			AppNames << AppName;
			AppUMIds << AppUMId;

			if (AppName.size() == 0)
			{
				AppName = "Unknown";
			} else if (AppName.at(0) == '@') {
				QString packageName = AppName.mid(AppName.indexOf('{') + 1, AppName.size() -1);
				packageName = packageName.mid(0, packageName.indexOf('?'));
				QStringList cachedNameChildGroups;
				QSettings settings("HKEY_CLASSES_ROOT\\Local Settings\\MrtCache", QSettings::NativeFormat);

				cachedNameChildGroups = settings.childGroups();

				for (auto &childGroup : cachedNameChildGroups)
				{

					if (childGroup.contains(packageName))
					{
						QSettings settings("HKEY_CLASSES_ROOT\\Local Settings\\MrtCache\\"+ childGroup, QSettings::NativeFormat);

						QStringList allKeys = settings.allKeys();

						AppName.replace("/", "\\");
						for (auto &key : allKeys)
						{
							if (key.contains(AppName))
							{
								AppName = settings.value(key).toString();
								break;
							}
						}

						break;
					}
				}
				if (AppName.at(0) == '@') {
					AppName = "Unknown";
				}
			}

			UWPPair uwpPair = {
				AppName,
				AppUMId,
			};

			pairs.push_back(uwpPair);

		}
		delete settings;
	}

	uwpPairs = pairs;

	UWPSelectDialog dialog(this);
	dialog.setUWPList(uwpPairs);
	int selection = dialog.exec();

	if (selection > -1)
	{
		ui.lePath->setText(uwpPairs.at(selection).AppUMId);
	}

}

void GloSC::on_lwInstances_currentRowChanged(int row)
{
	if (row < 0)
		return;
	QString entryName = ui.lwInstances->item(row)->text();
	ui.leName->setText(entryName);

	QSettings settings(entryName + "\\TargetConfig.ini", QSettings::IniFormat);

	settings.beginGroup("BaseConf");

	ui.cbOverlay->setChecked(settings.value("bEnableOverlay").toBool());
	ui.cbControllers->setChecked(settings.value("bEnableControllers").toBool());

	settings.endGroup();

	settings.beginGroup("LaunchGame");

	ui.cbLaunchGame->setChecked(settings.value("bLaunchGame").toBool());
	if (ui.cbLaunchGame->isChecked())
	{
		ui.lePath->setText(settings.value("Path").toString());
	}
	ui.cbCloseWhenDone->setChecked(settings.value("bCloseWhenDone").toBool());

	settings.endGroup();

}
<commit_msg>don't allow shortcuts to be added to steam if there aren't any<commit_after>/*
Copyright 2016 Peter Repukat - FlatspotSoftware

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "GloSC.h"

GloSC::GloSC(QWidget *parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	updateEntryList();
	updateTargetsToNewVersion();

}

void GloSC::updateEntryList()
{
	ui.lwInstances->clear();

	QDir dir(".\\");
	QStringList dirNames = dir.entryList(QDir::Dirs);

	for (auto &dirName : dirNames)
	{
		if (dirName != "." && dirName != ".." && dirName != "platforms")
			ui.lwInstances->addItem(dirName);
	}

}

void GloSC::writeIni(QString entryName)
{
	QSettings settings(entryName + "\\TargetConfig.ini", QSettings::IniFormat);

	settings.beginGroup("BaseConf");

	settings.setValue("bEnableOverlay", 0 + ui.cbOverlay->isChecked());
	settings.setValue("bEnableControllers", 0 + ui.cbControllers->isChecked());
	settings.setValue("bHookSteam", 1);

	settings.endGroup();

	settings.beginGroup("LaunchGame");

	settings.setValue("bLaunchGame", 0 + ui.cbLaunchGame->isChecked());
	if (ui.cbLaunchGame->isChecked())
	{
		settings.setValue("Path", ui.lePath->text());
		if (ui.lePath->text().contains("\\") || ui.lePath->text().contains("/"))
		{
			settings.setValue("Type", "Win32");
		} else {
			settings.setValue("Type", "UWP");
		}
	}

	settings.setValue("bCloseWhenDone", 0 + ui.cbCloseWhenDone->isChecked());

	settings.endGroup();

}

void GloSC::updateTargetsToNewVersion()
{
	//incredible lazy way to update to this next version but eh...
	for (int i = 0; i < ui.lwInstances->count(); i++)
	{
		on_lwInstances_currentRowChanged(i);
		QString name = ui.leName->text();

		QSettings settings(name + "\\TargetConfig.ini", QSettings::IniFormat);
		settings.beginGroup("BaseConf");
		bool newVersion = settings.value("bHookSteam").toBool();
		settings.endGroup();

		if (!newVersion)
			settings.endGroup();

		on_pbSave_clicked();
	}
}

void GloSC::on_pbSave_clicked()
{
	QString name = ui.leName->text();
	name.remove("\\");
	name.remove("/");
	name.remove(":");
	name.remove(".");

	QString temp = name;
	if (temp.remove(" ") == "")
		return;

	QDir dir(name);
	if (!dir.exists())
		dir.mkdir(".");

#ifdef NDEBUG
	QString fileNames[] = {
		"Qt5Core.dll",
		"Qt5Gui.dll",
		"Qt5Widgets.dll",
		"sfml-system-2.dll",
		"sfml-window-2.dll",
		"sfml-graphics-2.dll",
		"ViGEmUM.dll",
		"TargetConfig.ini" };
#else
	QString fileNames[] = {
		"Qt5Cored.dll",
		"Qt5Guid.dll",
		"Qt5Widgetsd.dll",
		"sfml-system-d-2.dll",
		"sfml-window-d-2.dll",
		"sfml-graphics-d-2.dll",
		"ViGEmUM.dll",
		"TargetConfig.ini"
};
#endif

	for (auto &fileName : fileNames)
	{
		QFile::copy(fileName, dir.path() + "\\" + fileName);
	}
	QDir platformdir(name + "\\platforms");
	if (!platformdir.exists())
		platformdir.mkdir(".");

	QFile::copy("platforms\\qwindows.dll", dir.path() + "\\" + "platforms\\qwindows.dll");
	QFile::copy("SteamTarget.exe", dir.path() + "\\" + name + ".exe");

	writeIni(name);

	updateEntryList();

}

void GloSC::on_pbDelete_clicked()
{
	QString name = ui.leName->text();
	name.remove("\\");
	name.remove("/");
	name.remove(":");
	name.remove(".");

	QString temp = name;
	if (temp.remove(" ") == "")
		return;

	QDir dir(name);
	if (dir.exists())
	{
		dir.removeRecursively();
	}
	updateEntryList();
}

void GloSC::on_pbAddToSteam_clicked()
{

	if (ui.lwInstances->count() <= 0)
	{
		QMessageBox::information(this, "GloSC", "No shortcuts! Create some shortcuts first for them to be added to Steam!", QMessageBox::Ok);
		return;
	}

	QSettings settings("HKEY_CURRENT_USER\\SOFTWARE\\Valve\\Steam", QSettings::NativeFormat);
	QString steamPath = settings.value("SteamPath").toString();
	QString activeUser = settings.value("ActiveProcess/ActiveUser").toString();

	QFile shortcutsFile(steamPath + "/userdata/" + activeUser + "/config/shortcuts.vdf");

	if (!shortcutsFile.exists())
	{
		QMessageBox::information(this, "GloSC", "Couldn't detect Steam shortcuts file!", QMessageBox::Ok);
		return;
	}
	if (!shortcutsFile.open(QFile::ReadWrite))
	{
		QMessageBox::information(this, "GloSC", "Couldn't open Steam shortcuts file!", QMessageBox::Ok);
		return;
	}

	//just detect already present paths the easy way and hardcode the actual shortcut structure
	//will prob. come back to bite me, but for now it should be enough
	QByteArray shortcutsFileBytes = shortcutsFile.readAll();

	//get shortcutcount
	QByteArray temp = shortcutsFileBytes;
	temp.chop(9); //chop off last "tags"
	temp = temp.mid(temp.lastIndexOf("tags") + 8, temp.size() - 1);
	int shortcutCount = QString(temp).toInt();

	QString itemName;
	QString appDir = QDir::toNativeSeparators(QCoreApplication::applicationFilePath().mid(0, QCoreApplication::applicationFilePath().lastIndexOf("/")));
	for (int i = 0; i < ui.lwInstances->count(); i++)
	{
		itemName = ui.lwInstances->item(i)->text();
		if (!shortcutsFileBytes.contains(QString(appDir + "\\" + itemName + "\\" + itemName + ".exe").toStdString().c_str()))
		{
			shortcutsFileBytes.chop(2); //chop of end bytes
			shortcutCount++;

			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString::number(shortcutCount));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("appname");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(itemName);
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("exe");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString("\"" + appDir + "\\" + itemName + "\\" + itemName + ".exe\""));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("StartDir");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append(QString("\"" + appDir + "\\" + itemName + "\\" + "\""));
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("icon");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append("ShortcutPath");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("IsHidden");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("AllowDesktopConfig");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x01');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x02');
			shortcutsFileBytes.append("OpenVR");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append("tags");
			shortcutsFileBytes.append('\x00');
			shortcutsFileBytes.append('\x08');
			shortcutsFileBytes.append('\x08');

			//append chopped of bytes
			shortcutsFileBytes.append('\x08');
			shortcutsFileBytes.append('\x08');
		}
	}

	shortcutsFile.close();
	if (!shortcutsFile.open(QFile::ReadWrite | QIODevice::Truncate)) //damn qt is complicated...
	{
		QMessageBox::information(this, "GloSC", "Couldn't open Steam shortcuts file!", QMessageBox::Ok);
		return;
	}

	shortcutsFile.write(shortcutsFileBytes);

	shortcutsFile.close();
	QMessageBox::information(this, "GloSC", "Shortcuts were added! Restart Steam for changes to take effect!", QMessageBox::Ok);

}

void GloSC::on_pbSearchPath_clicked()
{
	QString filePath = QFileDialog::getOpenFileName(this, "Select Game", "", "*.exe");
	ui.lePath->setText(filePath);
}

void GloSC::on_pbUWP_clicked()
{
	QSettings *settings = new QSettings("HKEY_CLASSES_ROOT", QSettings::NativeFormat);

	QStringList childs = settings->childGroups();
	QStringList packages;

	for (auto& child : childs)
	{
		if (child.indexOf("AppX") == 0)
		{
			packages << child;
		}
	}

	delete settings;

	QList<UWPPair> pairs;

	QString AppName;
	QString AppUMId;

	QStringList AppNames;
	QStringList AppUMIds;

	for (auto &package : packages)
	{
		settings = new QSettings("HKEY_CLASSES_ROOT\\"+package, QSettings::NativeFormat);

		AppName = settings->value("Application/ApplicationName").toString();
		AppUMId = settings->value("Application/AppUserModelID").toString();
		if (!AppNames.contains(AppName) && !AppUMIds.contains(AppUMId) && AppUMId.size() > 0)
		{

			AppNames << AppName;
			AppUMIds << AppUMId;

			if (AppName.size() == 0)
			{
				AppName = "Unknown";
			} else if (AppName.at(0) == '@') {
				QString packageName = AppName.mid(AppName.indexOf('{') + 1, AppName.size() -1);
				packageName = packageName.mid(0, packageName.indexOf('?'));
				QStringList cachedNameChildGroups;
				QSettings settings("HKEY_CLASSES_ROOT\\Local Settings\\MrtCache", QSettings::NativeFormat);

				cachedNameChildGroups = settings.childGroups();

				for (auto &childGroup : cachedNameChildGroups)
				{

					if (childGroup.contains(packageName))
					{
						QSettings settings("HKEY_CLASSES_ROOT\\Local Settings\\MrtCache\\"+ childGroup, QSettings::NativeFormat);

						QStringList allKeys = settings.allKeys();

						AppName.replace("/", "\\");
						for (auto &key : allKeys)
						{
							if (key.contains(AppName))
							{
								AppName = settings.value(key).toString();
								break;
							}
						}

						break;
					}
				}
				if (AppName.at(0) == '@') {
					AppName = "Unknown";
				}
			}

			UWPPair uwpPair = {
				AppName,
				AppUMId,
			};

			pairs.push_back(uwpPair);

		}
		delete settings;
	}

	uwpPairs = pairs;

	UWPSelectDialog dialog(this);
	dialog.setUWPList(uwpPairs);
	int selection = dialog.exec();

	if (selection > -1)
	{
		ui.lePath->setText(uwpPairs.at(selection).AppUMId);
	}

}

void GloSC::on_lwInstances_currentRowChanged(int row)
{
	if (row < 0)
		return;
	QString entryName = ui.lwInstances->item(row)->text();
	ui.leName->setText(entryName);

	QSettings settings(entryName + "\\TargetConfig.ini", QSettings::IniFormat);

	settings.beginGroup("BaseConf");

	ui.cbOverlay->setChecked(settings.value("bEnableOverlay").toBool());
	ui.cbControllers->setChecked(settings.value("bEnableControllers").toBool());

	settings.endGroup();

	settings.beginGroup("LaunchGame");

	ui.cbLaunchGame->setChecked(settings.value("bLaunchGame").toBool());
	if (ui.cbLaunchGame->isChecked())
	{
		ui.lePath->setText(settings.value("Path").toString());
	}
	ui.cbCloseWhenDone->setChecked(settings.value("bCloseWhenDone").toBool());

	settings.endGroup();

}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: MasterPageObserver.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 18:49:35 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "MasterPageObserver.hxx"

#include <algorithm>
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <hash_map>
#include <set>
#include <vector>
#include <svtools/lstner.hxx>
#ifndef INCLUDED_OSL_DOUBLECHECKEDLOCKING_H
#include <osl/doublecheckedlocking.h>
#endif
#ifndef INCLUDED_OSL_GETGLOBALMUTEX_HXX
#include <osl/getglobalmutex.hxx>
#endif

namespace sd {

class MasterPageObserver::Implementation
    : public SfxListener
{
public:
    /** The single instance of this class.  It is created on demand when
        Instance() is called for the first time.
    */
    static MasterPageObserver* mpInstance;

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
        SdDrawDocument& rDocument);

private:
    ::std::vector<Link> maListeners;

    struct DrawDocHash {
        size_t operator()(SdDrawDocument* argument) const
        { return reinterpret_cast<unsigned long>(argument); }
    };
    typedef ::std::hash_map<SdDrawDocument*,
                            MasterPageObserver::MasterPageNameSet,
                            DrawDocHash>
        MasterPageContainer;
    MasterPageContainer maUsedMasterPages;

    virtual void Notify(
        SfxBroadcaster& rBroadcaster,
        const SfxHint& rHint);

    void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);

    void SendEvent (MasterPageObserverEvent& rEvent);
};

MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;

//===== MasterPageObserver ====================================================

MasterPageObserver&  MasterPageObserver::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageObserver* pInstance = new MasterPageObserver ();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT(Implementation::mpInstance!=NULL,
        "MasterPageObserver::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}

void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->RegisterDocument (rDocument);
}

void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->UnregisterDocument (rDocument);
}

void MasterPageObserver::AddEventListener (const Link& rEventListener)
{

    mpImpl->AddEventListener (rEventListener);
}

void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
{
    mpImpl->RemoveEventListener (rEventListener);
}

MasterPageObserver::MasterPageObserver (void)
    : mpImpl (new Implementation())
{}

MasterPageObserver::~MasterPageObserver (void)
{}

MasterPageObserver::MasterPageNameSet MasterPageObserver::GetMasterPageNames (
    SdDrawDocument& rDocument)
{
    return mpImpl->GetMasterPageNames (rDocument);
}

//===== MasterPageObserver::Implementation ====================================

void MasterPageObserver::Implementation::RegisterDocument (
    SdDrawDocument& rDocument)
{
    // Gather the names of all the master pages in the given document.
    MasterPageContainer::data_type aMasterPageSet;
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aMasterPageSet.insert (pMasterPage->GetName());
    }

    maUsedMasterPages[&rDocument] = aMasterPageSet;

    StartListening (rDocument);
}

void MasterPageObserver::Implementation::UnregisterDocument (
    SdDrawDocument& rDocument)
{
    EndListening (rDocument);

    maUsedMasterPages.erase(maUsedMasterPages.find(&rDocument));
}

void MasterPageObserver::Implementation::AddEventListener (
    const Link& rEventListener)
{
    if (::std::find (
        maListeners.begin(),
        maListeners.end(),
        rEventListener) == maListeners.end())
    {
        maListeners.push_back (rEventListener);

        // Tell the new listener about all the master pages that are
        // currently in use.
        typedef ::std::vector<String> StringList;
        StringList aNewMasterPages;
        StringList aRemovedMasterPages;
        MasterPageContainer::iterator aDocumentIterator;
        for (aDocumentIterator=maUsedMasterPages.begin();
             aDocumentIterator!=maUsedMasterPages.end();
             ++aDocumentIterator)
        {
            ::std::set<String>::reverse_iterator aNameIterator;
            for (aNameIterator=aDocumentIterator->second.rbegin();
                 aNameIterator!=aDocumentIterator->second.rend();
                 ++aNameIterator)
            {
              MasterPageObserverEvent aEvent (
                  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
                  *aDocumentIterator->first,
                  *aNameIterator);
              SendEvent (aEvent);
            }
        }
    }
}

void MasterPageObserver::Implementation::RemoveEventListener (
    const Link& rEventListener)
{
    maListeners.erase (
        ::std::find (
            maListeners.begin(),
            maListeners.end(),
            rEventListener));
}

MasterPageObserver::MasterPageNameSet
    MasterPageObserver::Implementation::GetMasterPageNames (
        SdDrawDocument& rDocument)
{
    MasterPageContainer::iterator aMasterPageDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aMasterPageDescriptor != maUsedMasterPages.end())
        return aMasterPageDescriptor->second;
    else
        // Not found so return an empty set.
        return MasterPageObserver::MasterPageNameSet();
}

void MasterPageObserver::Implementation::Notify(
    SfxBroadcaster& rBroadcaster,
    const SfxHint& rHint)
{
    if (rHint.ISA(SdrHint))
    {
        SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
        switch (rSdrHint.GetKind())
        {
            case HINT_PAGEORDERCHG:
                // Process the modified set of pages only when the number of
                // standard and notes master pages are equal.  This test
                // filters out events that are sent in between the insertion
                // of a new standard master page and a new notes master
                // page.
                if (rBroadcaster.ISA(SdDrawDocument))
                {
                    SdDrawDocument& rDocument (
                        static_cast<SdDrawDocument&>(rBroadcaster));
                    if (rDocument.GetMasterSdPageCount(PK_STANDARD)
                        == rDocument.GetMasterSdPageCount(PK_NOTES))
                    {
                        AnalyzeUsedMasterPages (rDocument);
                    }
                }
                break;

            default:
                break;
        }
    }
}

void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
    SdDrawDocument& rDocument)
{
    // Create a set of names of the master pages used by the given document.
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    ::std::set<String> aCurrentMasterPages;
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aCurrentMasterPages.insert (pMasterPage->GetName());
        OSL_TRACE("currently used master page %d is %s",
            nIndex,
            ::rtl::OUStringToOString(pMasterPage->GetName(),
                RTL_TEXTENCODING_UTF8).getStr());
    }

    typedef ::std::vector<String> StringList;
    StringList aNewMasterPages;
    StringList aRemovedMasterPages;
    MasterPageContainer::iterator aOldMasterPagesDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
    {
        StringList::iterator I;

        ::std::set<String>::iterator J;
        int i=0;
        for (J=aOldMasterPagesDescriptor->second.begin();
             J!=aOldMasterPagesDescriptor->second.end();
             ++J)
            OSL_TRACE("old used master page %d is %s",
            i++,
            ::rtl::OUStringToOString(*J,
                RTL_TEXTENCODING_UTF8).getStr());

        // Send events about the newly used master pages.
        ::std::set_difference (
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            ::std::back_insert_iterator<StringList>(aNewMasterPages));
        for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
        {
            OSL_TRACE("    added master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Send events about master pages that are not used any longer.
        ::std::set_difference (
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
        for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
        {
            OSL_TRACE("    removed master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Store the new list of master pages.
        aOldMasterPagesDescriptor->second = aCurrentMasterPages;
    }
}

void MasterPageObserver::Implementation::SendEvent (
    MasterPageObserverEvent& rEvent)
{
    ::std::vector<Link>::iterator aLink (maListeners.begin());
    ::std::vector<Link>::iterator aEnd (maListeners.end());
    while (aLink!=aEnd)
    {
        aLink->Call (&rEvent);
        ++aLink;
    }
}

} // end of namespace sd
<commit_msg>INTEGRATION: CWS impress121 (1.6.98); FILE MERGED 2007/05/10 12:46:54 cl 1.6.98.1: #i76635# applied path for crash with STLport5<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: MasterPageObserver.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hr $ $Date: 2007-07-31 17:25:53 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"

#include "MasterPageObserver.hxx"

#include <algorithm>
#include "drawdoc.hxx"
#include "sdpage.hxx"
#include <hash_map>
#include <set>
#include <vector>
#include <svtools/lstner.hxx>
#ifndef INCLUDED_OSL_DOUBLECHECKEDLOCKING_H
#include <osl/doublecheckedlocking.h>
#endif
#ifndef INCLUDED_OSL_GETGLOBALMUTEX_HXX
#include <osl/getglobalmutex.hxx>
#endif

namespace sd {

class MasterPageObserver::Implementation
    : public SfxListener
{
public:
    /** The single instance of this class.  It is created on demand when
        Instance() is called for the first time.
    */
    static MasterPageObserver* mpInstance;

    /** The master page observer will listen to events of this document and
        detect changes of the use of master pages.
    */
    void RegisterDocument (SdDrawDocument& rDocument);

    /** The master page observer will stop to listen to events of this
        document.
    */
    void UnregisterDocument (SdDrawDocument& rDocument);

    /** Add a listener that is informed of master pages that are newly
        assigned to slides or become unassigned.
        @param rEventListener
            The event listener to call for future events.  Call
            RemoveEventListener() before the listener is destroyed.
    */
    void AddEventListener (const Link& rEventListener);

    /** Remove the given listener from the list of listeners.
        @param rEventListener
            After this method returns the given listener is not called back
            from this object.  Passing a listener that has not
            been registered before is safe and is silently ignored.
    */
    void RemoveEventListener (const Link& rEventListener);

    /** Return a set of the names of master pages for the given document.
        This convenience method exists because this set is part of the
        internal data structure and thus takes no time to create.
    */
    inline MasterPageObserver::MasterPageNameSet GetMasterPageNames (
        SdDrawDocument& rDocument);

private:
    ::std::vector<Link> maListeners;

    struct DrawDocHash {
        size_t operator()(SdDrawDocument* argument) const
        { return reinterpret_cast<unsigned long>(argument); }
    };
    typedef ::std::hash_map<SdDrawDocument*,
                            MasterPageObserver::MasterPageNameSet,
                            DrawDocHash>
        MasterPageContainer;
    MasterPageContainer maUsedMasterPages;

    virtual void Notify(
        SfxBroadcaster& rBroadcaster,
        const SfxHint& rHint);

    void AnalyzeUsedMasterPages (SdDrawDocument& rDocument);

    void SendEvent (MasterPageObserverEvent& rEvent);
};

MasterPageObserver* MasterPageObserver::Implementation::mpInstance = NULL;

//===== MasterPageObserver ====================================================

MasterPageObserver&  MasterPageObserver::Instance (void)
{
    if (Implementation::mpInstance == NULL)
    {
        ::osl::GetGlobalMutex aMutexFunctor;
        ::osl::MutexGuard aGuard (aMutexFunctor());
        if (Implementation::mpInstance == NULL)
        {
            MasterPageObserver* pInstance = new MasterPageObserver ();
            SdGlobalResourceContainer::Instance().AddResource (
                ::std::auto_ptr<SdGlobalResource>(pInstance));
            OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();
            Implementation::mpInstance = pInstance;
        }
    }
    else
        OSL_DOUBLE_CHECKED_LOCKING_MEMORY_BARRIER();

    DBG_ASSERT(Implementation::mpInstance!=NULL,
        "MasterPageObserver::Instance(): instance is NULL");
    return *Implementation::mpInstance;
}

void MasterPageObserver::RegisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->RegisterDocument (rDocument);
}

void MasterPageObserver::UnregisterDocument (SdDrawDocument& rDocument)
{
    mpImpl->UnregisterDocument (rDocument);
}

void MasterPageObserver::AddEventListener (const Link& rEventListener)
{

    mpImpl->AddEventListener (rEventListener);
}

void MasterPageObserver::RemoveEventListener (const Link& rEventListener)
{
    mpImpl->RemoveEventListener (rEventListener);
}

MasterPageObserver::MasterPageObserver (void)
    : mpImpl (new Implementation())
{}

MasterPageObserver::~MasterPageObserver (void)
{}

MasterPageObserver::MasterPageNameSet MasterPageObserver::GetMasterPageNames (
    SdDrawDocument& rDocument)
{
    return mpImpl->GetMasterPageNames (rDocument);
}

//===== MasterPageObserver::Implementation ====================================

void MasterPageObserver::Implementation::RegisterDocument (
    SdDrawDocument& rDocument)
{
    // Gather the names of all the master pages in the given document.
    MasterPageContainer::data_type aMasterPageSet;
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aMasterPageSet.insert (pMasterPage->GetName());
    }

    maUsedMasterPages[&rDocument] = aMasterPageSet;

    StartListening (rDocument);
}

void MasterPageObserver::Implementation::UnregisterDocument (
    SdDrawDocument& rDocument)
{
    EndListening (rDocument);

    MasterPageContainer::iterator aMasterPageDescriptor(maUsedMasterPages.find(&rDocument));
    if(aMasterPageDescriptor != maUsedMasterPages.end())
        maUsedMasterPages.erase(aMasterPageDescriptor);
}

void MasterPageObserver::Implementation::AddEventListener (
    const Link& rEventListener)
{
    if (::std::find (
        maListeners.begin(),
        maListeners.end(),
        rEventListener) == maListeners.end())
    {
        maListeners.push_back (rEventListener);

        // Tell the new listener about all the master pages that are
        // currently in use.
        typedef ::std::vector<String> StringList;
        StringList aNewMasterPages;
        StringList aRemovedMasterPages;
        MasterPageContainer::iterator aDocumentIterator;
        for (aDocumentIterator=maUsedMasterPages.begin();
             aDocumentIterator!=maUsedMasterPages.end();
             ++aDocumentIterator)
        {
            ::std::set<String>::reverse_iterator aNameIterator;
            for (aNameIterator=aDocumentIterator->second.rbegin();
                 aNameIterator!=aDocumentIterator->second.rend();
                 ++aNameIterator)
            {
              MasterPageObserverEvent aEvent (
                  MasterPageObserverEvent::ET_MASTER_PAGE_EXISTS,
                  *aDocumentIterator->first,
                  *aNameIterator);
              SendEvent (aEvent);
            }
        }
    }
}

void MasterPageObserver::Implementation::RemoveEventListener (
    const Link& rEventListener)
{
    maListeners.erase (
        ::std::find (
            maListeners.begin(),
            maListeners.end(),
            rEventListener));
}

MasterPageObserver::MasterPageNameSet
    MasterPageObserver::Implementation::GetMasterPageNames (
        SdDrawDocument& rDocument)
{
    MasterPageContainer::iterator aMasterPageDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aMasterPageDescriptor != maUsedMasterPages.end())
        return aMasterPageDescriptor->second;
    else
        // Not found so return an empty set.
        return MasterPageObserver::MasterPageNameSet();
}

void MasterPageObserver::Implementation::Notify(
    SfxBroadcaster& rBroadcaster,
    const SfxHint& rHint)
{
    if (rHint.ISA(SdrHint))
    {
        SdrHint& rSdrHint (*PTR_CAST(SdrHint,&rHint));
        switch (rSdrHint.GetKind())
        {
            case HINT_PAGEORDERCHG:
                // Process the modified set of pages only when the number of
                // standard and notes master pages are equal.  This test
                // filters out events that are sent in between the insertion
                // of a new standard master page and a new notes master
                // page.
                if (rBroadcaster.ISA(SdDrawDocument))
                {
                    SdDrawDocument& rDocument (
                        static_cast<SdDrawDocument&>(rBroadcaster));
                    if (rDocument.GetMasterSdPageCount(PK_STANDARD)
                        == rDocument.GetMasterSdPageCount(PK_NOTES))
                    {
                        AnalyzeUsedMasterPages (rDocument);
                    }
                }
                break;

            default:
                break;
        }
    }
}

void MasterPageObserver::Implementation::AnalyzeUsedMasterPages (
    SdDrawDocument& rDocument)
{
    // Create a set of names of the master pages used by the given document.
    USHORT nMasterPageCount = rDocument.GetMasterSdPageCount(PK_STANDARD);
    ::std::set<String> aCurrentMasterPages;
    for (USHORT nIndex=0; nIndex<nMasterPageCount; nIndex++)
    {
        SdPage* pMasterPage = rDocument.GetMasterSdPage (nIndex, PK_STANDARD);
        if (pMasterPage != NULL)
            aCurrentMasterPages.insert (pMasterPage->GetName());
        OSL_TRACE("currently used master page %d is %s",
            nIndex,
            ::rtl::OUStringToOString(pMasterPage->GetName(),
                RTL_TEXTENCODING_UTF8).getStr());
    }

    typedef ::std::vector<String> StringList;
    StringList aNewMasterPages;
    StringList aRemovedMasterPages;
    MasterPageContainer::iterator aOldMasterPagesDescriptor (
        maUsedMasterPages.find(&rDocument));
    if (aOldMasterPagesDescriptor != maUsedMasterPages.end())
    {
        StringList::iterator I;

        ::std::set<String>::iterator J;
        int i=0;
        for (J=aOldMasterPagesDescriptor->second.begin();
             J!=aOldMasterPagesDescriptor->second.end();
             ++J)
            OSL_TRACE("old used master page %d is %s",
            i++,
            ::rtl::OUStringToOString(*J,
                RTL_TEXTENCODING_UTF8).getStr());

        // Send events about the newly used master pages.
        ::std::set_difference (
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            ::std::back_insert_iterator<StringList>(aNewMasterPages));
        for (I=aNewMasterPages.begin(); I!=aNewMasterPages.end(); ++I)
        {
            OSL_TRACE("    added master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_ADDED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Send events about master pages that are not used any longer.
        ::std::set_difference (
            aOldMasterPagesDescriptor->second.begin(),
            aOldMasterPagesDescriptor->second.end(),
            aCurrentMasterPages.begin(),
            aCurrentMasterPages.end(),
            ::std::back_insert_iterator<StringList>(aRemovedMasterPages));
        for (I=aRemovedMasterPages.begin(); I!=aRemovedMasterPages.end(); ++I)
        {
            OSL_TRACE("    removed master page %s",
                ::rtl::OUStringToOString(*I,
                    RTL_TEXTENCODING_UTF8).getStr());

            MasterPageObserverEvent aEvent (
                MasterPageObserverEvent::ET_MASTER_PAGE_REMOVED,
                rDocument,
                *I);
            SendEvent (aEvent);
        }

        // Store the new list of master pages.
        aOldMasterPagesDescriptor->second = aCurrentMasterPages;
    }
}

void MasterPageObserver::Implementation::SendEvent (
    MasterPageObserverEvent& rEvent)
{
    ::std::vector<Link>::iterator aLink (maListeners.begin());
    ::std::vector<Link>::iterator aEnd (maListeners.end());
    while (aLink!=aEnd)
    {
        aLink->Call (&rEvent);
        ++aLink;
    }
}

} // end of namespace sd
<|endoftext|>


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

#if __cplusplus >= 201103L
#include <tuple>
#else
#include <boost/tuple/tuple.hpp>
#endif // __cplusplus >= 201103L

namespace tuples {

#if __cplusplus >= 201103L
using std::tuple;
using std::make_tuple;
using std::get;
#else // __cplusplus >= 201103L
using boost::tuples::tuple;
using boost::tuples::make_tuple;
using boost::get;
#endif // __cplusplus >= 201103L

} // namespace tuples

#endif // __STOUT_TUPLE_HPP__
<commit_msg>Updated stout tuple to pull in tr1::tuple instead of boost::tuple for pre-C++11.<commit_after>/**
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef __STOUT_TUPLE_HPP__
#define __STOUT_TUPLE_HPP__

#if __cplusplus >= 201103L
#include <tuple>
#else
#include <tr1/tuple>
#endif // __cplusplus >= 201103L

namespace tuples {

#if __cplusplus >= 201103L
using std::tuple;
using std::make_tuple;
using std::get;
#else // __cplusplus >= 201103L
using std::tr1::tuple;
using std::tr1::make_tuple;
using std::tr1::get;
#endif // __cplusplus >= 201103L

} // namespace tuples

#endif // __STOUT_TUPLE_HPP__
<|endoftext|>