<commit_before>// @(#)root/reflex:$Name:  $:$Id: NameLookup.cxx,v 1.11 2006/10/11 08:04:30 axel Exp $
// Author: Stefan Roiser 2006

// Copyright CERN, CH-1211 Geneva 23, 2004-2006, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#ifndef REFLEX_BUILD
#define REFLEX_BUILD
#endif

#include "NameLookup.h"
#include "Reflex/Base.h"
#include "Reflex/Scope.h"
#include "Reflex/Type.h"
#include "Reflex/Tools.h"
#include "Reflex/internal/OwnedMember.h"

//-------------------------------------------------------------------------------
ROOT::Reflex::NameLookup::NameLookup(const std::string& name, const Scope& current):
   fCurrentScope(current), fLookupName(name), fPartialSuccess(false),
   fPosNamePart(0), fPosNamePartLen(std::string::npos) {
   // Initialize a NameLookup object used internally to keep track of lookup
   // states.
   }
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
ROOT::Reflex::Type
ROOT::Reflex::NameLookup::LookupType( const std::string & nam,
                                      const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) type name appearing in the scope context
// current. This is the public interface for type lookup.
   NameLookup lookup(nam, current);
   return lookup.Lookup< Type >();
}

//-------------------------------------------------------------------------------
ROOT::Reflex::Scope
ROOT::Reflex::NameLookup::LookupScope( const std::string & nam,
                                         const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) scope name appearing in the scope context
// current. This is the public interface for scope lookup.
   NameLookup lookup(nam, current);
   return lookup.Lookup< Scope >();
}

/*
//-------------------------------------------------------------------------------
const ROOT::Reflex::Member & LookupMember( const std::string & nam,
                                           const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) member name appearing in the scope context
// current. This is the public interface for member lookup.
   NameLookup lookup(nam, current);

   // this will not work, member lookup is too different from type lookup...
   return lookup.Lookup<Member>();
}
*/

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::Lookup() {
//-------------------------------------------------------------------------------
// Lookup a type using fLookupName, fCurrentScope.
   fPartialSuccess = false;
   fPosNamePart = 0;
   fPosNamePartLen = std::string::npos;
   FindNextScopePos();

   if ( fPosNamePart == 2 ) {
      fLookedAtUsingDir.clear();
      // ::A...
      fCurrentScope = Scope::GlobalScope();
      return LookupInScope< T >();
   } else
      // A...
      return LookupInUnknownScope< T >();
}

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::LookupInScope() {
//-------------------------------------------------------------------------------
// Lookup a type in fCurrentScope.
// Checks sub-types, sub-scopes, using directives, and base classes for
// the name given by fLookupName, fPosNamePart, and fPosNamePartLen.
// If the name part is found, and another name part follows in fPosNamePart,
// LookupTypeInScope requests the scope found to lookup the next name
// part. fPartialMatch reflexts that the left part of the name was matched;
// even if the trailing part of fLookupName cannot be found, the lookup
// cannot continue on declaring scopes and has to fail.
// A list of lookups performed in namespaces pulled in via using directives is
// kept in fLookedAtUsingDir, to prevent infinite loops due to
//   namespace A{using namespace B;} namespace B{using namespace A;}
// loops.
// The lookup does not take the declaration order into account; the result of
// parts of the lookup algorithm which depend on the order will be unpredictable.

   if (!fCurrentScope) return Dummy::Get< T >();
   if (fLookedAtUsingDir.find(fCurrentScope) != fLookedAtUsingDir.end())
      // prevent inf loop from
      // ns A { using ns B; } ns B {using ns A;}
      return Dummy::Get< T >();

   for ( Type_Iterator it = fCurrentScope.SubType_Begin(); it != fCurrentScope.SubType_End(); ++it ) {
      if ( 0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*it).Name() ) ) {
         fPartialSuccess = true;
         fLookedAtUsingDir.clear();
         FindNextScopePos();
         if (fPosNamePart == std::string::npos) return *it;
         if (it->IsTypedef()) fCurrentScope = it->FinalType();
         else fCurrentScope = *it;
         return LookupInScope< T >();
      }
   }

   for ( Scope_Iterator in = fCurrentScope.SubScope_Begin(); in != fCurrentScope.SubScope_End(); ++in ) {
      // only take namespaces into account - classes were checked as part of SubType
      if (in->IsNamespace() &&
         0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*in).Name() ) ) {
         fPartialSuccess = true;
         fLookedAtUsingDir.clear();
         FindNextScopePos();
         if (fPosNamePart == std::string::npos) return (const T&) (*in);
         fCurrentScope = (const Scope&) (*in);
         return LookupInScope< T >();
      }
   }

   if (fCurrentScope.UsingDirectiveSize()) {
      fLookedAtUsingDir.insert(fCurrentScope);
      Scope storeCurrentScope = fCurrentScope;
      for ( Scope_Iterator si = storeCurrentScope.UsingDirective_Begin(); si != storeCurrentScope.UsingDirective_End(); ++si ) {
         fCurrentScope = *si;
         const T & t = LookupInScope< T >();
         if (fPartialSuccess) return t;
      }
      fCurrentScope = storeCurrentScope;
   }

   if (fPosNamePart == 0) // only for "BaseClass...", not for "A::BaseClass..."
      for ( Base_Iterator bi = fCurrentScope.Base_Begin(); bi != fCurrentScope.Base_End(); ++bi ) {
         if ( 0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*bi).Name() ) ) {
            fPartialSuccess = true;
            fLookedAtUsingDir.clear();
            FindNextScopePos();
            if (fPosNamePart == std::string::npos) return bi->ToType();
            fCurrentScope = bi->ToType().FinalType();
            return LookupInScope< T >();
         }
      }

   if (fCurrentScope.BaseSize()) {
      Scope storeCurrentScope = fCurrentScope;
      for ( Base_Iterator bi = storeCurrentScope.Base_Begin(); bi != storeCurrentScope.Base_End(); ++bi ) {
         fCurrentScope = bi->ToScope();
         const T & t = LookupInScope< T >();
         if (fPartialSuccess) return t;
      }
      fCurrentScope = storeCurrentScope;
   }

   return Dummy::Get< T >();
}

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::LookupInUnknownScope() {
//-------------------------------------------------------------------------------
// Lookup a type in fCurrentScope and its declaring scopes.
   for (fPartialSuccess = false; !fPartialSuccess && fCurrentScope; fCurrentScope = fCurrentScope.DeclaringScope()) {
      fLookedAtUsingDir.clear();
      const T & t = LookupInScope< T >();
      if (fPartialSuccess) return t;
      if (fCurrentScope.IsTopScope()) break;
   }
   return Dummy::Get< T >();
}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMember( const std::string & nam,
                                        const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup a member.
   if ( Tools::GetBasePosition(nam)) return LookupMemberQualified( nam );
   else                              return LookupMemberUnqualified( nam, current );

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMemberQualified( const std::string & nam ) {
//-------------------------------------------------------------------------------
// Lookup of a qualified member.
   const Scope & bscope = Scope::ByName(Tools::GetScopeName(nam));
   if ( bscope ) {
      return LookupMemberUnqualified( Tools::GetBaseName(nam), bscope);
   }
   else {
      return Dummy::Member();
   }

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMemberUnqualified( const std::string & nam,
                                                   const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup of an unqualified member.
   const Member & m0 = current.MemberByName(nam);
   if ( m0 ) return m0;

   for ( Scope_Iterator si = current.UsingDirective_Begin(); si != current.UsingDirective_End(); ++si ) {
      const Member & m1 = LookupMember( nam, *si );
      if ( m1 ) return m1;
   }

   for ( Base_Iterator bi = current.Base_Begin(); bi != current.Base_End(); ++ bi ) {
      const Member & m2 = LookupMember( nam, bi->ToScope() );
      if ( m2 ) return m2;
   }

   if ( ! current.IsTopScope() ) return LookupMember( nam, current.DeclaringScope() );

   return Dummy::Member();

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Type ROOT::Reflex::NameLookup::AccessControl( const Type & typ,
                                                            const Scope & /* current */ ) {
//-------------------------------------------------------------------------------
// Check access .

   //if ( typ.IsPublic()) return true;

   //else if ( typ.IsProtected() && current.HasBase(typ.DeclaringScope()) ) return true;

   return typ;

}

//-------------------------------------------------------------------------------
void ROOT::Reflex::NameLookup::FindNextScopePos() {
//-------------------------------------------------------------------------------
// Move fPosNamePart to point to the next scope in fLookupName, updating
// fPosNamePartLen. If fPosNamePartLen == std::string::npos, initialize
// fPosNamePart and fPosNamePartLen. If there is no next scope left, fPosNamePart
// will be set to std::string::npos and fPosNamePartLen will be set to 0.
   if (fPosNamePartLen != std::string::npos) {
      // we know the length, so jump
      fPosNamePart += fPosNamePartLen + 2;
      if (fPosNamePart > fLookupName.length()) {
         // past the string's end?
         fPosNamePart = std::string::npos;
         fPosNamePartLen = 0;
         return;
      }
   }
   else {
      // uninitialized
      // set fPosNamePartLen and check that fLookupName doesn't start with '::'
      if (fLookupName.compare(0, 2, "::") == 0)
         fPosNamePart = 2;
      else fPosNamePart = 0;
   }
   fPosNamePartLen = Tools::GetFirstScopePosition(fLookupName.substr(fPosNamePart));
   if (fPosNamePartLen == 0)
      // no next "::"
      fPosNamePartLen = fLookupName.length();
   else fPosNamePartLen -= 2; // no "::"
   // fPosNamePartLen -= fPosNamePart; No! We already look in substr()
}
<commit_msg>some more by-values ...<commit_after>// @(#)root/reflex:$Name:  $:$Id: NameLookup.cxx,v 1.12 2006/10/30 12:51:33 roiser Exp $
// Author: Stefan Roiser 2006

// Copyright CERN, CH-1211 Geneva 23, 2004-2006, All rights reserved.
//
// Permission to use, copy, modify, and distribute this software for any
// purpose is hereby granted without fee, provided that this copyright and
// permissions notice appear in all copies and derivatives.
//
// This software is provided "as is" without express or implied warranty.

#ifndef REFLEX_BUILD
#define REFLEX_BUILD
#endif

#include "NameLookup.h"
#include "Reflex/Base.h"
#include "Reflex/Scope.h"
#include "Reflex/Type.h"
#include "Reflex/Tools.h"
#include "Reflex/internal/OwnedMember.h"

//-------------------------------------------------------------------------------
ROOT::Reflex::NameLookup::NameLookup(const std::string& name, const Scope& current):
   fCurrentScope(current), fLookupName(name), fPartialSuccess(false),
   fPosNamePart(0), fPosNamePartLen(std::string::npos) {
   // Initialize a NameLookup object used internally to keep track of lookup
   // states.
   }
//-------------------------------------------------------------------------------

//-------------------------------------------------------------------------------
ROOT::Reflex::Type
ROOT::Reflex::NameLookup::LookupType( const std::string & nam,
                                      const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) type name appearing in the scope context
// current. This is the public interface for type lookup.
   NameLookup lookup(nam, current);
   return lookup.Lookup< Type >();
}

//-------------------------------------------------------------------------------
ROOT::Reflex::Scope
ROOT::Reflex::NameLookup::LookupScope( const std::string & nam,
                                         const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) scope name appearing in the scope context
// current. This is the public interface for scope lookup.
   NameLookup lookup(nam, current);
   return lookup.Lookup< Scope >();
}

/*
//-------------------------------------------------------------------------------
const ROOT::Reflex::Member & LookupMember( const std::string & nam,
                                           const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup up a (possibly scoped) member name appearing in the scope context
// current. This is the public interface for member lookup.
   NameLookup lookup(nam, current);

   // this will not work, member lookup is too different from type lookup...
   return lookup.Lookup<Member>();
}
*/

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::Lookup() {
//-------------------------------------------------------------------------------
// Lookup a type using fLookupName, fCurrentScope.
   fPartialSuccess = false;
   fPosNamePart = 0;
   fPosNamePartLen = std::string::npos;
   FindNextScopePos();

   if ( fPosNamePart == 2 ) {
      fLookedAtUsingDir.clear();
      // ::A...
      fCurrentScope = Scope::GlobalScope();
      return LookupInScope< T >();
   } else
      // A...
      return LookupInUnknownScope< T >();
}

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::LookupInScope() {
//-------------------------------------------------------------------------------
// Lookup a type in fCurrentScope.
// Checks sub-types, sub-scopes, using directives, and base classes for
// the name given by fLookupName, fPosNamePart, and fPosNamePartLen.
// If the name part is found, and another name part follows in fPosNamePart,
// LookupTypeInScope requests the scope found to lookup the next name
// part. fPartialMatch reflexts that the left part of the name was matched;
// even if the trailing part of fLookupName cannot be found, the lookup
// cannot continue on declaring scopes and has to fail.
// A list of lookups performed in namespaces pulled in via using directives is
// kept in fLookedAtUsingDir, to prevent infinite loops due to
//   namespace A{using namespace B;} namespace B{using namespace A;}
// loops.
// The lookup does not take the declaration order into account; the result of
// parts of the lookup algorithm which depend on the order will be unpredictable.

   if (!fCurrentScope) return Dummy::Get< T >();
   if (fLookedAtUsingDir.find(fCurrentScope) != fLookedAtUsingDir.end())
      // prevent inf loop from
      // ns A { using ns B; } ns B {using ns A;}
      return Dummy::Get< T >();

   for ( Type_Iterator it = fCurrentScope.SubType_Begin(); it != fCurrentScope.SubType_End(); ++it ) {
      if ( 0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*it).Name() ) ) {
         fPartialSuccess = true;
         fLookedAtUsingDir.clear();
         FindNextScopePos();
         if (fPosNamePart == std::string::npos) return *it;
         if (it->IsTypedef()) fCurrentScope = it->FinalType();
         else fCurrentScope = *it;
         return LookupInScope< T >();
      }
   }

   for ( Scope_Iterator in = fCurrentScope.SubScope_Begin(); in != fCurrentScope.SubScope_End(); ++in ) {
      // only take namespaces into account - classes were checked as part of SubType
      if (in->IsNamespace() &&
         0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*in).Name() ) ) {
         fPartialSuccess = true;
         fLookedAtUsingDir.clear();
         FindNextScopePos();
         if (fPosNamePart == std::string::npos) return (T) (*in);
         fCurrentScope = (Scope) (*in);
         return LookupInScope< T >();
      }
   }

   if (fCurrentScope.UsingDirectiveSize()) {
      fLookedAtUsingDir.insert(fCurrentScope);
      Scope storeCurrentScope = fCurrentScope;
      for ( Scope_Iterator si = storeCurrentScope.UsingDirective_Begin(); si != storeCurrentScope.UsingDirective_End(); ++si ) {
         fCurrentScope = *si;
         T t = LookupInScope< T >();
         if (fPartialSuccess) return t;
      }
      fCurrentScope = storeCurrentScope;
   }

   if (fPosNamePart == 0) // only for "BaseClass...", not for "A::BaseClass..."
      for ( Base_Iterator bi = fCurrentScope.Base_Begin(); bi != fCurrentScope.Base_End(); ++bi ) {
         if ( 0 == fLookupName.compare(fPosNamePart, fPosNamePartLen, (*bi).Name() ) ) {
            fPartialSuccess = true;
            fLookedAtUsingDir.clear();
            FindNextScopePos();
            if (fPosNamePart == std::string::npos) return bi->ToType();
            fCurrentScope = bi->ToType().FinalType();
            return LookupInScope< T >();
         }
      }

   if (fCurrentScope.BaseSize()) {
      Scope storeCurrentScope = fCurrentScope;
      for ( Base_Iterator bi = storeCurrentScope.Base_Begin(); bi != storeCurrentScope.Base_End(); ++bi ) {
         fCurrentScope = bi->ToScope();
         T t = LookupInScope< T >();
         if (fPartialSuccess) return t;
      }
      fCurrentScope = storeCurrentScope;
   }

   return Dummy::Get< T >();
}

