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

#include "common/common.h"
#include <assert.h>
#include <time.h>
#include <sys/timeb.h>
#ifdef UNIX
#include <sys/time.h>
#endif

#include "store/api/iterator.h"
#include "store/api/temp_seq.h"
#include "store/api/item_factory.h"
#include "store/api/store.h"
#include "store/api/index.h"
#include "store/api/ic.h"

#include "system/globalenv.h"

#include "context/dynamic_context.h"
#include "context/static_context.h"
#include "context/namespace_context.h"

#include "compiler/expression/var_expr.h"
#include "compiler/xqddf/value_index.h"
#include "compiler/parsetree/parsenodes.h"

#include "types/root_typemanager.h"

#include "runtime/api/plan_wrapper.h"
#include "runtime/base/plan_iterator.h"

#include "zorbautils/hashmap_itemp.h"
#include "util/string_util.h"

#include "zorbaerrors/assert.h"

using namespace std;

namespace zorba
{

/*******************************************************************************

********************************************************************************/
dynamic_context::VarValue::~VarValue()
{
  switch (theState)
  {
  case VarValue::undeclared:
  case VarValue::declared:
    assert(theValue.item == NULL);
    break;
  case VarValue::item:
    assert(theValue.item != NULL);
    theValue.item->removeReference();
    theValue.item = NULL;
    break;
  case VarValue::temp_seq:
    assert(theValue.temp_seq != NULL);
    RCHelper::removeReference(theValue.temp_seq);
    theValue.temp_seq = NULL;
    break;
  default:
    ZORBA_ASSERT(false);
  }

  theState = VarValue::undeclared;
}

dynamic_context::VarValue::VarValue(const VarValue& other)
{
  switch (other.theState)
  {
  case VarValue::undeclared:
  case VarValue::declared:
    assert(other.theValue.item == NULL);
    theValue.item = NULL;
    break;
  case VarValue::item:
    assert(other.theValue.item != NULL);
    theValue.item = other.theValue.item;
    theValue.item->addReference();
    break;
  case VarValue::temp_seq:
    assert(other.theValue.temp_seq != NULL);
    theValue.temp_seq = other.theValue.temp_seq;
    RCHelper::addReference(theValue.temp_seq);
    break;
  default:
    ZORBA_ASSERT(false);
  }

  theState = other.theState;
}

/*******************************************************************************

********************************************************************************/
dynamic_context::dynamic_context(dynamic_context* parent)
  :
  theParent(NULL),
  theAvailableIndices(NULL),
  theDocLoadingUserTime(0.0),
  theDocLoadingTime(0)
{
  theParent = parent;

  if(parent == NULL)
  {
    reset_current_date_time();
  }
  else
  {
    theCurrentDateTime = parent->theCurrentDateTime;
    theTimezone = parent->theTimezone;
    theDefaultCollectionUri = parent->theDefaultCollectionUri;
  }
}

/*******************************************************************************

********************************************************************************/
dynamic_context::~dynamic_context()
{
  if (theAvailableIndices)
    delete theAvailableIndices;
}

/*******************************************************************************

********************************************************************************/
store::Item_t dynamic_context::get_default_collection() const
{
  return theDefaultCollectionUri;
}

void dynamic_context::set_default_collection(const store::Item_t& default_collection_uri)
{
  theDefaultCollectionUri = default_collection_uri;
}

void dynamic_context::set_implicit_timezone(long tzone_seconds)
{
  theTimezone = tzone_seconds;
}

long dynamic_context::get_implicit_timezone() const
{
  return theTimezone;
}

void dynamic_context::set_current_date_time(const store::Item_t& aDateTimeItem)
{
  this->theCurrentDateTime = aDateTimeItem;
}

void dynamic_context::reset_current_date_time()
{
  int lTimeShift = 0;
#if defined (WIN32)
  struct _timeb timebuffer;
  _ftime_s( &timebuffer );
  struct ::tm gmtm;
  localtime_s(&gmtm, &timebuffer.time); //thread safe localtime on Windows
  lTimeShift = -timebuffer.timezone*60;
  if (gmtm.tm_isdst != 0)
    lTimeShift += 3600;
#else
  struct timeb timebuffer;
  ftime( &timebuffer );
  struct ::tm gmtm;
  localtime_r(&timebuffer.time, &gmtm); //thread safe localtime on Linux
  lTimeShift = gmtm.tm_gmtoff;
#endif

  set_implicit_timezone(lTimeShift);//in seconds

  GENV_ITEMFACTORY->createDateTime(theCurrentDateTime,
                                   gmtm.tm_year + 1900,
                                   gmtm.tm_mon + 1,
                                   gmtm.tm_mday,
                                   gmtm.tm_hour,
                                   gmtm.tm_min,
                                   gmtm.tm_sec + timebuffer.millitm/1000.0,
                                   static_cast<short>(theTimezone/3600));

#if WIN32
  time_t t0;
  time(&t0);
  GENV_ITEMFACTORY->createLong(theCurrentTimeMillis, t0*1000);
#else
  timeval tv;
  gettimeofday(&tv, 0);
  long long millis = tv.tv_sec;
  millis = millis * 1000 + tv.tv_usec/1000;
  GENV_ITEMFACTORY->createLong(theCurrentTimeMillis, millis);
#endif
}

store::Item_t dynamic_context::get_current_date_time() const
{
  return theCurrentDateTime;
}

store::Item_t dynamic_context::get_current_time_millis() const
{
  return theCurrentTimeMillis;
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::add_variable(ulong varid, store::Iterator_t& value)
{
  declare_variable(varid);
  set_variable(varid, NULL, QueryLoc::null, value);
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::add_variable(ulong varid, store::Item_t& value)
{
  declare_variable(varid);
  set_variable(varid, NULL, QueryLoc::null, value);
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::declare_variable(ulong varid)
{
  assert(varid > 0);

  if (varid >= theVarValues.size())
    theVarValues.resize(varid+1);

  if (theVarValues[varid].theState == VarValue::undeclared)
    theVarValues[varid].theState = VarValue::declared;
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::set_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Iterator_t& valueIter)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  VarValue& var = theVarValues[varid];

  valueIter->open();

  // For now, use eager eval because the assignment expression may reference
  // the variable itself, and the current value of the variable is overwriten
  // here by this temp sequence. TODO: use lazy eval if we know the the
  // assignment expression does not reference the variable itself.
  store::TempSeq_t seq = GENV_STORE.createTempSeq(valueIter,
                                                  false, // no copy
                                                  false); // no lazy eval

  valueIter->close();

  // variables can be set multiple times, so we need to make sure to remove
  // previously set temp sequences
  if (var.theState == VarValue::item)
  {
    assert(var.theValue.item != NULL);
    var.theValue.item->removeReference();
  }
  else if (var.theState == VarValue::temp_seq)
  {
    assert(var.theValue.temp_seq != NULL);
    RCHelper::removeReference(var.theValue.temp_seq);
  }
  else if (var.theState == VarValue::declared)
  {
    assert(var.theValue.item == NULL);
  }
  else
  {
    ZORBA_ASSERT(false);
  }

  var.theState = VarValue::temp_seq;
  var.theValue.temp_seq = seq.release();
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::set_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Item_t& valueItem)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  VarValue& var = theVarValues[varid];

  // variables can be set multiple times, so we need to make sure to remove
  // previously set temp sequences
  if (var.theState == VarValue::item)
  {
    assert(var.theValue.item != NULL);
    var.theValue.item->removeReference();
  }
  else if (var.theState == VarValue::temp_seq)
  {
    assert(var.theValue.temp_seq != NULL);
    RCHelper::removeReference(var.theValue.temp_seq);
  }
  else if (var.theState == VarValue::declared)
  {
    assert(var.theValue.item == NULL);
  }
  else
  {
    ZORBA_ASSERT(false);
  }

  var.theState = VarValue::item;
  var.theValue.item = valueItem.release();
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::get_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Item_t& itemValue,
    store::TempSeq_t& seqValue) const
{
  itemValue = NULL;
  seqValue = NULL;

  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  if (theVarValues[varid].theState == VarValue::declared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledHasNoValue ) ),
      ERROR_LOC( loc )
    );
  }

  const VarValue& var = theVarValues[varid];

  if (var.theState == VarValue::item)
    itemValue = var.theValue.item;
  else
    seqValue = var.theValue.temp_seq;
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::exists_variable(ulong varid)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    return false; // variable not found
  }

  return true;
}

