<commit_before>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

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 <vector>
#include "paddle/fluid/framework/executor.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/operators/detail/safe_ref.h"

namespace paddle {
namespace operators {

using StepScopeVar = std::vector<framework::Scope *>;
using LoDTensor = framework::LoDTensor;

static constexpr char kStepBlock[] = "sub_block";
static constexpr char kCondition[] = "Condition";
static constexpr char kStepScopes[] = "StepScopes";
static constexpr char kX[] = "X";
static constexpr char kXGRAD[] = "X@GRAD";
static constexpr char kOutputs[] = "Out";

class WhileOp : public framework::OperatorBase {
 public:
  WhileOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

 private:
  void RunImpl(const framework::Scope &scope,
               const platform::Place &dev_place) const override {
    PADDLE_ENFORCE_NOT_NULL(scope.FindVar(Input(kCondition)));
    auto &cond = scope.FindVar(Input(kCondition))->Get<LoDTensor>();
    PADDLE_ENFORCE_EQ(cond.dims(), paddle::framework::make_ddim({1}));

    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);

    auto *program = block->Program();

    auto step_scopes =
        scope.FindVar(Output(kStepScopes))->GetMutable<StepScopeVar>();

    PADDLE_ENFORCE(platform::is_cpu_place(cond.place()),
                   "Condition of while op must in CPU memory.");
    while (cond.data<bool>()[0]) {
      auto &current_scope = scope.NewScope();
      step_scopes->push_back(&current_scope);

      executor.Run(*program, &current_scope, block->ID(),
                   false /*create_local_scope*/);
    }
  }
};

class WhileOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  WhileOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kX,
             "A set of variables, which are required by operators inside the "
             "block of While Op.")
        .AsDuplicable();
    AddInput(
        kCondition,
        "(Bool) An scalar. When it's False, the While Op will be terminated.")
        .AsDuplicable();
    AddOutput(kOutputs,
              "A set of variables, which will be assigned with values "
              "generated by the operators inside the block of While Op.")
        .AsDuplicable();
    AddOutput(kStepScopes,
              "(StepScopeVar) A vector of local scope, which size equals the "
              "step number of While Op. The i'th scope storages temporary "
              "variables generated in the i'th step.");
    AddAttr<framework::BlockDesc *>(kStepBlock,
                                    "The step block inside WhileOp");
    AddComment(R"DOC(
)DOC");
  }
};

class WhileGradOp : public framework::OperatorBase {
 public:
  WhileGradOp(const std::string &type, const framework::VariableNameMap &inputs,
              const framework::VariableNameMap &outputs,
              const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

 private:
  void RunImpl(const framework::Scope &scope,
               const platform::Place &dev_place) const override {
    // get device context from pool
    platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
    auto &dev_ctx = *pool.Get(dev_place);
    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);
    auto *program = block->Program();

    auto *step_scopes =
        scope.FindVar(Input(kStepScopes))->GetMutable<StepScopeVar>();

    auto outside_og_names = Inputs(framework::GradVarName(kOutputs));
    auto inside_og_names =
        Attr<std::vector<std::string>>("original_output_grad");

    PADDLE_ENFORCE_EQ(outside_og_names.size(), inside_og_names.size());

    for (auto cur_scope_iter = step_scopes->rbegin();
         cur_scope_iter != step_scopes->rend(); ++cur_scope_iter) {
      VLOG(3) << "Start backward at time_step "
              << cur_scope_iter - step_scopes->rbegin();
      framework::Scope &cur_scope = **cur_scope_iter;
      // Link OG from outside to inside
      for (size_t i = 0; i < outside_og_names.size(); ++i) {
        auto outside_og_name = outside_og_names[i];
        auto inside_og_name = inside_og_names[i];
        VLOG(8) << "Linking outside " << outside_og_name << " --> inside "
                << inside_og_name;
        auto &og_outside =
            detail::Ref(scope.FindVar(outside_og_name),
                        "Cannot find Outside Gradient %s", outside_og_name);
        auto &og_inside =
            detail::Ref(cur_scope.Var(inside_og_name),
                        "Cannot find inside gradient %s", inside_og_name);
        if (og_outside.Type().hash_code() ==
            typeid(framework::LoDTensor).hash_code()) {
          auto &outside_tensor = og_outside.Get<framework::LoDTensor>();
          auto &inside_tensor =
              detail::Ref(og_inside.GetMutable<framework::LoDTensor>());
          inside_tensor.set_lod(outside_tensor.lod());
          inside_tensor.ShareDataWith(outside_tensor);
        } else if (og_outside.Type().hash_code() ==
                   typeid(framework::LoDTensorArray).hash_code()) {
          auto &outside_array = og_outside.Get<framework::LoDTensorArray>();
          auto &inside_array =
              detail::Ref(og_inside.GetMutable<framework::LoDTensorArray>());
          VLOG(8) << outside_og_name << " size = " << outside_array.size();
          inside_array.resize(outside_array.size());

          for (size_t j = 0; j < inside_array.size(); ++j) {
            VLOG(8) << j << " " << outside_array[j].numel();
            if (outside_array[j].numel() != 0) {
              inside_array[j].set_lod(outside_array[j].lod());
              inside_array[j].ShareDataWith(outside_array[j]);
            } else {
              PADDLE_ENFORCE_EQ(inside_array[j].numel(), 0);
            }
          }
        }
      }

      executor.Run(*program, *cur_scope_iter, block->ID(), false);

      auto &pg_names = Outputs(kXGRAD);
      auto &p_names = Inputs(kX);
      PADDLE_ENFORCE_EQ(pg_names.size(), p_names.size());
      for (size_t param_id = 0; param_id < pg_names.size(); ++param_id) {
        if (pg_names[param_id] == framework::kEmptyVarName) {
          continue;  // parameter doesn't have gradient
        }
        auto inside_grad_name = framework::GradVarName(p_names[param_id]);

        //  // TODO(tonyyang-svail): Not sure we need the following
        //  // If does not compute gradient of that variable inside rnn,
        //  just
        //  // continue
        //  if (local_var_names.find(inside_grad_name) ==
        //  local_var_names.end()) {
        //    continue;
        //  }

        // zero gradient variable in step 0
        if (cur_scope_iter == step_scopes->rbegin()) {
          auto *var = (*cur_scope_iter)->FindVar(inside_grad_name);
          PADDLE_ENFORCE_NOT_NULL(var, "Can not find var %s", inside_grad_name);
          if (var->IsType<LoDTensor>()) {
            auto &inside_tensor = var->Get<framework::LoDTensor>();
            framework::AttributeMap attrs;
            attrs["dtype"] = framework::ToDataType(inside_tensor.type());
            attrs["shape"] = framework::vectorize2int(inside_tensor.dims());
            attrs["value"] = 0.0f;

            auto var_name = pg_names[param_id];
            auto zero_op = framework::OpRegistry::CreateOp(
                "fill_constant", framework::VariableNameMap{},
                {{"Out", {var_name}}}, attrs);
            zero_op->Run(scope, dev_place);
            scope.FindVar(var_name)
                ->GetMutable<framework::LoDTensor>()
                ->set_lod(inside_tensor.lod());
          }
        }

        auto new_inside_name = cur_scope.Rename(inside_grad_name);
        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {pg_names[param_id], new_inside_name}}},
            {{"Out", {pg_names[param_id]}}}, framework::AttributeMap{});
        sum_op->Run(cur_scope, dev_place);
        cur_scope.Rename(new_inside_name, inside_grad_name);
      }
      dev_ctx.Wait();
      const_cast<framework::Scope &>(scope).DeleteScope(&cur_scope);
    }
  }
};

class WhileGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    auto *while_grad = new framework::OpDesc();
    while_grad->SetType("while_grad");
    while_grad->SetInput(kX, Input(kX));
    while_grad->SetInput(kOutputs, Output(kOutputs));
    while_grad->SetInput(kStepScopes, Output(kStepScopes));

    auto *grad_block = this->grad_block_[0];
    auto *fwd_block = grad_block->ForwardBlock();
    auto *parent_block = grad_block->ParentBlock();

    // Not all of IGs will be generated by inner gradient operators of while op.
    // Ignore IGs that is not generated by the inside block.
    std::unordered_set<std::string> inner_op_outputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &oname : op->OutputArgumentNames()) {
        inner_op_outputs.insert(oname);
      }
    }
    auto igs = InputGrad(kX, /*do not drop empty gradient*/ false);
    for (auto &each_ig : igs) {
      if (inner_op_outputs.find(each_ig) == inner_op_outputs.end()) {
        VLOG(8) << "Ignore " << each_ig;
        each_ig = framework::kEmptyVarName;
      }
    }
    while_grad->SetOutput(framework::GradVarName(kX), igs);

    // OG should be re-calculated by step blocks, since many outputs of while op
    // do not need to calculate gradients.
    std::unordered_set<std::string> block_ins;
    block_ins.reserve(Input(kX).size() + Output(kOutputs).size());
    for (auto &p : Input(kX)) {
      block_ins.insert(p);
    }
    for (auto &o : Output(kOutputs)) {
      block_ins.insert(o);
    }
    std::unordered_set<std::string> extra_inputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &input_name : op->InputArgumentNames()) {
        // If the input of Op has been recorded or is generated by the forward
        // block, do not make it as input again.

        if (block_ins.find(input_name) != block_ins.end() ||
            fwd_block->FindVar(input_name) != nullptr ||
            parent_block->FindVar(input_name) != nullptr) {
          continue;
        }
        extra_inputs.insert(input_name);
      }
      for (auto &output_name : op->OutputArgumentNames()) {
        block_ins.insert(output_name);
      }
    }

    std::vector<std::string> extra_inputs_list;
    extra_inputs_list.resize(extra_inputs.size());
    std::copy(extra_inputs.begin(), extra_inputs.end(),
              extra_inputs_list.begin());
    while_grad->SetInput(framework::GradVarName(kOutputs), extra_inputs_list);

    while_grad->SetAttrMap(this->Attrs());
    while_grad->SetBlockAttr(kStepBlock, *grad_block);
    // record the original output gradient names, since the gradient name of
    // while operator could be renamed.
    while_grad->SetAttr("original_output_grad", extra_inputs_list);

    return std::unique_ptr<framework::OpDesc>(while_grad);
  }
};

class WhileGradOpVarTypeInference : public framework::VarTypeInference {
 public:
  void operator()(const framework::OpDesc &op_desc,
                  framework::BlockDesc *block) const override {
    auto p_names = op_desc.Input(kX);
    auto pg_names = op_desc.Output(framework::GradVarName(kX));

    for (size_t i = 0; i < p_names.size(); ++i) {
      auto &p_var = detail::Ref(block->FindVarRecursive(p_names[i]));
      auto *g_var = block->FindVarRecursive(pg_names[i]);
      if (g_var != nullptr) {  // Gradient could be @EMPTY@
        VLOG(5) << "Setting " << pg_names[i] << " following " << p_names[i]
                << " type: " << p_var.GetType();
        g_var->SetType(p_var.GetType());
        g_var->SetDataType(p_var.GetDataType());
      }
    }
  }
};

class WhileGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    ctx->HasInputs(kX);
    ctx->HasOutputs(framework::GradVarName(kX));
    ctx->HasInputs(kOutputs);
    ctx->HasInputs(framework::GradVarName(kOutputs));

    auto p_names = ctx->Inputs(kX);
    auto pg_names = ctx->Outputs(kXGRAD);
    auto var_types = ctx->GetInputsVarType(kX);
    std::vector<std::string> names_to_set;
    std::vector<framework::DDim> dims_to_set;
    for (size_t i = 0; i < p_names.size(); ++i) {
      if (pg_names[i] == framework::kEmptyVarName) {
        continue;
      }
      auto dims = ctx->GetInputsElementDim(kX, i);
      if (var_types[i] == framework::proto::VarType::LOD_TENSOR) {
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      } else if (var_types[i] == framework::proto::VarType::LOD_TENSOR_ARRAY) {
        // not sure how to set the dim of LOD_TENSOR_ARRAY
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      }
    }
    ctx->SetDims(names_to_set, dims_to_set);
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(while, paddle::operators::WhileOp,
                  paddle::operators::WhileOpMaker,
                  paddle::operators::WhileGradOpDescMaker);
REGISTER_OPERATOR(while_grad, paddle::operators::WhileGradOp,
                  paddle::operators::WhileGradOpShapeInference,
                  paddle::operators::WhileGradOpVarTypeInference);
<commit_msg>Add comments<commit_after>/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved.

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 <vector>
#include "paddle/fluid/framework/executor.h"
#include "paddle/fluid/framework/lod_tensor_array.h"
#include "paddle/fluid/framework/op_registry.h"
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/operators/detail/safe_ref.h"

namespace paddle {
namespace operators {

using StepScopeVar = std::vector<framework::Scope *>;
using LoDTensor = framework::LoDTensor;

static constexpr char kStepBlock[] = "sub_block";
static constexpr char kCondition[] = "Condition";
static constexpr char kStepScopes[] = "StepScopes";
static constexpr char kX[] = "X";
static constexpr char kXGRAD[] = "X@GRAD";
static constexpr char kOutputs[] = "Out";

class WhileOp : public framework::OperatorBase {
 public:
  WhileOp(const std::string &type, const framework::VariableNameMap &inputs,
          const framework::VariableNameMap &outputs,
          const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

 private:
  void RunImpl(const framework::Scope &scope,
               const platform::Place &dev_place) const override {
    PADDLE_ENFORCE_NOT_NULL(scope.FindVar(Input(kCondition)));
    auto &cond = scope.FindVar(Input(kCondition))->Get<LoDTensor>();
    PADDLE_ENFORCE_EQ(cond.dims(), paddle::framework::make_ddim({1}));

    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);

    auto *program = block->Program();

    auto step_scopes =
        scope.FindVar(Output(kStepScopes))->GetMutable<StepScopeVar>();

    PADDLE_ENFORCE(platform::is_cpu_place(cond.place()),
                   "Condition of while op must in CPU memory.");
    while (cond.data<bool>()[0]) {
      auto &current_scope = scope.NewScope();
      step_scopes->push_back(&current_scope);

      executor.Run(*program, &current_scope, block->ID(),
                   false /*create_local_scope*/);
    }
  }
};

class WhileOpMaker : public framework::OpProtoAndCheckerMaker {
 public:
  WhileOpMaker(OpProto *proto, OpAttrChecker *op_checker)
      : OpProtoAndCheckerMaker(proto, op_checker) {
    AddInput(kX,
             "A set of variables, which are required by operators inside the "
             "block of While Op.")
        .AsDuplicable();
    AddInput(
        kCondition,
        "(Bool) An scalar. When it's False, the While Op will be terminated.")
        .AsDuplicable();
    AddOutput(kOutputs,
              "A set of variables, which will be assigned with values "
              "generated by the operators inside the block of While Op.")
        .AsDuplicable();
    AddOutput(kStepScopes,
              "(StepScopeVar) A vector of local scope, which size equals the "
              "step number of While Op. The i'th scope storages temporary "
              "variables generated in the i'th step.");
    AddAttr<framework::BlockDesc *>(kStepBlock,
                                    "The step block inside WhileOp");
    AddComment(R"DOC(
)DOC");
  }
};

class WhileGradOp : public framework::OperatorBase {
 public:
  WhileGradOp(const std::string &type, const framework::VariableNameMap &inputs,
              const framework::VariableNameMap &outputs,
              const framework::AttributeMap &attrs)
      : framework::OperatorBase(type, inputs, outputs, attrs) {}

 private:
  void RunImpl(const framework::Scope &scope,
               const platform::Place &dev_place) const override {
    // get device context from pool
    platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
    auto &dev_ctx = *pool.Get(dev_place);
    framework::Executor executor(dev_place);
    auto *block = Attr<framework::BlockDesc *>(kStepBlock);
    auto *program = block->Program();

    auto *step_scopes =
        scope.FindVar(Input(kStepScopes))->GetMutable<StepScopeVar>();

    auto outside_og_names = Inputs(framework::GradVarName(kOutputs));
    auto inside_og_names =
        Attr<std::vector<std::string>>("original_output_grad");

    PADDLE_ENFORCE_EQ(outside_og_names.size(), inside_og_names.size());

    for (auto cur_scope_iter = step_scopes->rbegin();
         cur_scope_iter != step_scopes->rend(); ++cur_scope_iter) {
      VLOG(3) << "Start backward at time_step "
              << cur_scope_iter - step_scopes->rbegin();
      framework::Scope &cur_scope = **cur_scope_iter;
      // Link OG from outside to inside
      for (size_t i = 0; i < outside_og_names.size(); ++i) {
        auto outside_og_name = outside_og_names[i];
        auto inside_og_name = inside_og_names[i];
        VLOG(8) << "Linking outside " << outside_og_name << " --> inside "
                << inside_og_name;
        auto &og_outside =
            detail::Ref(scope.FindVar(outside_og_name),
                        "Cannot find Outside Gradient %s", outside_og_name);
        auto &og_inside =
            detail::Ref(cur_scope.Var(inside_og_name),
                        "Cannot find inside gradient %s", inside_og_name);
        if (og_outside.Type().hash_code() ==
            typeid(framework::LoDTensor).hash_code()) {
          auto &outside_tensor = og_outside.Get<framework::LoDTensor>();
          auto &inside_tensor =
              detail::Ref(og_inside.GetMutable<framework::LoDTensor>());
          inside_tensor.set_lod(outside_tensor.lod());
          inside_tensor.ShareDataWith(outside_tensor);
        } else if (og_outside.Type().hash_code() ==
                   typeid(framework::LoDTensorArray).hash_code()) {
          auto &outside_array = og_outside.Get<framework::LoDTensorArray>();
          auto &inside_array =
              detail::Ref(og_inside.GetMutable<framework::LoDTensorArray>());
          VLOG(8) << outside_og_name << " size = " << outside_array.size();
          inside_array.resize(outside_array.size());

          for (size_t j = 0; j < inside_array.size(); ++j) {
            VLOG(8) << j << " " << outside_array[j].numel();
            if (outside_array[j].numel() != 0) {
              inside_array[j].set_lod(outside_array[j].lod());
              inside_array[j].ShareDataWith(outside_array[j]);
            } else {
              PADDLE_ENFORCE_EQ(inside_array[j].numel(), 0);
            }
          }
        }
      }

      executor.Run(*program, *cur_scope_iter, block->ID(), false);

      auto &pg_names = Outputs(kXGRAD);
      auto &p_names = Inputs(kX);
      PADDLE_ENFORCE_EQ(pg_names.size(), p_names.size());
      for (size_t param_id = 0; param_id < pg_names.size(); ++param_id) {
        if (pg_names[param_id] == framework::kEmptyVarName) {
          continue;  // parameter doesn't have gradient
        }
        auto inside_grad_name = framework::GradVarName(p_names[param_id]);

        //  // TODO(tonyyang-svail): Not sure we need the following
        //  // If does not compute gradient of that variable inside rnn,
        //  just
        //  // continue
        //  if (local_var_names.find(inside_grad_name) ==
        //  local_var_names.end()) {
        //    continue;
        //  }

        // zero gradient variable in step 0
        if (cur_scope_iter == step_scopes->rbegin()) {
          auto *var = (*cur_scope_iter)->FindVar(inside_grad_name);
          PADDLE_ENFORCE_NOT_NULL(var, "Can not find var %s", inside_grad_name);
          if (var->IsType<LoDTensor>()) {
            auto &inside_tensor = var->Get<framework::LoDTensor>();
            framework::AttributeMap attrs;
            attrs["dtype"] = framework::ToDataType(inside_tensor.type());
            attrs["shape"] = framework::vectorize2int(inside_tensor.dims());
            attrs["value"] = 0.0f;

            auto var_name = pg_names[param_id];
            auto zero_op = framework::OpRegistry::CreateOp(
                "fill_constant", framework::VariableNameMap{},
                {{"Out", {var_name}}}, attrs);
            zero_op->Run(scope, dev_place);
            scope.FindVar(var_name)
                ->GetMutable<framework::LoDTensor>()
                ->set_lod(inside_tensor.lod());
          }
        }

        auto new_inside_name = cur_scope.Rename(inside_grad_name);
        auto sum_op = framework::OpRegistry::CreateOp(
            "sum", {{"X", {pg_names[param_id], new_inside_name}}},
            {{"Out", {pg_names[param_id]}}}, framework::AttributeMap{});
        sum_op->Run(cur_scope, dev_place);
        cur_scope.Rename(new_inside_name, inside_grad_name);
      }
      dev_ctx.Wait();
      const_cast<framework::Scope &>(scope).DeleteScope(&cur_scope);
    }
  }
};

class WhileGradOpDescMaker : public framework::SingleGradOpDescMaker {
 public:
  using framework::SingleGradOpDescMaker::SingleGradOpDescMaker;

 protected:
  std::unique_ptr<framework::OpDesc> Apply() const override {
    auto *while_grad = new framework::OpDesc();
    while_grad->SetType("while_grad");
    while_grad->SetInput(kX, Input(kX));
    while_grad->SetInput(kOutputs, Output(kOutputs));
    while_grad->SetInput(kStepScopes, Output(kStepScopes));

    auto *grad_block = this->grad_block_[0];
    auto *fwd_block = grad_block->ForwardBlock();
    auto *parent_block = grad_block->ParentBlock();

    // Not all of IGs will be generated by inner gradient operators of while op.
    // Ignore IGs that is not generated by the inside block.
    std::unordered_set<std::string> inner_op_outputs;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &oname : op->OutputArgumentNames()) {
        inner_op_outputs.insert(oname);
      }
    }
    auto igs = InputGrad(kX, /*do not drop empty gradient*/ false);
    for (auto &each_ig : igs) {
      if (inner_op_outputs.find(each_ig) == inner_op_outputs.end()) {
        VLOG(8) << "Ignore " << each_ig;
        each_ig = framework::kEmptyVarName;
      }
    }
    while_grad->SetOutput(framework::GradVarName(kX), igs);

