<commit_before>#include "rules.h"
#include "tokenizer.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "tree.h"
#include "helpers.h"
#include "scratchpad.h"
#include <regex>

#define internal static

extern kwm_settings KWMSettings;

/* Current Window Properties:
 *          float = "true" | "false"
 *          display = "id"
 *          space = "id"
 *
 * Examples:
 *          kwmc rule owner="" name="" properties={float=""; display=""; space=""} except=""
 *
 * Apply given properties to all iTerm2 windows that does not have
 * a title containing $except:
 *          kwmc rule owner="iTerm2" properties={float="true"} except="borderless"
 *
 * Apply given properties to all iTerm2 windows that does have a
 * title containing $name and at the same times does not contain $except:
 *          kwmc rule owner="iTerm2" name="borderless" properties={float="true"} except="ignore"
 *
 * Apply given properties to all Steam windows
 *          kwmc rule owner="Steam" properties={float="true"}
 *
 * Apply given properties to all iTunes windows
 *          kwmc rule owner="iTunes" properties={display="1"}
 *
 * Assign iTunes to space 1 of display 1
 *          kwmc rule owner="iTunes" properties={space="1"; display="1"}
*/

internal void
ReportInvalidRule(std::string Command)
{
    std::cerr << "  Rule Parse error: " << Command << std::endl;
}

internal bool
ParseIdentifier(tokenizer *Tokenizer, std::string *Member)
{
    if(RequireToken(Tokenizer, Token_Equals))
    {
        token Token = GetToken(Tokenizer);
        switch(Token.Type)
        {
            case Token_String:
            {
                std::string String;
                for(int Index = 0; Index < Token.TextLength; ++Index)
                    String += Token.Text[Index];
                *Member = String;
                return true;
            } break;
            default:
            {
                ReportInvalidRule("Expected token of type Token_String: '" + std::string(Token.Text, Token.TextLength) + "'");
            } break;
        }
    }
    else
    {
        ReportInvalidRule("Expected token: '='");
    }

    return false;
}