/*******************************************************************************

********************************************************************************/
ulong dynamic_context::get_next_var_id() const
{
  // 0 is reserved as an invalide var id, and 1 is taken by the context item
  // in the main module.
  return (theVarValues.empty() ? 2 : theVarValues.size());
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::destroy_dctx_value(dctx_value_t* val)
{
  switch (val->type)
  {
  case dynamic_context::dctx_value_t::no_val:
    break;
  default:
    ZORBA_ASSERT (false);
  }

  val->type = dynamic_context::dctx_value_t::no_val;
}

/*******************************************************************************

********************************************************************************/
store::Index* dynamic_context::getIndex(store::Item* qname) const
{
  if (theAvailableIndices == NULL)
    return NULL;

  store::Index_t index;

  if (theAvailableIndices->get(qname, index))
  {
    return index.getp();
  }
  else
  {
    return NULL;
  }
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::bindIndex(
    store::Item* qname,
    store::Index_t& index)
{
  if (theAvailableIndices == NULL)
    theAvailableIndices = new IndexMap(0, NULL, 8, false);

  if (!theAvailableIndices->insert(qname, index))
  {
    ZORBA_ASSERT(false);
  }
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::unbindIndex(store::Item* qname)
{
  if (theAvailableIndices != NULL)
    theAvailableIndices->remove(qname);
}

/*******************************************************************************

********************************************************************************/
store::Iterator_t dynamic_context::listActiveICNames()
{
  return GENV_STORE.listActiveICNames();
}

/*******************************************************************************

********************************************************************************/
store::IC* dynamic_context::getIC(const store::Item* qname)
{
  return GENV_STORE.getIC(qname);
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::addExternalFunctionParam (
    const std::string& aName,
    void* aValue )
{
  dctx_value_t val;
  val.type = dynamic_context::dctx_value_t::ext_func_param;
  val.func_param = aValue;

  return keymap.put ( aName, val);
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::getExternalFunctionParam (
  const std::string& aName,
  void*& aValue) const
{
  dctx_value_t val;
  val.type = dynamic_context::dctx_value_t::no_val;
  val.func_param = 0;

  if ( !keymap.get(aName, val) ) {
    if (theParent)
      return theParent->getExternalFunctionParam(aName, aValue);
    else
      return false;
  }

  ZORBA_ASSERT(val.type == dynamic_context::dctx_value_t::ext_func_param);
  aValue = val.func_param;
  return true;
}

/*
std::vector<zstring>* dynamic_context::get_all_keymap_keys() const
{
  std::auto_ptr<std::vector<zstring> > keys;
  if (theParent != NULL)
    keys.reset(theParent->get_all_keymap_keys());
  else
    keys.reset(new std::vector<zstring>);

  for (unsigned int i=0; i<keymap.size(); i++)
    keys->push_back(keymap.getentryKey(i));

  return keys.release();
}
*/

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<commit_msg>Fixed a bug in setting the value of a variable in the dynamic context. <commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "common/common.h"
#include <assert.h>
#include <time.h>
#include <sys/timeb.h>
#ifdef UNIX
#include <sys/time.h>
#endif

#include "store/api/iterator.h"
#include "store/api/temp_seq.h"
#include "store/api/item_factory.h"
#include "store/api/store.h"
#include "store/api/index.h"
#include "store/api/ic.h"

#include "system/globalenv.h"

#include "context/dynamic_context.h"
#include "context/static_context.h"
#include "context/namespace_context.h"

#include "compiler/expression/var_expr.h"
#include "compiler/xqddf/value_index.h"
#include "compiler/parsetree/parsenodes.h"

#include "types/root_typemanager.h"

#include "runtime/api/plan_wrapper.h"
#include "runtime/base/plan_iterator.h"

#include "zorbautils/hashmap_itemp.h"
#include "util/string_util.h"

#include "zorbaerrors/assert.h"

using namespace std;

namespace zorba
{

/*******************************************************************************

********************************************************************************/
dynamic_context::VarValue::~VarValue()
{
  switch (theState)
  {
  case VarValue::undeclared:
  case VarValue::declared:
    assert(theValue.item == NULL);
    break;
  case VarValue::item:
    assert(theValue.item != NULL);
    theValue.item->removeReference();
    theValue.item = NULL;
    break;
  case VarValue::temp_seq:
    assert(theValue.temp_seq != NULL);
    RCHelper::removeReference(theValue.temp_seq);
    theValue.temp_seq = NULL;
    break;
  default:
    ZORBA_ASSERT(false);
  }

  theState = VarValue::undeclared;
}

dynamic_context::VarValue::VarValue(const VarValue& other)
{
  switch (other.theState)
  {
  case VarValue::undeclared:
  case VarValue::declared:
    assert(other.theValue.item == NULL);
    theValue.item = NULL;
    break;
  case VarValue::item:
    assert(other.theValue.item != NULL);
    theValue.item = other.theValue.item;
    theValue.item->addReference();
    break;
  case VarValue::temp_seq:
    assert(other.theValue.temp_seq != NULL);
    theValue.temp_seq = other.theValue.temp_seq;
    RCHelper::addReference(theValue.temp_seq);
    break;
  default:
    ZORBA_ASSERT(false);
  }

  theState = other.theState;
}

/*******************************************************************************

********************************************************************************/
dynamic_context::dynamic_context(dynamic_context* parent)
  :
  theParent(NULL),
  theAvailableIndices(NULL),
  theDocLoadingUserTime(0.0),
  theDocLoadingTime(0)
{
  theParent = parent;

  if(parent == NULL)
  {
    reset_current_date_time();
  }
  else
  {
    theCurrentDateTime = parent->theCurrentDateTime;
    theTimezone = parent->theTimezone;
    theDefaultCollectionUri = parent->theDefaultCollectionUri;
  }
}

/*******************************************************************************

********************************************************************************/
dynamic_context::~dynamic_context()
{
  if (theAvailableIndices)
    delete theAvailableIndices;
}

/*******************************************************************************

********************************************************************************/
store::Item_t dynamic_context::get_default_collection() const
{
  return theDefaultCollectionUri;
}

void dynamic_context::set_default_collection(const store::Item_t& default_collection_uri)
{
  theDefaultCollectionUri = default_collection_uri;
}

void dynamic_context::set_implicit_timezone(long tzone_seconds)
{
  theTimezone = tzone_seconds;
}

long dynamic_context::get_implicit_timezone() const
{
  return theTimezone;
}

void dynamic_context::set_current_date_time(const store::Item_t& aDateTimeItem)
{
  this->theCurrentDateTime = aDateTimeItem;
}

void dynamic_context::reset_current_date_time()
{
  int lTimeShift = 0;
#if defined (WIN32)
  struct _timeb timebuffer;
  _ftime_s( &timebuffer );
  struct ::tm gmtm;
  localtime_s(&gmtm, &timebuffer.time); //thread safe localtime on Windows
  lTimeShift = -timebuffer.timezone*60;
  if (gmtm.tm_isdst != 0)
    lTimeShift += 3600;
#else
  struct timeb timebuffer;
  ftime( &timebuffer );
  struct ::tm gmtm;
  localtime_r(&timebuffer.time, &gmtm); //thread safe localtime on Linux
  lTimeShift = gmtm.tm_gmtoff;
#endif

  set_implicit_timezone(lTimeShift);//in seconds

  GENV_ITEMFACTORY->createDateTime(theCurrentDateTime,
                                   gmtm.tm_year + 1900,
                                   gmtm.tm_mon + 1,
                                   gmtm.tm_mday,
                                   gmtm.tm_hour,
                                   gmtm.tm_min,
                                   gmtm.tm_sec + timebuffer.millitm/1000.0,
                                   static_cast<short>(theTimezone/3600));

#if WIN32
  time_t t0;
  time(&t0);
  GENV_ITEMFACTORY->createLong(theCurrentTimeMillis, t0*1000);
#else
  timeval tv;
  gettimeofday(&tv, 0);
  long long millis = tv.tv_sec;
  millis = millis * 1000 + tv.tv_usec/1000;
  GENV_ITEMFACTORY->createLong(theCurrentTimeMillis, millis);
#endif
}

store::Item_t dynamic_context::get_current_date_time() const
{
  return theCurrentDateTime;
}

store::Item_t dynamic_context::get_current_time_millis() const
{
  return theCurrentTimeMillis;
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::add_variable(ulong varid, store::Iterator_t& value)
{
  declare_variable(varid);
  set_variable(varid, NULL, QueryLoc::null, value);
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::add_variable(ulong varid, store::Item_t& value)
{
  declare_variable(varid);
  set_variable(varid, NULL, QueryLoc::null, value);
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::declare_variable(ulong varid)
{
  assert(varid > 0);

  if (varid >= theVarValues.size())
    theVarValues.resize(varid+1);

  if (theVarValues[varid].theState == VarValue::undeclared)
    theVarValues[varid].theState = VarValue::declared;
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::set_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Iterator_t& valueIter)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  valueIter->open();

  // For now, use eager eval because the assignment expression may reference
  // the variable itself, and the current value of the variable is overwriten
  // here by this temp sequence. TODO: use lazy eval if we know the the
  // assignment expression does not reference the variable itself.
  store::TempSeq_t seq = GENV_STORE.createTempSeq(valueIter,
                                                  false, // no copy
                                                  false); // no lazy eval

  valueIter->close();

  VarValue& var = theVarValues[varid];

  // variables can be set multiple times, so we need to make sure to remove
  // previously set temp sequences
  if (var.theState == VarValue::item)
  {
    assert(var.theValue.item != NULL);
    var.theValue.item->removeReference();
  }
  else if (var.theState == VarValue::temp_seq)
  {
    assert(var.theValue.temp_seq != NULL);
    RCHelper::removeReference(var.theValue.temp_seq);
  }
  else if (var.theState == VarValue::declared)
  {
    assert(var.theValue.item == NULL);
  }
  else
  {
    ZORBA_ASSERT(false);
  }

  var.theState = VarValue::temp_seq;
  var.theValue.temp_seq = seq.release();
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::set_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Item_t& valueItem)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  VarValue& var = theVarValues[varid];

  // variables can be set multiple times, so we need to make sure to remove
  // previously set temp sequences
  if (var.theState == VarValue::item)
  {
    assert(var.theValue.item != NULL);
    var.theValue.item->removeReference();
  }
  else if (var.theState == VarValue::temp_seq)
  {
    assert(var.theValue.temp_seq != NULL);
    RCHelper::removeReference(var.theValue.temp_seq);
  }
  else if (var.theState == VarValue::declared)
  {
    assert(var.theValue.item == NULL);
  }
  else
  {
    ZORBA_ASSERT(false);
  }

  var.theState = VarValue::item;
  var.theValue.item = valueItem.release();
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::get_variable(
    ulong varid,
    const store::Item_t& varname,
    const QueryLoc& loc,
    store::Item_t& itemValue,
    store::TempSeq_t& seqValue) const
{
  itemValue = NULL;
  seqValue = NULL;

  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledUndeclared ) ),
      ERROR_LOC( loc )
    );
  }

  if (theVarValues[varid].theState == VarValue::declared)
  {
    throw XQUERY_EXCEPTION(
      XPDY0002,
      ERROR_PARAMS( varname->getStringValue(), ZED( VariabledHasNoValue ) ),
      ERROR_LOC( loc )
    );
  }

  const VarValue& var = theVarValues[varid];

  if (var.theState == VarValue::item)
    itemValue = var.theValue.item;
  else
    seqValue = var.theValue.temp_seq;
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::exists_variable(ulong varid)
{
  if (varid >= theVarValues.size() ||
      theVarValues[varid].theState == VarValue::undeclared)
  {
    return false; // variable not found
  }

  return true;
}

/*******************************************************************************

********************************************************************************/
ulong dynamic_context::get_next_var_id() const
{
  // 0 is reserved as an invalide var id, and 1 is taken by the context item
  // in the main module.
  return (theVarValues.empty() ? 2 : theVarValues.size());
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::destroy_dctx_value(dctx_value_t* val)
{
  switch (val->type)
  {
  case dynamic_context::dctx_value_t::no_val:
    break;
  default:
    ZORBA_ASSERT (false);
  }

  val->type = dynamic_context::dctx_value_t::no_val;
}

/*******************************************************************************

********************************************************************************/
store::Index* dynamic_context::getIndex(store::Item* qname) const
{
  if (theAvailableIndices == NULL)
    return NULL;

  store::Index_t index;

  if (theAvailableIndices->get(qname, index))
  {
    return index.getp();
  }
  else
  {
    return NULL;
  }
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::bindIndex(
    store::Item* qname,
    store::Index_t& index)
{
  if (theAvailableIndices == NULL)
    theAvailableIndices = new IndexMap(0, NULL, 8, false);

  if (!theAvailableIndices->insert(qname, index))
  {
    ZORBA_ASSERT(false);
  }
}

/*******************************************************************************

********************************************************************************/
void dynamic_context::unbindIndex(store::Item* qname)
{
  if (theAvailableIndices != NULL)
    theAvailableIndices->remove(qname);
}

/*******************************************************************************

********************************************************************************/
store::Iterator_t dynamic_context::listActiveICNames()
{
  return GENV_STORE.listActiveICNames();
}

/*******************************************************************************

********************************************************************************/
store::IC* dynamic_context::getIC(const store::Item* qname)
{
  return GENV_STORE.getIC(qname);
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::addExternalFunctionParam (
    const std::string& aName,
    void* aValue )
{
  dctx_value_t val;
  val.type = dynamic_context::dctx_value_t::ext_func_param;
  val.func_param = aValue;

  return keymap.put ( aName, val);
}

/*******************************************************************************

********************************************************************************/
bool dynamic_context::getExternalFunctionParam (
  const std::string& aName,
  void*& aValue) const
{
  dctx_value_t val;
  val.type = dynamic_context::dctx_value_t::no_val;
  val.func_param = 0;

  if ( !keymap.get(aName, val) ) {
    if (theParent)
      return theParent->getExternalFunctionParam(aName, aValue);
    else
      return false;
  }

  ZORBA_ASSERT(val.type == dynamic_context::dctx_value_t::ext_func_param);
  aValue = val.func_param;
  return true;
}

/*
std::vector<zstring>* dynamic_context::get_all_keymap_keys() const
{
  std::auto_ptr<std::vector<zstring> > keys;
  if (theParent != NULL)
    keys.reset(theParent->get_all_keymap_keys());
  else
    keys.reset(new std::vector<zstring>);

  for (unsigned int i=0; i<keymap.size(); i++)
    keys->push_back(keymap.getentryKey(i));

  return keys.release();
}
*/

} // namespace zorba
/* vim:set et sw=2 ts=2: */
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "amqp/inoutexchange.h"
#include "amqp/channel.h"
#include "amqp/envelope.h"
#include "amqp/exception.h"
#include "amqp/message.h"
#include "utils/log.h"
#include <cstring>
#include <iostream>

namespace winterwind
{
namespace amqp
{

bool InOutExchange::connect_to_rabbitmq()
{
	try {
		m_rabbitmq_con = std::make_shared<amqp::Connection>(m_rabbitmq_url, 20);
		m_rabbitmq_channel = m_rabbitmq_con->create_channel();

		std::shared_ptr<amqp::Exchange> exchange =
			m_rabbitmq_channel->declare_exchange(m_exchange_name);

		if (!exchange) {
			return false;
		}

		m_command_queue = m_rabbitmq_channel->declare_queue(m_queue_name);
		if (!m_command_queue->bind_exchange(exchange, m_routing_key)) {
			log_error(logger, "Unable to bind queue with exchange, invalidate "
				"connection");
			return false;
		}

		m_command_queue->consume(m_consumer_tag, m_recv_callback);

		return true;
	}
	catch (amqp::exception &e) {
		return false;
	}
}

void* InOutExchange::run()
{
	Thread::set_thread_name("RabbitMQInOut(" + m_exchange_name + ")");

	log_notice(logger, "Starting RabbitMQ In/Out Thread bound on '" + m_exchange_name
		+ "' exchange");

	ThreadStarted();

	while (!is_stopping()) {
		std::shared_ptr<amqp::Exchange> exchange = get_valid_exchange();
		if (!exchange) {
			log_error(logger, "Cannot connect to rabbitmq, retrying in "
				+ std::to_string(m_connection_retry_interval) + "sec...");
			std::this_thread::sleep_for(
				std::chrono::seconds(m_connection_retry_interval));
			continue;
		}

		if (!m_rabbitmq_con->consume_one()) {
			// Consuming failed, maybe a big error happened, restart loop
			continue;
		}

		if (m_response_queue_mtx.try_lock()) {
			if (!m_response_queue.empty()) {
				std::pair<std::string, amqp::Message> response = m_response_queue.front();
				exchange->basic_publish(response.first, response.second);
				m_response_queue.pop();
			}
			m_response_queue_mtx.unlock();
		}
	}

	return nullptr;
}

std::shared_ptr<amqp::Exchange> InOutExchange::get_valid_exchange()
{
	if (!verify_rabbitmq_connection()) {
		return nullptr;
	}

	std::shared_ptr<amqp::Exchange> exchange =
		m_rabbitmq_channel->declare_exchange(m_exchange_name);

	// Failed to declare exchange, connection should be incorrect, reconnect
	if (!exchange) {
		if (!connect_to_rabbitmq()) {
			// On failure return nullptr
			return nullptr;
		}

		exchange =
			m_rabbitmq_channel->declare_exchange(m_exchange_name);
	}

	m_command_queue->bind_exchange(exchange, m_routing_key);

	return exchange;
}

}
}
<commit_msg>inoutexchange: Use a constref<commit_after>/**
 * Copyright (c) 2017, Loic Blot <loic.blot@unix-experience.fr>
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "amqp/inoutexchange.h"
#include "amqp/channel.h"
#include "amqp/envelope.h"
#include "amqp/exception.h"
#include "amqp/message.h"
#include "utils/log.h"
#include <cstring>
#include <iostream>

namespace winterwind
{
namespace amqp
{

bool InOutExchange::connect_to_rabbitmq()
{
	try {
		m_rabbitmq_con = std::make_shared<amqp::Connection>(m_rabbitmq_url, 20);
		m_rabbitmq_channel = m_rabbitmq_con->create_channel();

		std::shared_ptr<amqp::Exchange> exchange =
			m_rabbitmq_channel->declare_exchange(m_exchange_name);

		if (!exchange) {
			return false;
		}

		m_command_queue = m_rabbitmq_channel->declare_queue(m_queue_name);
		if (!m_command_queue->bind_exchange(exchange, m_routing_key)) {
			log_error(logger, "Unable to bind queue with exchange, invalidate "
				"connection");
			return false;
		}

		m_command_queue->consume(m_consumer_tag, m_recv_callback);

		return true;
	}
	catch (amqp::exception &e) {
		return false;
	}
}

void* InOutExchange::run()
{
	Thread::set_thread_name("RabbitMQInOut(" + m_exchange_name + ")");

	log_notice(logger, "Starting RabbitMQ In/Out Thread bound on '" + m_exchange_name
		+ "' exchange");

	ThreadStarted();

	while (!is_stopping()) {
		std::shared_ptr<amqp::Exchange> exchange = get_valid_exchange();
		if (!exchange) {
			log_error(logger, "Cannot connect to rabbitmq, retrying in "
				+ std::to_string(m_connection_retry_interval) + "sec...");
			std::this_thread::sleep_for(
				std::chrono::seconds(m_connection_retry_interval));
			continue;
		}

		if (!m_rabbitmq_con->consume_one()) {
			// Consuming failed, maybe a big error happened, restart loop
			continue;
		}

		if (m_response_queue_mtx.try_lock()) {
			if (!m_response_queue.empty()) {
				const std::pair<std::string, amqp::Message> &response =
					m_response_queue.front();
				exchange->basic_publish(response.first, response.second);
				m_response_queue.pop();
			}
			m_response_queue_mtx.unlock();
		}
	}

	return nullptr;
}

std::shared_ptr<amqp::Exchange> InOutExchange::get_valid_exchange()
{
	if (!verify_rabbitmq_connection()) {
		return nullptr;
	}

	std::shared_ptr<amqp::Exchange> exchange =
		m_rabbitmq_channel->declare_exchange(m_exchange_name);

	// Failed to declare exchange, connection should be incorrect, reconnect
	if (!exchange) {
		if (!connect_to_rabbitmq()) {
			// On failure return nullptr
			return nullptr;
		}

		exchange =
			m_rabbitmq_channel->declare_exchange(m_exchange_name);
	}

	m_command_queue->bind_exchange(exchange, m_routing_key);

	return exchange;
}

}
}
<|endoftext|>


<commit_before>#pragma once

#include "blitz_typedefs.hpp"
#include "constants.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {

    typedef std::array<int, 3> BC_Size_t;
    typedef std::array<Boundary, 6> BC_Type_t;

    /**
     * This defines a general boundary condition container, which can store an
     * angular flux condition as a 1-dimensional collection of values for
     * each dimension-normal, angle, and energy. It is the responsibility of the
     * sweeper itself to determine what the indices of the actual conditions
     * mean.
     */
    class BoundaryCondition {
    public:
        /**
         * \brief Construct a simple boundary condition, where there are the
         * same number of conditions per face/angle (Sn case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc the number of conditions to store for each direction
         * normal.
         *
         * To cut down on code duplication, just expand the scalar \p n_bc into
         * a vector and call the general case (below).
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, BC_Size_t n_bc ):
            BoundaryCondition( n_group,
                               angquad,
                               bc,
                               std::vector<BC_Size_t>(angquad.ndir(), n_bc) )
        {
            return;
        }

        /**
         * \brief Construct a more complicated boundary condition, where each
         * angle can have a different number of conditions (MoC case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc a vector containing the number of BCs needed for each
         * angle.
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, std::vector< BC_Size_t > n_bc ):
            n_group_(n_group),
            n_angle_(n_bc.size()),
            bc_(bc),
            size_(n_bc),
            ang_quad_(angquad)
        {
            assert( (angquad.ndir()   == (int)n_bc.size()) ||
                    (angquad.ndir()/2 == (int)n_bc.size()) );

            int n_angle = n_bc.size();

            bc_per_group_ = 0;
            for( auto n: n_bc ) {
                bc_per_group_ += n[0] + n[1] + n[2];
            }

            size_t total_size = bc_per_group_*n_group;
            data_.resize(total_size);
            offset_.resize(n_angle, 3);
            assert(offset_( 0, blitz::Range::all() ).isStorageContiguous());

            int offset = 0;
            int iang = 0;
            for( auto n_ang: n_bc ) {
                int iface = 0;
                for( auto n: n_ang ) {
                    offset_(iang, iface) = offset;
                    offset += n;
                    iface++;
                }
                iang++;
            }
            return;
        }

        /**
         * \brief Return the total number of boundary condition points.
         */
        int size() const {
            return data_.size();
        }

        /**
         * \brief Initialize all BC points with a given value
         */
        void initialize_scalar( real_t val ) {
            data_ = val;
        }

        /**
         * \brief Initialize the boundary conditions with an energy spectrum.
         */
        void initialize_spectrum( const ArrayB1 &spectrum ) {
            assert( (int)spectrum.size() == n_group_ );
            int it = 0;
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t val = spectrum(ig);
                data_( blitz::Range(it, it+bc_per_group_-1) ) = val;
                it += bc_per_group_;
            }
            return;
        }

        /**
         * \brief Return a const pointer to the beginning of a boundary
         * condition face
         */
        const real_t* get_face( int group, int angle, Normal norm ) const {
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of a boundary condition face
         */
        real_t* get_face( int group, int angle, Normal norm ) {
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Update the boundary condition for all angles for a single
         * group using a passed-in "outgoing" condition.
         *
         * \param int the energy group to update
         * \param out the "outgoing" angular flux boundary condition to use in
         * the update. It should only have one group of storage
         *
         * This would be used for a Jacobi-style iteration on the boundary
         * source.
         */
        void update( int group, const BoundaryCondition &out ) {
            assert( out.n_group_ == 1 );
            int group_offset = bc_per_group_*group;

            for( int iang=0; iang<n_angle_; iang++ ) {
                const auto &ang = ang_quad_[iang];
                for( Normal n: AllNormals ) {
                    int size = size_[iang][(int)n];
                    int offset = group_offset + offset_(iang, (int)n);

                    int iang_out;
                    int out_offset;

                    switch( bc_[(int)(ang.upwind_surface(n))] ) {
                    case Boundary::VACUUM:
                        data_(blitz::Range(offset, offset+size)) = 0.0;
                        break;

                    case Boundary::REFLECT:
                        // Make sure there are actually BCs here to copy
                        if(size == 0) {
                            break;
                        }
                        iang_out = ang_quad_.reflect(iang, n);
                        out_offset = offset_(iang_out, (int)n);
                        data_(blitz::Range(offset, offset+size)) =
                            out.data_(blitz::Range(out_offset,
                                        out_offset+size));
                        break;

                    default:
                        throw EXCEPT("Unsupported boundary condition type");
                    }
                }

            }

            return;
        }

        /**
         * \brief Update the boundary condition for a single outgoing angle for
         * a single group using a passed-in "outgoing" condition.
         *
         * This would be used for a Gauss-Seidel-style iteration on the boundary
         * source.
         */
        void update( int group, int angle, const BoundaryCondition &out ) {
            return;
        }

    private:
        // Number of energy groups
        int n_group_;

        // Number of angles to track
        int n_angle_;

        // Boundary conditions
        std::array<Boundary, 6> bc_;

        std::vector<BC_Size_t> size_;

        // Angular quadratrue used to do angle index reflections
        const AngularQuadrature &ang_quad_;

        // Number of BCs per energy groups. Essentially the sum of the BCs on
        // all faces for all angles
        int bc_per_group_;

        // Large vector containing all of the boundary conditions for all
        // angles, groups and faces
        ArrayB1 data_;

        // An array of index offsets to get to an angle/face. Needs to be
        // incremented by bc_per_group_*group to yield final starting index of a
        // face of BCs
        blitz::Array<int, 2> offset_;

    };
}
<commit_msg>Fix more docs<commit_after>#pragma once

#include "blitz_typedefs.hpp"
#include "constants.hpp"
#include "error.hpp"
#include "global_config.hpp"

namespace mocc {

    typedef std::array<int, 3> BC_Size_t;
    typedef std::array<Boundary, 6> BC_Type_t;

    /**
     * This defines a general boundary condition container, which can store an
     * angular flux condition as a 1-dimensional collection of values for
     * each dimension-normal, angle, and energy. It is the responsibility of the
     * sweeper itself to determine what the indices of the actual conditions
     * mean.
     */
    class BoundaryCondition {
    public:
        /**
         * \brief Construct a simple boundary condition, where there are the
         * same number of conditions per face/angle (Sn case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc the number of conditions to store for each direction
         * normal.
         *
         * To cut down on code duplication, just expand the scalar \p n_bc into
         * a vector and call the general case (below).
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, BC_Size_t n_bc ):
            BoundaryCondition( n_group,
                               angquad,
                               bc,
                               std::vector<BC_Size_t>(angquad.ndir(), n_bc) )
        {
            return;
        }

        /**
         * \brief Construct a more complicated boundary condition, where each
         * angle can have a different number of conditions (MoC case).
         *
         * \param n_group the number of groups
         * \param angquad the \ref AngularQuadrature to use for reflections and
         * such
         * \param bc the \ref Boundary condition to enforce at each domain
         * boundary
         * \param n_bc a vector containing the number of BCs needed for each
         * angle.
         */
        BoundaryCondition( int n_group, const AngularQuadrature &angquad,
                BC_Type_t bc, std::vector< BC_Size_t > n_bc ):
            n_group_(n_group),
            n_angle_(n_bc.size()),
            bc_(bc),
            size_(n_bc),
            ang_quad_(angquad)
        {
            assert( (angquad.ndir()   == (int)n_bc.size()) ||
                    (angquad.ndir()/2 == (int)n_bc.size()) );

            int n_angle = n_bc.size();

            bc_per_group_ = 0;
            for( auto n: n_bc ) {
                bc_per_group_ += n[0] + n[1] + n[2];
            }

            size_t total_size = bc_per_group_*n_group;
            data_.resize(total_size);
            offset_.resize(n_angle, 3);
            assert(offset_( 0, blitz::Range::all() ).isStorageContiguous());

            int offset = 0;
            int iang = 0;
            for( auto n_ang: n_bc ) {
                int iface = 0;
                for( auto n: n_ang ) {
                    offset_(iang, iface) = offset;
                    offset += n;
                    iface++;
                }
                iang++;
            }
            return;
        }

        /**
         * \brief Return the total number of boundary condition points.
         */
        int size() const {
            return data_.size();
        }

        /**
         * \brief Initialize all BC points with a given value
         */
        void initialize_scalar( real_t val ) {
            data_ = val;
        }

        /**
         * \brief Initialize the boundary conditions with an energy spectrum.
         */
        void initialize_spectrum( const ArrayB1 &spectrum ) {
            assert( (int)spectrum.size() == n_group_ );
            int it = 0;
            for( int ig=0; ig<n_group_; ig++ ) {
                real_t val = spectrum(ig);
                data_( blitz::Range(it, it+bc_per_group_-1) ) = val;
                it += bc_per_group_;
            }
            return;
        }

        /**
         * \brief Return a const pointer to the beginning of a boundary
         * condition face
         */
        const real_t* get_face( int group, int angle, Normal norm ) const {
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Return a pointer to the beginning of a boundary condition face
         */
        real_t* get_face( int group, int angle, Normal norm ) {
            int off = bc_per_group_*group + offset_(angle, (int)norm);
            return &data_(off);
        }

        /**
         * \brief Update the boundary condition for all angles for a single
         * group using a passed-in "outgoing" condition.
         *
         * \param group the energy group to update
         * \param out the "outgoing" angular flux boundary condition to use in
         * the update. It should only have one group of storage
         *
         * This would be used for a Jacobi-style iteration on the boundary
         * source.
         */
        void update( int group, const BoundaryCondition &out ) {
            assert( out.n_group_ == 1 );
            int group_offset = bc_per_group_*group;

            for( int iang=0; iang<n_angle_; iang++ ) {
                const auto &ang = ang_quad_[iang];
                for( Normal n: AllNormals ) {
                    int size = size_[iang][(int)n];
                    int offset = group_offset + offset_(iang, (int)n);

                    int iang_out;
                    int out_offset;

                    switch( bc_[(int)(ang.upwind_surface(n))] ) {
                    case Boundary::VACUUM:
                        data_(blitz::Range(offset, offset+size)) = 0.0;
                        break;

                    case Boundary::REFLECT:
                        // Make sure there are actually BCs here to copy
                        if(size == 0) {
                            break;
                        }
                        iang_out = ang_quad_.reflect(iang, n);
                        out_offset = offset_(iang_out, (int)n);
                        data_(blitz::Range(offset, offset+size)) =
                            out.data_(blitz::Range(out_offset,
                                        out_offset+size));
                        break;

                    default:
                        throw EXCEPT("Unsupported boundary condition type");
                    }
                }

            }

            return;
        }

        /**
         * \brief Update the boundary condition for a single outgoing angle for
         * a single group using a passed-in "outgoing" condition.
         *
         * This would be used for a Gauss-Seidel-style iteration on the boundary
         * source.
         */
        void update( int group, int angle, const BoundaryCondition &out ) {
            return;
        }

    private:
        // Number of energy groups
        int n_group_;

        // Number of angles to track
        int n_angle_;

        // Boundary conditions
        std::array<Boundary, 6> bc_;

        std::vector<BC_Size_t> size_;

        // Angular quadratrue used to do angle index reflections
        const AngularQuadrature &ang_quad_;

        // Number of BCs per energy groups. Essentially the sum of the BCs on
        // all faces for all angles
        int bc_per_group_;

        // Large vector containing all of the boundary conditions for all
        // angles, groups and faces
        ArrayB1 data_;

        // An array of index offsets to get to an angle/face. Needs to be
        // incremented by bc_per_group_*group to yield final starting index of a
        // face of BCs
        blitz::Array<int, 2> offset_;

    };
}
<|endoftext|>


<commit_before>#include "setupdialog.h"
#include "debug.h"
#include "utils.h"

#include <QDateTime>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QHostInfo>
#include <QSettings>
#include <QStandardPaths>

SetupDialog::SetupDialog(QWidget *parent)
    : QDialog(parent), _loadingAnimation(":/icons/loading.gif")
{
    _ui.setupUi(this);
    setWindowFlags((windowFlags() | Qt::CustomizeWindowHint)
                   & ~Qt::WindowMaximizeButtonHint);

    // These should be done before connecting objects to
    // validateAdvancedSetupPage() to avoid calling that function
    // unnecessarily.
    _tarsnapDir = Utils::findTarsnapClientInPath("", true);
    _ui.tarsnapPathLineEdit->setText(_tarsnapDir);
    _ui.machineNameLineEdit->setText(QHostInfo::localHostName());
    _ui.wizardStackedWidget->setCurrentWidget(_ui.welcomePage);

    _appDataDir = QStandardPaths::writableLocation(APPDATA);
    QDir keysDir(_appDataDir);
    if(!keysDir.exists())
        keysDir.mkpath(_appDataDir);
    _ui.appDataPathLineEdit->setText(_appDataDir);

    // find existing keys
    foreach(QFileInfo file, Utils::findKeysInPath(_appDataDir))
        _ui.machineKeyCombo->addItem(file.canonicalFilePath());

    _tarsnapCacheDir =
        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
    QDir cacheDir(_tarsnapCacheDir);
    if(!cacheDir.exists())
        cacheDir.mkpath(_tarsnapCacheDir);
    _ui.tarsnapCacheLineEdit->setText(_tarsnapCacheDir);

    _ui.loadingIconLabel->setMovie(&_loadingAnimation);
    _ui.advancedCLIWidget->hide();

    // All pages
    connect(_ui.backButton, &QPushButton::clicked, this,
            &SetupDialog::backButtonClicked);
    connect(_ui.nextButton, &QPushButton::clicked, this,
            &SetupDialog::nextButtonClicked);
    connect(_ui.welcomePageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.advancedPageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.registerPageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.donePageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);

    connect(_ui.wizardStackedWidget, &QStackedWidget::currentChanged, this,
            &SetupDialog::wizardPageChanged);

    // Advanced setup page
    connect(_ui.advancedCLIButton, &QPushButton::toggled, _ui.advancedCLIWidget,
            &QWidget::setVisible);
    connect(_ui.tarsnapPathBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapPathBrowse);
    connect(_ui.tarsnapPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);
    connect(_ui.tarsnapCacheBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapCacheBrowse);
    connect(_ui.tarsnapCacheLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);
    connect(_ui.appDataBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showAppDataBrowse);
    connect(_ui.appDataPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);

    // Register page
    connect(_ui.restoreNoButton, &QPushButton::clicked, this,
            &SetupDialog::restoreNo);
    connect(_ui.restoreYesButton, &QPushButton::clicked, this,
            &SetupDialog::restoreYes);
    connect(_ui.tarsnapUserLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.tarsnapPasswordLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.machineNameLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.machineKeyCombo, &QComboBox::currentTextChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.browseKeyButton, &QPushButton::clicked, this,
            &SetupDialog::registerHaveKeyBrowse);

    _ui.backButton->setText(tr("Skip wizard"));
}

SetupDialog::~SetupDialog()
{
}

void SetupDialog::wizardPageChanged(int)
{
    // Values which might be overwritten below.
    _ui.backButton->setText(tr("Back"));
    _ui.nextButton->setText(tr("Next"));
    _ui.nextButton->setEnabled(true);

    if(_ui.wizardStackedWidget->currentWidget() == _ui.welcomePage)
    {
        _ui.welcomePageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Setup wizard"));
        _ui.backButton->setText(tr("Skip wizard"));
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.advancedPage)
    {
        _ui.advancedPageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Command-line utilities"));
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
    {
        _ui.registerPageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Register with server"));
        _ui.nextButton->setText(tr("Register machine"));
        if(_ui.machineKeyCombo->count() > 0)
        {
            _ui.restoreYesButton->setChecked(true);
            restoreYes();
        }
        else
        {
            _ui.restoreNoButton->setChecked(true);
            restoreNo();
        }
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.donePage)
    {
        _ui.donePageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Setup complete!"));
        _ui.nextButton->setText(tr("Start using Tarsnap"));
    }
}

void SetupDialog::backButtonClicked()
{
    int nextIndex = _ui.wizardStackedWidget->currentIndex() - 1;
    if(nextIndex < 0)
        commitSettings(true);
    else
        _ui.wizardStackedWidget->setCurrentIndex(nextIndex);
}

void SetupDialog::nextButtonClicked()
{
    if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
        registerMachine();
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.donePage)
        commitSettings(false);
    else
        setNextPage();
}

void SetupDialog::skipToPage()
{
    if(sender() == _ui.welcomePageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.welcomePage);
    else if(sender() == _ui.advancedPageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.advancedPage);
    else if(sender() == _ui.registerPageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.registerPage);
    else if(sender() == _ui.donePageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.donePage);
}

void SetupDialog::setNextPage()
{
    if(_ui.wizardStackedWidget->currentWidget() == _ui.welcomePage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.advancedPage);
        _ui.advancedPageRadioButton->setEnabled(true);
        bool advancedOk = validateAdvancedSetupPage();
        _ui.advancedCLIButton->setChecked(!advancedOk);
        if(advancedOk)
            _ui.nextButton->setFocus();
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.advancedPage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.registerPage);
        _ui.registerPageRadioButton->setEnabled(true);
        if(validateRegisterPage())
            _ui.nextButton->setFocus();
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.donePage);
        _ui.donePageRadioButton->setEnabled(true);
    }
}

void SetupDialog::showTarsnapPathBrowse()
{
    QString tarsnapPath =
        QFileDialog::getExistingDirectory(this, tr("Find Tarsnap client"), "");
    _ui.tarsnapPathLineEdit->setText(tarsnapPath);
}

void SetupDialog::showTarsnapCacheBrowse()
{
    QString tarsnapCacheDir =
        QFileDialog::getExistingDirectory(this, tr("Tarsnap cache location"),
                                          _tarsnapCacheDir);
    _ui.tarsnapCacheLineEdit->setText(tarsnapCacheDir);
}

void SetupDialog::showAppDataBrowse()
{
    QString appDataDir =
        QFileDialog::getExistingDirectory(this, tr("App data location"), "");
    _ui.appDataPathLineEdit->setText(appDataDir);
}

bool SetupDialog::validateAdvancedSetupPage()
{
    bool result = true;

    _appDataDir = Utils::validateAppDataDir(_ui.appDataPathLineEdit->text());
    if(_appDataDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(tr("Invalid App data directory "
                                                "set."));
        result = false;
    }

    _tarsnapCacheDir =
        Utils::validateTarsnapCache(_ui.tarsnapCacheLineEdit->text());
    if(result && _tarsnapCacheDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Invalid Tarsnap cache directory"
               " set."));
        result = false;
    }

    _tarsnapDir =
        Utils::findTarsnapClientInPath(_ui.tarsnapPathLineEdit->text(), true);
    if(result && _tarsnapDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Tarsnap utilities not found. Visit "
               "tarsnap.com "
               "for help with acquiring them."));
        result = false;
    }
    else if(result)
    {
        emit getTarsnapVersion(_tarsnapDir);
    }

    _ui.nextButton->setEnabled(result);

    return result;
}

void SetupDialog::restoreNo()
{
    _ui.registerKeyStackedWidget->setCurrentWidget(_ui.keyNoPage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui.gridKeyNoLayout->addWidget(_ui.machineNameLineEdit, 1, 1);
    _ui.statusLabel->clear();
    if(validateRegisterPage())
        _ui.nextButton->setFocus();
}

void SetupDialog::restoreYes()
{
    _ui.registerKeyStackedWidget->setCurrentWidget(_ui.keyYesPage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui.gridKeyYesLayout->addWidget(_ui.machineNameLineEdit, 1, 1);
    _ui.statusLabel->clear();
    if(validateRegisterPage())
        _ui.nextButton->setFocus();
}

bool SetupDialog::validateRegisterPage()
{
    bool result = false;
    if(_ui.restoreYesButton->isChecked())
    {
        // user specified key
        QFileInfo machineKeyFile(_ui.machineKeyCombo->currentText());
        if(!_ui.machineNameLineEdit->text().isEmpty() && machineKeyFile.exists()
           && machineKeyFile.isFile() && machineKeyFile.isReadable())
        {
            result = true;
        }
    }
    else
    {
        if(!_ui.tarsnapUserLineEdit->text().isEmpty()
           && !_ui.tarsnapPasswordLineEdit->text().isEmpty()
           && !_ui.machineNameLineEdit->text().isEmpty())
        {
            result = true;
        }
    }

    _ui.nextButton->setEnabled(result);
    return result;
}

void SetupDialog::registerHaveKeyBrowse()
{
    QString existingMachineKey =
        QFileDialog::getOpenFileName(this,
                                     tr("Browse for existing machine key"));
    if(!existingMachineKey.isEmpty())
        _ui.machineKeyCombo->setCurrentText(existingMachineKey);
}

void SetupDialog::registerMachine()
{
    _ui.nextButton->setEnabled(false);
    _ui.statusLabel->clear();
    _ui.statusLabel->setStyleSheet("");
    if(_ui.restoreYesButton->isChecked())
    {
        _ui.statusLabel->setText("Verifying archive integrity...");
        _tarsnapKeyFile = _ui.machineKeyCombo->currentText();
    }
    else
    {
        _ui.statusLabel->setText("Generating keyfile...");
        _tarsnapKeyFile =
            _appDataDir + QDir::separator() + _ui.machineNameLineEdit->text()
            + "-" + QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")
            + ".key";
    }

    DEBUG << "Registration details >>\n"
          << _tarsnapDir << ::endl
          << _appDataDir << ::endl
          << _tarsnapKeyFile << ::endl
          << _tarsnapCacheDir;

    emit requestRegisterMachine(_ui.tarsnapUserLineEdit->text(),
                                _ui.tarsnapPasswordLineEdit->text(),
                                _ui.machineNameLineEdit->text(),
                                _tarsnapKeyFile, _tarsnapDir, _tarsnapCacheDir);
}

void SetupDialog::registerMachineStatus(TaskStatus status, QString reason)
{
    switch(status)
    {
    case TaskStatus::Completed:
        _ui.statusLabel->clear();
        _ui.doneKeyFileNameLabel->setText(
            QString("%2")
                .arg(QUrl::fromLocalFile(QFileInfo(_tarsnapKeyFile).absolutePath())
                         .toString())
                .arg(_tarsnapKeyFile));
        _ui.nextButton->setEnabled(true);
        setNextPage();
        break;
    case TaskStatus::Failed:
        _ui.statusLabel->setText(reason);
        _ui.statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui.nextButton->setEnabled(true);
        break;
    default:
        break;
    }
}

void SetupDialog::updateLoadingAnimation(bool idle)
{
    if(idle)
    {
        _loadingAnimation.stop();
        _ui.loadingIconLabel->hide();
    }
    else
    {
        _loadingAnimation.start();
        _ui.loadingIconLabel->show();
    }
}

void SetupDialog::setTarsnapVersion(QString versionString)
{
    _tarsnapVersion = versionString;
    if(!_tarsnapVersion.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Tarsnap CLI version ") + _tarsnapVersion + tr(" detected.  ✔"));
    }
}

void SetupDialog::commitSettings(bool skipped)
{
    QSettings settings;

    DEBUG << "Settings location is " << settings.fileName();

    settings.setValue("app/wizard_done", true);

    if(!skipped)
    {
        settings.setValue("app/app_data",    _appDataDir);
        settings.setValue("tarsnap/path",    _tarsnapDir);
        settings.setValue("tarsnap/version", _tarsnapVersion);
        settings.setValue("tarsnap/cache",   _tarsnapCacheDir);
        settings.setValue("tarsnap/key",     _tarsnapKeyFile);
        settings.setValue("tarsnap/user",    _ui.tarsnapUserLineEdit->text());
        settings.setValue("tarsnap/machine", _ui.machineNameLineEdit->text());
    }
    settings.sync();

    // We initialize/verify the cache with fsck-prune for existing keys
    // anyway, so we only need to initialize for new keys here.
    if(!skipped && _ui.restoreNoButton->isChecked())
        emit initializeCache();

    accept();
}
<commit_msg>clang-format *.cpp: misalign consecutive function params<commit_after>#include "setupdialog.h"
#include "debug.h"
#include "utils.h"

#include <QDateTime>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>
#include <QHostInfo>
#include <QSettings>
#include <QStandardPaths>

SetupDialog::SetupDialog(QWidget *parent)
    : QDialog(parent), _loadingAnimation(":/icons/loading.gif")
{
    _ui.setupUi(this);
    setWindowFlags((windowFlags() | Qt::CustomizeWindowHint)
                   & ~Qt::WindowMaximizeButtonHint);

    // These should be done before connecting objects to
    // validateAdvancedSetupPage() to avoid calling that function
    // unnecessarily.
    _tarsnapDir = Utils::findTarsnapClientInPath("", true);
    _ui.tarsnapPathLineEdit->setText(_tarsnapDir);
    _ui.machineNameLineEdit->setText(QHostInfo::localHostName());
    _ui.wizardStackedWidget->setCurrentWidget(_ui.welcomePage);

    _appDataDir = QStandardPaths::writableLocation(APPDATA);
    QDir keysDir(_appDataDir);
    if(!keysDir.exists())
        keysDir.mkpath(_appDataDir);
    _ui.appDataPathLineEdit->setText(_appDataDir);

    // find existing keys
    foreach(QFileInfo file, Utils::findKeysInPath(_appDataDir))
        _ui.machineKeyCombo->addItem(file.canonicalFilePath());

    _tarsnapCacheDir =
        QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
    QDir cacheDir(_tarsnapCacheDir);
    if(!cacheDir.exists())
        cacheDir.mkpath(_tarsnapCacheDir);
    _ui.tarsnapCacheLineEdit->setText(_tarsnapCacheDir);

    _ui.loadingIconLabel->setMovie(&_loadingAnimation);
    _ui.advancedCLIWidget->hide();

    // All pages
    connect(_ui.backButton, &QPushButton::clicked, this,
            &SetupDialog::backButtonClicked);
    connect(_ui.nextButton, &QPushButton::clicked, this,
            &SetupDialog::nextButtonClicked);
    connect(_ui.welcomePageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.advancedPageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.registerPageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);
    connect(_ui.donePageRadioButton, &QRadioButton::clicked, this,
            &SetupDialog::skipToPage);

    connect(_ui.wizardStackedWidget, &QStackedWidget::currentChanged, this,
            &SetupDialog::wizardPageChanged);

    // Advanced setup page
    connect(_ui.advancedCLIButton, &QPushButton::toggled, _ui.advancedCLIWidget,
            &QWidget::setVisible);
    connect(_ui.tarsnapPathBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapPathBrowse);
    connect(_ui.tarsnapPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);
    connect(_ui.tarsnapCacheBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showTarsnapCacheBrowse);
    connect(_ui.tarsnapCacheLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);
    connect(_ui.appDataBrowseButton, &QPushButton::clicked, this,
            &SetupDialog::showAppDataBrowse);
    connect(_ui.appDataPathLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateAdvancedSetupPage);

    // Register page
    connect(_ui.restoreNoButton, &QPushButton::clicked, this,
            &SetupDialog::restoreNo);
    connect(_ui.restoreYesButton, &QPushButton::clicked, this,
            &SetupDialog::restoreYes);
    connect(_ui.tarsnapUserLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.tarsnapPasswordLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.machineNameLineEdit, &QLineEdit::textChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.machineKeyCombo, &QComboBox::currentTextChanged, this,
            &SetupDialog::validateRegisterPage);
    connect(_ui.browseKeyButton, &QPushButton::clicked, this,
            &SetupDialog::registerHaveKeyBrowse);

    _ui.backButton->setText(tr("Skip wizard"));
}

SetupDialog::~SetupDialog()
{
}

void SetupDialog::wizardPageChanged(int)
{
    // Values which might be overwritten below.
    _ui.backButton->setText(tr("Back"));
    _ui.nextButton->setText(tr("Next"));
    _ui.nextButton->setEnabled(true);

    if(_ui.wizardStackedWidget->currentWidget() == _ui.welcomePage)
    {
        _ui.welcomePageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Setup wizard"));
        _ui.backButton->setText(tr("Skip wizard"));
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.advancedPage)
    {
        _ui.advancedPageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Command-line utilities"));
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
    {
        _ui.registerPageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Register with server"));
        _ui.nextButton->setText(tr("Register machine"));
        if(_ui.machineKeyCombo->count() > 0)
        {
            _ui.restoreYesButton->setChecked(true);
            restoreYes();
        }
        else
        {
            _ui.restoreNoButton->setChecked(true);
            restoreNo();
        }
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.donePage)
    {
        _ui.donePageRadioButton->setChecked(true);
        _ui.titleLabel->setText(tr("Setup complete!"));
        _ui.nextButton->setText(tr("Start using Tarsnap"));
    }
}

void SetupDialog::backButtonClicked()
{
    int nextIndex = _ui.wizardStackedWidget->currentIndex() - 1;
    if(nextIndex < 0)
        commitSettings(true);
    else
        _ui.wizardStackedWidget->setCurrentIndex(nextIndex);
}

void SetupDialog::nextButtonClicked()
{
    if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
        registerMachine();
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.donePage)
        commitSettings(false);
    else
        setNextPage();
}

void SetupDialog::skipToPage()
{
    if(sender() == _ui.welcomePageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.welcomePage);
    else if(sender() == _ui.advancedPageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.advancedPage);
    else if(sender() == _ui.registerPageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.registerPage);
    else if(sender() == _ui.donePageRadioButton)
        _ui.wizardStackedWidget->setCurrentWidget(_ui.donePage);
}

void SetupDialog::setNextPage()
{
    if(_ui.wizardStackedWidget->currentWidget() == _ui.welcomePage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.advancedPage);
        _ui.advancedPageRadioButton->setEnabled(true);
        bool advancedOk = validateAdvancedSetupPage();
        _ui.advancedCLIButton->setChecked(!advancedOk);
        if(advancedOk)
            _ui.nextButton->setFocus();
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.advancedPage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.registerPage);
        _ui.registerPageRadioButton->setEnabled(true);
        if(validateRegisterPage())
            _ui.nextButton->setFocus();
    }
    else if(_ui.wizardStackedWidget->currentWidget() == _ui.registerPage)
    {
        _ui.wizardStackedWidget->setCurrentWidget(_ui.donePage);
        _ui.donePageRadioButton->setEnabled(true);
    }
}

void SetupDialog::showTarsnapPathBrowse()
{
    QString tarsnapPath =
        QFileDialog::getExistingDirectory(this, tr("Find Tarsnap client"), "");
    _ui.tarsnapPathLineEdit->setText(tarsnapPath);
}

void SetupDialog::showTarsnapCacheBrowse()
{
    QString tarsnapCacheDir =
        QFileDialog::getExistingDirectory(this, tr("Tarsnap cache location"),
                                          _tarsnapCacheDir);
    _ui.tarsnapCacheLineEdit->setText(tarsnapCacheDir);
}

void SetupDialog::showAppDataBrowse()
{
    QString appDataDir =
        QFileDialog::getExistingDirectory(this, tr("App data location"), "");
    _ui.appDataPathLineEdit->setText(appDataDir);
}

bool SetupDialog::validateAdvancedSetupPage()
{
    bool result = true;

    _appDataDir = Utils::validateAppDataDir(_ui.appDataPathLineEdit->text());
    if(_appDataDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(tr("Invalid App data directory "
                                                "set."));
        result = false;
    }

    _tarsnapCacheDir =
        Utils::validateTarsnapCache(_ui.tarsnapCacheLineEdit->text());
    if(result && _tarsnapCacheDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Invalid Tarsnap cache directory"
               " set."));
        result = false;
    }

    _tarsnapDir =
        Utils::findTarsnapClientInPath(_ui.tarsnapPathLineEdit->text(), true);
    if(result && _tarsnapDir.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Tarsnap utilities not found. Visit "
               "tarsnap.com "
               "for help with acquiring them."));
        result = false;
    }
    else if(result)
    {
        emit getTarsnapVersion(_tarsnapDir);
    }

    _ui.nextButton->setEnabled(result);

    return result;
}