    // OG should be re-calculated by step blocks, since many outputs of while op
    // do not need to calculate gradients.
    std::unordered_set<std::string> block_ins;
    block_ins.reserve(Input(kX).size() + Output(kOutputs).size());
    for (auto &p : Input(kX)) {
      block_ins.insert(p);
    }
    for (auto &o : Output(kOutputs)) {
      block_ins.insert(o);
    }
    std::unordered_set<std::string> output_grads;
    for (const auto *op : grad_block->AllOps()) {
      for (auto &input_name : op->InputArgumentNames()) {
        // If the input of Op has been recorded or is generated by the forward
        // block, do not make it as input again.

        // The input is located in I/O or other op's outputs or the variable is
        // located in grad_block's parents
        if (block_ins.find(input_name) != block_ins.end() ||
            (fwd_block->FindVarRecursive(input_name) != nullptr ||
             parent_block->FindVarRecursive(input_name) != nullptr)) {
          continue;
        }
        output_grads.insert(input_name);
      }
      for (auto &output_name : op->OutputArgumentNames()) {
        block_ins.insert(output_name);
      }
    }

    std::vector<std::string> output_grads_list;
    output_grads_list.resize(output_grads.size());
    std::copy(output_grads.begin(), output_grads.end(),
              output_grads_list.begin());
    while_grad->SetInput(framework::GradVarName(kOutputs), output_grads_list);

    while_grad->SetAttrMap(this->Attrs());
    while_grad->SetBlockAttr(kStepBlock, *grad_block);
    // record the original output gradient names, since the gradient name of
    // while operator could be renamed.
    while_grad->SetAttr("original_output_grad", output_grads_list);

    return std::unique_ptr<framework::OpDesc>(while_grad);
  }
};

class WhileGradOpVarTypeInference : public framework::VarTypeInference {
 public:
  void operator()(const framework::OpDesc &op_desc,
                  framework::BlockDesc *block) const override {
    auto p_names = op_desc.Input(kX);
    auto pg_names = op_desc.Output(framework::GradVarName(kX));

    for (size_t i = 0; i < p_names.size(); ++i) {
      auto &p_var = detail::Ref(block->FindVarRecursive(p_names[i]));
      auto *g_var = block->FindVarRecursive(pg_names[i]);
      if (g_var != nullptr) {  // Gradient could be @EMPTY@
        VLOG(5) << "Setting " << pg_names[i] << " following " << p_names[i]
                << " type: " << p_var.GetType();
        g_var->SetType(p_var.GetType());
        g_var->SetDataType(p_var.GetDataType());
      }
    }
  }
};

class WhileGradOpShapeInference : public framework::InferShapeBase {
 public:
  void operator()(framework::InferShapeContext *ctx) const override {
    ctx->HasInputs(kX);
    ctx->HasOutputs(framework::GradVarName(kX));
    ctx->HasInputs(kOutputs);
    ctx->HasInputs(framework::GradVarName(kOutputs));

    auto p_names = ctx->Inputs(kX);
    auto pg_names = ctx->Outputs(kXGRAD);
    auto var_types = ctx->GetInputsVarType(kX);
    std::vector<std::string> names_to_set;
    std::vector<framework::DDim> dims_to_set;
    for (size_t i = 0; i < p_names.size(); ++i) {
      if (pg_names[i] == framework::kEmptyVarName) {
        continue;
      }
      auto dims = ctx->GetInputsElementDim(kX, i);
      if (var_types[i] == framework::proto::VarType::LOD_TENSOR) {
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      } else if (var_types[i] == framework::proto::VarType::LOD_TENSOR_ARRAY) {
        // not sure how to set the dim of LOD_TENSOR_ARRAY
        names_to_set.push_back(pg_names[i]);
        dims_to_set.push_back(dims);
      }
    }
    ctx->SetDims(names_to_set, dims_to_set);
  }
};

}  // namespace operators
}  // namespace paddle

REGISTER_OPERATOR(while, paddle::operators::WhileOp,
                  paddle::operators::WhileOpMaker,
                  paddle::operators::WhileGradOpDescMaker);
REGISTER_OPERATOR(while_grad, paddle::operators::WhileGradOp,
                  paddle::operators::WhileGradOpShapeInference,
                  paddle::operators::WhileGradOpVarTypeInference);
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Marat "Morion" Talipov <morion.self@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "configpaneldialog.h"
#include "ui_configpaneldialog.h"
#include "../razorpanel.h"

#include <QDebug>
#include <QtGui/QDesktopWidget>

#include <razorqt/xfitman.h>

struct ScreenPosition
{
    int screen;
    IRazorPanel::Position position;
};
Q_DECLARE_METATYPE(ScreenPosition)

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

 ************************************************/
ConfigPanelDialog *ConfigPanelDialog::exec(RazorPanel *panel)
{
    ConfigPanelDialog *dialog =
        panel->findChild<ConfigPanelDialog*>();

    if (!dialog)
    {
        dialog = new ConfigPanelDialog(panel, panel);
    }

    dialog->show();
    dialog->raise();
    dialog->activateWindow();
    xfitMan().raiseWindow(dialog->effectiveWinId());
    xfitMan().moveWindowToDesktop(dialog->effectiveWinId(), qMax(xfitMan().getActiveDesktop(), 0));
    return dialog;
}

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

 ************************************************/
ConfigPanelDialog::ConfigPanelDialog(RazorPanel *panel, QWidget *parent):
    RazorConfigDialog(tr("Configure panel"), panel->settings(), parent)
{
    setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
    setAttribute(Qt::WA_DeleteOnClose);

    ConfigPanelWidget* page = new ConfigPanelWidget(panel, this);
    addPage(page, tr("Configure panel"));
    connect(this, SIGNAL(reset()), page, SLOT(reset()));
}

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

 ************************************************/
ConfigPanelWidget::ConfigPanelWidget(RazorPanel *panel, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ConfigPanelWidget),
    mPanel(panel)
{
    ui->setupUi(this);
    fillComboBox_position();
    fillComboBox_alignment();

    mOldLineSize  = mPanel->lineSize();
    mOldLineCount = mPanel->lineCount();

    mOldLength = mPanel->length();
    mOldLengthInPercents = mPanel->lengthInPercents();

    mOldAlignment = mPanel->alignment();

    mOldScreenNum = mPanel->screenNum();
    mScreenNum = mOldScreenNum;

    mOldPosition = mPanel->position();
    mPosition = mOldPosition;

    reset();

    connect(ui->spinBox_lineSize,   SIGNAL(valueChanged(int)), this, SLOT(editChanged()));
    connect(ui->spinBox_lineCount,  SIGNAL(valueChanged(int)), this, SLOT(editChanged()));

    connect(ui->spinBox_length,     SIGNAL(valueChanged(int)), this, SLOT(editChanged()));
    connect(ui->comboBox_lenghtType,SIGNAL(activated(int)),    this, SLOT(widthTypeChanged()));

    connect(ui->comboBox_alignment, SIGNAL(activated(int)),    this, SLOT(editChanged()));
    connect(ui->comboBox_position,  SIGNAL(activated(int)),    this, SLOT(posittionChanged()));
}

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

 ************************************************/
void ConfigPanelWidget::reset()
{
    ui->spinBox_lineSize->setValue(mOldLineSize);
    ui->spinBox_lineCount->setValue(mOldLineCount);

    ui->comboBox_position->setCurrentIndex(indexForPosition(mOldScreenNum, mOldPosition));

    fillComboBox_alignment();
    ui->comboBox_alignment->setCurrentIndex(mOldAlignment + 1);

    ui->comboBox_lenghtType->setCurrentIndex(mOldLengthInPercents ? 0 : 1);
    widthTypeChanged();
    ui->spinBox_length->setValue(mOldLength);
}

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

 ************************************************/