//-------------------------------------------------------------------------------
template< class T > T
ROOT::Reflex::NameLookup::LookupInUnknownScope() {
//-------------------------------------------------------------------------------
// Lookup a type in fCurrentScope and its declaring scopes.
   for (fPartialSuccess = false; !fPartialSuccess && fCurrentScope; fCurrentScope = fCurrentScope.DeclaringScope()) {
      fLookedAtUsingDir.clear();
      T t = LookupInScope< T >();
      if (fPartialSuccess) return t;
      if (fCurrentScope.IsTopScope()) break;
   }
   return Dummy::Get< T >();
}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMember( const std::string & nam,
                                        const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup a member.
   if ( Tools::GetBasePosition(nam)) return LookupMemberQualified( nam );
   else                              return LookupMemberUnqualified( nam, current );

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMemberQualified( const std::string & nam ) {
//-------------------------------------------------------------------------------
// Lookup of a qualified member.
   Scope bscope = Scope::ByName(Tools::GetScopeName(nam));
   if ( bscope ) {
      return LookupMemberUnqualified( Tools::GetBaseName(nam), bscope);
   }
   else {
      return Dummy::Member();
   }

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Member
ROOT::Reflex::NameLookup::LookupMemberUnqualified( const std::string & nam,
                                                   const Scope & current ) {
//-------------------------------------------------------------------------------
// Lookup of an unqualified member.
   Member m0 = current.MemberByName(nam);
   if ( m0 ) return m0;

   for ( Scope_Iterator si = current.UsingDirective_Begin(); si != current.UsingDirective_End(); ++si ) {
      Member m1 = LookupMember( nam, *si );
      if ( m1 ) return m1;
   }

   for ( Base_Iterator bi = current.Base_Begin(); bi != current.Base_End(); ++ bi ) {
      Member m2 = LookupMember( nam, bi->ToScope() );
      if ( m2 ) return m2;
   }

   if ( ! current.IsTopScope() ) return LookupMember( nam, current.DeclaringScope() );

   return Dummy::Member();

}

//-------------------------------------------------------------------------------
ROOT::Reflex::Type ROOT::Reflex::NameLookup::AccessControl( const Type & typ,
                                                            const Scope & /* current */ ) {
//-------------------------------------------------------------------------------
// Check access .

   //if ( typ.IsPublic()) return true;

   //else if ( typ.IsProtected() && current.HasBase(typ.DeclaringScope()) ) return true;

   return typ;

}

//-------------------------------------------------------------------------------
void ROOT::Reflex::NameLookup::FindNextScopePos() {
//-------------------------------------------------------------------------------
// Move fPosNamePart to point to the next scope in fLookupName, updating
// fPosNamePartLen. If fPosNamePartLen == std::string::npos, initialize
// fPosNamePart and fPosNamePartLen. If there is no next scope left, fPosNamePart
// will be set to std::string::npos and fPosNamePartLen will be set to 0.
   if (fPosNamePartLen != std::string::npos) {
      // we know the length, so jump
      fPosNamePart += fPosNamePartLen + 2;
      if (fPosNamePart > fLookupName.length()) {
         // past the string's end?
         fPosNamePart = std::string::npos;
         fPosNamePartLen = 0;
         return;
      }
   }
   else {
      // uninitialized
      // set fPosNamePartLen and check that fLookupName doesn't start with '::'
      if (fLookupName.compare(0, 2, "::") == 0)
         fPosNamePart = 2;
      else fPosNamePart = 0;
   }
   fPosNamePartLen = Tools::GetFirstScopePosition(fLookupName.substr(fPosNamePart));
   if (fPosNamePartLen == 0)
      // no next "::"
      fPosNamePartLen = fLookupName.length();
   else fPosNamePartLen -= 2; // no "::"
   // fPosNamePartLen -= fPosNamePart; No! We already look in substr()
}
<|endoftext|>


<commit_before>/*
 * sim900.cpp
 * A library for SeeedStudio seeeduino GPRS shield
 *
 * Copyright (c) 2015 seeed technology inc.
 * Website    : www.seeed.cc
 * Author     : lawliet zou
 * Create Time: April 2015
 * Change Log :
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "sim900.h"

SoftwareSerial *serialSIM900 = NULL;

void  sim900_init(void * uart_device, uint32_t baud)
{
    serialSIM900 = (SoftwareSerial*)uart_device;
	serialSIM900->begin(baud);
}

int sim900_check_readable()
{
    return serialSIM900->available();
}

int sim900_wait_readable (int wait_time)
{
    unsigned long timerStart;
    int dataLen = 0;
    timerStart = millis();
    while((unsigned long) (millis() - timerStart) > wait_time * 1000UL) {
        delay(500);
        dataLen = sim900_check_readable();
        if(dataLen > 0){
            break;
        }
    }
    return dataLen;
}

void sim900_flush_serial()
{
    while(sim900_check_readable()){
        serialSIM900->read();
    }
}

void sim900_read_buffer(char *buffer, int count, unsigned int timeout, unsigned int chartimeout)
{
    int i = 0;
    unsigned long timerStart, prevChar;
    timerStart = millis();
    prevChar = 0;
    while(1) {
        while (sim900_check_readable()) {
            char c = serialSIM900->read();
            prevChar = millis();
            buffer[i++] = c;
			DEBUG("-");DEBUG(c);
            if(i >= count)break;
        }
        if(i >= count)break;
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
}

uint16_t sim900_read_string_until(char *buffer, int count, char *pattern, unsigned int timeout, unsigned int chartimeout)
{
    uint16_t i = 0;
    uint8_t sum = 0;
    uint8_t len = strlen(pattern);
    bool is_timeout = false;
    unsigned long timerStart, prevChar;

    timerStart = millis();
    prevChar = 0;
    while(1) {
        if(serialSIM900->available()) {
            char c = serialSIM900->read();
            DEBUG(c);
            prevChar = millis();
            buffer[i++] = c;
            if(i >= count)break;
            sum = (c==pattern[sum]) ? sum+1 : 0;
            if(sum == len)break;
        }
        if(i >= count)break;
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
    return (uint16_t)(i - 1);
}

void sim900_clean_buffer(char *buffer, int count)
{
    for(int i=0; i < count; i++) {
        buffer[i] = '\0';
    }
}

void sim900_send_byte(uint8_t data)
{
	serialSIM900->write(data);
	DEBUG((char)data);
}

void sim900_send_char(const char c)
{
	serialSIM900->write(c);
	DEBUG(c);
}

void sim900_send_cmd(const char* cmd)
{
  for(uint16_t i=0; i<strlen(cmd); i++)
    {
        sim900_send_byte(cmd[i]);
    }
}

void sim900_send_cmd(const __FlashStringHelper* cmd)
{
  int i = 0;
  const char *ptr = (const char *) cmd;
  while (pgm_read_byte(ptr + i) != 0x00) {
    sim900_send_byte(pgm_read_byte(ptr + i++));
  }
}

void sim900_send_cmd_P(const char* cmd)
{
  while (pgm_read_byte(cmd) != 0x00)
    sim900_send_byte(pgm_read_byte(cmd++));
}

boolean sim900_send_AT(void)
{
    return sim900_check_with_cmd(F("AT\r\n"),"OK",CMD);
}

void sim900_send_End_Mark(void)
{
    sim900_send_byte((char)26);
}

boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    int len = strlen(resp);
    int sum = 0;
    unsigned long timerStart, prevChar;    //prevChar is the time when the previous Char has been read.
    timerStart = millis();
    prevChar = 0;
    while(1) {
        if(sim900_check_readable()) {
            char c = serialSIM900->read();
			DEBUG("-");
			DEBUG(c);
            prevChar = millis();
            sum = (c==resp[sum]) ? sum+1 : 0;
            if(sum == len)break;
        }
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            return false;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function.
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            return false;
        }

    }
    //If is a CMD, we will finish to read buffer.
    if(type == CMD) sim900_flush_serial();
    return true;
}

boolean sim900_check_with_cmd(const char* cmd, const char *resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp,type,timeout,chartimeout);
}

//HACERR que tambien la respuesta pueda ser FLASH STRING
boolean sim900_check_with_cmd(const __FlashStringHelper* cmd, const char *resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp,type,timeout,chartimeout);
}

void sim900_AT_bypass()
{
  if(serialSIM900->available()){
    Serial.write(serialSIM900->read());
  }
  if(Serial.available()){
    serialSIM900->write(Serial.read());
  }
}					   <commit_msg>fixed compiler warning: is_timeout is not used in sim900_read_string_until()<commit_after>/*
 * sim900.cpp
 * A library for SeeedStudio seeeduino GPRS shield
 *
 * Copyright (c) 2015 seeed technology inc.
 * Website    : www.seeed.cc
 * Author     : lawliet zou
 * Create Time: April 2015
 * Change Log :
 *
 * The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "sim900.h"

SoftwareSerial *serialSIM900 = NULL;

void  sim900_init(void * uart_device, uint32_t baud)
{
    serialSIM900 = (SoftwareSerial*)uart_device;
	serialSIM900->begin(baud);
}

int sim900_check_readable()
{
    return serialSIM900->available();
}

int sim900_wait_readable (int wait_time)
{
    unsigned long timerStart;
    int dataLen = 0;
    timerStart = millis();
    while((unsigned long) (millis() - timerStart) > wait_time * 1000UL) {
        delay(500);
        dataLen = sim900_check_readable();
        if(dataLen > 0){
            break;
        }
    }
    return dataLen;
}

void sim900_flush_serial()
{
    while(sim900_check_readable()){
        serialSIM900->read();
    }
}

void sim900_read_buffer(char *buffer, int count, unsigned int timeout, unsigned int chartimeout)
{
    int i = 0;
    unsigned long timerStart, prevChar;
    timerStart = millis();
    prevChar = 0;
    while(1) {
        while (sim900_check_readable()) {
            char c = serialSIM900->read();
            prevChar = millis();
            buffer[i++] = c;
			DEBUG("-");DEBUG(c);
            if(i >= count)break;
        }
        if(i >= count)break;
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
}

uint16_t sim900_read_string_until(char *buffer, int count, char *pattern, unsigned int timeout, unsigned int chartimeout)
{
    uint16_t i = 0;
    uint8_t sum = 0;
    uint8_t len = strlen(pattern);
    unsigned long timerStart, prevChar;

    timerStart = millis();
    prevChar = 0;
    while(1) {
        if(serialSIM900->available()) {
            char c = serialSIM900->read();
            DEBUG(c);
            prevChar = millis();
            buffer[i++] = c;
            if(i >= count)break;
            sum = (c==pattern[sum]) ? sum+1 : 0;
            if(sum == len)break;
        }
        if(i >= count)break;
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            break;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function. Not DO it if we dont recieve at least one char (prevChar <> 0)
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            break;
        }
    }
    return (uint16_t)(i - 1);
}

void sim900_clean_buffer(char *buffer, int count)
{
    for(int i=0; i < count; i++) {
        buffer[i] = '\0';
    }
}

void sim900_send_byte(uint8_t data)
{
	serialSIM900->write(data);
	DEBUG((char)data);
}

void sim900_send_char(const char c)
{
	serialSIM900->write(c);
	DEBUG(c);
}

void sim900_send_cmd(const char* cmd)
{
  for(uint16_t i=0; i<strlen(cmd); i++)
    {
        sim900_send_byte(cmd[i]);
    }
}

void sim900_send_cmd(const __FlashStringHelper* cmd)
{
  int i = 0;
  const char *ptr = (const char *) cmd;
  while (pgm_read_byte(ptr + i) != 0x00) {
    sim900_send_byte(pgm_read_byte(ptr + i++));
  }
}

void sim900_send_cmd_P(const char* cmd)
{
  while (pgm_read_byte(cmd) != 0x00)
    sim900_send_byte(pgm_read_byte(cmd++));
}

boolean sim900_send_AT(void)
{
    return sim900_check_with_cmd(F("AT\r\n"),"OK",CMD);
}

void sim900_send_End_Mark(void)
{
    sim900_send_byte((char)26);
}

boolean sim900_wait_for_resp(const char* resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    int len = strlen(resp);
    int sum = 0;
    unsigned long timerStart, prevChar;    //prevChar is the time when the previous Char has been read.
    timerStart = millis();
    prevChar = 0;
    while(1) {
        if(sim900_check_readable()) {
            char c = serialSIM900->read();
			DEBUG("-");
			DEBUG(c);
            prevChar = millis();
            sum = (c==resp[sum]) ? sum+1 : 0;
            if(sum == len)break;
        }
        if ((unsigned long) (millis() - timerStart) > timeout * 1000UL) {
            return false;
        }
        //If interchar Timeout => return FALSE. So we can return sooner from this function.
        if (((unsigned long) (millis() - prevChar) > chartimeout) && (prevChar != 0)) {
            return false;
        }

    }
    //If is a CMD, we will finish to read buffer.
    if(type == CMD) sim900_flush_serial();
    return true;
}

boolean sim900_check_with_cmd(const char* cmd, const char *resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp,type,timeout,chartimeout);
}

//HACERR que tambien la respuesta pueda ser FLASH STRING
boolean sim900_check_with_cmd(const __FlashStringHelper* cmd, const char *resp, DataType type, unsigned int timeout, unsigned int chartimeout)
{
    sim900_send_cmd(cmd);
    return sim900_wait_for_resp(resp,type,timeout,chartimeout);
}

void sim900_AT_bypass()
{
  if(serialSIM900->available()){
    Serial.write(serialSIM900->read());
  }
  if(Serial.available()){
    serialSIM900->write(Serial.read());
  }
}					   <|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

extern "C" {
#include <lirc/lirc_client.h>
}

void ir_received(char* raw_code){
    std::string full_code(raw_code);

    auto code_end = full_code.find(' ');
    std::string code(full_code.begin(), full_code.begin() + code_end);

    auto repeat_end = full_code.find(' ', code_end + 1);
    std::string repeat(full_code.begin() + code_end + 1, full_code.begin() + repeat_end);

    auto key_end = full_code.find(' ', repeat_end + 1);
    std::string key(full_code.begin() + repeat_end + 1, full_code.begin() + key_end);

    std::cout << "Code: " << code << std::endl;
    std::cout << "Repeat: " << repeat << std::endl;
    std::cout << "Key: " << key << std::endl;
}

int main(){
    //Initiate LIRC. Exit on failure
    char lirc_name[] = "lirc";
    if(lirc_init(lirc_name, 1) == -1){
        return 1;
    }

    struct lirc_config* config;

    //Read the default LIRC config at /etc/lirc/lircd.conf  This is the config for your remote.
    if(lirc_readconfig(NULL,&config,NULL)==0){
        char* code;

        //Do stuff while LIRC socket is open  0=open  -1=closed.
        while(lirc_nextcode(&code)==0){
            //If code = NULL, nothing was returned from LIRC socket
            if(code){
                //Send code further
                ir_received(code);

                //Need to free up code before the next loop
                free(code);
            }
        }

        //Frees the data structures associated with config.
        lirc_freeconfig(config);
    }

    //Closes LIRC
    lirc_deinit();

    return 0;
}
<commit_msg>Start code for client<commit_after>#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

extern "C" {
#include <lirc/lirc_client.h>
}

void ir_received(char* raw_code){
    std::string full_code(raw_code);

    auto code_end = full_code.find(' ');
    std::string code(full_code.begin(), full_code.begin() + code_end);

    auto repeat_end = full_code.find(' ', code_end + 1);
    std::string repeat(full_code.begin() + code_end + 1, full_code.begin() + repeat_end);

    auto key_end = full_code.find(' ', repeat_end + 1);
    std::string key(full_code.begin() + repeat_end + 1, full_code.begin() + key_end);

    std::cout << "Code: " << code << std::endl;
    std::cout << "Repeat: " << repeat << std::endl;
    std::cout << "Key: " << key << std::endl;
}

int main(){
    //Initiate LIRC. Exit on failure
    char lirc_name[] = "lirc";
    if(lirc_init(lirc_name, 1) == -1){
        std::cout << "asgard:ir: Failed to init LIRC" << std::endl;
        return 1;
    }

    //Open the socket
    auto socket_fd = socket(PF_UNIX, SOCK_STREAM, 0);
    if(socket_fd < 0){
        std::cout << "asgard:ir: socket() failed" << std::endl;
        return 1;
    }

    //Init the address
    struct sockaddr_un address;
    memset(&address, 0, sizeof(struct sockaddr_un));
    address.sun_family = AF_UNIX;
    snprintf(address.sun_path, UNIX_PATH_MAX, "/tmp/asgard_socket");

    //Connect to the server
    if(connect(socket_fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0){
        std::cout << "asgard:ir: connect() failed" << std::endl;
        return 1;
    }

    char buffer[4096];

    auto nbytes = snprintf(buffer, 4096, "hello from a client");
    write(socket_fd, buffer, nbytes);

    nbytes = read(socket_fd, buffer, 4096);
    buffer[nbytes] = 0;

    printf("MESSAGE FROM SERVER: %s\n", buffer);

    //Read the default LIRC config
    struct lirc_config* config;
    if(lirc_readconfig(NULL,&config,NULL)==0){
        char* code;

        //Do stuff while LIRC socket is open  0=open  -1=closed.
        while(lirc_nextcode(&code)==0){
            //If code = NULL, nothing was returned from LIRC socket
            if(code){
                //Send code further
                ir_received(code);

                //Need to free up code before the next loop
                free(code);
            }
        }

        //Frees the data structures associated with config.
        lirc_freeconfig(config);
    } else {
        std::cout << "asgard:ir: Failed to read LIRC config" << std::endl;
    }

    //Closes LIRC
    lirc_deinit();

    //Close the socket
    close(socket_fd);

    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Remove print in test (#1634)<commit_after><|endoftext|>


<commit_before>#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstVisitor.h"
#include <set>
#include <list>
using namespace llvm;

namespace {

    class GenAndKillSets {
        public:
            std::set<StoreInst *> gen;
            std::set<StoreInst *> kill;
    };

    class BBGenAndKillSets {
        public:
            BasicBlock *bb;
            std::set<StoreInst *> gen;
            std::set<StoreInst *> kill;
            BBGenAndKillSets(BasicBlock *val) { bb = val; }
            std::string genString() {
                std::string ret = "Gen Set of BB:" + bb->getName().str() + '\n';
                for (std::set<StoreInst *>::iterator it = gen.begin(); it != gen.end(); it++) {
                    StoreInst *inst = *it;
                    ret += '\t' + inst->getPointerOperand()->getName().str() + '\n';
                }
                return ret;
            }
    };

    struct NaivePass : public FunctionPass {
        static char ID;
        NaivePass() : FunctionPass(ID) {}

        virtual bool runOnFunction(Function &F) {
            std::list<BBGenAndKillSets> listOfSets;
            for (Function::iterator f_it = F.begin(); f_it != F.end(); ++f_it) {
                BBGenAndKillSets bbSets = createBBGenAndKillSets(F, f_it);
                errs() << bbSets.genString();
            }
            return false;
        }

        BBGenAndKillSets createBBGenAndKillSets(Function &F, BasicBlock *f_it) {
            BBGenAndKillSets bbSets(f_it);
            for (BasicBlock::iterator bb_it = f_it->begin(); bb_it != f_it->end(); bb_it++) {
                if (StoreInst *inst = dyn_cast<StoreInst>(bb_it)) {
                    Value *var = inst->getPointerOperand();
                    GenAndKillSets sets;
                    sets.gen.insert(inst);
                    for (Function::iterator f2_it = F.begin(); f2_it != F.end(); ++f2_it) {
                        for (BasicBlock::iterator bb2_it = f2_it->begin();
                                bb2_it != f2_it->end(); bb2_it++) {
                            if (bb2_it == bb_it) {
                                continue;
                            }

                            if (StoreInst *inst2 = dyn_cast<StoreInst>(bb2_it)) {
                                if (inst2->getPointerOperand() == var) {
                                    sets.kill.insert(inst2);
                                }
                            }
                        }
                    }
                    for (std::set<StoreInst *>::iterator gen = sets.gen.begin(); gen != sets.gen.end(); gen++) {
                        bbSets.gen.insert(*gen);
                    }
                    for (std::set<StoreInst *>::iterator kill = sets.kill.begin(); kill != sets.kill.end(); kill++) {
                        bbSets.kill.insert(*kill);
                    }
                }
            }
            return bbSets;
        }

    };

    char NaivePass::ID = 0;
    static RegisterPass<NaivePass> X("naive-reaching", "Naive Reaching Analysis", false, false);
}
<commit_msg>Made Reaching Analysis compile and not infinite loop, hooray.<commit_after>#include "llvm/Pass.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/InstVisitor.h"
#include "llvm/Analysis/CFG.h"
#include <set>
#include <list>
using namespace llvm;

namespace {

    class GenAndKillSets {
        public:
            std::set<StoreInst *> gen;
            std::set<StoreInst *> kill;
    };

    class BBGenAndKillSets {
        public:
            BasicBlock *bb;
            std::set<StoreInst *> gen;
            std::set<StoreInst *> kill;
            BBGenAndKillSets(BasicBlock *val) { bb = val; }
            //Sanity Check function, used to ensure my output made sense with personal test case.
            std::string genString() {
                std::string ret = "Gen Set of BB:" + bb->getName().str() + '\n';
                for (std::set<StoreInst *>::iterator it = gen.begin(); it != gen.end(); it++) {
                    StoreInst *inst = *it;
                    ret += '\t' + inst->getPointerOperand()->getName().str() + '\n';
                }
                return ret;
            }
    };

    class BBInAndOut {
        public:
            BasicBlock *bb;
            std::set<StoreInst *> in;
            std::set<StoreInst *> out;
            BBInAndOut(BasicBlock *val) { bb = val; }
    };

    struct NaivePass : public FunctionPass {
        static char ID;
        NaivePass() : FunctionPass(ID) {}

        virtual bool runOnFunction(Function &F) {
            std::list<BBGenAndKillSets> listOfSets;
            std::list<BBInAndOut> output;
            //First, Generate the Gen And Kill Sets And initialize the output
            for (Function::iterator f_it = F.begin(); f_it != F.end(); ++f_it) {
                listOfSets.push_back(createBBGenAndKillSets(F, f_it));
            }
            for (Function::iterator bb = F.begin(); bb != F.end(); bb++) {
               BBInAndOut out(bb);
               output.push_back(out);
            }

            //Now go through a while loop to generate ins and outs.
            bool change = true;
            while (change) {
                //Set this to false for now, change if changes are made.
                change = false;

                //Abusing the fact that I pushed the blocks in order. Doesn't include entry.
                for (BBGenAndKillSets sets : listOfSets) {
                    if (sets.bb == &(F.getEntryBlock())) {
                        continue;
                    }
                    std::set<StoreInst *> new_in;
                    std::set<StoreInst *> new_out;

                    //First get out the in and out for this basic block.
                    BBInAndOut myout = NULL;
                    for (BBInAndOut out : output) {
                        if (out.bb == sets.bb)
                            myout = out;
                    }

                    //Go through predecessors and get new In
                    for (pred_iterator pi = pred_begin(sets.bb); pi != pred_end(sets.bb); pi++) {
                        BasicBlock *pred = *pi;
                        for (BBInAndOut pred_out : output) {
                            if (pred_out.bb == pred) {
                                for (StoreInst * inst  : pred_out.out) {
                                    new_in.insert(inst);
                                }
                            }
                        }
                    }

                    //Early check on ins, if they don't change, outs can't.
                    if (new_in == myout.in) continue;

                    //Now get new Out from gen set union (IN - Kill)
                    for (StoreInst *inst : sets.gen) {
                        new_out.insert(inst);
                    }
                    for (StoreInst *inst : myout.in) {
                        if (sets.kill.find(inst) == sets.kill.end()) {
                            new_out.insert(inst);
                        }
                    }

                    //Now Check for Changes
                    myout.in.swap(new_in);
                    if (new_out != myout.out) {
                        change = true;
                        errs() << "Size of old" << myout.out.size() << " Size of New" << new_out.size() << '\n';
                        myout.out.swap(new_out);
                    }

                }
            }

            return false;
        }

        BBGenAndKillSets createBBGenAndKillSets(Function &F, BasicBlock *f_it) {
            BBGenAndKillSets bbSets(f_it);
            for (BasicBlock::iterator bb_it = f_it->begin(); bb_it != f_it->end(); bb_it++) {
                if (StoreInst *inst = dyn_cast<StoreInst>(bb_it)) {
                    Value *var = inst->getPointerOperand();
                    GenAndKillSets sets;
                    sets.gen.insert(inst);
                    for (Function::iterator f2_it = F.begin(); f2_it != F.end(); ++f2_it) {
                        for (BasicBlock::iterator bb2_it = f2_it->begin();
                                bb2_it != f2_it->end(); bb2_it++) {
                            if (bb2_it == bb_it) {
                                continue;
                            }

                            if (StoreInst *inst2 = dyn_cast<StoreInst>(bb2_it)) {
                                if (inst2->getPointerOperand() == var) {
                                    sets.kill.insert(inst2);
                                }
                            }
                        }
                    }
                    for (std::set<StoreInst *>::iterator gen = sets.gen.begin(); gen != sets.gen.end(); gen++) {
                        bbSets.gen.insert(*gen);
                    }
                    for (std::set<StoreInst *>::iterator kill = sets.kill.begin(); kill != sets.kill.end(); kill++) {
                        bbSets.kill.insert(*kill);
                    }
                }
            }
            return bbSets;
        }

    };

    char NaivePass::ID = 0;
    static RegisterPass<NaivePass> X("naive-reaching", "Naive Reaching Analysis", false, false);
}
<|endoftext|>


<commit_before>//===-- safestack.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the runtime support for the safe stack protection
// mechanism. The runtime manages allocation/deallocation of the unsafe stack
// for the main thread, as well as all pthreads that are created/destroyed
// during program execution.
//
//===----------------------------------------------------------------------===//

#include <limits.h>
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/types.h>
#if !defined(__NetBSD__)
#include <sys/user.h>
#endif

#include "interception/interception.h"
#include "sanitizer_common/sanitizer_common.h"

// TODO: The runtime library does not currently protect the safe stack beyond
// relying on the system-enforced ASLR. The protection of the (safe) stack can
// be provided by three alternative features:
//
// 1) Protection via hardware segmentation on x86-32 and some x86-64
// architectures: the (safe) stack segment (implicitly accessed via the %ss
// segment register) can be separated from the data segment (implicitly
// accessed via the %ds segment register). Dereferencing a pointer to the safe
// segment would result in a segmentation fault.
//
// 2) Protection via software fault isolation: memory writes that are not meant
// to access the safe stack can be prevented from doing so through runtime
// instrumentation. One way to do it is to allocate the safe stack(s) in the
// upper half of the userspace and bitmask the corresponding upper bit of the
// memory addresses of memory writes that are not meant to access the safe
// stack.
//
// 3) Protection via information hiding on 64 bit architectures: the location
// of the safe stack(s) can be randomized through secure mechanisms, and the
// leakage of the stack pointer can be prevented. Currently, libc can leak the
// stack pointer in several ways (e.g. in longjmp, signal handling, user-level
// context switching related functions, etc.). These can be fixed in libc and
// in other low-level libraries, by either eliminating the escaping/dumping of
// the stack pointer (i.e., %rsp) when that's possible, or by using
// encryption/PTR_MANGLE (XOR-ing the dumped stack pointer with another secret
// we control and protect better, as is already done for setjmp in glibc.)
// Furthermore, a static machine code level verifier can be ran after code
// generation to make sure that the stack pointer is never written to memory,
// or if it is, its written on the safe stack.
//
// Finally, while the Unsafe Stack pointer is currently stored in a thread
// local variable, with libc support it could be stored in the TCB (thread
// control block) as well, eliminating another level of indirection and making
// such accesses faster. Alternatively, dedicating a separate register for
// storing it would also be possible.

/// Minimum stack alignment for the unsafe stack.
const unsigned kStackAlign = 16;

/// Default size of the unsafe stack. This value is only used if the stack
/// size rlimit is set to infinity.
const unsigned kDefaultUnsafeStackSize = 0x2800000;

/// Runtime page size obtained through sysconf
static unsigned pageSize;

// TODO: To make accessing the unsafe stack pointer faster, we plan to
// eventually store it directly in the thread control block data structure on
// platforms where this structure is pointed to by %fs or %gs. This is exactly
// the same mechanism as currently being used by the traditional stack
// protector pass to store the stack guard (see getStackCookieLocation()
// function above). Doing so requires changing the tcbhead_t struct in glibc
// on Linux and tcb struct in libc on FreeBSD.
//
// For now, store it in a thread-local variable.
extern "C" {
__attribute__((visibility(
    "default"))) __thread void *__safestack_unsafe_stack_ptr = nullptr;
}

// Per-thread unsafe stack information. It's not frequently accessed, so there
// it can be kept out of the tcb in normal thread-local variables.
static __thread void *unsafe_stack_start = nullptr;
static __thread size_t unsafe_stack_size = 0;
static __thread size_t unsafe_stack_guard = 0;

using namespace __sanitizer;

static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
  CHECK_GE(size + guard, size);
  void *addr = MmapOrDie(size + guard, "unsafe_stack_alloc");
  MprotectNoAccess((uptr)addr, (uptr)guard);
  return (char *)addr + guard;
}

static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
  CHECK_GE((char *)start + size, (char *)start);
  CHECK_GE((char *)start + guard, (char *)start);
  void *stack_ptr = (char *)start + size;
  CHECK_EQ((((size_t)stack_ptr) & (kStackAlign - 1)), 0);

  __safestack_unsafe_stack_ptr = stack_ptr;
  unsafe_stack_start = start;
  unsafe_stack_size = size;
  unsafe_stack_guard = guard;
}

static void unsafe_stack_free() {
  if (unsafe_stack_start) {
    UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
               unsafe_stack_size + unsafe_stack_guard);
  }
  unsafe_stack_start = nullptr;
}

/// Thread data for the cleanup handler
static pthread_key_t thread_cleanup_key;

/// Safe stack per-thread information passed to the thread_start function
struct tinfo {
  void *(*start_routine)(void *);
  void *start_routine_arg;

  void *unsafe_stack_start;
  size_t unsafe_stack_size;
  size_t unsafe_stack_guard;
};

/// Wrap the thread function in order to deallocate the unsafe stack when the
/// thread terminates by returning from its main function.
static void *thread_start(void *arg) {
  struct tinfo *tinfo = (struct tinfo *)arg;

  void *(*start_routine)(void *) = tinfo->start_routine;
  void *start_routine_arg = tinfo->start_routine_arg;

  // Setup the unsafe stack; this will destroy tinfo content
  unsafe_stack_setup(tinfo->unsafe_stack_start, tinfo->unsafe_stack_size,
                     tinfo->unsafe_stack_guard);

  // Make sure out thread-specific destructor will be called
  // FIXME: we can do this only any other specific key is set by
  // intercepting the pthread_setspecific function itself
  pthread_setspecific(thread_cleanup_key, (void *)1);

  return start_routine(start_routine_arg);
}

/// Thread-specific data destructor
static void thread_cleanup_handler(void *_iter) {
  // We want to free the unsafe stack only after all other destructors
  // have already run. We force this function to be called multiple times.
  // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
  // times might still end up executing after the unsafe stack is deallocated.
  size_t iter = (size_t)_iter;
  if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
    pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
  } else {
    // This is the last iteration
    unsafe_stack_free();
  }
}

static void EnsureInterceptorsInitialized();

/// Intercept thread creation operation to allocate and setup the unsafe stack
INTERCEPTOR(int, pthread_create, pthread_t *thread,
            const pthread_attr_t *attr,
            void *(*start_routine)(void*), void *arg) {
  EnsureInterceptorsInitialized();
  size_t size = 0;
  size_t guard = 0;

  if (attr) {
    pthread_attr_getstacksize(attr, &size);
    pthread_attr_getguardsize(attr, &guard);
  } else {
    // get pthread default stack size
    pthread_attr_t tmpattr;
    pthread_attr_init(&tmpattr);
    pthread_attr_getstacksize(&tmpattr, &size);
    pthread_attr_getguardsize(&tmpattr, &guard);
    pthread_attr_destroy(&tmpattr);
  }

  CHECK_NE(size, 0);
  CHECK_EQ((size & (kStackAlign - 1)), 0);
  CHECK_EQ((guard & (pageSize - 1)), 0);

  void *addr = unsafe_stack_alloc(size, guard);
  struct tinfo *tinfo =
      (struct tinfo *)(((char *)addr) + size - sizeof(struct tinfo));
  tinfo->start_routine = start_routine;
  tinfo->start_routine_arg = arg;
  tinfo->unsafe_stack_start = addr;
  tinfo->unsafe_stack_size = size;
  tinfo->unsafe_stack_guard = guard;

  return REAL(pthread_create)(thread, attr, thread_start, tinfo);
}

static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED);
static bool interceptors_inited = false;

static void EnsureInterceptorsInitialized() {
  BlockingMutexLock lock(&interceptor_init_lock);
  if (interceptors_inited) return;

  // Initialize pthread interceptors for thread allocation
  INTERCEPT_FUNCTION(pthread_create);

  interceptors_inited = true;
}

extern "C" __attribute__((visibility("default")))
#if !SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, the constructor is invoked using .preinit_array (see below)
__attribute__((constructor(0)))
#endif
void __safestack_init() {
  // Determine the stack size for the main thread.
  size_t size = kDefaultUnsafeStackSize;
  size_t guard = 4096;

  struct rlimit limit;
  if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
    size = limit.rlim_cur;

  // Allocate unsafe stack for main thread
  void *addr = unsafe_stack_alloc(size, guard);

  unsafe_stack_setup(addr, size, guard);
  pageSize = sysconf(_SC_PAGESIZE);

  // Setup the cleanup handler
  pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
}

#if SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, run safestack initialization before any other constructors.
// On other platforms we use the constructor attribute to arrange to run our
// initialization early.
extern "C" {
__attribute__((section(".preinit_array"),
               used)) void (*__safestack_preinit)(void) = __safestack_init;
}
#endif

extern "C"
    __attribute__((visibility("default"))) void *__get_unsafe_stack_start() {
  return unsafe_stack_start;
}

extern "C"
    __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
  return __safestack_unsafe_stack_ptr;
}
<commit_msg>SafeStack: Add builtins to read unsafe stack top/bottom<commit_after>//===-- safestack.cc ------------------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the runtime support for the safe stack protection
// mechanism. The runtime manages allocation/deallocation of the unsafe stack
// for the main thread, as well as all pthreads that are created/destroyed
// during program execution.
//
//===----------------------------------------------------------------------===//

#include <limits.h>
#include <pthread.h>
#include <stddef.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/types.h>
#if !defined(__NetBSD__)
#include <sys/user.h>
#endif

#include "interception/interception.h"
#include "sanitizer_common/sanitizer_common.h"

// TODO: The runtime library does not currently protect the safe stack beyond
// relying on the system-enforced ASLR. The protection of the (safe) stack can
// be provided by three alternative features:
//
// 1) Protection via hardware segmentation on x86-32 and some x86-64
// architectures: the (safe) stack segment (implicitly accessed via the %ss
// segment register) can be separated from the data segment (implicitly
// accessed via the %ds segment register). Dereferencing a pointer to the safe
// segment would result in a segmentation fault.
//
// 2) Protection via software fault isolation: memory writes that are not meant
// to access the safe stack can be prevented from doing so through runtime
// instrumentation. One way to do it is to allocate the safe stack(s) in the
// upper half of the userspace and bitmask the corresponding upper bit of the
// memory addresses of memory writes that are not meant to access the safe
// stack.
//
// 3) Protection via information hiding on 64 bit architectures: the location
// of the safe stack(s) can be randomized through secure mechanisms, and the
// leakage of the stack pointer can be prevented. Currently, libc can leak the
// stack pointer in several ways (e.g. in longjmp, signal handling, user-level
// context switching related functions, etc.). These can be fixed in libc and
// in other low-level libraries, by either eliminating the escaping/dumping of
// the stack pointer (i.e., %rsp) when that's possible, or by using
// encryption/PTR_MANGLE (XOR-ing the dumped stack pointer with another secret
// we control and protect better, as is already done for setjmp in glibc.)
// Furthermore, a static machine code level verifier can be ran after code
// generation to make sure that the stack pointer is never written to memory,
// or if it is, its written on the safe stack.
//
// Finally, while the Unsafe Stack pointer is currently stored in a thread
// local variable, with libc support it could be stored in the TCB (thread
// control block) as well, eliminating another level of indirection and making
// such accesses faster. Alternatively, dedicating a separate register for
// storing it would also be possible.

/// Minimum stack alignment for the unsafe stack.
const unsigned kStackAlign = 16;

/// Default size of the unsafe stack. This value is only used if the stack
/// size rlimit is set to infinity.
const unsigned kDefaultUnsafeStackSize = 0x2800000;

/// Runtime page size obtained through sysconf
static unsigned pageSize;

// TODO: To make accessing the unsafe stack pointer faster, we plan to
// eventually store it directly in the thread control block data structure on
// platforms where this structure is pointed to by %fs or %gs. This is exactly
// the same mechanism as currently being used by the traditional stack
// protector pass to store the stack guard (see getStackCookieLocation()
// function above). Doing so requires changing the tcbhead_t struct in glibc
// on Linux and tcb struct in libc on FreeBSD.
//
// For now, store it in a thread-local variable.
extern "C" {
__attribute__((visibility(
    "default"))) __thread void *__safestack_unsafe_stack_ptr = nullptr;
}

// Per-thread unsafe stack information. It's not frequently accessed, so there
// it can be kept out of the tcb in normal thread-local variables.
static __thread void *unsafe_stack_start = nullptr;
static __thread size_t unsafe_stack_size = 0;
static __thread size_t unsafe_stack_guard = 0;

using namespace __sanitizer;

static inline void *unsafe_stack_alloc(size_t size, size_t guard) {
  CHECK_GE(size + guard, size);
  void *addr = MmapOrDie(size + guard, "unsafe_stack_alloc");
  MprotectNoAccess((uptr)addr, (uptr)guard);
  return (char *)addr + guard;
}

static inline void unsafe_stack_setup(void *start, size_t size, size_t guard) {
  CHECK_GE((char *)start + size, (char *)start);
  CHECK_GE((char *)start + guard, (char *)start);
  void *stack_ptr = (char *)start + size;
  CHECK_EQ((((size_t)stack_ptr) & (kStackAlign - 1)), 0);

  __safestack_unsafe_stack_ptr = stack_ptr;
  unsafe_stack_start = start;
  unsafe_stack_size = size;
  unsafe_stack_guard = guard;
}

static void unsafe_stack_free() {
  if (unsafe_stack_start) {
    UnmapOrDie((char *)unsafe_stack_start - unsafe_stack_guard,
               unsafe_stack_size + unsafe_stack_guard);
  }
  unsafe_stack_start = nullptr;
}

/// Thread data for the cleanup handler
static pthread_key_t thread_cleanup_key;

/// Safe stack per-thread information passed to the thread_start function
struct tinfo {
  void *(*start_routine)(void *);
  void *start_routine_arg;

  void *unsafe_stack_start;
  size_t unsafe_stack_size;
  size_t unsafe_stack_guard;
};

/// Wrap the thread function in order to deallocate the unsafe stack when the
/// thread terminates by returning from its main function.
static void *thread_start(void *arg) {
  struct tinfo *tinfo = (struct tinfo *)arg;

  void *(*start_routine)(void *) = tinfo->start_routine;
  void *start_routine_arg = tinfo->start_routine_arg;

  // Setup the unsafe stack; this will destroy tinfo content
  unsafe_stack_setup(tinfo->unsafe_stack_start, tinfo->unsafe_stack_size,
                     tinfo->unsafe_stack_guard);

  // Make sure out thread-specific destructor will be called
  // FIXME: we can do this only any other specific key is set by
  // intercepting the pthread_setspecific function itself
  pthread_setspecific(thread_cleanup_key, (void *)1);

  return start_routine(start_routine_arg);
}

/// Thread-specific data destructor
static void thread_cleanup_handler(void *_iter) {
  // We want to free the unsafe stack only after all other destructors
  // have already run. We force this function to be called multiple times.
  // User destructors that might run more then PTHREAD_DESTRUCTOR_ITERATIONS-1
  // times might still end up executing after the unsafe stack is deallocated.
  size_t iter = (size_t)_iter;
  if (iter < PTHREAD_DESTRUCTOR_ITERATIONS) {
    pthread_setspecific(thread_cleanup_key, (void *)(iter + 1));
  } else {
    // This is the last iteration
    unsafe_stack_free();
  }
}

static void EnsureInterceptorsInitialized();

/// Intercept thread creation operation to allocate and setup the unsafe stack
INTERCEPTOR(int, pthread_create, pthread_t *thread,
            const pthread_attr_t *attr,
            void *(*start_routine)(void*), void *arg) {
  EnsureInterceptorsInitialized();
  size_t size = 0;
  size_t guard = 0;

  if (attr) {
    pthread_attr_getstacksize(attr, &size);
    pthread_attr_getguardsize(attr, &guard);
  } else {
    // get pthread default stack size
    pthread_attr_t tmpattr;
    pthread_attr_init(&tmpattr);
    pthread_attr_getstacksize(&tmpattr, &size);
    pthread_attr_getguardsize(&tmpattr, &guard);
    pthread_attr_destroy(&tmpattr);
  }

  CHECK_NE(size, 0);
  CHECK_EQ((size & (kStackAlign - 1)), 0);
  CHECK_EQ((guard & (pageSize - 1)), 0);

  void *addr = unsafe_stack_alloc(size, guard);
  struct tinfo *tinfo =
      (struct tinfo *)(((char *)addr) + size - sizeof(struct tinfo));
  tinfo->start_routine = start_routine;
  tinfo->start_routine_arg = arg;
  tinfo->unsafe_stack_start = addr;
  tinfo->unsafe_stack_size = size;
  tinfo->unsafe_stack_guard = guard;

  return REAL(pthread_create)(thread, attr, thread_start, tinfo);
}

static BlockingMutex interceptor_init_lock(LINKER_INITIALIZED);
static bool interceptors_inited = false;

static void EnsureInterceptorsInitialized() {
  BlockingMutexLock lock(&interceptor_init_lock);
  if (interceptors_inited) return;

  // Initialize pthread interceptors for thread allocation
  INTERCEPT_FUNCTION(pthread_create);

  interceptors_inited = true;
}

extern "C" __attribute__((visibility("default")))
#if !SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, the constructor is invoked using .preinit_array (see below)
__attribute__((constructor(0)))
#endif
void __safestack_init() {
  // Determine the stack size for the main thread.
  size_t size = kDefaultUnsafeStackSize;
  size_t guard = 4096;

  struct rlimit limit;
  if (getrlimit(RLIMIT_STACK, &limit) == 0 && limit.rlim_cur != RLIM_INFINITY)
    size = limit.rlim_cur;

  // Allocate unsafe stack for main thread
  void *addr = unsafe_stack_alloc(size, guard);

  unsafe_stack_setup(addr, size, guard);
  pageSize = sysconf(_SC_PAGESIZE);

  // Setup the cleanup handler
  pthread_key_create(&thread_cleanup_key, thread_cleanup_handler);
}

#if SANITIZER_CAN_USE_PREINIT_ARRAY
// On ELF platforms, run safestack initialization before any other constructors.
// On other platforms we use the constructor attribute to arrange to run our
// initialization early.
extern "C" {
__attribute__((section(".preinit_array"),
               used)) void (*__safestack_preinit)(void) = __safestack_init;
}
#endif

extern "C"
    __attribute__((visibility("default"))) void *__get_unsafe_stack_bottom() {
  return unsafe_stack_start;
}

extern "C"
    __attribute__((visibility("default"))) void *__get_unsafe_stack_top() {
  return (char*)unsafe_stack_start + unsafe_stack_size;
}

extern "C"
    __attribute__((visibility("default"), alias("__get_unsafe_stack_bottom")))
    void *__get_unsafe_stack_start();

extern "C"
    __attribute__((visibility("default"))) void *__get_unsafe_stack_ptr() {
  return __safestack_unsafe_stack_ptr;
}
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QFrame>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QModelIndexList>
#include <QVBoxLayout>

#include <nitroshare/application.h>
#include <nitroshare/transfer.h>
#include <nitroshare/transfermodel.h>

#include "transferdialog.h"

TransferDialog::TransferDialog(Application *application)
    : mApplication(application),
      mTableView(new QTableView),
      mStopButton(new QPushButton(tr("Stop"))),
      mDismissButton(new QPushButton(tr("Dismiss")))
{
    setWindowTitle(tr("Transfers"));
    resize(800, 300);

    mModel.setSourceModel(mApplication->transferModel());

    mTableView->setModel(&mModel);
    mTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    mTableView->horizontalHeader()->setStretchLastSection(true);
    mTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    mTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    mTableView->verticalHeader()->setVisible(false);

    connect(&mModel, &TransferProxyModel::dataChanged, this, &TransferDialog::updateButtons);
    connect(&mModel, &TransferProxyModel::rowsRemoved, this, &TransferDialog::updateButtons);
    connect(mTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TransferDialog::updateButtons);

    connect(mStopButton, &QPushButton::clicked, this, &TransferDialog::onStop);
    connect(mDismissButton, &QPushButton::clicked, this, &TransferDialog::onDismiss);

    QPushButton *dismissAllButton = new QPushButton(tr("Dismiss All"));
    connect(dismissAllButton, &QPushButton::clicked, this, &TransferDialog::onDismissAll);

    QFrame *frame = new QFrame;
    frame->setFrameShape(QFrame::HLine);
    frame->setFrameShadow(QFrame::Sunken);

    QPushButton *openReceivedButton = new QPushButton(tr("Show Received Files"));
    connect(openReceivedButton, &QPushButton::clicked, this, &TransferDialog::onOpenReceivedFiles);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(mStopButton);
    vboxLayout->addWidget(mDismissButton);
    vboxLayout->addWidget(dismissAllButton);
    vboxLayout->addWidget(frame);
    vboxLayout->addWidget(openReceivedButton);
    vboxLayout->addStretch(1);

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(mTableView);
    hboxLayout->addLayout(vboxLayout);
    setLayout(hboxLayout);

    // Update the initial state of the buttons
    updateButtons();
}

void TransferDialog::updateButtons()
{
    QModelIndex index = currentIndex();

    Transfer *transfer = nullptr;
    if (index.isValid()) {
        transfer = index.data(Qt::UserRole).value<Transfer*>();
    }

    mStopButton->setEnabled(transfer && !transfer->isFinished());
    mDismissButton->setEnabled(transfer && transfer->isFinished());
}

void TransferDialog::onStop()
{
    QModelIndex index = currentIndex();
    if (index.isValid()) {
        index.data(Qt::UserRole).value<Transfer*>()->cancel();
        mTableView->selectionModel()->clear();
    }
}

void TransferDialog::onDismiss()
{
    QModelIndex index = currentIndex();
    if (index.isValid()) {
        mApplication->transferModel()->dismiss(index.row());
    }
}

void TransferDialog::onDismissAll()
{
    mApplication->transferModel()->dismissAll();
}

void TransferDialog::onOpenReceivedFiles()
{
    //...
}

QModelIndex TransferDialog::currentIndex() const
{
    QModelIndexList selection = mTableView->selectionModel()->selectedIndexes();
    return selection.size() ? selection.at(0) : QModelIndex();
}
<commit_msg>Implement button that displays transfer directory (fixes #140).<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Nathan Osman
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include <QDesktopServices>
#include <QFrame>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QModelIndexList>
#include <QUrl>
#include <QVBoxLayout>

#include <nitroshare/application.h>
#include <nitroshare/settingsregistry.h>
#include <nitroshare/transfer.h>
#include <nitroshare/transfermodel.h>

#include "transferdialog.h"

const QString TransferDirectory = "TransferDirectory";

TransferDialog::TransferDialog(Application *application)
    : mApplication(application),
      mTableView(new QTableView),
      mStopButton(new QPushButton(tr("Stop"))),
      mDismissButton(new QPushButton(tr("Dismiss")))
{
    setWindowTitle(tr("Transfers"));
    resize(800, 300);

    mModel.setSourceModel(mApplication->transferModel());

    mTableView->setModel(&mModel);
    mTableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
    mTableView->horizontalHeader()->setStretchLastSection(true);
    mTableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    mTableView->setSelectionMode(QAbstractItemView::SingleSelection);
    mTableView->verticalHeader()->setVisible(false);

    connect(&mModel, &TransferProxyModel::dataChanged, this, &TransferDialog::updateButtons);
    connect(&mModel, &TransferProxyModel::rowsRemoved, this, &TransferDialog::updateButtons);
    connect(mTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &TransferDialog::updateButtons);

    connect(mStopButton, &QPushButton::clicked, this, &TransferDialog::onStop);
    connect(mDismissButton, &QPushButton::clicked, this, &TransferDialog::onDismiss);

    QPushButton *dismissAllButton = new QPushButton(tr("Dismiss All"));
    connect(dismissAllButton, &QPushButton::clicked, this, &TransferDialog::onDismissAll);

    QFrame *frame = new QFrame;
    frame->setFrameShape(QFrame::HLine);
    frame->setFrameShadow(QFrame::Sunken);

    QPushButton *openReceivedButton = new QPushButton(tr("Show Received Files"));
    connect(openReceivedButton, &QPushButton::clicked, this, &TransferDialog::onOpenReceivedFiles);

    QVBoxLayout *vboxLayout = new QVBoxLayout;
    vboxLayout->addWidget(mStopButton);
    vboxLayout->addWidget(mDismissButton);
    vboxLayout->addWidget(dismissAllButton);
    vboxLayout->addWidget(frame);
    vboxLayout->addWidget(openReceivedButton);
    vboxLayout->addStretch(1);

    QHBoxLayout *hboxLayout = new QHBoxLayout;
    hboxLayout->addWidget(mTableView);
    hboxLayout->addLayout(vboxLayout);
    setLayout(hboxLayout);

    // Update the initial state of the buttons
    updateButtons();
}

void TransferDialog::updateButtons()
{
    QModelIndex index = currentIndex();

    Transfer *transfer = nullptr;
    if (index.isValid()) {
        transfer = index.data(Qt::UserRole).value<Transfer*>();
    }

    mStopButton->setEnabled(transfer && !transfer->isFinished());
    mDismissButton->setEnabled(transfer && transfer->isFinished());
}

void TransferDialog::onStop()
{
    QModelIndex index = currentIndex();
    if (index.isValid()) {
        index.data(Qt::UserRole).value<Transfer*>()->cancel();
        mTableView->selectionModel()->clear();
    }
}

void TransferDialog::onDismiss()
{
    QModelIndex index = currentIndex();
    if (index.isValid()) {
        mApplication->transferModel()->dismiss(index.row());
    }
}

void TransferDialog::onDismissAll()
{
    mApplication->transferModel()->dismissAll();
}

void TransferDialog::onOpenReceivedFiles()
{
    QDesktopServices::openUrl(QUrl::fromLocalFile(
        mApplication->settingsRegistry()->value(TransferDirectory).toString()
    ));
}

QModelIndex TransferDialog::currentIndex() const
{
    QModelIndexList selection = mTableView->selectionModel()->selectedIndexes();
    return selection.size() ? selection.at(0) : QModelIndex();
}
<|endoftext|>


<commit_before>// Copyright (c) 2008-2010, Andrew Walker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "dubins.h"
#include <cmath>
#include <cassert>
#include <iostream>

#define LSL (0)
#define LSR (1)
#define RSL (2)
#define RSR (3)
#define RLR (4)
#define LRL (5)

#define L_SEG (0)
#define S_SEG (1)
#define R_SEG (2)

const int DIRDATA[][3] = {
    { L_SEG, S_SEG, L_SEG },
    { L_SEG, S_SEG, R_SEG },
    { R_SEG, S_SEG, L_SEG },
    { R_SEG, S_SEG, R_SEG },
    { R_SEG, L_SEG, R_SEG },
    { L_SEG, R_SEG, L_SEG }
};

#define UNPACK_INPUTS(alpha, beta)       \
    double sa = ::sin(alpha);            \
    double sb = ::sin(beta);             \
    double ca = ::cos(alpha);            \
    double cb = ::cos(beta);             \
    double c_ab = ::cos(alpha - beta);   \

#define PACK_OUTPUTS(outputs)       \
    outputs[0]  = t;                \
    outputs[1]  = p;                \
    outputs[2]  = q;

double fmodr( double x, double y)
{
    return x - y*::floor(x/y);
}

double normaliseAngle( double theta )
{
    return fmodr( theta, 2 * M_PI );
}
int dubins_init( double q0[3], double q1[3], double r, DubinsPath* path )
{
    double dx = q1[0] - q0[0];
    double dy = q1[1] - q0[1];
    double d = ::sqrt( dx * dx + dy * dy );
    double theta = normaliseAngle(::atan2( dy, dx ));
    double alpha = normaliseAngle(q0[2] - theta);
    double beta  = normaliseAngle(q1[2] - theta);
    for( int i = 0; i < 3; i ++ ) {
        path->qi[i] = q0[i];
    }
    return dubins_init_normalised( alpha, beta, d, path );
}

void dubins_LSL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp0 = d+sa-sb;
    double tmp2 = 2 + (d*d) -(2*c_ab) + (2*d*(sa - sb));
    if( tmp2 >= 0 && tmp0 >= 0) {
        double tmp1 = atan( (cb-ca)/tmp0 );
        double t = normaliseAngle(-alpha + tmp1 );
        double p = sqrt( tmp2 );
        double q = normaliseAngle(beta -   tmp1 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RSR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp0 = d-sa+sb;
    double tmp2 = 2 + (d*d) -(2*c_ab) + (2*d*(sb-sa));
    if( tmp2 >= 0 && tmp0 >= 0) {
        double tmp1 = atan( (ca-cb)/tmp0 );
        double t = normaliseAngle( alpha - tmp1 );
        double p = sqrt( tmp2 );
        double q = normaliseAngle( -beta + tmp1 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_LSR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp1 = -2 + (d*d) + (2*c_ab) + (2*d*(sa+sb));
    if( tmp1 >= 0 ) {
        double p    = ::sqrt( tmp1 );
        double tmp2 = ::atan( (-ca-cb)/(d+sa+sb) ) - ::atan(-2.0/p);
        double t    = normaliseAngle(-alpha + tmp2);
        double q    = normaliseAngle( -normaliseAngle(beta) + tmp2 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RSL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp1 = (d*d) -2 + (2*c_ab) - (2*d*(sa+sb));
    if( tmp1 > 0 ) {
        double p    = ::sqrt( tmp1 );
        double tmp2 = ::atan( (ca+cb)/(d-sa-sb) ) - ::atan(2.0/p);
        double t    = normaliseAngle(alpha - tmp2);
        double q    = normaliseAngle(beta - tmp2);
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RLR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp_rlr = (6. - d*d + 2*c_ab + 2*d*(sa-sb)) / 8.;
    if( ::fabs(tmp_rlr) < 1) {
        double p = ::acos( tmp_rlr );
        double t = normaliseAngle(alpha - ::atan2( ca-cb, d-sa+sb ) + normaliseAngle(p/2.));
        double q = normaliseAngle(alpha - beta - t + normaliseAngle(p));
        PACK_OUTPUTS( outputs );
    }
}

void dubins_LRL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp_lrl = (6. - d*d + 2*c_ab + 2*d*(- sa + sb)) / 8.;

    if( ::fabs(tmp_lrl) < 1) {
        double p = normaliseAngle(::acos(tmp_lrl));
        double t = normaliseAngle(-alpha - ::atan2( ca-cb, d+sa-sb ) + p/2.);
        double q = normaliseAngle(normaliseAngle(beta) - alpha -t + normaliseAngle(p));
        PACK_OUTPUTS( outputs );
    }

}

int dubins_init_normalised( double alpha,
                            double beta,
                            double d,
                            DubinsPath* path)
{

    // Take the precaution of initialising all results
    double results[6][4];
    for( int i = 0; i < 6; i++ ) {
        results[i][0] = INFINITY;
        results[i][1] = INFINITY;
        results[i][2] = INFINITY;
    }

    // For each trajectory class, find the solution
    dubins_LSL( alpha, beta, d, results[LSL] );
    dubins_LSR( alpha, beta, d, results[LSR] );
    dubins_RSL( alpha, beta, d, results[RSL] );
    dubins_RSR( alpha, beta, d, results[RSR] );
    dubins_RLR( alpha, beta, d, results[RLR] );
    dubins_LRL( alpha, beta, d, results[LRL] );

    // Generate the total costs for each trajectory class
    for(int i = 0; i < 6; i++)
    {
        results[i][3] = 0;
        for(int j = 0; j < 3; j++) {
            assert( results[i][j] >= 0. );
            results[i][3] += results[i][j];
        }
    }

    // Extract the best cost path
    int bestType = 0;
    double minCost = results[0][3];
    for(int i = 1; i < 6; i++)
    {
        //std::cout << i << " " << results[i][3] << std::endl;
        if( results[i][3] < minCost ) {
            minCost = results[i][3];
            bestType = i;
        }
    }
    //std::cout << "best = " << bestType << std::endl;

    // Copy the results into the output structure
    path->type = bestType;
    for(int i = 0; i < 3; i++)
    {
        path->param[i] = results[bestType][i];
    }
    return 0;
}

double dubins_path_length( DubinsPath* path )
{
    double length = 0.;
    length += path->param[0];
    length += path->param[1];
    length += path->param[2];
    return length;
}

void dubins_segment( double t, double qi[3], double qt[3], int type)
{
    assert( type == L_SEG || type == S_SEG || type == R_SEG );
    if( type == L_SEG )
    {
        qt[0] = qi[0] + ::sin(qi[2]+t) - ::sin(qi[2]);
        qt[1] = qi[1] - ::cos(qi[2]+t) + ::cos(qi[2]);
        qt[2] = qi[2] + t;
    }
    else if( type == R_SEG )
    {
        qt[0] = qi[0] - ::sin(qi[2]-t) + ::sin(qi[2]);
        qt[1] = qi[1] + ::cos(qi[2]-t) - ::cos(qi[2]);
        qt[2] = qi[2] - t;
    }
    else // type == S_SEG
    {
        qt[0] = qi[0] + ::cos(qi[2]) * t;
        qt[1] = qi[1] + ::sin(qi[2]) * t;
        qt[2] = qi[2];
    }
}

int dubins_path_sample( DubinsPath* path, double t, double q[3] )
{
    if( t < 0 || t >= dubins_path_length(path) ) {
        return 1;
    }
    const int* types = DIRDATA[path->type];
    double p1 = path->param[0];
    double p2 = path->param[1];
    double q1[3]; // end-of segment 1
    double q2[3]; // end-of segment 2
    dubins_segment( p1,      path->qi,  q1, types[0] );
    dubins_segment( p2,      q1,        q2, types[1] );
    if( t < p1 ) {
        dubins_segment( t, path->qi, q, types[0] );
    }
    else if( t < (p1+p2) ) {
        dubins_segment( t-p1, q1,        q,  types[1] );
    }
    else {
        dubins_segment( t-p1-p2, q2,        q,  types[2] );
    }
    q[2] = normaliseAngle(q[2]);
    return 0;
}

int dubins_path_sample_many( DubinsPath* path, DubinsPathSamplingCallback cb, double stepSize )
{
    // TODO - this implementation could be optimised by caching
    //        some of the calculations from dubins_path_sample

    double x = 0.0;
    double length = dubins_path_length(path);
    while( x <  length ) {
        double q[3];
        dubins_path_sample( path, x, q );
        int retcode = cb(q, x);
        if( retcode != 0 ) {
            return retcode;
        }
        x += stepSize;
    }
    return 0;
}

<commit_msg>renamed normaliseAngle to mod2pi to be closer to existing conventions<commit_after>// Copyright (c) 2008-2010, Andrew Walker
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "dubins.h"
#include <cmath>
#include <cassert>
#include <iostream>

#define LSL (0)
#define LSR (1)
#define RSL (2)
#define RSR (3)
#define RLR (4)
#define LRL (5)

#define L_SEG (0)
#define S_SEG (1)
#define R_SEG (2)

const int DIRDATA[][3] = {
    { L_SEG, S_SEG, L_SEG },
    { L_SEG, S_SEG, R_SEG },
    { R_SEG, S_SEG, L_SEG },
    { R_SEG, S_SEG, R_SEG },
    { R_SEG, L_SEG, R_SEG },
    { L_SEG, R_SEG, L_SEG }
};

#define UNPACK_INPUTS(alpha, beta)       \
    double sa = ::sin(alpha);            \
    double sb = ::sin(beta);             \
    double ca = ::cos(alpha);            \
    double cb = ::cos(beta);             \
    double c_ab = ::cos(alpha - beta);   \

#define PACK_OUTPUTS(outputs)       \
    outputs[0]  = t;                \
    outputs[1]  = p;                \
    outputs[2]  = q;

/**
 * Floating point modulus suitable for rings
 *
 * fmod doesn't behave correctly for angular quantities, this function does
 */
double fmodr( double x, double y)
{
    return x - y*::floor(x/y);
}

double mod2pi( double theta )
{
    return fmodr( theta, 2 * M_PI );
}

int dubins_init( double q0[3], double q1[3], double r, DubinsPath* path )
{
    double dx = q1[0] - q0[0];
    double dy = q1[1] - q0[1];
    double d = ::sqrt( dx * dx + dy * dy );
    double theta = mod2pi(::atan2( dy, dx ));
    double alpha = mod2pi(q0[2] - theta);
    double beta  = mod2pi(q1[2] - theta);
    for( int i = 0; i < 3; i ++ ) {
        path->qi[i] = q0[i];
    }
    return dubins_init_normalised( alpha, beta, d, path );
}

void dubins_LSL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp0 = d+sa-sb;
    double tmp2 = 2 + (d*d) -(2*c_ab) + (2*d*(sa - sb));
    if( tmp2 >= 0 && tmp0 >= 0) {
        double tmp1 = atan( (cb-ca)/tmp0 );
        double t = mod2pi(-alpha + tmp1 );
        double p = sqrt( tmp2 );
        double q = mod2pi(beta -   tmp1 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RSR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp0 = d-sa+sb;
    double tmp2 = 2 + (d*d) -(2*c_ab) + (2*d*(sb-sa));
    if( tmp2 >= 0 && tmp0 >= 0) {
        double tmp1 = atan( (ca-cb)/tmp0 );
        double t = mod2pi( alpha - tmp1 );
        double p = sqrt( tmp2 );
        double q = mod2pi( -beta + tmp1 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_LSR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp1 = -2 + (d*d) + (2*c_ab) + (2*d*(sa+sb));
    if( tmp1 >= 0 ) {
        double p    = ::sqrt( tmp1 );
        double tmp2 = ::atan( (-ca-cb)/(d+sa+sb) ) - ::atan(-2.0/p);
        double t    = mod2pi(-alpha + tmp2);
        double q    = mod2pi( -mod2pi(beta) + tmp2 );
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RSL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp1 = (d*d) -2 + (2*c_ab) - (2*d*(sa+sb));
    if( tmp1 > 0 ) {
        double p    = ::sqrt( tmp1 );
        double tmp2 = ::atan( (ca+cb)/(d-sa-sb) ) - ::atan(2.0/p);
        double t    = mod2pi(alpha - tmp2);
        double q    = mod2pi(beta - tmp2);
        PACK_OUTPUTS(outputs);
    }
}

void dubins_RLR( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp_rlr = (6. - d*d + 2*c_ab + 2*d*(sa-sb)) / 8.;
    if( ::fabs(tmp_rlr) < 1) {
        double p = ::acos( tmp_rlr );
        double t = mod2pi(alpha - ::atan2( ca-cb, d-sa+sb ) + mod2pi(p/2.));
        double q = mod2pi(alpha - beta - t + mod2pi(p));
        PACK_OUTPUTS( outputs );
    }
}

void dubins_LRL( double alpha, double beta, double d, double* outputs )
{
    UNPACK_INPUTS(alpha, beta);

    double tmp_lrl = (6. - d*d + 2*c_ab + 2*d*(- sa + sb)) / 8.;

    if( ::fabs(tmp_lrl) < 1) {
        double p = mod2pi(::acos(tmp_lrl));
        double t = mod2pi(-alpha - ::atan2( ca-cb, d+sa-sb ) + p/2.);
        double q = mod2pi(mod2pi(beta) - alpha -t + mod2pi(p));
        PACK_OUTPUTS( outputs );
    }

}

int dubins_init_normalised( double alpha,
                            double beta,
                            double d,
                            DubinsPath* path)
{

    // Take the precaution of initialising all results
    double results[6][4];
    for( int i = 0; i < 6; i++ ) {
        results[i][0] = INFINITY;
        results[i][1] = INFINITY;
        results[i][2] = INFINITY;
    }

    // For each trajectory class, find the solution
    dubins_LSL( alpha, beta, d, results[LSL] );
    dubins_LSR( alpha, beta, d, results[LSR] );
    dubins_RSL( alpha, beta, d, results[RSL] );
    dubins_RSR( alpha, beta, d, results[RSR] );
    dubins_RLR( alpha, beta, d, results[RLR] );
    dubins_LRL( alpha, beta, d, results[LRL] );

    // Generate the total costs for each trajectory class
    for(int i = 0; i < 6; i++)
    {
        results[i][3] = 0;
        for(int j = 0; j < 3; j++) {
            //assert( results[i][j] >= 0. );
            std::cout << results[i][j] << " ";
            results[i][3] += results[i][j];
        }
        std::cout << std::endl;
    }

    // Extract the best cost path
    int bestType = 0;
    double minCost = results[0][3];
    for(int i = 1; i < 6; i++)
    {
        //std::cout << i << " " << results[i][3] << std::endl;
        if( results[i][3] < minCost ) {
            minCost = results[i][3];
            bestType = i;
        }
    }
    //std::cout << "best = " << bestType << std::endl;

    // Copy the results into the output structure
    path->type = bestType;
    for(int i = 0; i < 3; i++)
    {
        path->param[i] = results[bestType][i];
    }
    return 0;
}

double dubins_path_length( DubinsPath* path )
{
    double length = 0.;
    length += path->param[0];
    length += path->param[1];
    length += path->param[2];
    return length;
}

void dubins_segment( double t, double qi[3], double qt[3], int type)
{
    assert( type == L_SEG || type == S_SEG || type == R_SEG );
    if( type == L_SEG )
    {
        qt[0] = qi[0] + ::sin(qi[2]+t) - ::sin(qi[2]);
        qt[1] = qi[1] - ::cos(qi[2]+t) + ::cos(qi[2]);
        qt[2] = qi[2] + t;
    }
    else if( type == R_SEG )
    {
        qt[0] = qi[0] - ::sin(qi[2]-t) + ::sin(qi[2]);
        qt[1] = qi[1] + ::cos(qi[2]-t) - ::cos(qi[2]);
        qt[2] = qi[2] - t;
    }
    else // type == S_SEG
    {
        qt[0] = qi[0] + ::cos(qi[2]) * t;
        qt[1] = qi[1] + ::sin(qi[2]) * t;
        qt[2] = qi[2];
    }
}

int dubins_path_sample( DubinsPath* path, double t, double q[3] )
{
    if( t < 0 || t >= dubins_path_length(path) ) {
        return 1;
    }
    const int* types = DIRDATA[path->type];
    double p1 = path->param[0];
    double p2 = path->param[1];
    double q1[3]; // end-of segment 1
    double q2[3]; // end-of segment 2
    dubins_segment( p1,      path->qi,  q1, types[0] );
    dubins_segment( p2,      q1,        q2, types[1] );
    if( t < p1 ) {
        dubins_segment( t, path->qi, q, types[0] );
    }
    else if( t < (p1+p2) ) {
        dubins_segment( t-p1, q1,        q,  types[1] );
    }
    else {
        dubins_segment( t-p1-p2, q2,        q,  types[2] );
    }
    q[2] = mod2pi(q[2]);
    return 0;
}

int dubins_path_sample_many( DubinsPath* path, DubinsPathSamplingCallback cb, double stepSize )
{
    // TODO - this implementation could be optimised by caching
    //        some of the calculations from dubins_path_sample

    double x = 0.0;
    double length = dubins_path_length(path);
    while( x <  length ) {
        double q[3];
        dubins_path_sample( path, x, q );
        int retcode = cb(q, x);
        if( retcode != 0 ) {
            return retcode;
        }
        x += stepSize;
    }
    return 0;
}

<|endoftext|>


<commit_before><commit_msg>Fixed formatting errors and lint errors<commit_after><|endoftext|>