void SetupDialog::restoreNo()
{
    _ui.registerKeyStackedWidget->setCurrentWidget(_ui.keyNoPage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui.gridKeyNoLayout->addWidget(_ui.machineNameLineEdit, 1, 1);
    _ui.statusLabel->clear();
    if(validateRegisterPage())
        _ui.nextButton->setFocus();
}

void SetupDialog::restoreYes()
{
    _ui.registerKeyStackedWidget->setCurrentWidget(_ui.keyYesPage);
    // Share machineNameLineEdit in both pages of the keyStackedWidget
    _ui.gridKeyYesLayout->addWidget(_ui.machineNameLineEdit, 1, 1);
    _ui.statusLabel->clear();
    if(validateRegisterPage())
        _ui.nextButton->setFocus();
}

bool SetupDialog::validateRegisterPage()
{
    bool result = false;
    if(_ui.restoreYesButton->isChecked())
    {
        // user specified key
        QFileInfo machineKeyFile(_ui.machineKeyCombo->currentText());
        if(!_ui.machineNameLineEdit->text().isEmpty() && machineKeyFile.exists()
           && machineKeyFile.isFile() && machineKeyFile.isReadable())
        {
            result = true;
        }
    }
    else
    {
        if(!_ui.tarsnapUserLineEdit->text().isEmpty()
           && !_ui.tarsnapPasswordLineEdit->text().isEmpty()
           && !_ui.machineNameLineEdit->text().isEmpty())
        {
            result = true;
        }
    }

    _ui.nextButton->setEnabled(result);
    return result;
}

void SetupDialog::registerHaveKeyBrowse()
{
    QString existingMachineKey =
        QFileDialog::getOpenFileName(this,
                                     tr("Browse for existing machine key"));
    if(!existingMachineKey.isEmpty())
        _ui.machineKeyCombo->setCurrentText(existingMachineKey);
}

void SetupDialog::registerMachine()
{
    _ui.nextButton->setEnabled(false);
    _ui.statusLabel->clear();
    _ui.statusLabel->setStyleSheet("");
    if(_ui.restoreYesButton->isChecked())
    {
        _ui.statusLabel->setText("Verifying archive integrity...");
        _tarsnapKeyFile = _ui.machineKeyCombo->currentText();
    }
    else
    {
        _ui.statusLabel->setText("Generating keyfile...");
        _tarsnapKeyFile =
            _appDataDir + QDir::separator() + _ui.machineNameLineEdit->text()
            + "-" + QDateTime::currentDateTime().toString("yyyy-MM-dd-HH-mm-ss")
            + ".key";
    }

    DEBUG << "Registration details >>\n"
          << _tarsnapDir << ::endl
          << _appDataDir << ::endl
          << _tarsnapKeyFile << ::endl
          << _tarsnapCacheDir;

    emit requestRegisterMachine(_ui.tarsnapUserLineEdit->text(),
                                _ui.tarsnapPasswordLineEdit->text(),
                                _ui.machineNameLineEdit->text(),
                                _tarsnapKeyFile, _tarsnapDir, _tarsnapCacheDir);
}

void SetupDialog::registerMachineStatus(TaskStatus status, QString reason)
{
    switch(status)
    {
    case TaskStatus::Completed:
        _ui.statusLabel->clear();
        _ui.doneKeyFileNameLabel->setText(
            QString("%2")
                .arg(QUrl::fromLocalFile(QFileInfo(_tarsnapKeyFile).absolutePath())
                         .toString())
                .arg(_tarsnapKeyFile));
        _ui.nextButton->setEnabled(true);
        setNextPage();
        break;
    case TaskStatus::Failed:
        _ui.statusLabel->setText(reason);
        _ui.statusLabel->setStyleSheet("#statusLabel { color: darkred; }");
        _ui.nextButton->setEnabled(true);
        break;
    default:
        break;
    }
}

void SetupDialog::updateLoadingAnimation(bool idle)
{
    if(idle)
    {
        _loadingAnimation.stop();
        _ui.loadingIconLabel->hide();
    }
    else
    {
        _loadingAnimation.start();
        _ui.loadingIconLabel->show();
    }
}

void SetupDialog::setTarsnapVersion(QString versionString)
{
    _tarsnapVersion = versionString;
    if(!_tarsnapVersion.isEmpty())
    {
        _ui.advancedValidationLabel->setText(
            tr("Tarsnap CLI version ") + _tarsnapVersion + tr(" detected.  ✔"));
    }
}

void SetupDialog::commitSettings(bool skipped)
{
    QSettings settings;

    DEBUG << "Settings location is " << settings.fileName();

    settings.setValue("app/wizard_done", true);

    if(!skipped)
    {
        settings.setValue("app/app_data", _appDataDir);
        settings.setValue("tarsnap/path", _tarsnapDir);
        settings.setValue("tarsnap/version", _tarsnapVersion);
        settings.setValue("tarsnap/cache", _tarsnapCacheDir);
        settings.setValue("tarsnap/key", _tarsnapKeyFile);
        settings.setValue("tarsnap/user", _ui.tarsnapUserLineEdit->text());
        settings.setValue("tarsnap/machine", _ui.machineNameLineEdit->text());
    }
    settings.sync();

    // We initialize/verify the cache with fsck-prune for existing keys
    // anyway, so we only need to initialize for new keys here.
    if(!skipped && _ui.restoreNoButton->isChecked())
        emit initializeCache();

    accept();
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <winsock2.h>

#include <xenia/kernel/xam_net.h>

#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/xam_private.h>
#include <xenia/kernel/util/shim_utils.h>

using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xam;

namespace xe {
namespace kernel {

SHIM_CALL NetDll_XNetStartup_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t params_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "NetDll_XNetStartup(%d, %.8X)",
      arg0,
      params_ptr);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL NetDll_WSAStartup_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t version = SHIM_GET_ARG_16(1);
  uint32_t data_ptr = SHIM_GET_ARG_32(2);

  XELOGD(
      "NetDll_WSAStartup(%d, %.4X, %.8X)",
      arg0,
      version,
      data_ptr);

  if (data_ptr) {
    SHIM_SET_MEM_16(data_ptr + 0x000, version);
    SHIM_SET_MEM_16(data_ptr + 0x002, 0);
    SHIM_SET_MEM_32(data_ptr + 0x004, 0);
    SHIM_SET_MEM_32(data_ptr + 0x105, 0);
    SHIM_SET_MEM_16(data_ptr + 0x186, 0);
    SHIM_SET_MEM_16(data_ptr + 0x188, 0);
    SHIM_SET_MEM_32(data_ptr + 0x190, 0);
  }

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL NetDll_WSAGetLastError_shim(
    PPCContext* ppc_state, KernelState* state) {
  XELOGD("NetDll_WSAGetLastError()");
  SHIM_SET_RETURN_32(WSAENETDOWN);
}

SHIM_CALL NetDll_XNetGetEthernetLinkStatus_shim(
    PPCContext* ppc_state, KernelState* state) {
  // Games seem to call this before *Startup. If we return 0, they don't even
  // try.
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  XELOGD(
      "NetDll_XNetGetEthernetLinkStatus(%d)",
      arg0);
  SHIM_SET_RETURN_32(0);
}

SHIM_CALL NetDll_inet_addr_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t cp_ptr = SHIM_GET_ARG_32(0);
  XELOGD(
      "NetDll_inet_addr(%.8X)",
      cp_ptr);
  SHIM_SET_RETURN_32(INADDR_NONE);
}

SHIM_CALL NetDll_socket_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t af = SHIM_GET_ARG_32(1);
  uint32_t type = SHIM_GET_ARG_32(2);
  uint32_t protocol = SHIM_GET_ARG_32(3);
  XELOGD(
      "NetDll_socket(%d, %d, %d, %d)",
      arg0,
      af,
      type,
      protocol);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_setsockopt_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t level = SHIM_GET_ARG_32(2);
  uint32_t optname = SHIM_GET_ARG_32(3);
  uint32_t optval_ptr = SHIM_GET_ARG_32(4);
  uint32_t optlen = SHIM_GET_ARG_32(5);
  XELOGD(
      "NetDll_setsockopt(%d, %.8X, %d, %d, %.8X, %d)",
      arg0,
      socket_ptr,
      level,
      optname,
      optval_ptr,
      optlen);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_connect_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t socket_ptr = SHIM_GET_ARG_32(0);
  uint32_t sockaddr_ptr = SHIM_GET_ARG_32(1);
  uint32_t namelen = SHIM_GET_ARG_32(2);
  XELOGD(
      "NetDll_connect(%.8X, %.8X, %d)",
      socket_ptr,
      sockaddr_ptr,
      namelen);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_recv_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t buf_ptr = SHIM_GET_ARG_32(2);
  uint32_t len = SHIM_GET_ARG_32(3);
  uint32_t flags = SHIM_GET_ARG_32(4);
  XELOGD(
      "NetDll_recv(%d, %.8X, %.8X, %d, %d)",
      arg0,
      socket_ptr,
      buf_ptr,
      len,
      flags);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_recvfrom_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t buf_ptr = SHIM_GET_ARG_32(2);
  uint32_t len = SHIM_GET_ARG_32(3);
  uint32_t flags = SHIM_GET_ARG_32(4);
  uint32_t from_ptr = SHIM_GET_ARG_32(5);
  uint32_t fromlen_ptr = SHIM_GET_ARG_32(6);
  XELOGD(
      "NetDll_recvfrom(%d, %.8X, %.8X, %d, %d, %.8X, %.8X)",
      arg0,
      socket_ptr,
      buf_ptr,
      len,
      flags,
      from_ptr,
      fromlen_ptr);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_send_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t socket_ptr = SHIM_GET_ARG_32(0);
  uint32_t buf_ptr = SHIM_GET_ARG_32(1);
  uint32_t len = SHIM_GET_ARG_32(2);
  uint32_t flags = SHIM_GET_ARG_32(3);
  XELOGD(
      "NetDll_send(%.8X, %.8X, %d, %d)",
      socket_ptr,
      buf_ptr,
      len,
      flags);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterNetExports(
    ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", NetDll_XNetStartup, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_WSAStartup, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_WSAGetLastError, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_XNetGetEthernetLinkStatus, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_inet_addr, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_socket, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_setsockopt, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_connect, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_recv, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_recvfrom, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_send, state);
}
<commit_msg>Fixed arguments for NetDll_send.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include <winsock2.h>

#include <xenia/kernel/xam_net.h>

#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/xam_private.h>
#include <xenia/kernel/util/shim_utils.h>

using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xam;

namespace xe {
namespace kernel {

SHIM_CALL NetDll_XNetStartup_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t params_ptr = SHIM_GET_ARG_32(1);

  XELOGD(
      "NetDll_XNetStartup(%d, %.8X)",
      arg0,
      params_ptr);

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL NetDll_WSAStartup_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t version = SHIM_GET_ARG_16(1);
  uint32_t data_ptr = SHIM_GET_ARG_32(2);

  XELOGD(
      "NetDll_WSAStartup(%d, %.4X, %.8X)",
      arg0,
      version,
      data_ptr);

  if (data_ptr) {
    SHIM_SET_MEM_16(data_ptr + 0x000, version);
    SHIM_SET_MEM_16(data_ptr + 0x002, 0);
    SHIM_SET_MEM_32(data_ptr + 0x004, 0);
    SHIM_SET_MEM_32(data_ptr + 0x105, 0);
    SHIM_SET_MEM_16(data_ptr + 0x186, 0);
    SHIM_SET_MEM_16(data_ptr + 0x188, 0);
    SHIM_SET_MEM_32(data_ptr + 0x190, 0);
  }

  SHIM_SET_RETURN_64(0);
}

SHIM_CALL NetDll_WSAGetLastError_shim(
    PPCContext* ppc_state, KernelState* state) {
  XELOGD("NetDll_WSAGetLastError()");
  SHIM_SET_RETURN_32(WSAENETDOWN);
}

SHIM_CALL NetDll_XNetGetEthernetLinkStatus_shim(
    PPCContext* ppc_state, KernelState* state) {
  // Games seem to call this before *Startup. If we return 0, they don't even
  // try.
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  XELOGD(
      "NetDll_XNetGetEthernetLinkStatus(%d)",
      arg0);
  SHIM_SET_RETURN_32(0);
}

SHIM_CALL NetDll_inet_addr_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t cp_ptr = SHIM_GET_ARG_32(0);
  XELOGD(
      "NetDll_inet_addr(%.8X)",
      cp_ptr);
  SHIM_SET_RETURN_32(INADDR_NONE);
}

SHIM_CALL NetDll_socket_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t af = SHIM_GET_ARG_32(1);
  uint32_t type = SHIM_GET_ARG_32(2);
  uint32_t protocol = SHIM_GET_ARG_32(3);
  XELOGD(
      "NetDll_socket(%d, %d, %d, %d)",
      arg0,
      af,
      type,
      protocol);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_setsockopt_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t level = SHIM_GET_ARG_32(2);
  uint32_t optname = SHIM_GET_ARG_32(3);
  uint32_t optval_ptr = SHIM_GET_ARG_32(4);
  uint32_t optlen = SHIM_GET_ARG_32(5);
  XELOGD(
      "NetDll_setsockopt(%d, %.8X, %d, %d, %.8X, %d)",
      arg0,
      socket_ptr,
      level,
      optname,
      optval_ptr,
      optlen);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_connect_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t socket_ptr = SHIM_GET_ARG_32(0);
  uint32_t sockaddr_ptr = SHIM_GET_ARG_32(1);
  uint32_t namelen = SHIM_GET_ARG_32(2);
  XELOGD(
      "NetDll_connect(%.8X, %.8X, %d)",
      socket_ptr,
      sockaddr_ptr,
      namelen);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_recv_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t buf_ptr = SHIM_GET_ARG_32(2);
  uint32_t len = SHIM_GET_ARG_32(3);
  uint32_t flags = SHIM_GET_ARG_32(4);
  XELOGD(
      "NetDll_recv(%d, %.8X, %.8X, %d, %d)",
      arg0,
      socket_ptr,
      buf_ptr,
      len,
      flags);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_recvfrom_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t buf_ptr = SHIM_GET_ARG_32(2);
  uint32_t len = SHIM_GET_ARG_32(3);
  uint32_t flags = SHIM_GET_ARG_32(4);
  uint32_t from_ptr = SHIM_GET_ARG_32(5);
  uint32_t fromlen_ptr = SHIM_GET_ARG_32(6);
  XELOGD(
      "NetDll_recvfrom(%d, %.8X, %.8X, %d, %d, %.8X, %.8X)",
      arg0,
      socket_ptr,
      buf_ptr,
      len,
      flags,
      from_ptr,
      fromlen_ptr);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

SHIM_CALL NetDll_send_shim(
    PPCContext* ppc_state, KernelState* state) {
  uint32_t arg0 = SHIM_GET_ARG_32(0);
  uint32_t socket_ptr = SHIM_GET_ARG_32(1);
  uint32_t buf_ptr = SHIM_GET_ARG_32(2);
  uint32_t len = SHIM_GET_ARG_32(3);
  uint32_t flags = SHIM_GET_ARG_32(4);
  XELOGD(
      "NetDll_send(%d,%.8X, %.8X, %d, %d)",
      arg0,
      socket_ptr,
      buf_ptr,
      len,
      flags);
  SHIM_SET_RETURN_32(SOCKET_ERROR);
}

}  // namespace kernel
}  // namespace xe

void xe::kernel::xam::RegisterNetExports(
    ExportResolver* export_resolver, KernelState* state) {
  SHIM_SET_MAPPING("xam.xex", NetDll_XNetStartup, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_WSAStartup, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_WSAGetLastError, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_XNetGetEthernetLinkStatus, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_inet_addr, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_socket, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_setsockopt, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_connect, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_recv, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_recvfrom, state);
  SHIM_SET_MAPPING("xam.xex", NetDll_send, state);
}
<|endoftext|>