void ConfigPanelWidget::fillComboBox_position()
{
    int screenCount = QApplication::desktop()->screenCount();
    if (screenCount == 1)
    {
        addPosition(tr("Top of desktop"), 0, RazorPanel::PositionTop);
        addPosition(tr("Left of desktop"), 0, RazorPanel::PositionLeft);
        addPosition(tr("Right of desktop"), 0, RazorPanel::PositionRight);
        addPosition(tr("Bottom of desktop"), 0, RazorPanel::PositionBottom);
    }
    else
    {
        for (int screenNum = 0; screenNum < screenCount; screenNum++)
        {
            if (screenNum)
                ui->comboBox_position->insertSeparator(9999);

            addPosition(tr("Top of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionTop);
            addPosition(tr("Left of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionLeft);
            addPosition(tr("Right of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionRight);
            addPosition(tr("Bottom of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionBottom);
        }
    }
}

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

 ************************************************/
void ConfigPanelWidget::fillComboBox_alignment()
{
    ui->comboBox_alignment->setItemData(0, QVariant(RazorPanel::AlignmentLeft));
    ui->comboBox_alignment->setItemData(1, QVariant(RazorPanel::AlignmentCenter));
    ui->comboBox_alignment->setItemData(2,  QVariant(RazorPanel::AlignmentRight));

    if (mPosition   == IRazorPanel::PositionTop ||
        mPosition   == IRazorPanel::PositionBottom)
    {
        ui->comboBox_alignment->setItemText(0, tr("Left"));
        ui->comboBox_alignment->setItemText(1, tr("Center"));
        ui->comboBox_alignment->setItemText(2, tr("Right"));
    }
    else
    {
        ui->comboBox_alignment->setItemText(0, tr("Top"));
        ui->comboBox_alignment->setItemText(1, tr("Center"));
        ui->comboBox_alignment->setItemText(2, tr("Bottom"));
    };
}

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

 ************************************************/
void ConfigPanelWidget::addPosition(const QString& name, int screen, RazorPanel::Position position)
{
    if (RazorPanel::canPlacedOn(screen, position))
        ui->comboBox_position->addItem(name, QVariant::fromValue((ScreenPosition){screen, position}));
}

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

 ************************************************/
int ConfigPanelWidget::indexForPosition(int screen, IRazorPanel::Position position)
{
    for (int i = 0; i < ui->comboBox_position->count(); i++)
    {
        ScreenPosition sp = ui->comboBox_position->itemData(i).value<ScreenPosition>();
        if (screen == sp.screen && position == sp.position)
            return i;
    }
    return -1;
}

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

 ************************************************/
ConfigPanelWidget::~ConfigPanelWidget()
{
    delete ui;
}

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

 ************************************************/
void ConfigPanelWidget::editChanged()
{
    mPanel->setLineSize(ui->spinBox_lineSize->value());
    mPanel->setLineCount(ui->spinBox_lineCount->value());

    mPanel->setLength(ui->spinBox_length->value(),
                      ui->comboBox_lenghtType->currentIndex() == 0);

    RazorPanel::Alignment align = RazorPanel::Alignment(
                ui->comboBox_alignment->itemData(
                    ui->comboBox_alignment->currentIndex()
                    ).toInt());

    mPanel->setAlignment(align);

    mPanel->setPosition(mScreenNum, mPosition);
}

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

 ************************************************/
void ConfigPanelWidget::widthTypeChanged()
{
    int max = getMaxLength();

    if (ui->comboBox_lenghtType->currentIndex() == 0)
    {
        // Percents .............................
        int v = ui->spinBox_length->value() * 100.0 / max;
        ui->spinBox_length->setMaximum(100);
        ui->spinBox_length->setValue(v);
    }
    else
    {
        // Pixels ...............................
        int v =  max / 100.0 * ui->spinBox_length->value();
        ui->spinBox_length->setMaximum(max);
        ui->spinBox_length->setValue(v);
    }
}

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

 ************************************************/
int ConfigPanelWidget::getMaxLength()
{
    QDesktopWidget* dw = QApplication::desktop();

    if (mPosition == IRazorPanel::PositionTop ||
        mPosition == IRazorPanel::PositionBottom)
    {
        return dw->screenGeometry(mScreenNum).width();
    }
    else
    {
        return dw->screenGeometry(mScreenNum).height();
    }
}

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

 ************************************************/
void ConfigPanelWidget::posittionChanged()
{
    ScreenPosition sp = ui->comboBox_position->itemData(
                ui->comboBox_position->currentIndex()).value<ScreenPosition>();

    bool updateAlig = (sp.position == IRazorPanel::PositionTop ||
                       sp.position == IRazorPanel::PositionBottom) !=
                      (mPosition   == IRazorPanel::PositionTop ||
                       mPosition   == IRazorPanel::PositionBottom);

    int oldMax = getMaxLength();
    mPosition = sp.position;
    mScreenNum = sp.screen;
    int newMax = getMaxLength();

    if (ui->comboBox_lenghtType->currentIndex() == 1 &&
        oldMax != newMax)
    {
        // Pixels ...............................
        int v = ui->spinBox_length->value() * 1.0 * newMax / oldMax;
        ui->spinBox_length->setMaximum(newMax);
        ui->spinBox_length->setValue(v);
    }

    if (updateAlig)
        fillComboBox_alignment();

    editChanged();
}
<commit_msg>razorqt-panel/panel: Save settings right after the close button clicked<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * Razor - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2010-2011 Razor team
 * Authors:
 *   Marat "Morion" Talipov <morion.self@gmail.com>
 *
 * This program or library is free software; you can redistribute it
 * and/or modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "configpaneldialog.h"
#include "ui_configpaneldialog.h"
#include "../razorpanel.h"

#include <QDebug>
#include <QtGui/QDesktopWidget>

#include <razorqt/xfitman.h>

struct ScreenPosition
{
    int screen;
    IRazorPanel::Position position;
};
Q_DECLARE_METATYPE(ScreenPosition)

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

 ************************************************/
ConfigPanelDialog *ConfigPanelDialog::exec(RazorPanel *panel)
{
    ConfigPanelDialog *dialog =
        panel->findChild<ConfigPanelDialog*>();

    if (!dialog)
    {
        dialog = new ConfigPanelDialog(panel, panel);
    }

    dialog->show();
    dialog->raise();
    dialog->activateWindow();
    xfitMan().raiseWindow(dialog->effectiveWinId());
    xfitMan().moveWindowToDesktop(dialog->effectiveWinId(), qMax(xfitMan().getActiveDesktop(), 0));
    return dialog;
}

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

 ************************************************/
ConfigPanelDialog::ConfigPanelDialog(RazorPanel *panel, QWidget *parent):
    RazorConfigDialog(tr("Configure panel"), panel->settings(), parent)
{
    setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
    setAttribute(Qt::WA_DeleteOnClose);

    ConfigPanelWidget* page = new ConfigPanelWidget(panel, this);
    addPage(page, tr("Configure panel"));
    connect(this, SIGNAL(reset()), page, SLOT(reset()));
    connect(this, SIGNAL(accepted()), panel, SLOT(saveSettings(false)));
}

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

 ************************************************/
ConfigPanelWidget::ConfigPanelWidget(RazorPanel *panel, QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ConfigPanelWidget),
    mPanel(panel)
{
    ui->setupUi(this);
    fillComboBox_position();
    fillComboBox_alignment();

    mOldLineSize  = mPanel->lineSize();
    mOldLineCount = mPanel->lineCount();

    mOldLength = mPanel->length();
    mOldLengthInPercents = mPanel->lengthInPercents();

    mOldAlignment = mPanel->alignment();

    mOldScreenNum = mPanel->screenNum();
    mScreenNum = mOldScreenNum;

    mOldPosition = mPanel->position();
    mPosition = mOldPosition;

    reset();

    connect(ui->spinBox_lineSize,   SIGNAL(valueChanged(int)), this, SLOT(editChanged()));
    connect(ui->spinBox_lineCount,  SIGNAL(valueChanged(int)), this, SLOT(editChanged()));

    connect(ui->spinBox_length,     SIGNAL(valueChanged(int)), this, SLOT(editChanged()));
    connect(ui->comboBox_lenghtType,SIGNAL(activated(int)),    this, SLOT(widthTypeChanged()));

    connect(ui->comboBox_alignment, SIGNAL(activated(int)),    this, SLOT(editChanged()));
    connect(ui->comboBox_position,  SIGNAL(activated(int)),    this, SLOT(posittionChanged()));
}

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

 ************************************************/
void ConfigPanelWidget::reset()
{
    ui->spinBox_lineSize->setValue(mOldLineSize);
    ui->spinBox_lineCount->setValue(mOldLineCount);

    ui->comboBox_position->setCurrentIndex(indexForPosition(mOldScreenNum, mOldPosition));

    fillComboBox_alignment();
    ui->comboBox_alignment->setCurrentIndex(mOldAlignment + 1);

    ui->comboBox_lenghtType->setCurrentIndex(mOldLengthInPercents ? 0 : 1);
    widthTypeChanged();
    ui->spinBox_length->setValue(mOldLength);
}

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

 ************************************************/
void ConfigPanelWidget::fillComboBox_position()
{
    int screenCount = QApplication::desktop()->screenCount();
    if (screenCount == 1)
    {
        addPosition(tr("Top of desktop"), 0, RazorPanel::PositionTop);
        addPosition(tr("Left of desktop"), 0, RazorPanel::PositionLeft);
        addPosition(tr("Right of desktop"), 0, RazorPanel::PositionRight);
        addPosition(tr("Bottom of desktop"), 0, RazorPanel::PositionBottom);
    }
    else
    {
        for (int screenNum = 0; screenNum < screenCount; screenNum++)
        {
            if (screenNum)
                ui->comboBox_position->insertSeparator(9999);

            addPosition(tr("Top of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionTop);
            addPosition(tr("Left of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionLeft);
            addPosition(tr("Right of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionRight);
            addPosition(tr("Bottom of desktop %1").arg(screenNum +1), screenNum, RazorPanel::PositionBottom);
        }
    }
}

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

 ************************************************/
void ConfigPanelWidget::fillComboBox_alignment()
{
    ui->comboBox_alignment->setItemData(0, QVariant(RazorPanel::AlignmentLeft));
    ui->comboBox_alignment->setItemData(1, QVariant(RazorPanel::AlignmentCenter));
    ui->comboBox_alignment->setItemData(2,  QVariant(RazorPanel::AlignmentRight));

    if (mPosition   == IRazorPanel::PositionTop ||
        mPosition   == IRazorPanel::PositionBottom)
    {
        ui->comboBox_alignment->setItemText(0, tr("Left"));
        ui->comboBox_alignment->setItemText(1, tr("Center"));
        ui->comboBox_alignment->setItemText(2, tr("Right"));
    }
    else
    {
        ui->comboBox_alignment->setItemText(0, tr("Top"));
        ui->comboBox_alignment->setItemText(1, tr("Center"));
        ui->comboBox_alignment->setItemText(2, tr("Bottom"));
    };
}

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

 ************************************************/
void ConfigPanelWidget::addPosition(const QString& name, int screen, RazorPanel::Position position)
{
    if (RazorPanel::canPlacedOn(screen, position))
        ui->comboBox_position->addItem(name, QVariant::fromValue((ScreenPosition){screen, position}));
}

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

 ************************************************/
int ConfigPanelWidget::indexForPosition(int screen, IRazorPanel::Position position)
{
    for (int i = 0; i < ui->comboBox_position->count(); i++)
    {
        ScreenPosition sp = ui->comboBox_position->itemData(i).value<ScreenPosition>();
        if (screen == sp.screen && position == sp.position)
            return i;
    }
    return -1;
}

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

 ************************************************/
ConfigPanelWidget::~ConfigPanelWidget()
{
    delete ui;
}

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

 ************************************************/
void ConfigPanelWidget::editChanged()
{
    mPanel->setLineSize(ui->spinBox_lineSize->value());
    mPanel->setLineCount(ui->spinBox_lineCount->value());

    mPanel->setLength(ui->spinBox_length->value(),
                      ui->comboBox_lenghtType->currentIndex() == 0);

    RazorPanel::Alignment align = RazorPanel::Alignment(
                ui->comboBox_alignment->itemData(
                    ui->comboBox_alignment->currentIndex()
                    ).toInt());

    mPanel->setAlignment(align);

    mPanel->setPosition(mScreenNum, mPosition);
}

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

 ************************************************/
void ConfigPanelWidget::widthTypeChanged()
{
    int max = getMaxLength();

    if (ui->comboBox_lenghtType->currentIndex() == 0)
    {
        // Percents .............................
        int v = ui->spinBox_length->value() * 100.0 / max;
        ui->spinBox_length->setMaximum(100);
        ui->spinBox_length->setValue(v);
    }
    else
    {
        // Pixels ...............................
        int v =  max / 100.0 * ui->spinBox_length->value();
        ui->spinBox_length->setMaximum(max);
        ui->spinBox_length->setValue(v);
    }
}

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

 ************************************************/
int ConfigPanelWidget::getMaxLength()
{
    QDesktopWidget* dw = QApplication::desktop();

    if (mPosition == IRazorPanel::PositionTop ||
        mPosition == IRazorPanel::PositionBottom)
    {
        return dw->screenGeometry(mScreenNum).width();
    }
    else
    {
        return dw->screenGeometry(mScreenNum).height();
    }
}

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

 ************************************************/
void ConfigPanelWidget::posittionChanged()
{
    ScreenPosition sp = ui->comboBox_position->itemData(
                ui->comboBox_position->currentIndex()).value<ScreenPosition>();

    bool updateAlig = (sp.position == IRazorPanel::PositionTop ||
                       sp.position == IRazorPanel::PositionBottom) !=
                      (mPosition   == IRazorPanel::PositionTop ||
                       mPosition   == IRazorPanel::PositionBottom);

    int oldMax = getMaxLength();
    mPosition = sp.position;
    mScreenNum = sp.screen;
    int newMax = getMaxLength();

    if (ui->comboBox_lenghtType->currentIndex() == 1 &&
        oldMax != newMax)
    {
        // Pixels ...............................
        int v = ui->spinBox_length->value() * 1.0 * newMax / oldMax;
        ui->spinBox_length->setMaximum(newMax);
        ui->spinBox_length->setValue(v);
    }

    if (updateAlig)
        fillComboBox_alignment();

    editChanged();
}
<|endoftext|>


<commit_before>#include "zbs/_error.hh"
#include <cstdio>
#include <cstdlib>
#include <cstdarg>

#include "zbs/fmt.hh"

namespace zbs {

//============================================================================
// error
//============================================================================

error_code error::code() const {
	return _code;
}

void error::set(error_code code, const char*, ...) {
	_code = code;
}

const char *error::what() const {
	return "";
}

error::operator bool() const {
	return (bool)_code;
}

static error_domain generic_error_domain;
error_code generic_error_code(generic_error_domain, 1);

//============================================================================
// verbose_error
//============================================================================

verbose_error::~verbose_error() {
	if (_message) {
		::free(_message);
	}
}

void verbose_error::set(error_code code, const char *format, ...) {
	va_list vl;
	_code = code;

	va_start(vl, format);
	auto s = fmt::vsprintf(format, vl);
	va_end(vl);
	_message = s.detach_unsafe();
}

const char *verbose_error::what() const {
	if (_message) {
		return _message;
	}
	return "";
}

//============================================================================
// abort_error
//============================================================================

void abort_error::set(error_code, const char *format, ...) {
	fprintf(stderr, "abort: ");
	va_list vl;
	va_start(vl, format);
	vfprintf(stderr, format, vl);
	va_end(vl);
	fprintf(stderr, "\n");
	abort();
}

abort_error default_error;

} // namespace zbs
<commit_msg>Make generic_error_code visible..<commit_after>#include "zbs/_error.hh"
#include <cstdio>
#include <cstdlib>
#include <cstdarg>

#include "zbs/fmt.hh"

namespace zbs {

//============================================================================
// error
//============================================================================

error_code error::code() const {
	return _code;
}

void error::set(error_code code, const char*, ...) {
	_code = code;
}

const char *error::what() const {
	return "";
}

error::operator bool() const {
	return (bool)_code;
}

error_domain generic_error_domain;
error_code generic_error_code(generic_error_domain, 1);

//============================================================================
// verbose_error
//============================================================================

verbose_error::~verbose_error() {
	if (_message) {
		::free(_message);
	}
}

void verbose_error::set(error_code code, const char *format, ...) {
	va_list vl;
	_code = code;

	va_start(vl, format);
	auto s = fmt::vsprintf(format, vl);
	va_end(vl);
	_message = s.detach_unsafe();
}

const char *verbose_error::what() const {
	if (_message) {
		return _message;
	}
	return "";
}

//============================================================================
// abort_error
//============================================================================

void abort_error::set(error_code, const char *format, ...) {
	fprintf(stderr, "abort: ");
	va_list vl;
	va_start(vl, format);
	vfprintf(stderr, format, vl);
	va_end(vl);
	fprintf(stderr, "\n");
	abort();
}

abort_error default_error;

} // namespace zbs
<|endoftext|>


<commit_before>/*! \file */ // Copyright 2011-2020 Tyler Gilbert and Stratify Labs, Inc; see LICENSE.md for rights.
#include <cstring>
#include <mcu/types.h>
#include "api/ApiObject.hpp"

#include "var/String.hpp"

#if defined __link
#define API_MINIMUM_CHUNK_SIZE 1024
#define API_MALLOC_CHUNK_SIZE 1024
#else
#define API_MINIMUM_CHUNK_SIZE 52
#define API_MALLOC_CHUNK_SIZE 64
#endif

using namespace api;

const char * ApiInfo::git_hash(){
	return SOS_GIT_HASH;
}

const char * ApiInfo::operating_system_name(){
#if defined __link

#if defined __macosx
	return "macosx";
#endif
#if defined __win32
	return "windows";
#endif
#if defined __linux
	return "linux";
#endif

#else
	return "stratifyos";
#endif

	return "unknown";
}

bool ApiInfo::is_windows(){ return strcmp(operating_system_name(), "windows") == 0; }
bool ApiInfo::is_macosx(){ return strcmp(operating_system_name(), "macosx") == 0; }
bool ApiInfo::is_linux(){ return strcmp(operating_system_name(), "linux") == 0; }
bool ApiInfo::is_stratify_os(){ return strcmp(operating_system_name(), "stratifyos") == 0; }

u32 ApiInfo::malloc_start_chunk_size(){ return API_MINIMUM_CHUNK_SIZE; }
u32 ApiInfo::malloc_chunk_size(){ return API_MALLOC_CHUNK_SIZE; }

const char * ApiInfo::user_data_path(){

#if defined __link
	static var::String result;
	result.clear();
	char * path;
	if( is_windows() ){
		path = getenv("LocalAppData");
		result << path;
	}

	if( is_macosx() ){
		//read env home variable
		path = getenv("HOME");
		result << path << "/Library/Application Support";
	}

	return result.cstring();
#else
	return "/home";
#endif
}

const char * api::get_error_code_description(s32 ec){
	switch(ec){
		case error_code_flag_calc: return "error_code_flag_calc";
		case error_code_flag_chrono: return "error_code_flag_chrono";
		case error_code_flag_crypto: return "error_code_flag_crypto";
		case error_code_flag_fmt: return "error_code_flag_fmt";
		case error_code_flag_fs: return "error_code_flag_fs";
		case error_code_flag_hal: return "error_code_flag_hal";
		case error_code_flag_inet: return "error_code_flag_inet";
		case error_code_flag_sgfx: return "error_code_flag_sgfx";
		case error_code_flag_sys: return "error_code_flag_sys";
		case error_code_flag_test: return "error_code_flag_test";
		case error_code_flag_ux: return "error_code_flag_ux";
		case error_code_flag_var: return "error_code_flag_var";

		case error_code_crypto_size_mismatch: return "error_code_crypto_size_mismatch";
		case error_code_crypto_bad_block_size: return "error_code_crypto_bad_block_size";
		case error_code_crypto_operation_failed: return "error_code_crypto_operation_failed";
		case error_code_crypto_missing_api: return "error_code_crypto_missing_api";
		case error_code_crypto_unsupported_operation: return "error_code_crypto_unsupported_operation";
		case error_code_crypto_bad_iv_size: return "error_code_crypto_bad_iv_size";

		case error_code_fs_failed_to_open: return "error_code_fs_failed_to_open";
		case error_code_fs_failed_to_read: return "error_code_fs_failed_to_read";
		case error_code_fs_failed_to_write: return "error_code_fs_failed_to_write";
		case error_code_fs_failed_to_seek: return "error_code_fs_failed_to_seek";
		case error_code_fs_failed_to_create: return "error_code_fs_failed_to_create";
		case error_code_fs_failed_to_stat: return "error_code_fs_failed_to_stat";
		case error_code_fs_unsupported_operation: return "error_code_fs_unsupported_operation";
		case error_code_fs_bad_descriptor: return "error_code_fs_bad_descriptor";
		case error_code_fs_cant_read: return "error_code_fs_cant_read";
		case error_code_fs_cant_write: return "error_code_fs_cant_write";
		case error_code_fs_cant_write_read_only: return "error_code_fs_cant_write_read_only";
		case error_code_fs_cant_write_append_only: return "error_code_fs_cant_write_append_only";
		case error_code_fs_not_open: return "error_code_fs_not_open";
		case error_code_fs_failed_to_close: return "error_code_fs_failed_to_close";

		case error_code_inet_failed_to_create_socket: return "error_code_inet_failed_to_create_socket";
		case error_code_inet_failed_to_connect_to_socket: return "error_code_inet_failed_to_connect_to_socket";
		case error_code_inet_failed_to_write_header: return "error_code_inet_failed_to_write_header";
		case error_code_inet_failed_to_write_data: return "error_code_inet_failed_to_write_data";
		case error_code_inet_failed_to_write_incoming_data_to_file: return "error_code_inet_failed_to_write_incoming_data_to_file";
		case error_code_inet_failed_to_find_address: return "error_code_inet_failed_to_find_address";
		case error_code_inet_failed_to_get_status_code: return "error_code_inet_failed_to_get_status_code";
		case error_code_inet_failed_to_get_header: return "error_code_inet_failed_to_get_header";
		case error_code_inet_failed_wrong_domain: return "error_code_inet_failed_wrong_domain";
	}
	return "unknown error code";
}
<commit_msg>Update ApiObject.cpp<commit_after>/*! \file */ // Copyright 2011-2020 Tyler Gilbert and Stratify Labs, Inc; see LICENSE.md for rights.
#include <cstring>
#include <mcu/types.h>
#include "api/ApiObject.hpp"

#include "var/String.hpp"

#if defined __link
#define API_MINIMUM_CHUNK_SIZE 1024
#define API_MALLOC_CHUNK_SIZE 1024
#else
#define API_MINIMUM_CHUNK_SIZE 52
#define API_MALLOC_CHUNK_SIZE 64
#endif

using namespace api;

const char * ApiInfo::git_hash(){
	return SOS_GIT_HASH;
}

const char * ApiInfo::operating_system_name(){
#if defined __link

#if defined __macosx
	return "macosx";
#endif
#if defined __win32
	return "windows";
#endif
#if defined __linux
	return "linux";
#endif

#else
	return "stratifyos";
#endif

	return "unknown";
}

bool ApiInfo::is_windows(){ return strcmp(operating_system_name(), "windows") == 0; }
bool ApiInfo::is_macosx(){ return strcmp(operating_system_name(), "macosx") == 0; }
bool ApiInfo::is_linux(){ return strcmp(operating_system_name(), "linux") == 0; }
bool ApiInfo::is_stratify_os(){ return strcmp(operating_system_name(), "stratifyos") == 0; }

u32 ApiInfo::malloc_start_chunk_size(){ return API_MINIMUM_CHUNK_SIZE; }
u32 ApiInfo::malloc_chunk_size(){ return API_MALLOC_CHUNK_SIZE; }

const char * ApiInfo::user_data_path(){

#if defined __link
	static var::String result;
	result.clear();
	char * path;
	if( is_windows() ){
		path = getenv("LocalAppData");
		result << path;
	}

	if( is_macosx() ){
		//read env home variable
		path = getenv("HOME");
		result << path << "/Library/Application Support";
	}

	if( is_linux() ){
		path = getenv("HOME");
		result << path << "/.sl";
	}

	return result.cstring();
#else
	return "/home";
#endif
}

const char * api::get_error_code_description(s32 ec){
	switch(ec){
		case error_code_flag_calc: return "error_code_flag_calc";
		case error_code_flag_chrono: return "error_code_flag_chrono";
		case error_code_flag_crypto: return "error_code_flag_crypto";
		case error_code_flag_fmt: return "error_code_flag_fmt";
		case error_code_flag_fs: return "error_code_flag_fs";
		case error_code_flag_hal: return "error_code_flag_hal";
		case error_code_flag_inet: return "error_code_flag_inet";
		case error_code_flag_sgfx: return "error_code_flag_sgfx";
		case error_code_flag_sys: return "error_code_flag_sys";
		case error_code_flag_test: return "error_code_flag_test";
		case error_code_flag_ux: return "error_code_flag_ux";
		case error_code_flag_var: return "error_code_flag_var";

		case error_code_crypto_size_mismatch: return "error_code_crypto_size_mismatch";
		case error_code_crypto_bad_block_size: return "error_code_crypto_bad_block_size";
		case error_code_crypto_operation_failed: return "error_code_crypto_operation_failed";
		case error_code_crypto_missing_api: return "error_code_crypto_missing_api";
		case error_code_crypto_unsupported_operation: return "error_code_crypto_unsupported_operation";
		case error_code_crypto_bad_iv_size: return "error_code_crypto_bad_iv_size";

		case error_code_fs_failed_to_open: return "error_code_fs_failed_to_open";
		case error_code_fs_failed_to_read: return "error_code_fs_failed_to_read";
		case error_code_fs_failed_to_write: return "error_code_fs_failed_to_write";
		case error_code_fs_failed_to_seek: return "error_code_fs_failed_to_seek";
		case error_code_fs_failed_to_create: return "error_code_fs_failed_to_create";
		case error_code_fs_failed_to_stat: return "error_code_fs_failed_to_stat";
		case error_code_fs_unsupported_operation: return "error_code_fs_unsupported_operation";
		case error_code_fs_bad_descriptor: return "error_code_fs_bad_descriptor";
		case error_code_fs_cant_read: return "error_code_fs_cant_read";
		case error_code_fs_cant_write: return "error_code_fs_cant_write";
		case error_code_fs_cant_write_read_only: return "error_code_fs_cant_write_read_only";
		case error_code_fs_cant_write_append_only: return "error_code_fs_cant_write_append_only";
		case error_code_fs_not_open: return "error_code_fs_not_open";
		case error_code_fs_failed_to_close: return "error_code_fs_failed_to_close";

		case error_code_inet_failed_to_create_socket: return "error_code_inet_failed_to_create_socket";
		case error_code_inet_failed_to_connect_to_socket: return "error_code_inet_failed_to_connect_to_socket";
		case error_code_inet_failed_to_write_header: return "error_code_inet_failed_to_write_header";
		case error_code_inet_failed_to_write_data: return "error_code_inet_failed_to_write_data";
		case error_code_inet_failed_to_write_incoming_data_to_file: return "error_code_inet_failed_to_write_incoming_data_to_file";
		case error_code_inet_failed_to_find_address: return "error_code_inet_failed_to_find_address";
		case error_code_inet_failed_to_get_status_code: return "error_code_inet_failed_to_get_status_code";
		case error_code_inet_failed_to_get_header: return "error_code_inet_failed_to_get_header";
		case error_code_inet_failed_wrong_domain: return "error_code_inet_failed_wrong_domain";
	}
	return "unknown error code";
}
<|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS impress17 (1.46.46); FILE MERGED 2004/10/29 11:35:37 cl 1.46.46.1: #i13778# convert twips to 100th mm for connector ends in writer<commit_after><|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS tbe19 (1.58.6); FILE MERGED 2005/02/04 17:18:06 tbe 1.58.6.2: RESYNC: (1.58-1.60); FILE MERGED 2005/01/27 17:02:36 tbe 1.58.6.1: #i40118# undo & restore in basic<commit_after><|endoftext|>


<commit_before><commit_msg>New Attribute handler<commit_after><|endoftext|>


<commit_before><commit_msg>INTEGRATION: CWS sixtyfour11 (1.145.112); FILE MERGED 2007/02/13 13:55:26 kendy 1.145.112.1: #i74451# Fix type size mismatch in ww8 import on 64bit<commit_after><|endoftext|>


<commit_before>/*

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

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

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

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

*/

#include "libtorrent/pch.hpp"
#include "libtorrent/assert.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			TORRENT_ASSERT(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_in);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_out);
			TORRENT_ASSERT(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << strerror(errno);
				throw file_error(msg.str());
			}
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<commit_msg>fixed static assert being hit on linux systems<commit_after>/*

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

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

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

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

*/

#include "libtorrent/pch.hpp"

#ifdef _WIN32
// windows part
#include "libtorrent/utf8.hpp"

#include <io.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef _MODE_T_
typedef int mode_t;
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#else
// unix part
#define _FILE_OFFSET_BITS 64
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include <boost/static_assert.hpp>
// make sure the _FILE_OFFSET_BITS define worked
// on this platform
BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8);

#endif

#include <boost/filesystem/operations.hpp>
#include "libtorrent/file.hpp"
#include <sstream>

#ifndef O_BINARY
#define O_BINARY 0
#endif

#ifndef O_RANDOM
#define O_RANDOM 0
#endif

#ifdef UNICODE
#include "libtorrent/storage.hpp"
#endif

#include "libtorrent/assert.hpp"

namespace
{
	enum { mode_in = 1, mode_out = 2 };

	mode_t map_open_mode(int m)
	{
		if (m == (mode_in | mode_out)) return O_RDWR | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_out) return O_WRONLY | O_CREAT | O_BINARY | O_RANDOM;
		if (m == mode_in) return O_RDONLY | O_BINARY | O_RANDOM;
		TORRENT_ASSERT(false);
		return 0;
	}

#ifdef WIN32
	std::string utf8_native(std::string const& s)
	{
		try
		{
			std::wstring ws;
			libtorrent::utf8_wchar(s, ws);
			std::size_t size = wcstombs(0, ws.c_str(), 0);
			if (size == std::size_t(-1)) return s;
			std::string ret;
			ret.resize(size);
			size = wcstombs(&ret[0], ws.c_str(), size + 1);
			if (size == wchar_t(-1)) return s;
			ret.resize(size);
			return ret;
		}
		catch(std::exception)
		{
			return s;
		}
	}
#else
	std::string utf8_native(std::string const& s)
	{
		return s;
	}
#endif

}

namespace libtorrent
{

	namespace fs = boost::filesystem;

	const file::open_mode file::in(mode_in);
	const file::open_mode file::out(mode_out);

	const file::seek_mode file::begin(1);
	const file::seek_mode file::end(2);

	struct file::impl
	{
		impl()
			: m_fd(-1)
			, m_open_mode(0)
		{}

		impl(fs::path const& path, int mode)
			: m_fd(-1)
			, m_open_mode(0)
		{
			open(path, mode);
		}

		~impl()
		{
			close();
		}

		void open(fs::path const& path, int mode)
		{
			TORRENT_ASSERT(path.is_complete());
			close();
#if defined(_WIN32) && defined(UNICODE)
			std::wstring wpath(safe_convert(path.native_file_string()));
			m_fd = ::_wopen(
				wpath.c_str()
				, map_open_mode(mode)
				, S_IREAD | S_IWRITE);
#else
#ifdef _WIN32
			m_fd = ::_open(
#else
			m_fd = ::open(
#endif
				utf8_native(path.native_file_string()).c_str()
				, map_open_mode(mode)
#ifdef _WIN32
				, S_IREAD | S_IWRITE);
#else
				, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
#endif
#endif
			if (m_fd == -1)
			{
				std::stringstream msg;
				msg << "open failed: '" << path.native_file_string() << "'. "
					<< strerror(errno);
				throw file_error(msg.str());
			}
			m_open_mode = mode;
		}

		void close()
		{
			if (m_fd == -1) return;

#ifdef _WIN32
			::_close(m_fd);
#else
			::close(m_fd);
#endif
			m_fd = -1;
			m_open_mode = 0;
		}

		size_type read(char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_in);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			size_type ret = ::_read(m_fd, buf, num_bytes);
#else
			size_type ret = ::read(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "read failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type write(const char* buf, size_type num_bytes)
		{
			TORRENT_ASSERT(m_open_mode & mode_out);
			TORRENT_ASSERT(m_fd != -1);

			// TODO: Test this a bit more, what happens with random failures in
			// the files?
//			if ((rand() % 100) > 80)
//				throw file_error("debug");

#ifdef _WIN32
			size_type ret = ::_write(m_fd, buf, num_bytes);
#else
			size_type ret = ::write(m_fd, buf, num_bytes);
#endif
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "write failed: " << strerror(errno);
				throw file_error(msg.str());
			}
			return ret;
		}

		void set_size(size_type s)
		{
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
			if (ftruncate(m_fd, s) < 0)
			{
				std::stringstream msg;
				msg << "ftruncate failed: '" << strerror(errno);
				throw file_error(msg.str());
			}
#endif
		}

		size_type seek(size_type offset, int m = 1)
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

			int seekdir = (m == 1)?SEEK_SET:SEEK_END;
#ifdef _WIN32
			size_type ret = _lseeki64(m_fd, offset, seekdir);
#else
			size_type ret = lseek(m_fd, offset, seekdir);
#endif

			// For some strange reason this fails
			// on win32. Use windows specific file
			// wrapper instead.
			if (ret == -1)
			{
				std::stringstream msg;
				msg << "seek failed: '" << strerror(errno)
					<< "' fd: " << m_fd
					<< " offset: " << offset
					<< " seekdir: " << seekdir;
				throw file_error(msg.str());
			}
			return ret;
		}

		size_type tell()
		{
			TORRENT_ASSERT(m_open_mode);
			TORRENT_ASSERT(m_fd != -1);

#ifdef _WIN32
			return _telli64(m_fd);
#else
			return lseek(m_fd, 0, SEEK_CUR);
#endif
		}

		int m_fd;
		int m_open_mode;
	};

	// pimpl forwardings

	file::file() : m_impl(new impl()) {}

	file::file(fs::path const& p, file::open_mode m)
		: m_impl(new impl(p, m.m_mask))
	{}

	file::~file() {}

	void file::open(fs::path const& p, file::open_mode m)
	{
		m_impl->open(p, m.m_mask);
	}

	void file::close()
	{
		m_impl->close();
	}

	size_type file::write(const char* buf, size_type num_bytes)
	{
		return m_impl->write(buf, num_bytes);
	}

	size_type file::read(char* buf, size_type num_bytes)
	{
		return m_impl->read(buf, num_bytes);
	}

	void file::set_size(size_type s)
	{
		m_impl->set_size(s);
	}

	size_type file::seek(size_type pos, file::seek_mode m)
	{
		return m_impl->seek(pos, m.m_val);
	}

	size_type file::tell()
	{
		return m_impl->tell();
	}

}
<|endoftext|>


<commit_before>#include "applesoftfile.h"
#include <QDebug>

ApplesoftFile::ApplesoftFile(QByteArray data) : GenericFile(data)
{
    if (m_tokens.size() == 0)
    {
        makeTokens();
    }

    if (!data.isEmpty())
    {
        setData(data);
    }
}

void ApplesoftFile::setData(QByteArray data)
{
    GenericFile::setData(data);

    quint8 addlo = m_data.at(0);
    quint8 addhi = m_data.at(1);
    m_length = addlo + (addhi * 256);
    m_data.remove(0,2);
    m_detokenized = detokenize();
}

QList<ApplesoftLine> ApplesoftFile::detokenize()
{
    QList<ApplesoftLine> retval;

/*
    qDebug() << "Length: " << m_length;
    for (int idx = 0; idx < m_length; idx += 8)
    {
        qDebug()
                 << QString("%1 (%2): %3 %4 %5 %6 %7 %8 %9 %10")
                .arg((quint16) idx + 0x801,4,16,QChar('0')).toUpper()
                .arg((quint16) idx + 0x801,4,10,QChar('0'))
                .arg((quint8) m_data[idx],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+1],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+2],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+3],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+4],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+5],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+6],2,16,QChar('0')).toUpper()
                .arg((quint8) m_data[idx+7],2,16,QChar('0')).toUpper();

    }
*/
    int idx = 0;
    quint8 val = 0;
    while (idx < m_data.length()) {
        ApplesoftLine line;
        line.next_address = (quint8) m_data[idx] + (((quint8) m_data[idx+1]) *256);
        line.tokens.append(m_data[idx]);
        line.tokens.append(m_data[idx+1]);
        idx++; idx++;
        line.linenum = (quint8) m_data[idx] + (((quint8) m_data[idx+1])*256);
        line.tokens.append(m_data[idx]);
        line.tokens.append(m_data[idx+1]);
        idx++; idx++;
        if (line.next_address == 0x00) { break; }
        do {
            val = m_data[idx++];
            line.tokens.append(val);
            if (val >= 0x80) {
                line.detokenized_line.append(" " + m_tokens[val]);
            } else {
                if (val >= 0x20) {
                    line.detokenized_line.append(val);
                } else if (val == 0x7F) {
                    QChar ch = QChar(0x2401);
                    line.detokenized_line.append(ch);
                }else if (val > 0x00) {
                    QChar ch = QChar(0x00 + val);
                    line.detokenized_line.append(ch);
                }
            }
        } while (val != 0x00);
        retval.append(line);
    }

    m_data_end = idx;

    if (idx < m_data.length()) {
        qDebug() << QString("%1 byte(s) unaccounted for.").arg(m_data.length() - idx);
    }

    return retval;
}

void ApplesoftFile::list() {
    foreach (ApplesoftLine line,detokenized()) {
        QString debugline = QString("%1  %2  %3").arg(line.next_address,4,16,QChar('0')).arg(line.linenum).arg(line.detokenized_line);
        qDebug() << debugline;
/*
        debugline = "";
        foreach (quint8 val, line.tokens) {
            debugline.append(QString("%1 ").arg(val,2,16,QChar('0')));
        }
        qDebug() << "  " << debugline;
        qDebug() << "\n";
*/
    }

    qDebug() << extraDataHexValues().join("\n");
}

QStringList ApplesoftFile::extraDataHexValues() {
    QStringList retval;

    QString debugline = "";
    int count = 0;
    foreach (quint8 val, extraData()) {
        debugline.append(QString("%1").arg(val,2,16,QChar('0')).toUpper());
        count++;
        if (count == 16) {
            retval.append(debugline);
            debugline = "";
            count = 0;
        } else {
            debugline.append(" ");
        }
    }
    if (!debugline.simplified().isEmpty()) {
        retval.append(debugline);
    }
    return retval;
}

QByteArray ApplesoftFile::extraData()
{
    return m_data.mid(m_data_end);
}

void ApplesoftFile::makeTokens()
{
    m_tokens[0x80] = " END ";     m_tokens[0x81] = " FOR ";     m_tokens[0x82] = " NEXT ";
    m_tokens[0x83] = " DATA ";    m_tokens[0x84] = " INPUT ";   m_tokens[0x85] = " DEL ";
    m_tokens[0x86] = " DIM ";     m_tokens[0x87] = " READ ";    m_tokens[0x88] = " GR ";
    m_tokens[0x89] = " TEXT ";    m_tokens[0x8A] = " PR# ";     m_tokens[0x8B] = " IN# ";
    m_tokens[0x8C] = " CALL ";    m_tokens[0x8D] = " PLOT ";    m_tokens[0x8E] = " HLIN ";
    m_tokens[0x8F] = " VLIN ";    m_tokens[0x90] = " HGR2 ";    m_tokens[0x91] = " HGR ";
    m_tokens[0x92] = " HCOLOR= "; m_tokens[0x93] = " HPLOT ";   m_tokens[0x94] = " DRAW ";
    m_tokens[0x95] = " XDRAW ";   m_tokens[0x96] = " HTAB ";    m_tokens[0x97] = " HOME ";
    m_tokens[0x98] = " ROT= ";    m_tokens[0x99] = " SCALE= ";  m_tokens[0x9A] = " SHLOAD ";
    m_tokens[0x9B] = " TRACE ";   m_tokens[0x9C] = " NOTRACE "; m_tokens[0x9D] = " NORMAL ";
    m_tokens[0x9E] = " INVERSE "; m_tokens[0x9F] = " FLASH ";   m_tokens[0xA0] = " COLOR= ";
    m_tokens[0xA1] = " POP ";     m_tokens[0xA2] = " VTAB ";    m_tokens[0xA3] = " HIMEM: ";
    m_tokens[0xA4] = " LOMEM: ";  m_tokens[0xA5] = " ONERR ";   m_tokens[0xA6] = " RESUME ";
    m_tokens[0xA7] = " RECALL ";  m_tokens[0xA8] = " STORE ";   m_tokens[0xA9] = " SPEED= ";
    m_tokens[0xAA] = " LET ";     m_tokens[0xAB] = " GOTO ";    m_tokens[0xAC] = " RUN ";
    m_tokens[0xAD] = " IF ";      m_tokens[0xAE] = " RESTORE "; m_tokens[0xAF] = " & ";
    m_tokens[0xB0] = " GOSUB ";   m_tokens[0xB1] = " RETURN ";  m_tokens[0xB2] = " REM ";
    m_tokens[0xB3] = " STOP ";    m_tokens[0xB4] = " ON ";      m_tokens[0xB5] = " WAIT ";
    m_tokens[0xB6] = " LOAD ";    m_tokens[0xB7] = " SAVE ";    m_tokens[0xB8] = " DEF ";
    m_tokens[0xB9] = " POKE ";    m_tokens[0xBA] = " PRINT ";   m_tokens[0xBB] = " CONT ";
    m_tokens[0xBC] = " LIST ";    m_tokens[0xBD] = " CLEAR ";   m_tokens[0xBE] = " GET ";
    m_tokens[0xBF] = " NEW ";     m_tokens[0xC0] = " TAB ";     m_tokens[0xC1] = "  TO ";
    m_tokens[0xC2] = " FN ";      m_tokens[0xC3] = " SPC( ";    m_tokens[0xC4] = "  THEN ";
    m_tokens[0xC5] = " AT ";      m_tokens[0xC6] = "  NOT ";    m_tokens[0xC7] = "   STEP ";
    m_tokens[0xC8] = " +";        m_tokens[0xC9] = " -";        m_tokens[0xCA] = " *";
    m_tokens[0xCB] = " /";        m_tokens[0xCC] = " ^";        m_tokens[0xCD] = "  AND ";
    m_tokens[0xCE] = "  OR ";     m_tokens[0xCF] = " >";        m_tokens[0xD0] = " =";
    m_tokens[0xD1] = " <";        m_tokens[0xD2] = " SGN";      m_tokens[0xD3] = " INT";
    m_tokens[0xD4] = " ABS";      m_tokens[0xD5] = " USR";      m_tokens[0xD6] = " FRE";
    m_tokens[0xD7] = " SCRN( ";   m_tokens[0xD8] = " PDL";      m_tokens[0xD9] = " POS";
    m_tokens[0xDA] = " SQR";      m_tokens[0xDB] = " RND";      m_tokens[0xDC] = " LOG";
    m_tokens[0xDD] = " EXP";      m_tokens[0xDE] = " COS";      m_tokens[0xDF] = " SIN";
    m_tokens[0xE0] = " TAN";      m_tokens[0xE1] = " ATN";      m_tokens[0xE2] = " PEEK";
    m_tokens[0xE3] = " LEN";      m_tokens[0xE4] = " STR$";     m_tokens[0xE5] = " VAL";
    m_tokens[0xE6] = " ASC";      m_tokens[0xE7] = " CHR$";     m_tokens[0xE8] = " LEFT$ ";
    m_tokens[0xE9] = " RIGHT$ ";  m_tokens[0xEA] = " MID$ ";    m_tokens[0xEB] = "{Token 0xEB} ";
    m_tokens[0xEC] = "{Token 0xEC} ";
    m_tokens[0xED] = "{Token 0xED} ";
    m_tokens[0xEE] = "{Token 0xEE} ";
    m_tokens[0xEF] = "{Token 0xEF} ";
    m_tokens[0xF0] = "{Token 0xF0} ";
    m_tokens[0xF1] = "{Token 0xF1} ";
    m_tokens[0xF2] = "{Token 0xF2} ";
    m_tokens[0xF3] = "{Token 0xF3} ";
    m_tokens[0xF4] = "{Token 0xF4} ";
    m_tokens[0xF5] = "{Token 0xF5} ";
    m_tokens[0xF6] = "{Token 0xF6} ";
    m_tokens[0xF7] = "{Token 0xF7} ";
    m_tokens[0xF8] = "{Token 0xF8} ";
    m_tokens[0xF9] = "{Token 0xF9} ";
    m_tokens[0xFA] = "{Token 0xFA} ";
    m_tokens[0xFB] = "{Token 0xFB} ";
    m_tokens[0xFC] = "{Token 0xFC} ";
    m_tokens[0xFD] = "{Token 0xFD} ";
    m_tokens[0xFE] = "{Token 0xFE} ";
    m_tokens[0xFF] = "{Token 0xFF} ";
}
<commit_msg>Changed token spacing and removed hard-coded space before tokens.<commit_after>#include "applesoftfile.h"
#include <QDebug>

ApplesoftFile::ApplesoftFile(QByteArray data) : GenericFile(data)
{
    if (m_tokens.size() == 0)
    {
        makeTokens();
    }

    if (!data.isEmpty())
    {
        setData(data);
    }
}

void ApplesoftFile::setData(QByteArray data)
{
    GenericFile::setData(data);

    quint8 addlo = m_data.at(0);
    quint8 addhi = m_data.at(1);
    m_length = addlo + (addhi * 256);
    m_data.remove(0,2);
    m_detokenized = detokenize();
}

QList<ApplesoftLine> ApplesoftFile::detokenize()
{
    QList<ApplesoftLine> retval;

    int idx = 0;
    quint8 val = 0;
    while (idx < m_data.length()) {
        ApplesoftLine line;
        line.next_address = (quint8) m_data[idx] + (((quint8) m_data[idx+1]) *256);
        line.tokens.append(m_data[idx]);
        line.tokens.append(m_data[idx+1]);
        idx++; idx++;
        line.linenum = (quint8) m_data[idx] + (((quint8) m_data[idx+1])*256);
        line.tokens.append(m_data[idx]);
        line.tokens.append(m_data[idx+1]);
        idx++; idx++;
        if (line.next_address == 0x00) { break; }
        do {
            val = m_data[idx++];
            line.tokens.append(val);
            if (val >= 0x80) {
                line.detokenized_line.append(m_tokens[val]);
            } else {
                if (val >= 0x20) {
                    line.detokenized_line.append(val);
                } else if (val == 0x7F) {
                    QChar ch = QChar(0x2401);
                    line.detokenized_line.append(ch);
                }else if (val > 0x00) {
                    QChar ch = QChar(0x2400 + val);
                    line.detokenized_line.append(ch);
                }
            }
        } while (val != 0x00);
        retval.append(line);
    }

    m_data_end = idx;

    if (idx < m_data.length()) {
        qDebug() << QString("%1 byte(s) unaccounted for.").arg(m_data.length() - idx);
    }

    return retval;
}

void ApplesoftFile::list() {
    foreach (ApplesoftLine line,detokenized()) {
        QString debugline = QString("%1  %2  %3").arg(line.next_address,4,16,QChar('0')).arg(line.linenum).arg(line.detokenized_line);
        qDebug() << debugline;
/*
        debugline = "";
        foreach (quint8 val, line.tokens) {
            debugline.append(QString("%1 ").arg(val,2,16,QChar('0')));
        }
        qDebug() << "  " << debugline;
        qDebug() << "\n";
*/
    }

    qDebug() << extraDataHexValues().join("\n");
}

QStringList ApplesoftFile::extraDataHexValues() {
    QStringList retval;

    QString debugline = "";
    int count = 0;
    foreach (quint8 val, extraData()) {
        debugline.append(QString("%1").arg(val,2,16,QChar('0')).toUpper());
        count++;
        if (count == 16) {
            retval.append(debugline);
            debugline = "";
            count = 0;
        } else {
            debugline.append(" ");
        }
    }
    if (!debugline.simplified().isEmpty()) {
        retval.append(debugline);
    }
    return retval;
}

QByteArray ApplesoftFile::extraData()
{
    return m_data.mid(m_data_end);
}

void ApplesoftFile::makeTokens()
{
    m_tokens[0x80] = " END ";     m_tokens[0x81] = " FOR ";     m_tokens[0x82] = " NEXT ";
    m_tokens[0x83] = " DATA ";    m_tokens[0x84] = " INPUT ";   m_tokens[0x85] = " DEL ";
    m_tokens[0x86] = " DIM ";     m_tokens[0x87] = " READ ";    m_tokens[0x88] = " GR ";
    m_tokens[0x89] = " TEXT ";    m_tokens[0x8A] = " PR# ";     m_tokens[0x8B] = " IN# ";
    m_tokens[0x8C] = " CALL ";    m_tokens[0x8D] = " PLOT ";    m_tokens[0x8E] = " HLIN ";
    m_tokens[0x8F] = " VLIN ";    m_tokens[0x90] = " HGR2 ";    m_tokens[0x91] = " HGR ";
    m_tokens[0x92] = " HCOLOR= "; m_tokens[0x93] = " HPLOT ";   m_tokens[0x94] = " DRAW ";
    m_tokens[0x95] = " XDRAW ";   m_tokens[0x96] = " HTAB ";    m_tokens[0x97] = " HOME ";
    m_tokens[0x98] = " ROT= ";    m_tokens[0x99] = " SCALE= ";  m_tokens[0x9A] = " SHLOAD ";
    m_tokens[0x9B] = " TRACE ";   m_tokens[0x9C] = " NOTRACE "; m_tokens[0x9D] = " NORMAL ";
    m_tokens[0x9E] = " INVERSE "; m_tokens[0x9F] = " FLASH ";   m_tokens[0xA0] = " COLOR= ";
    m_tokens[0xA1] = " POP ";     m_tokens[0xA2] = " VTAB ";    m_tokens[0xA3] = " HIMEM: ";
    m_tokens[0xA4] = " LOMEM: ";  m_tokens[0xA5] = " ONERR ";   m_tokens[0xA6] = " RESUME ";
    m_tokens[0xA7] = " RECALL ";  m_tokens[0xA8] = " STORE ";   m_tokens[0xA9] = " SPEED= ";
    m_tokens[0xAA] = " LET ";     m_tokens[0xAB] = " GOTO ";    m_tokens[0xAC] = " RUN ";
    m_tokens[0xAD] = " IF ";      m_tokens[0xAE] = " RESTORE "; m_tokens[0xAF] = " & ";
    m_tokens[0xB0] = " GOSUB ";   m_tokens[0xB1] = " RETURN ";  m_tokens[0xB2] = " REM ";
    m_tokens[0xB3] = " STOP ";    m_tokens[0xB4] = " ON ";      m_tokens[0xB5] = " WAIT ";
    m_tokens[0xB6] = " LOAD ";    m_tokens[0xB7] = " SAVE ";    m_tokens[0xB8] = " DEF ";
    m_tokens[0xB9] = " POKE ";    m_tokens[0xBA] = " PRINT ";   m_tokens[0xBB] = " CONT ";
    m_tokens[0xBC] = " LIST ";    m_tokens[0xBD] = " CLEAR ";   m_tokens[0xBE] = " GET ";
    m_tokens[0xBF] = " NEW ";     m_tokens[0xC0] = " TAB(";     m_tokens[0xC1] = " TO ";
    m_tokens[0xC2] = " FN ";      m_tokens[0xC3] = " SPC( ";    m_tokens[0xC4] = " THEN ";
    m_tokens[0xC5] = " AT ";      m_tokens[0xC6] = " NOT ";     m_tokens[0xC7] = " STEP ";
    m_tokens[0xC8] = " + ";       m_tokens[0xC9] = " - ";       m_tokens[0xCA] = " * ";
    m_tokens[0xCB] = " / ";       m_tokens[0xCC] = " ^ ";       m_tokens[0xCD] = " AND ";
    m_tokens[0xCE] = "  OR ";     m_tokens[0xCF] = " > ";       m_tokens[0xD0] = " = ";
    m_tokens[0xD1] = " < ";       m_tokens[0xD2] = " SGN";      m_tokens[0xD3] = " INT";
    m_tokens[0xD4] = " ABS";      m_tokens[0xD5] = " USR";      m_tokens[0xD6] = " FRE";
    m_tokens[0xD7] = " SCRN( ";   m_tokens[0xD8] = " PDL";      m_tokens[0xD9] = " POS";
    m_tokens[0xDA] = " SQR";      m_tokens[0xDB] = " RND";      m_tokens[0xDC] = " LOG";
    m_tokens[0xDD] = " EXP";      m_tokens[0xDE] = " COS";      m_tokens[0xDF] = " SIN";
    m_tokens[0xE0] = " TAN";      m_tokens[0xE1] = " ATN";      m_tokens[0xE2] = " PEEK";
    m_tokens[0xE3] = " LEN";      m_tokens[0xE4] = " STR$";     m_tokens[0xE5] = " VAL";
    m_tokens[0xE6] = " ASC";      m_tokens[0xE7] = " CHR$";     m_tokens[0xE8] = " LEFT$ ";
    m_tokens[0xE9] = " RIGHT$ ";  m_tokens[0xEA] = " MID$ ";    m_tokens[0xEB] = "{Token 0xEB} ";
    m_tokens[0xEC] = "{Token 0xEC} ";
    m_tokens[0xED] = "{Token 0xED} ";
    m_tokens[0xEE] = "{Token 0xEE} ";
    m_tokens[0xEF] = "{Token 0xEF} ";
    m_tokens[0xF0] = "{Token 0xF0} ";
    m_tokens[0xF1] = "{Token 0xF1} ";
    m_tokens[0xF2] = "{Token 0xF2} ";
    m_tokens[0xF3] = "{Token 0xF3} ";
    m_tokens[0xF4] = "{Token 0xF4} ";
    m_tokens[0xF5] = "{Token 0xF5} ";
    m_tokens[0xF6] = "{Token 0xF6} ";
    m_tokens[0xF7] = "{Token 0xF7} ";
    m_tokens[0xF8] = "{Token 0xF8} ";
    m_tokens[0xF9] = "{Token 0xF9} ";
    m_tokens[0xFA] = "{Token 0xFA} ";
    m_tokens[0xFB] = "{Token 0xFB} ";
    m_tokens[0xFC] = "{Token 0xFC} ";
    m_tokens[0xFD] = "{Token 0xFD} ";
    m_tokens[0xFE] = "{Token 0xFE} ";
    m_tokens[0xFF] = "{Token 0xFF} ";
}
<|endoftext|>


<commit_before>#include "../../TsunagariC/src/area.h"
#include "../../TsunagariC/src/random.h"
#include "../../TsunagariC/src/timer.h"
#include "../../TsunagariC/src/data/area.h"

class grove01 : public DataArea
{
	bool drinking = false;
	Timer wellTimer;
	static constexpr double duration = 1.0;
	static constexpr int maxAlpha = 192;

public:
	grove01() {
		scripts["well"] = (TileScript)&grove01::onWell;
	}

	void onLoad() {
		auto cloud = area->spawnOverlay("entities/cloud/cloud.xml", 11, 2, 10.0, "down");
		cloud->move(-400, 0);
	}

	void onTick() {
		if (drinking == true) {
			int overlayAlpha;

			double progress = wellTimer.count() / duration;
			if (progress < 0.5)
				overlayAlpha = int(2 * maxAlpha * progress);
			else if (progress < 1.0)
				overlayAlpha = int(2 * maxAlpha * (1 - progress));
			else {
				overlayAlpha = 0;
				drinking = false;
			}

			area->setColorOverlay(255, 255, 255, overlayAlpha); // white overlay
		}
	}

	void onWell(Entity&, Tile&) {
		if (drinking == false) {
			wellTimer.reset();
			wellTimer.setRunning(true);

			auto splash = SoundManager::instance().play("sounds/splash.oga");
			splash->setSpeed(1.0 + randFloat(-0.1, 0.1));
		}
	}
};
<commit_msg>move constants local to where their used<commit_after>#include "../../TsunagariC/src/area.h"
#include "../../TsunagariC/src/random.h"
#include "../../TsunagariC/src/timer.h"
#include "../../TsunagariC/src/data/area.h"

class grove01 : public DataArea
{
	bool drinking = false;
	Timer wellTimer;

public:
	grove01() {
		scripts["well"] = (TileScript)&grove01::onWell;
	}

	void onLoad() {
		auto cloud = area->spawnOverlay("entities/cloud/cloud.xml", 11, 2, 10.0, "down");
		cloud->move(-400, 0);
	}

	void onTick() {
		static constexpr double duration = 1.0;
		static constexpr int maxAlpha = 192;

		if (drinking == true) {
			int overlayAlpha;

			double progress = wellTimer.count() / duration;
			if (progress < 0.5)
				overlayAlpha = int(2 * maxAlpha * progress);
			else if (progress < 1.0)
				overlayAlpha = int(2 * maxAlpha * (1 - progress));
			else {
				overlayAlpha = 0;
				drinking = false;
			}

			area->setColorOverlay(255, 255, 255, overlayAlpha); // white overlay
		}
	}

	void onWell(Entity&, Tile&) {
		if (drinking == false) {
			wellTimer.reset();
			wellTimer.setRunning(true);

			auto splash = SoundManager::instance().play("sounds/splash.oga");
			splash->setSpeed(1.0 + randFloat(-0.1, 0.1));
		}
	}
};
<|endoftext|>