internal bool
ParseProperties(tokenizer *Tokenizer, window_properties *Properties)
{
    if(RequireToken(Tokenizer, Token_Equals))
    {
        if(RequireToken(Tokenizer, Token_OpenBrace))
        {
            Properties->Scratchpad = -1;
            Properties->Display = -1;
            Properties->Space = -1;
            Properties->Float = -1;
            bool ValidState = true;

            while(ValidState)
            {
                token Token = GetToken(Tokenizer);
                switch(Token.Type)
                {
                    case Token_SemiColon: { continue; } break;
                    case Token_CloseBrace: { ValidState = false; } break;
                    case Token_Identifier:
                    {
                        if(TokenEquals(Token, "float"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                            {
                                if(Value == "true")
                                    Properties->Float = 1;
                                else if(Value == "false")
                                    Properties->Float = 0;
                            }
                        }
                        else if(TokenEquals(Token, "display"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                Properties->Display = ConvertStringToInt(Value);
                        }
                        else if(TokenEquals(Token, "space"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                Properties->Space = ConvertStringToInt(Value);
                        }
                        else if(TokenEquals(Token, "scratchpad"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                            {
                                if(Value == "visible")
                                    Properties->Scratchpad = 1;
                                else if(Value == "hidden")
                                    Properties->Scratchpad = 0;
                            }
                        }
                        else if(TokenEquals(Token, "role"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                    Properties->Role = Value;
                        }
                    } break;
                    default: { ReportInvalidRule("Expected token of type Token_Identifier: '" + std::string(Token.Text, Token.TextLength) + "'"); } break;
                }
            }

            return true;
        }
        else
        {
            ReportInvalidRule("Expected token '{'");
        }
    }
    else
    {
        ReportInvalidRule("Expected token '='");
    }

    return false;
}

internal bool
KwmParseRule(std::string RuleSym, window_rule *Rule)
{
    tokenizer Tokenizer = {};
    Tokenizer.At = const_cast<char*>(RuleSym.c_str());

    bool Result = true;
    bool Parsing = true;
    while(Parsing)
    {
        token Token = GetToken(&Tokenizer);
        switch(Token.Type)
        {
            case Token_EndOfStream:
            {
                Parsing = false;
            } break;
            case Token_Unknown:
            {
            } break;
            case Token_Identifier:
            {
                if(TokenEquals(Token, "owner"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Owner);
                else if(TokenEquals(Token, "name"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Name);
                else if(TokenEquals(Token, "properties"))
                    Result = Result && ParseProperties(&Tokenizer, &Rule->Properties);
                else if(TokenEquals(Token, "except"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Except);
            } break;
            default: { } break;
        }
    }

    return Result;
}

internal bool
MatchWindowRule(window_rule *Rule, ax_window *Window)
{
    if(!Window)
        return false;

    if(!AXLibIsWindowStandard(Window) &&
       !AXLibIsWindowCustom(Window))
        return false;

    bool Match = true;
    if(!Rule->Owner.empty())
    {
        std::regex Exp(Rule->Owner);
        Match = std::regex_match(Window->Application->Name, Exp);
    }

    if(!Rule->Name.empty())
    {
        std::regex Exp(Rule->Name);
        Match = Match && std::regex_match(Window->Name, Exp);
    }

    if(!Rule->Except.empty())
    {
        std::regex Exp(Rule->Except);
        Match = Match && !std::regex_match(Window->Name, Exp);
    }

    return Match;
}

void KwmAddRule(std::string RuleSym)
{
    window_rule Rule = {};
    if(!RuleSym.empty() && KwmParseRule(RuleSym, &Rule))
        KWMSettings.WindowRules.push_back(Rule);
}

bool ApplyWindowRules(ax_window *Window)
{
    bool Skip = false;
    for(int Index = 0; Index < KWMSettings.WindowRules.size(); ++Index)
    {
        window_rule *Rule = &KWMSettings.WindowRules[Index];
        if(MatchWindowRule(Rule, Window))
        {
            if(Rule->Properties.Float == 1)
                AXLibAddFlags(Window, AXWindow_Floating);

            if(!Rule->Properties.Role.empty())
                Window->Type.CustomRole = CFStringCreateWithCString(NULL,
                                                                    Rule->Properties.Role.c_str(),
                                                                    kCFStringEncodingMacRoman);

            if(Rule->Properties.Scratchpad != -1)
            {
                AddWindowToScratchpad(Window);
                if(Rule->Properties.Scratchpad == 0)
                {
                    HideScratchpadWindow(GetScratchpadSlotOfWindow(Window));
                    Skip = true;
                }
            }

            if(Rule->Properties.Display != -1 && Rule->Properties.Space == -1)
            {
                ax_display *Display = AXLibArrangementDisplay(Rule->Properties.Display);
                if(Display && Display != AXLibWindowDisplay(Window))
                {
                    MoveWindowToDisplay(Window, Display->ArrangementID, false);
                    Skip = true;
                }
            }

            if(Rule->Properties.Space != -1)
            {
                int Display = Rule->Properties.Display == -1 ? 0 : Rule->Properties.Display;
                ax_display *SourceDisplay = AXLibWindowDisplay(Window);
                ax_display *DestinationDisplay = AXLibArrangementDisplay(Display);
                int TotalSpaces = AXLibDisplaySpacesCount(DestinationDisplay);
                if(Rule->Properties.Space <= TotalSpaces && Rule->Properties.Space >= 1)
                {
                    int SourceCGSSpaceID = SourceDisplay->Space->ID;
                    int DestinationCGSSpaceID = AXLibCGSSpaceIDFromDesktopID(DestinationDisplay, Rule->Properties.Space);
                    if(!AXLibSpaceHasWindow(Window, DestinationCGSSpaceID))
                    {
                        AXLibAddFlags(Window, AXWindow_Minimized);
                        AXLibAddFlags(&DestinationDisplay->Spaces[DestinationCGSSpaceID], AXSpace_NeedsUpdate);
                        AXLibSpaceAddWindow(DestinationCGSSpaceID, Window->ID);
                        AXLibSpaceRemoveWindow(SourceCGSSpaceID, Window->ID);
                        Skip = true;
                    }
                }
            }
        }
    }

    return Skip;
}
<commit_msg>move rule restriction<commit_after>#include "rules.h"
#include "tokenizer.h"
#include "display.h"
#include "space.h"
#include "window.h"
#include "tree.h"
#include "helpers.h"
#include "scratchpad.h"
#include <regex>

#define internal static

extern kwm_settings KWMSettings;

/* Current Window Properties:
 *          float = "true" | "false"
 *          display = "id"
 *          space = "id"
 *
 * Examples:
 *          kwmc rule owner="" name="" properties={float=""; display=""; space=""} except=""
 *
 * Apply given properties to all iTerm2 windows that does not have
 * a title containing $except:
 *          kwmc rule owner="iTerm2" properties={float="true"} except="borderless"
 *
 * Apply given properties to all iTerm2 windows that does have a
 * title containing $name and at the same times does not contain $except:
 *          kwmc rule owner="iTerm2" name="borderless" properties={float="true"} except="ignore"
 *
 * Apply given properties to all Steam windows
 *          kwmc rule owner="Steam" properties={float="true"}
 *
 * Apply given properties to all iTunes windows
 *          kwmc rule owner="iTunes" properties={display="1"}
 *
 * Assign iTunes to space 1 of display 1
 *          kwmc rule owner="iTunes" properties={space="1"; display="1"}
*/

internal void
ReportInvalidRule(std::string Command)
{
    std::cerr << "  Rule Parse error: " << Command << std::endl;
}

internal bool
ParseIdentifier(tokenizer *Tokenizer, std::string *Member)
{
    if(RequireToken(Tokenizer, Token_Equals))
    {
        token Token = GetToken(Tokenizer);
        switch(Token.Type)
        {
            case Token_String:
            {
                std::string String;
                for(int Index = 0; Index < Token.TextLength; ++Index)
                    String += Token.Text[Index];
                *Member = String;
                return true;
            } break;
            default:
            {
                ReportInvalidRule("Expected token of type Token_String: '" + std::string(Token.Text, Token.TextLength) + "'");
            } break;
        }
    }
    else
    {
        ReportInvalidRule("Expected token: '='");
    }

    return false;
}

internal bool
ParseProperties(tokenizer *Tokenizer, window_properties *Properties)
{
    if(RequireToken(Tokenizer, Token_Equals))
    {
        if(RequireToken(Tokenizer, Token_OpenBrace))
        {
            Properties->Scratchpad = -1;
            Properties->Display = -1;
            Properties->Space = -1;
            Properties->Float = -1;
            bool ValidState = true;

            while(ValidState)
            {
                token Token = GetToken(Tokenizer);
                switch(Token.Type)
                {
                    case Token_SemiColon: { continue; } break;
                    case Token_CloseBrace: { ValidState = false; } break;
                    case Token_Identifier:
                    {
                        if(TokenEquals(Token, "float"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                            {
                                if(Value == "true")
                                    Properties->Float = 1;
                                else if(Value == "false")
                                    Properties->Float = 0;
                            }
                        }
                        else if(TokenEquals(Token, "display"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                Properties->Display = ConvertStringToInt(Value);
                        }
                        else if(TokenEquals(Token, "space"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                Properties->Space = ConvertStringToInt(Value);
                        }
                        else if(TokenEquals(Token, "scratchpad"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                            {
                                if(Value == "visible")
                                    Properties->Scratchpad = 1;
                                else if(Value == "hidden")
                                    Properties->Scratchpad = 0;
                            }
                        }
                        else if(TokenEquals(Token, "role"))
                        {
                            std::string Value;
                            if(ParseIdentifier(Tokenizer, &Value))
                                    Properties->Role = Value;
                        }
                    } break;
                    default: { ReportInvalidRule("Expected token of type Token_Identifier: '" + std::string(Token.Text, Token.TextLength) + "'"); } break;
                }
            }

            return true;
        }
        else
        {
            ReportInvalidRule("Expected token '{'");
        }
    }
    else
    {
        ReportInvalidRule("Expected token '='");
    }

    return false;
}

internal bool
KwmParseRule(std::string RuleSym, window_rule *Rule)
{
    tokenizer Tokenizer = {};
    Tokenizer.At = const_cast<char*>(RuleSym.c_str());

    bool Result = true;
    bool Parsing = true;
    while(Parsing)
    {
        token Token = GetToken(&Tokenizer);
        switch(Token.Type)
        {
            case Token_EndOfStream:
            {
                Parsing = false;
            } break;
            case Token_Unknown:
            {
            } break;
            case Token_Identifier:
            {
                if(TokenEquals(Token, "owner"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Owner);
                else if(TokenEquals(Token, "name"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Name);
                else if(TokenEquals(Token, "properties"))
                    Result = Result && ParseProperties(&Tokenizer, &Rule->Properties);
                else if(TokenEquals(Token, "except"))
                    Result = Result && ParseIdentifier(&Tokenizer, &Rule->Except);
            } break;
            default: { } break;
        }
    }

    return Result;
}

internal bool
MatchWindowRule(window_rule *Rule, ax_window *Window)
{
    if(!Window)
        return false;

    bool Match = true;
    if(!Rule->Owner.empty())
    {
        std::regex Exp(Rule->Owner);
        Match = std::regex_match(Window->Application->Name, Exp);
    }

    if(!Rule->Name.empty())
    {
        std::regex Exp(Rule->Name);
        Match = Match && std::regex_match(Window->Name, Exp);
    }

    if(!Rule->Except.empty())
    {
        std::regex Exp(Rule->Except);
        Match = Match && !std::regex_match(Window->Name, Exp);
    }

    return Match;
}

void KwmAddRule(std::string RuleSym)
{
    window_rule Rule = {};
    if(!RuleSym.empty() && KwmParseRule(RuleSym, &Rule))
        KWMSettings.WindowRules.push_back(Rule);
}

bool ApplyWindowRules(ax_window *Window)
{
    bool Skip = false;
    for(int Index = 0; Index < KWMSettings.WindowRules.size(); ++Index)
    {
        window_rule *Rule = &KWMSettings.WindowRules[Index];
        if(MatchWindowRule(Rule, Window))
        {
            if(Rule->Properties.Float == 1)
                AXLibAddFlags(Window, AXWindow_Floating);

            if(!Rule->Properties.Role.empty())
                Window->Type.CustomRole = CFStringCreateWithCString(NULL,
                                                                    Rule->Properties.Role.c_str(),
                                                                    kCFStringEncodingMacRoman);

            if(Rule->Properties.Scratchpad != -1)
            {
                AddWindowToScratchpad(Window);
                if(Rule->Properties.Scratchpad == 0)
                {
                    HideScratchpadWindow(GetScratchpadSlotOfWindow(Window));
                    Skip = true;
                }
            }

            if(Rule->Properties.Display != -1 && Rule->Properties.Space == -1)
            {
                if(!AXLibIsWindowStandard(Window) &&
                   !AXLibIsWindowCustom(Window))
                    continue;

                ax_display *Display = AXLibArrangementDisplay(Rule->Properties.Display);
                if(Display && Display != AXLibWindowDisplay(Window))
                {
                    MoveWindowToDisplay(Window, Display->ArrangementID, false);
                    Skip = true;
                }
            }

            if(Rule->Properties.Space != -1)
            {
                if(!AXLibIsWindowStandard(Window) &&
                   !AXLibIsWindowCustom(Window))
                    continue;

                int Display = Rule->Properties.Display == -1 ? 0 : Rule->Properties.Display;
                ax_display *SourceDisplay = AXLibWindowDisplay(Window);
                ax_display *DestinationDisplay = AXLibArrangementDisplay(Display);
                int TotalSpaces = AXLibDisplaySpacesCount(DestinationDisplay);
                if(Rule->Properties.Space <= TotalSpaces && Rule->Properties.Space >= 1)
                {
                    int SourceCGSSpaceID = SourceDisplay->Space->ID;
                    int DestinationCGSSpaceID = AXLibCGSSpaceIDFromDesktopID(DestinationDisplay, Rule->Properties.Space);
                    if(!AXLibSpaceHasWindow(Window, DestinationCGSSpaceID))
                    {
                        AXLibAddFlags(Window, AXWindow_Minimized);
                        AXLibAddFlags(&DestinationDisplay->Spaces[DestinationCGSSpaceID], AXSpace_NeedsUpdate);
                        AXLibSpaceAddWindow(DestinationCGSSpaceID, Window->ID);
                        AXLibSpaceRemoveWindow(SourceCGSSpaceID, Window->ID);
                        Skip = true;
                    }
                }
            }
        }
    }

    return Skip;
}
<|endoftext|>


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

#ifndef HPP_CORE_STEERING_METHOD_HH
# define HPP_CORE_STEERING_METHOD_HH

# include <hpp/core/fwd.hh>
# include <hpp/core/path.hh>

namespace hpp {
  namespace core {
    /// \addtogroup steering_method
    /// \{

    /// Steering method
    ///
    /// A steering method creates paths between pairs of
    /// configurations for a robot. They are usually used to take
    /// into account nonholonomic constraints of some robots
    class HPP_CORE_DLLAPI SteeringMethod
    {
    public:
      /// create a path between two configurations
      /// \return a Path from q1 to q2 if found. An empty
      /// Path if Path could not be built.
      PathPtr_t operator() (ConfigurationIn_t q1,
			    ConfigurationIn_t q2) const
      {
	return impl_compute (q1, q2);
      }

      /// Copy instance and return shared pointer
      virtual SteeringMethodPtr_t copy () const = 0;

      /// \name Constraints applicable to the robot.
      /// These constraints are not automatically taken into
      /// account. Child class can use it if they need.
      /// \{

      /// Set constraint set
      void constraints (const ConstraintSetPtr_t& constraints)
      {
	constraints_ = constraints;
      }

      /// Get constraint set
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }
      /// \}

    protected:
      /// Constructor
      SteeringMethod (ProblemPtr_t problem) :
        problem_ (problem), constraints_ (), weak_ ()
      {
      }
      /// Copy constructor
      ///
      /// Constraints are copied
      SteeringMethod (const SteeringMethod& other) : constraints_ (), weak_ ()
	{
	  if (other.constraints_) {
	    constraints_ = HPP_DYNAMIC_PTR_CAST (ConstraintSet,
						 other.constraints_->copy ());
	  }
	}
      /// create a path between two configurations
      virtual PathPtr_t impl_compute (ConfigurationIn_t q1,
				      ConfigurationIn_t q2) const = 0;
      /// Store weak pointer to itself.
      void init (SteeringMethodWkPtr_t weak)
      {
	weak_ = weak;
      }

      ProblemPtr_t problem_;

    private:
      /// Set of constraints to apply on the paths produced
      ConstraintSetPtr_t constraints_;
      /// Weak pointer to itself
      SteeringMethodWkPtr_t weak_;
    }; // class SteeringMethod
    /// \}
  } // namespace core
} // namespace hpp
#endif // HPP_CORE_STEERING_METHOD_HH
<commit_msg>Fix copy constructor of SteeringMethod<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_STEERING_METHOD_HH
# define HPP_CORE_STEERING_METHOD_HH

# include <hpp/core/fwd.hh>
# include <hpp/core/path.hh>

namespace hpp {
  namespace core {
    /// \addtogroup steering_method
    /// \{

    /// Steering method
    ///
    /// A steering method creates paths between pairs of
    /// configurations for a robot. They are usually used to take
    /// into account nonholonomic constraints of some robots
    class HPP_CORE_DLLAPI SteeringMethod
    {
    public:
      /// create a path between two configurations
      /// \return a Path from q1 to q2 if found. An empty
      /// Path if Path could not be built.
      PathPtr_t operator() (ConfigurationIn_t q1,
			    ConfigurationIn_t q2) const
      {
	return impl_compute (q1, q2);
      }

      /// Copy instance and return shared pointer
      virtual SteeringMethodPtr_t copy () const = 0;

      /// \name Constraints applicable to the robot.
      /// These constraints are not automatically taken into
      /// account. Child class can use it if they need.
      /// \{

      /// Set constraint set
      void constraints (const ConstraintSetPtr_t& constraints)
      {
	constraints_ = constraints;
      }

      /// Get constraint set
      const ConstraintSetPtr_t& constraints () const
      {
	return constraints_;
      }
      /// \}

    protected:
      /// Constructor
      SteeringMethod (ProblemPtr_t problem) :
        problem_ (problem), constraints_ (), weak_ ()
      {
      }
      /// Copy constructor
      ///
      /// Constraints are copied
      SteeringMethod (const SteeringMethod& other) :
        problem_ (other.problem_), constraints_ (), weak_ ()
	{
	  if (other.constraints_) {
	    constraints_ = HPP_DYNAMIC_PTR_CAST (ConstraintSet,
						 other.constraints_->copy ());
	  }
	}
      /// create a path between two configurations
      virtual PathPtr_t impl_compute (ConfigurationIn_t q1,
				      ConfigurationIn_t q2) const = 0;
      /// Store weak pointer to itself.
      void init (SteeringMethodWkPtr_t weak)
      {
	weak_ = weak;
      }

      ProblemPtr_t problem_;

    private:
      /// Set of constraints to apply on the paths produced
      ConstraintSetPtr_t constraints_;
      /// Weak pointer to itself
      SteeringMethodWkPtr_t weak_;
    }; // class SteeringMethod
    /// \}
  } // namespace core
} // namespace hpp
#endif // HPP_CORE_STEERING_METHOD_HH
<|endoftext|>


<commit_before>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BUILD_CONFIG_HPP_INCLUDED
#define TORRENT_BUILD_CONFIG_HPP_INCLUDED

#include "libtorrent/config.hpp"
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>

#ifdef TORRENT_DEBUG
#define TORRENT_CFG_DEBUG dbg_
#else
#define TORRENT_CFG_DEBUG rel_
#endif

#if TORRENT_USE_BOOST_DATE_TIME
#define TORRENT_CFG_TIME boosttime_
#elif TORRENT_USE_ABSOLUTE_TIME
#define TORRENT_CFG_TIME absolutetime_
#elif TORRENT_USE_PERFORMANCE_TIMER
#define TORRENT_CFG_TIME performancetimer_
#elif TORRENT_USE_CLOCK_GETTIME
#define TORRENT_CFG_TIME clocktime_
#elif TORRENT_USE_SYSTEM_TIME
#define TORRENT_CFG_TIME systime_
#else
#error what timer is used?
#endif

#if TORRENT_USE_IPV6
#define TORRENT_CFG_IPV6 ipv6_
#else
#define TORRENT_CFG_IPV6 noipv_-
#endif

#ifdef TORRENT_DISABLE_DHT
#define TORRENT_CFG_DHT nodht_
#else
#define TORRENT_CFG_DHT dht_
#endif

#ifdef TORRENT_DISABLE_POOL_ALLOCATORS
#define TORRENT_CFG_POOL nopools_
#else
#define TORRENT_CFG_POOL pools_
#endif

#ifdef TORRENT_VERBOSE_LOGGING
#define TORRENT_CFG_LOG verboselog_
#elif defined TORRENT_LOGGING
#define TORRENT_CFG_LOG log_
#else
#define TORRENT_CFG_LOG nolog_
#endif

#ifdef _UNICODE
#define TORRENT_CFG_UNICODE unicode_
#else
#define TORRENT_CFG_UNICODE ansi_
#endif

#ifdef TORRENT_DISABLE_RESOLVE_COUNTRIES
#define TORRENT_CFG_RESOLVE noresolvecountries_
#else
#define TORRENT_CFG_RESOLVE resolvecountries_
#endif

#ifdef TORRENT_NO_DEPRECATE
#define TORRENT_CFG_DEPR nodeprecate_
#else
#define TORRENT_CFG_DEPR deprecated_
#endif

#ifdef TORRENT_DISABLE_FULL_STATS
#define TORRENT_CFG_STATS partialstats_
#else
#define TORRENT_CFG_STATS fullstats_
#endif

#ifdef TORRENT_DISABLE_EXTENSIONS
#define TORRENT_CFG_EXT noext_
#else
#define TORRENT_CFG_EXT ext_
#endif

#define TORRENT_CFG \
	BOOST_PP_CAT(TORRENT_CFG_DEBUG, \
	BOOST_PP_CAT(TORRENT_CFG_TIME, \
	BOOST_PP_CAT(TORRENT_CFG_POOL, \
	BOOST_PP_CAT(TORRENT_CFG_LOG, \
	BOOST_PP_CAT(TORRENT_CFG_RESOLVE, \
	BOOST_PP_CAT(TORRENT_CFG_DEPR, \
	BOOST_PP_CAT(TORRENT_CFG_DHT, \
	TORRENT_CFG_EXT)))))))

#define TORRENT_CFG_STRING BOOST_PP_STRINGIZE(TORRENT_CFG)

#endif

<commit_msg>fixed performance counter macro<commit_after>/*

Copyright (c) 2010, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_BUILD_CONFIG_HPP_INCLUDED
#define TORRENT_BUILD_CONFIG_HPP_INCLUDED

#include "libtorrent/config.hpp"
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>

#ifdef TORRENT_DEBUG
#define TORRENT_CFG_DEBUG dbg_
#else
#define TORRENT_CFG_DEBUG rel_
#endif

#if TORRENT_USE_BOOST_DATE_TIME
#define TORRENT_CFG_TIME boosttime_
#elif TORRENT_USE_ABSOLUTE_TIME
#define TORRENT_CFG_TIME absolutetime_
#elif TORRENT_USE_QUERY_PERFORMANCE_TIMER
#define TORRENT_CFG_TIME performancetimer_
#elif TORRENT_USE_CLOCK_GETTIME
#define TORRENT_CFG_TIME clocktime_
#elif TORRENT_USE_SYSTEM_TIME
#define TORRENT_CFG_TIME systime_
#else
#error what timer is used?
#endif

#if TORRENT_USE_IPV6
#define TORRENT_CFG_IPV6 ipv6_
#else
#define TORRENT_CFG_IPV6 noipv_-
#endif

#ifdef TORRENT_DISABLE_DHT
#define TORRENT_CFG_DHT nodht_
#else
#define TORRENT_CFG_DHT dht_
#endif

#ifdef TORRENT_DISABLE_POOL_ALLOCATORS
#define TORRENT_CFG_POOL nopools_
#else
#define TORRENT_CFG_POOL pools_
#endif

#ifdef TORRENT_VERBOSE_LOGGING
#define TORRENT_CFG_LOG verboselog_
#elif defined TORRENT_LOGGING
#define TORRENT_CFG_LOG log_
#else
#define TORRENT_CFG_LOG nolog_
#endif

#ifdef _UNICODE
#define TORRENT_CFG_UNICODE unicode_
#else
#define TORRENT_CFG_UNICODE ansi_
#endif

#ifdef TORRENT_DISABLE_RESOLVE_COUNTRIES
#define TORRENT_CFG_RESOLVE noresolvecountries_
#else
#define TORRENT_CFG_RESOLVE resolvecountries_
#endif

#ifdef TORRENT_NO_DEPRECATE
#define TORRENT_CFG_DEPR nodeprecate_
#else
#define TORRENT_CFG_DEPR deprecated_
#endif

#ifdef TORRENT_DISABLE_FULL_STATS
#define TORRENT_CFG_STATS partialstats_
#else
#define TORRENT_CFG_STATS fullstats_
#endif

#ifdef TORRENT_DISABLE_EXTENSIONS
#define TORRENT_CFG_EXT noext_
#else
#define TORRENT_CFG_EXT ext_
#endif

#define TORRENT_CFG \
	BOOST_PP_CAT(TORRENT_CFG_DEBUG, \
	BOOST_PP_CAT(TORRENT_CFG_TIME, \
	BOOST_PP_CAT(TORRENT_CFG_POOL, \
	BOOST_PP_CAT(TORRENT_CFG_LOG, \
	BOOST_PP_CAT(TORRENT_CFG_RESOLVE, \
	BOOST_PP_CAT(TORRENT_CFG_DEPR, \
	BOOST_PP_CAT(TORRENT_CFG_DHT, \
	TORRENT_CFG_EXT)))))))

#define TORRENT_CFG_STRING BOOST_PP_STRINGIZE(TORRENT_CFG)

#endif

<|endoftext|>


<commit_before>/*

Copyright (c) 2003-2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
#define TORRENT_TORRENT_INFO_HPP_INCLUDED

#include <string>
#include <vector>
#include <iosfwd>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/shared_array.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/entry.hpp"
#include "libtorrent/lazy_entry.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_storage.hpp"

namespace libtorrent
{
	namespace pt = boost::posix_time;
	namespace gr = boost::gregorian;
	namespace fs = boost::filesystem;

	enum
	{
		// wait 60 seconds before retrying a failed tracker
		tracker_retry_delay_min = 10
		// when tracker_failed_max trackers
		// has failed, wait 60 minutes instead
		, tracker_retry_delay_max = 60 * 60
	};

	struct TORRENT_EXPORT announce_entry
	{
		announce_entry(std::string const& u)
			: url(u)
			, tier(0)
			, fail_limit(3)
			, fails(0)
			, source(0)
			, verified(false)
			, updating(false)
			, start_sent(false)
			, complete_sent(false)
		{}

		std::string url;

		// the time of next tracker announce
		ptime next_announce;

		boost::uint8_t tier;
		// the number of times this tracker can fail
		// in a row before it's removed. 0 means unlimited
		boost::uint8_t fail_limit;

		// the number of times in a row this tracker has failed
		boost::uint8_t fails;

		enum tracker_source
		{
			source_torrent = 1,
			source_client = 2,
			source_magnet_link = 4,
			source_tex = 8
		};
		// where did we get this tracker from
		boost::uint8_t source;

		// is set to true if we have ever received a response from
		// this tracker
		bool verified:1;

		// true if we're currently trying to announce with
		// this tracker
		bool updating:1;

		// this is true if event start has been sent to the tracker
		bool start_sent:1;

		// this is true if event completed has been sent to the tracker
		bool complete_sent:1;

		void reset()
		{
			start_sent = false;
			next_announce = min_time();
		}

		void failed()
		{
			++fails;
			int delay = (std::min)(tracker_retry_delay_min + int(fails) * int(fails) * tracker_retry_delay_min
				, int(tracker_retry_delay_max));
			next_announce = time_now() + seconds(delay);
			updating = false;
		}

		bool can_announce(ptime now) const
		{
			return now >= next_announce
				&& (fails < fail_limit || fail_limit == 0)
				&& !updating;
		}

		bool is_working() const
		{
			return fails == 0;
		}
	};

#ifndef BOOST_NO_EXCEPTIONS
	struct TORRENT_EXPORT invalid_torrent_file: std::exception
	{
		virtual const char* what() const throw() { return "invalid torrent file"; }
	};
#endif

	int TORRENT_EXPORT load_file(fs::path const& filename, std::vector<char>& v);

	class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
	{
	public:

		torrent_info(sha1_hash const& info_hash);
		torrent_info(lazy_entry const& torrent_file);
		torrent_info(char const* buffer, int size);
		torrent_info(fs::path const& filename);
		torrent_info(fs::wpath const& filename);
		~torrent_info();

		file_storage const& files() const { return m_files; }
		file_storage const& orig_files() const { return m_orig_files ? *m_orig_files : m_files; }

		void rename_file(int index, std::string const& new_filename)
		{
			copy_on_write();
			m_files.rename_file(index, new_filename);
		}

		void rename_file(int index, std::wstring const& new_filename)
		{
			copy_on_write();
			m_files.rename_file(index, new_filename);
		}

		void add_tracker(std::string const& url, int tier = 0);
		std::vector<announce_entry> const& trackers() const { return m_urls; }

		std::vector<std::string> const& url_seeds() const
		{ return m_url_seeds; }
		void add_url_seed(std::string const& url)
		{ m_url_seeds.push_back(url); }

		std::vector<std::string> const& http_seeds() const
		{ return m_http_seeds; }
		void add_http_seed(std::string const& url)
		{ m_http_seeds.push_back(url); }

		size_type total_size() const { return m_files.total_size(); }
		int piece_length() const { return m_files.piece_length(); }
		int num_pieces() const { return m_files.num_pieces(); }
		const sha1_hash& info_hash() const { return m_info_hash; }
		const std::string& name() const { return m_files.name(); }

		typedef file_storage::iterator file_iterator;
		typedef file_storage::reverse_iterator reverse_file_iterator;

		file_iterator begin_files() const { return m_files.begin(); }
		file_iterator end_files() const { return m_files.end(); }
		reverse_file_iterator rbegin_files() const { return m_files.rbegin(); }
		reverse_file_iterator rend_files() const { return m_files.rend(); }
		int num_files() const { return m_files.num_files(); }
		file_entry const& file_at(int index) const { return m_files.at(index); }

		file_iterator file_at_offset(size_type offset) const
		{ return m_files.file_at_offset(offset); }
		std::vector<file_slice> map_block(int piece, size_type offset, int size) const
		{ return m_files.map_block(piece, offset, size); }
		peer_request map_file(int file, size_type offset, int size) const
		{ return m_files.map_file(file, offset, size); }

#ifndef TORRENT_NO_DEPRECATE
// ------- start deprecation -------
// these functions will be removed in a future version
		torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
		void print(std::ostream& os) const TORRENT_DEPRECATED;
		file_storage& files() TORRENT_DEPRECATED { return m_files; }
// ------- end deprecation -------
#endif

		bool is_valid() const { return m_files.is_valid(); }

		bool priv() const { return m_private; }

		int piece_size(int index) const { return m_files.piece_size(index); }

		sha1_hash hash_for_piece(int index) const
		{ return sha1_hash(hash_for_piece_ptr(index)); }

		char const* hash_for_piece_ptr(int index) const
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_files.num_pieces());
			TORRENT_ASSERT(m_piece_hashes);
			TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
			TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
			return &m_piece_hashes[index*20];
		}

		boost::optional<pt::ptime> creation_date() const;

		const std::string& creator() const
		{ return m_created_by; }

		const std::string& comment() const
		{ return m_comment; }

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;

		nodes_t const& nodes() const
		{ return m_nodes; }
		void add_node(std::pair<std::string, int> const& node)
		{ m_nodes.push_back(node); }

		bool parse_info_section(lazy_entry const& e, std::string& error);

		lazy_entry const* info(char const* key) const
		{
			if (m_info_dict.type() == lazy_entry::none_t)
				lazy_bdecode(m_info_section.get(), m_info_section.get()
					+ m_info_section_size, m_info_dict);
			return m_info_dict.dict_find(key);
		}

		void swap(torrent_info& ti);

		boost::shared_array<char> metadata() const
		{ return m_info_section; }

		int metadata_size() const { return m_info_section_size; }

	private:

		void copy_on_write();
		bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);

		file_storage m_files;

		// if m_files is modified, it is first copied into
		// m_orig_files so that the original name and
		// filenames are preserved.
		boost::shared_ptr<const file_storage> m_orig_files;

		// the urls to the trackers
		std::vector<announce_entry> m_urls;
		std::vector<std::string> m_url_seeds;
		std::vector<std::string> m_http_seeds;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;

		// this is a copy of the info section from the torrent.
		// it use maintained in this flat format in order to
		// make it available through the metadata extension
		boost::shared_array<char> m_info_section;
		int m_info_section_size;

		// this is a pointer into the m_info_section buffer
		// pointing to the first byte of the first sha-1 hash
		char const* m_piece_hashes;

		// the info section parsed. points into m_info_section
		// parsed lazily
		mutable lazy_entry m_info_dict;
	};

}

#endif // TORRENT_TORRENT_INFO_HPP_INCLUDED

<commit_msg>remove (deprecated) non-const files() from torrent_info since it opens a loop-hole to modifying the filenames without preserving the original ones<commit_after>/*

Copyright (c) 2003-2008, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_TORRENT_INFO_HPP_INCLUDED
#define TORRENT_TORRENT_INFO_HPP_INCLUDED

#include <string>
#include <vector>
#include <iosfwd>

#ifdef _MSC_VER
#pragma warning(push, 1)
#endif

#include <boost/optional.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/shared_array.hpp>

#ifdef _MSC_VER
#pragma warning(pop)
#endif

#include "libtorrent/entry.hpp"
#include "libtorrent/lazy_entry.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/intrusive_ptr_base.hpp"
#include "libtorrent/assert.hpp"
#include "libtorrent/file_storage.hpp"

namespace libtorrent
{
	namespace pt = boost::posix_time;
	namespace gr = boost::gregorian;
	namespace fs = boost::filesystem;

	enum
	{
		// wait 60 seconds before retrying a failed tracker
		tracker_retry_delay_min = 10
		// when tracker_failed_max trackers
		// has failed, wait 60 minutes instead
		, tracker_retry_delay_max = 60 * 60
	};

	struct TORRENT_EXPORT announce_entry
	{
		announce_entry(std::string const& u)
			: url(u)
			, tier(0)
			, fail_limit(3)
			, fails(0)
			, source(0)
			, verified(false)
			, updating(false)
			, start_sent(false)
			, complete_sent(false)
		{}

		std::string url;

		// the time of next tracker announce
		ptime next_announce;

		boost::uint8_t tier;
		// the number of times this tracker can fail
		// in a row before it's removed. 0 means unlimited
		boost::uint8_t fail_limit;

		// the number of times in a row this tracker has failed
		boost::uint8_t fails;

		enum tracker_source
		{
			source_torrent = 1,
			source_client = 2,
			source_magnet_link = 4,
			source_tex = 8
		};
		// where did we get this tracker from
		boost::uint8_t source;

		// is set to true if we have ever received a response from
		// this tracker
		bool verified:1;

		// true if we're currently trying to announce with
		// this tracker
		bool updating:1;

		// this is true if event start has been sent to the tracker
		bool start_sent:1;

		// this is true if event completed has been sent to the tracker
		bool complete_sent:1;

		void reset()
		{
			start_sent = false;
			next_announce = min_time();
		}

		void failed()
		{
			++fails;
			int delay = (std::min)(tracker_retry_delay_min + int(fails) * int(fails) * tracker_retry_delay_min
				, int(tracker_retry_delay_max));
			next_announce = time_now() + seconds(delay);
			updating = false;
		}

		bool can_announce(ptime now) const
		{
			return now >= next_announce
				&& (fails < fail_limit || fail_limit == 0)
				&& !updating;
		}

		bool is_working() const
		{
			return fails == 0;
		}
	};

#ifndef BOOST_NO_EXCEPTIONS
	struct TORRENT_EXPORT invalid_torrent_file: std::exception
	{
		virtual const char* what() const throw() { return "invalid torrent file"; }
	};
#endif

	int TORRENT_EXPORT load_file(fs::path const& filename, std::vector<char>& v);

	class TORRENT_EXPORT torrent_info : public intrusive_ptr_base<torrent_info>
	{
	public:

		torrent_info(sha1_hash const& info_hash);
		torrent_info(lazy_entry const& torrent_file);
		torrent_info(char const* buffer, int size);
		torrent_info(fs::path const& filename);
		torrent_info(fs::wpath const& filename);
		~torrent_info();

		file_storage const& files() const { return m_files; }
		file_storage const& orig_files() const { return m_orig_files ? *m_orig_files : m_files; }

		void rename_file(int index, std::string const& new_filename)
		{
			copy_on_write();
			m_files.rename_file(index, new_filename);
		}

		void rename_file(int index, std::wstring const& new_filename)
		{
			copy_on_write();
			m_files.rename_file(index, new_filename);
		}

		void add_tracker(std::string const& url, int tier = 0);
		std::vector<announce_entry> const& trackers() const { return m_urls; }

		std::vector<std::string> const& url_seeds() const
		{ return m_url_seeds; }
		void add_url_seed(std::string const& url)
		{ m_url_seeds.push_back(url); }

		std::vector<std::string> const& http_seeds() const
		{ return m_http_seeds; }
		void add_http_seed(std::string const& url)
		{ m_http_seeds.push_back(url); }

		size_type total_size() const { return m_files.total_size(); }
		int piece_length() const { return m_files.piece_length(); }
		int num_pieces() const { return m_files.num_pieces(); }
		const sha1_hash& info_hash() const { return m_info_hash; }
		const std::string& name() const { return m_files.name(); }

		typedef file_storage::iterator file_iterator;
		typedef file_storage::reverse_iterator reverse_file_iterator;

		file_iterator begin_files() const { return m_files.begin(); }
		file_iterator end_files() const { return m_files.end(); }
		reverse_file_iterator rbegin_files() const { return m_files.rbegin(); }
		reverse_file_iterator rend_files() const { return m_files.rend(); }
		int num_files() const { return m_files.num_files(); }
		file_entry const& file_at(int index) const { return m_files.at(index); }

		file_iterator file_at_offset(size_type offset) const
		{ return m_files.file_at_offset(offset); }
		std::vector<file_slice> map_block(int piece, size_type offset, int size) const
		{ return m_files.map_block(piece, offset, size); }
		peer_request map_file(int file, size_type offset, int size) const
		{ return m_files.map_file(file, offset, size); }

#ifndef TORRENT_NO_DEPRECATE
// ------- start deprecation -------
// these functions will be removed in a future version
		torrent_info(entry const& torrent_file) TORRENT_DEPRECATED;
		void print(std::ostream& os) const TORRENT_DEPRECATED;
// ------- end deprecation -------
#endif

		bool is_valid() const { return m_files.is_valid(); }

		bool priv() const { return m_private; }

		int piece_size(int index) const { return m_files.piece_size(index); }

		sha1_hash hash_for_piece(int index) const
		{ return sha1_hash(hash_for_piece_ptr(index)); }

		char const* hash_for_piece_ptr(int index) const
		{
			TORRENT_ASSERT(index >= 0);
			TORRENT_ASSERT(index < m_files.num_pieces());
			TORRENT_ASSERT(m_piece_hashes);
			TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
			TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
			return &m_piece_hashes[index*20];
		}

		boost::optional<pt::ptime> creation_date() const;

		const std::string& creator() const
		{ return m_created_by; }

		const std::string& comment() const
		{ return m_comment; }

		// dht nodes to add to the routing table/bootstrap from
		typedef std::vector<std::pair<std::string, int> > nodes_t;

		nodes_t const& nodes() const
		{ return m_nodes; }
		void add_node(std::pair<std::string, int> const& node)
		{ m_nodes.push_back(node); }

		bool parse_info_section(lazy_entry const& e, std::string& error);

		lazy_entry const* info(char const* key) const
		{
			if (m_info_dict.type() == lazy_entry::none_t)
				lazy_bdecode(m_info_section.get(), m_info_section.get()
					+ m_info_section_size, m_info_dict);
			return m_info_dict.dict_find(key);
		}

		void swap(torrent_info& ti);

		boost::shared_array<char> metadata() const
		{ return m_info_section; }

		int metadata_size() const { return m_info_section_size; }

	private:

		void copy_on_write();
		bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error);

		file_storage m_files;

		// if m_files is modified, it is first copied into
		// m_orig_files so that the original name and
		// filenames are preserved.
		boost::shared_ptr<const file_storage> m_orig_files;

		// the urls to the trackers
		std::vector<announce_entry> m_urls;
		std::vector<std::string> m_url_seeds;
		std::vector<std::string> m_http_seeds;
		nodes_t m_nodes;

		// the hash that identifies this torrent
		sha1_hash m_info_hash;

		// if a creation date is found in the torrent file
		// this will be set to that, otherwise it'll be
		// 1970, Jan 1
		pt::ptime m_creation_date;

		// if a comment is found in the torrent file
		// this will be set to that comment
		std::string m_comment;

		// an optional string naming the software used
		// to create the torrent file
		std::string m_created_by;

		// this is used when creating a torrent. If there's
		// only one file there are cases where it's impossible
		// to know if it should be written as a multifile torrent
		// or not. e.g. test/test  there's one file and one directory
		// and they have the same name.
		bool m_multifile;

		// this is true if the torrent is private. i.e., is should not
		// be announced on the dht
		bool m_private;

		// this is a copy of the info section from the torrent.
		// it use maintained in this flat format in order to
		// make it available through the metadata extension
		boost::shared_array<char> m_info_section;
		int m_info_section_size;

		// this is a pointer into the m_info_section buffer
		// pointing to the first byte of the first sha-1 hash
		char const* m_piece_hashes;

		// the info section parsed. points into m_info_section
		// parsed lazily
		mutable lazy_entry m_info_dict;
	};

}

#endif // TORRENT_TORRENT_INFO_HPP_INCLUDED

<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOncePtr.h"
#include "SkString.h"
#include "SkTime.h"
#include "SkTypes.h"

void SkTime::DateTime::toISO8601(SkString* dst) const {
    if (dst) {
        int timeZoneMinutes = SkToInt(fTimeZoneMinutes);
        char timezoneSign = timeZoneMinutes >= 0 ? '+' : '-';
        int timeZoneHours = SkTAbs(timeZoneMinutes) / 60;
        timeZoneMinutes = SkTAbs(timeZoneMinutes) % 60;
        dst->printf("%04u-%02u-%02uT%02u:%02u:%02u%c%02d:%02d",
                    static_cast<unsigned>(fYear), static_cast<unsigned>(fMonth),
                    static_cast<unsigned>(fDay), static_cast<unsigned>(fHour),
                    static_cast<unsigned>(fMinute),
                    static_cast<unsigned>(fSecond), timezoneSign, timeZoneHours,
                    timeZoneMinutes);
    }
}

#ifdef SK_BUILD_FOR_WIN32

#include "Windows.h"
void SkTime::GetDateTime(DateTime* dt) {
    if (dt) {
        SYSTEMTIME st;
        GetSystemTime(&st);
        dt->fTimeZoneMinutes = 0;
        dt->fYear       = st.wYear;
        dt->fMonth      = SkToU8(st.wMonth);
        dt->fDayOfWeek  = SkToU8(st.wDayOfWeek);
        dt->fDay        = SkToU8(st.wDay);
        dt->fHour       = SkToU8(st.wHour);
        dt->fMinute     = SkToU8(st.wMinute);
        dt->fSecond     = SkToU8(st.wSecond);
    }
}

#else // SK_BUILD_FOR_WIN32

#include <time.h>
void SkTime::GetDateTime(DateTime* dt) {
    if (dt) {
        time_t m_time;
        time(&m_time);
        struct tm* tstruct;
        tstruct = gmtime(&m_time);
        dt->fTimeZoneMinutes = 0;
        dt->fYear       = tstruct->tm_year + 1900;
        dt->fMonth      = SkToU8(tstruct->tm_mon + 1);
        dt->fDayOfWeek  = SkToU8(tstruct->tm_wday);
        dt->fDay        = SkToU8(tstruct->tm_mday);
        dt->fHour       = SkToU8(tstruct->tm_hour);
        dt->fMinute     = SkToU8(tstruct->tm_min);
        dt->fSecond     = SkToU8(tstruct->tm_sec);
    }
}
#endif // SK_BUILD_FOR_WIN32

#if defined(_MSC_VER)
    // TODO: try std::chrono again with MSVC 2015?
    #include <intrin.h>
    SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
    double SkTime::GetNSecs() {
        uint64_t ticks = __rdtsc();
        return ticks * *ns_per_tick.get([]{
            LARGE_INTEGER khz;  // The docs say this returns Hz, but it returns KHz.
            QueryPerformanceFrequency(&khz);
            return new double(1e6 / khz.QuadPart);
        });
    }
#elif defined(__MACH__)
    // TODO: fold into std::chrono when available?
    #include <mach/mach_time.h>
    SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
    double SkTime::GetNSecs() {
        uint64_t ticks = mach_absolute_time();
        return ticks * *ns_per_tick.get([]{
            mach_timebase_info_data_t timebase;
            (void)mach_timebase_info(&timebase);
            return new double(timebase.numer * 1.0 / timebase.denom);
        });
    }
#else
    // This std::chrono code looks great on Linux and Android,
    // but MSVC 2013 returned mostly garbage (0ns times, etc).
    #include <chrono>
    double SkTime::GetNSecs() {
        auto now = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::nano> ns = now.time_since_epoch();
        return ns.count();
    }
#endif
<commit_msg>Minor mingw cross compilation fix.<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkOncePtr.h"
#include "SkString.h"
#include "SkTime.h"
#include "SkTypes.h"

void SkTime::DateTime::toISO8601(SkString* dst) const {
    if (dst) {
        int timeZoneMinutes = SkToInt(fTimeZoneMinutes);
        char timezoneSign = timeZoneMinutes >= 0 ? '+' : '-';
        int timeZoneHours = SkTAbs(timeZoneMinutes) / 60;
        timeZoneMinutes = SkTAbs(timeZoneMinutes) % 60;
        dst->printf("%04u-%02u-%02uT%02u:%02u:%02u%c%02d:%02d",
                    static_cast<unsigned>(fYear), static_cast<unsigned>(fMonth),
                    static_cast<unsigned>(fDay), static_cast<unsigned>(fHour),
                    static_cast<unsigned>(fMinute),
                    static_cast<unsigned>(fSecond), timezoneSign, timeZoneHours,
                    timeZoneMinutes);
    }
}

#ifdef SK_BUILD_FOR_WIN32

#include "windows.h"
void SkTime::GetDateTime(DateTime* dt) {
    if (dt) {
        SYSTEMTIME st;
        GetSystemTime(&st);
        dt->fTimeZoneMinutes = 0;
        dt->fYear       = st.wYear;
        dt->fMonth      = SkToU8(st.wMonth);
        dt->fDayOfWeek  = SkToU8(st.wDayOfWeek);
        dt->fDay        = SkToU8(st.wDay);
        dt->fHour       = SkToU8(st.wHour);
        dt->fMinute     = SkToU8(st.wMinute);
        dt->fSecond     = SkToU8(st.wSecond);
    }
}

#else // SK_BUILD_FOR_WIN32

#include <time.h>
void SkTime::GetDateTime(DateTime* dt) {
    if (dt) {
        time_t m_time;
        time(&m_time);
        struct tm* tstruct;
        tstruct = gmtime(&m_time);
        dt->fTimeZoneMinutes = 0;
        dt->fYear       = tstruct->tm_year + 1900;
        dt->fMonth      = SkToU8(tstruct->tm_mon + 1);
        dt->fDayOfWeek  = SkToU8(tstruct->tm_wday);
        dt->fDay        = SkToU8(tstruct->tm_mday);
        dt->fHour       = SkToU8(tstruct->tm_hour);
        dt->fMinute     = SkToU8(tstruct->tm_min);
        dt->fSecond     = SkToU8(tstruct->tm_sec);
    }
}
#endif // SK_BUILD_FOR_WIN32

#if defined(_MSC_VER)
    // TODO: try std::chrono again with MSVC 2015?
    #include <intrin.h>
    SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
    double SkTime::GetNSecs() {
        uint64_t ticks = __rdtsc();
        return ticks * *ns_per_tick.get([]{
            LARGE_INTEGER khz;  // The docs say this returns Hz, but it returns KHz.
            QueryPerformanceFrequency(&khz);
            return new double(1e6 / khz.QuadPart);
        });
    }
#elif defined(__MACH__)
    // TODO: fold into std::chrono when available?
    #include <mach/mach_time.h>
    SK_DECLARE_STATIC_ONCE_PTR(double, ns_per_tick);
    double SkTime::GetNSecs() {
        uint64_t ticks = mach_absolute_time();
        return ticks * *ns_per_tick.get([]{
            mach_timebase_info_data_t timebase;
            (void)mach_timebase_info(&timebase);
            return new double(timebase.numer * 1.0 / timebase.denom);
        });
    }
#else
    // This std::chrono code looks great on Linux and Android,
    // but MSVC 2013 returned mostly garbage (0ns times, etc).
    #include <chrono>
    double SkTime::GetNSecs() {
        auto now = std::chrono::high_resolution_clock::now();
        std::chrono::duration<double, std::nano> ns = now.time_since_epoch();
        return ns.count();
    }
#endif
<|endoftext|>


<commit_before>#include "hphp/runtime/base/base-includes.h"
#include "hphp/runtime/ext/std/ext_std_errorfunc.h"
#include "hphp/runtime/base/php-globals.h"
#include "hphp/runtime/base/hphp-system.h"
#include "hphp/runtime/ext/ext_hotprofiler.h"
#include "newrelic_transaction.h"
#include "newrelic_collector_client.h"
#include "newrelic_common.h"
#include "newrelic_profiler.h"
#include "hphp/runtime/server/transport.h"

#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <thread>
#include <unistd.h>

using namespace std;

namespace HPHP {

bool keep_running = true;

class ScopedGenericSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedGenericSegment)
    CLASSNAME_IS("scoped_generic_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedGenericSegment(string name) : name(name) {
        segment_id = newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
    }

    virtual ~ScopedGenericSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string name;
};

void ScopedGenericSegment::sweep() { }

class ScopedDatastoreSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedDatastoreSegment)
    CLASSNAME_IS("scoped_database_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedDatastoreSegment(string table, string operation, string sql, string sql_trace_rollup_name) : table(table), operation(operation), sql(sql), sql_trace_rollup_name(sql_trace_rollup_name) {
        //TODO sql_trace_rollup_name
        if (sql_trace_rollup_name == "") {
            segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), NULL, NULL);
        } else {
            segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), NULL);
        }
    }

    virtual ~ScopedDatastoreSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string table;
    string operation;
    string sql;
    string sql_trace_rollup_name;
};

void ScopedDatastoreSegment::sweep() { }

class ScopedExternalSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedExternalSegment)
    CLASSNAME_IS("scoped_external_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedExternalSegment(string host, string name) : host(host), name(name) {
        segment_id = newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
    }

    virtual ~ScopedExternalSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string host;
    string name;
};

void ScopedExternalSegment::sweep() { }

// Profiler factory- for starting and stopping the profiler
DECLARE_EXTERN_REQUEST_LOCAL(ProfilerFactory, s_profiler_factory);

static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) {
    int64_t transaction_id = newrelic_transaction_begin();
    return transaction_id;
}

static int64_t HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) {
    return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) {
    return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_max_trace_segments, int threshold) {
    return newrelic_transaction_set_max_trace_segments(NEWRELIC_AUTOSCOPE, threshold);
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_threshold, int threshold) {
    //deprecated
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_end_transaction) {
    return newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
}

static int64_t HHVM_FUNCTION(newrelic_segment_generic_begin, const String & name) {
    return newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_datastore_begin, const String & table, const String & operation, const String & sql, const String & sql_trace_rollup_name, String & sql_obfuscator) {
    return newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), NULL);
}

static int64_t HHVM_FUNCTION(newrelic_segment_external_begin, const String & host, const String & name) {
    return newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_end, int64_t id) {
    return newrelic_segment_end(NEWRELIC_AUTOSCOPE, id);
}

static int64_t HHVM_FUNCTION(newrelic_notice_error_intern, const String & exception_type,  const String & error_message,  const String & stack_trace,  const String & stack_frame_delimiter) {
    return newrelic_transaction_notice_error(NEWRELIC_AUTOSCOPE, exception_type.c_str(), error_message.c_str(), stack_trace.c_str(), stack_frame_delimiter.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_add_attribute_intern, const String & name, const String & value) {
    return newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, name.c_str(), value.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_custom_metric, const String & name, double value) {
    return newrelic_record_metric(name.c_str(), value);
}

static void HHVM_FUNCTION(newrelic_set_external_profiler, int64_t maxdepth ) {
    Profiler *pr = new NewRelicProfiler(maxdepth);
    s_profiler_factory->setExternalProfiler(pr);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_generic_segment, const String & name) {
    ScopedGenericSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedGenericSegment)(name.c_str());
    #else
        segment = newres<ScopedGenericSegment>(name.c_str());
    #endif
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_database_segment, const String & table, const String & operation, const String sql, const String sql_trace_rollup_name) {
    ScopedDatastoreSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedDatastoreSegment)(table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str());
    #else
        segment = newres<ScopedDatastoreSegment>(table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str());
    #endif
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_external_segment, const String & host, const String & name) {
    ScopedExternalSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedExternalSegment)(host.c_str(), name.c_str());
    #else
        segment = newres<ScopedExternalSegment>(host.c_str(), name.c_str());
    #endif
    return Resource(segment);
}

const StaticString
  s__NR_ERROR_CALLBACK("NewRelicExtensionHelper::errorCallback"),
  s__NR_EXCEPTION_CALLBACK("NewRelicExtensionHelper::exceptionCallback");

static class NewRelicExtension : public Extension {
public:
    NewRelicExtension () : Extension("newrelic", NO_EXTENSION_VERSION_YET) {
        config_loaded = false;
    }

    virtual void init_newrelic() {
        newrelic_register_message_handler(newrelic_message_handler);
        newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str());
    }

    virtual void moduleLoad(const IniSetting::Map& ini, Hdf config) {

        license_key = RuntimeOption::EnvVariables["NEWRELIC_LICENSE_KEY"];
        app_name = RuntimeOption::EnvVariables["NEWRELIC_APP_NAME"];
        app_language = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE"];
        app_language_version = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE_VERSION"];

        if (app_language.empty()) {
            app_language = "php-hhvm";
        }

        if (app_language_version.empty()) {
            app_language_version = HPHP::getHphpCompilerVersion();
        }

        setenv("NEWRELIC_LICENSE_KEY", license_key.c_str(), 1);
        setenv("NEWRELIC_APP_NAME", app_name.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE", app_language.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE_VERSION", app_language_version.c_str(), 1);

        if (!license_key.empty() && !app_name.empty() && !app_language.empty() && !app_language_version.empty())
            config_loaded = true;

    }

    void moduleInit () override {
        if (config_loaded) init_newrelic();

        HHVM_FE(newrelic_start_transaction_intern);
        HHVM_FE(newrelic_name_transaction_intern);
        HHVM_FE(newrelic_transaction_set_request_url);
        HHVM_FE(newrelic_transaction_set_max_trace_segments);
        HHVM_FE(newrelic_transaction_set_threshold);
        HHVM_FE(newrelic_end_transaction);
        HHVM_FE(newrelic_segment_generic_begin);
        HHVM_FE(newrelic_segment_datastore_begin);
        HHVM_FE(newrelic_segment_external_begin);
        HHVM_FE(newrelic_segment_end);
        HHVM_FE(newrelic_get_scoped_generic_segment);
        HHVM_FE(newrelic_get_scoped_database_segment);
        HHVM_FE(newrelic_get_scoped_external_segment);
        HHVM_FE(newrelic_notice_error_intern);
        HHVM_FE(newrelic_add_attribute_intern);
        HHVM_FE(newrelic_set_external_profiler);

        loadSystemlib();
    }

    virtual void requestShutdown() {

        newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
    }

    void requestInit() override {
        auto serverVars = php_global(s__SERVER).toArray();

        f_set_error_handler(s__NR_ERROR_CALLBACK);
        f_set_exception_handler(s__NR_EXCEPTION_CALLBACK);
        //TODO: make it possible to disable that via ini
        newrelic_transaction_begin();
        String request_url = serverVars[s__REQUEST_URI].toString();
        String https = serverVars[s__HTTPS].toString();
        String http_host = serverVars[s__HTTP_HOST].toString();
        String script_name = serverVars[s__SCRIPT_NAME].toString();
        String query_string = serverVars[s__QUERY_STRING].toString();
        String transaction_name = request_url == s__EMPTY ? script_name : request_url;
        String full_uri;

        if (request_url == s__EMPTY) {
            full_uri = script_name;
        } else {
            if (https == s__EMPTY) {
                full_uri = s__PROTO_HTTP;
            } else {
                full_uri = s__PROTO_HTTPS;
            }
            full_uri += http_host + request_url;
        }

        newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, full_uri.c_str());
        //set request_url strips query parameter, add a custom attribute with the full param
        if (query_string != s__EMPTY) {
            newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "FULL_URL", full_uri.c_str());
        }

        newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, transaction_name.c_str());

        // add http request headers to transaction attributes
        Transport *transport = g_context->getTransport();
        if (transport) {
            HeaderMap headers;
            transport->getHeaders(headers);
            for (auto& iter : headers) {
                const auto& values = iter.second;
                if (!values.size()) {
                    continue;
                }
                if (iter.first == "User-Agent") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.User-Agent", values.back().c_str());
                } else if (iter.first == "Accept") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Accept", values.back().c_str());
                } else if (iter.first == "Accept-Language") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Accept-Language", values.back().c_str());
                } else if (iter.first == "Api-Version") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Api-Version", values.back().c_str());
                }
            }
        }

    }

private:
    std::string license_key;
    std::string app_name;
    std::string app_language;
    std::string app_language_version;
    bool config_loaded;
} s_newrelic_extension;

HHVM_GET_MODULE(newrelic)

} // namespace HPHP
<commit_msg>Strip GET parameters from transaction names<commit_after>#include "hphp/runtime/base/base-includes.h"
#include "hphp/runtime/ext/std/ext_std_errorfunc.h"
#include "hphp/runtime/base/php-globals.h"
#include "hphp/runtime/base/hphp-system.h"
#include "hphp/runtime/ext/ext_hotprofiler.h"
#include "newrelic_transaction.h"
#include "newrelic_collector_client.h"
#include "newrelic_common.h"
#include "newrelic_profiler.h"
#include "hphp/runtime/server/transport.h"

#include <string>
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <thread>
#include <unistd.h>

using namespace std;

namespace HPHP {

bool keep_running = true;

class ScopedGenericSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedGenericSegment)
    CLASSNAME_IS("scoped_generic_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedGenericSegment(string name) : name(name) {
        segment_id = newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
    }

    virtual ~ScopedGenericSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string name;
};

void ScopedGenericSegment::sweep() { }

class ScopedDatastoreSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedDatastoreSegment)
    CLASSNAME_IS("scoped_database_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedDatastoreSegment(string table, string operation, string sql, string sql_trace_rollup_name) : table(table), operation(operation), sql(sql), sql_trace_rollup_name(sql_trace_rollup_name) {
        //TODO sql_trace_rollup_name
        if (sql_trace_rollup_name == "") {
            segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), NULL, NULL);
        } else {
            segment_id = newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), NULL);
        }
    }

    virtual ~ScopedDatastoreSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string table;
    string operation;
    string sql;
    string sql_trace_rollup_name;
};

void ScopedDatastoreSegment::sweep() { }

class ScopedExternalSegment : public SweepableResourceData {
public:
    DECLARE_RESOURCE_ALLOCATION(ScopedExternalSegment)
    CLASSNAME_IS("scoped_external_segment")

    virtual const String& o_getClassNameHook() const { return classnameof(); }

    explicit ScopedExternalSegment(string host, string name) : host(host), name(name) {
        segment_id = newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
    }

    virtual ~ScopedExternalSegment() {
        if (segment_id < 0) return;
        newrelic_segment_end(NEWRELIC_AUTOSCOPE, segment_id);
    }

private:
    int64_t segment_id;
    string host;
    string name;
};

void ScopedExternalSegment::sweep() { }

// Profiler factory- for starting and stopping the profiler
DECLARE_EXTERN_REQUEST_LOCAL(ProfilerFactory, s_profiler_factory);

static int64_t HHVM_FUNCTION(newrelic_start_transaction_intern) {
    int64_t transaction_id = newrelic_transaction_begin();
    return transaction_id;
}

static int64_t HHVM_FUNCTION(newrelic_name_transaction_intern, const String & name) {
    return newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_request_url, const String & request_url) {
    return newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, request_url.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_max_trace_segments, int threshold) {
    return newrelic_transaction_set_max_trace_segments(NEWRELIC_AUTOSCOPE, threshold);
}

static int64_t HHVM_FUNCTION(newrelic_transaction_set_threshold, int threshold) {
    //deprecated
    return false;
}

static int64_t HHVM_FUNCTION(newrelic_end_transaction) {
    return newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
}

static int64_t HHVM_FUNCTION(newrelic_segment_generic_begin, const String & name) {
    return newrelic_segment_generic_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_datastore_begin, const String & table, const String & operation, const String & sql, const String & sql_trace_rollup_name, String & sql_obfuscator) {
    return newrelic_segment_datastore_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str(), NULL);
}

static int64_t HHVM_FUNCTION(newrelic_segment_external_begin, const String & host, const String & name) {
    return newrelic_segment_external_begin(NEWRELIC_AUTOSCOPE, NEWRELIC_AUTOSCOPE, host.c_str(), name.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_segment_end, int64_t id) {
    return newrelic_segment_end(NEWRELIC_AUTOSCOPE, id);
}

static int64_t HHVM_FUNCTION(newrelic_notice_error_intern, const String & exception_type,  const String & error_message,  const String & stack_trace,  const String & stack_frame_delimiter) {
    return newrelic_transaction_notice_error(NEWRELIC_AUTOSCOPE, exception_type.c_str(), error_message.c_str(), stack_trace.c_str(), stack_frame_delimiter.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_add_attribute_intern, const String & name, const String & value) {
    return newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, name.c_str(), value.c_str());
}

static int64_t HHVM_FUNCTION(newrelic_custom_metric, const String & name, double value) {
    return newrelic_record_metric(name.c_str(), value);
}

static void HHVM_FUNCTION(newrelic_set_external_profiler, int64_t maxdepth ) {
    Profiler *pr = new NewRelicProfiler(maxdepth);
    s_profiler_factory->setExternalProfiler(pr);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_generic_segment, const String & name) {
    ScopedGenericSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedGenericSegment)(name.c_str());
    #else
        segment = newres<ScopedGenericSegment>(name.c_str());
    #endif
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_database_segment, const String & table, const String & operation, const String sql, const String sql_trace_rollup_name) {
    ScopedDatastoreSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedDatastoreSegment)(table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str());
    #else
        segment = newres<ScopedDatastoreSegment>(table.c_str(), operation.c_str(), sql.c_str(), sql_trace_rollup_name.c_str());
    #endif
    return Resource(segment);
}

static Variant HHVM_FUNCTION(newrelic_get_scoped_external_segment, const String & host, const String & name) {
    ScopedExternalSegment * segment = nullptr;
    // NEWOBJ existsonly until HHVM 3.4
    #ifdef NEWOBJ
        segment = NEWOBJ(ScopedExternalSegment)(host.c_str(), name.c_str());
    #else
        segment = newres<ScopedExternalSegment>(host.c_str(), name.c_str());
    #endif
    return Resource(segment);
}

const StaticString
  s__NR_ERROR_CALLBACK("NewRelicExtensionHelper::errorCallback"),
  s__NR_EXCEPTION_CALLBACK("NewRelicExtensionHelper::exceptionCallback");

static class NewRelicExtension : public Extension {
public:
    NewRelicExtension () : Extension("newrelic", NO_EXTENSION_VERSION_YET) {
        config_loaded = false;
    }

    virtual void init_newrelic() {
        newrelic_register_message_handler(newrelic_message_handler);
        newrelic_init(license_key.c_str(), app_name.c_str(), app_language.c_str(), app_language_version.c_str());
    }

    virtual void moduleLoad(const IniSetting::Map& ini, Hdf config) {

        license_key = RuntimeOption::EnvVariables["NEWRELIC_LICENSE_KEY"];
        app_name = RuntimeOption::EnvVariables["NEWRELIC_APP_NAME"];
        app_language = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE"];
        app_language_version = RuntimeOption::EnvVariables["NEWRELIC_APP_LANGUAGE_VERSION"];

        if (app_language.empty()) {
            app_language = "php-hhvm";
        }

        if (app_language_version.empty()) {
            app_language_version = HPHP::getHphpCompilerVersion();
        }

        setenv("NEWRELIC_LICENSE_KEY", license_key.c_str(), 1);
        setenv("NEWRELIC_APP_NAME", app_name.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE", app_language.c_str(), 1);
        setenv("NEWRELIC_APP_LANGUAGE_VERSION", app_language_version.c_str(), 1);

        if (!license_key.empty() && !app_name.empty() && !app_language.empty() && !app_language_version.empty())
            config_loaded = true;

    }

    void moduleInit () override {
        if (config_loaded) init_newrelic();

        HHVM_FE(newrelic_start_transaction_intern);
        HHVM_FE(newrelic_name_transaction_intern);
        HHVM_FE(newrelic_transaction_set_request_url);
        HHVM_FE(newrelic_transaction_set_max_trace_segments);
        HHVM_FE(newrelic_transaction_set_threshold);
        HHVM_FE(newrelic_end_transaction);
        HHVM_FE(newrelic_segment_generic_begin);
        HHVM_FE(newrelic_segment_datastore_begin);
        HHVM_FE(newrelic_segment_external_begin);
        HHVM_FE(newrelic_segment_end);
        HHVM_FE(newrelic_get_scoped_generic_segment);
        HHVM_FE(newrelic_get_scoped_database_segment);
        HHVM_FE(newrelic_get_scoped_external_segment);
        HHVM_FE(newrelic_notice_error_intern);
        HHVM_FE(newrelic_add_attribute_intern);
        HHVM_FE(newrelic_set_external_profiler);

        loadSystemlib();
    }

    virtual void requestShutdown() {

        newrelic_transaction_end(NEWRELIC_AUTOSCOPE);
    }

    void requestInit() override {
        auto serverVars = php_global(s__SERVER).toArray();

        f_set_error_handler(s__NR_ERROR_CALLBACK);
        f_set_exception_handler(s__NR_EXCEPTION_CALLBACK);
        //TODO: make it possible to disable that via ini
        newrelic_transaction_begin();
        String request_url = serverVars[s__REQUEST_URI].toString();
        String https = serverVars[s__HTTPS].toString();
        String http_host = serverVars[s__HTTP_HOST].toString();
        String script_name = serverVars[s__SCRIPT_NAME].toString();
        String query_string = serverVars[s__QUERY_STRING].toString();
        String full_uri;

        if (request_url == s__EMPTY) {
            full_uri = script_name;
        } else {
            if (https == s__EMPTY) {
                full_uri = s__PROTO_HTTP;
            } else {
                full_uri = s__PROTO_HTTPS;
            }
            full_uri += http_host + request_url;
        }

        newrelic_transaction_set_request_url(NEWRELIC_AUTOSCOPE, full_uri.c_str());
        //set request_url strips query parameter, add a custom attribute with the full param
        if (query_string != s__EMPTY) {
            newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "FULL_URL", full_uri.c_str());
        }

        //build transaction name
        String transaction_name = request_url == s__EMPTY ? script_name : request_url;
        size_t get_param_loc = transaction_name.find('?');
        if(get_param_loc != string::npos) {
            transaction_name = transaction_name.substr(0, get_param_loc);
        }

        newrelic_transaction_set_name(NEWRELIC_AUTOSCOPE, transaction_name.c_str());

        // add http request headers to transaction attributes
        Transport *transport = g_context->getTransport();
        if (transport) {
            HeaderMap headers;
            transport->getHeaders(headers);
            for (auto& iter : headers) {
                const auto& values = iter.second;
                if (!values.size()) {
                    continue;
                }
                if (iter.first == "User-Agent") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.User-Agent", values.back().c_str());
                } else if (iter.first == "Accept") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Accept", values.back().c_str());
                } else if (iter.first == "Accept-Language") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Accept-Language", values.back().c_str());
                } else if (iter.first == "Api-Version") {
                    newrelic_transaction_add_attribute(NEWRELIC_AUTOSCOPE, "request.headers.Api-Version", values.back().c_str());
                }
            }
        }

    }

private:
    std::string license_key;
    std::string app_name;
    std::string app_language;
    std::string app_language_version;
    bool config_loaded;
} s_newrelic_extension;

HHVM_GET_MODULE(newrelic)

} // namespace HPHP
<|endoftext|>