<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "RenameClasses.h"

#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>

#include "walkers.h"
#include "DexClass.h"
#include "DexInstruction.h"
#include "DexUtil.h"
#include "ReachableClasses.h"

#define MAX_DESCRIPTOR_LENGTH (1024)
#define MAX_IDENT_CHAR (52)
#define MAX_IDENT (MAX_IDENT_CHAR * MAX_IDENT_CHAR * MAX_IDENT_CHAR)

#define METRIC_RENAMED_CLASSES "renamed_classes"

int match_short = 0;
int match_long = 0;
int match_inner = 0;

int base_strings_size = 0;
int ren_strings_size = 0;

static char getident(int num) {
  if (num < 26) {
    return 'a' + num;
  } else {
    return 'A' + num - 26;
  }
}

void get_next_ident(char *out, int &num) {
  // *sigh* re-write when not tired.
  int low = num;
  int mid = (num / 52);
  int top = (mid / 52);
  always_assert_log(num <= MAX_IDENT,
                    "Bailing, Ident %d, greater than maximum\n", num);
  if (top) {
    *out++ = getident(top - 1);
    low -= (top *52*52);
  }
  if (mid) {
    mid -= (top * 52);
    *out++ = getident(mid);
    low -= (mid * 52);
  }
  *out++ = getident(low);
  *out++ = '\0';
  num++;
}

void unpackage_private(Scope &scope) {
  walk_methods(scope,
      [&](DexMethod *method) {
        if (is_package_protected(method)) set_public(method);
      });
  walk_fields(scope,
      [&](DexField *field) {
        if (is_package_protected(field)) set_public(field);
      });
  for (auto clazz : scope) {
    if (is_package_protected(clazz)) set_public(clazz);
  }
}

bool should_rename(DexClass *clazz,
    std::vector<std::string>& pre_patterns,
    std::vector<std::string>& post_patterns,
    std::unordered_set<const DexType*>& untouchables,
    bool rename_annotations) {
  if (!rename_annotations && is_annotation(clazz)) return false;
  if (untouchables.count(clazz->get_type())) return false;
  auto chstring = clazz->get_type()->get_name()->c_str();
  /* We're assuming anonymous classes are safe always safe to rename. */
  auto substr = strrchr(chstring, '$');
  if (substr != nullptr) {
    auto val = *++substr;
    if (val >= '0' && val <= '9') {
      match_inner++;
      return true;
    }
  }
  /* Check for more aggressive, but finer grained filters first */
  for (auto p : pre_patterns) {
    auto substr = strstr(chstring, p.c_str());
    if (substr != nullptr) {
      if (p.length() > 1) {
        match_long++;
      } else {
        match_short++;
      }
      return true;
    }
  }
  if (!can_rename(clazz) && !can_delete(clazz)) {
    return false;
  }
  /* Check for wider, less precise filters */
  for (auto p : post_patterns) {
    auto substr = strstr(chstring, p.c_str());
    if (substr != nullptr) {
      if (p.length() > 1) {
        match_long++;
      } else {
        match_short++;
      }
      return true;
    }
  }
  return false;
}

void rename_classes(
    Scope& scope,
    std::vector<std::string>& pre_whitelist_patterns,
    std::vector<std::string>& post_whitelist_patterns,
    const std::string& path,
    std::unordered_set<const DexType*>& untouchables,
    ProguardMap& proguard_map,
    bool rename_annotations,
    PassManager& mgr) {
  unpackage_private(scope);
  int clazz_ident = 0;
  std::map<DexString*, DexString*> aliases;
  for(auto clazz: scope) {
    if (!should_rename(
        clazz, pre_whitelist_patterns, post_whitelist_patterns,
        untouchables, rename_annotations)) {
      continue;
    }
    char clzname[4];
    get_next_ident(clzname, clazz_ident);

    auto dtype = clazz->get_type();
    auto oldname = dtype->get_name();

    // The X helps our hacked Dalvik classloader recognize that a
    // class name is the output of the redex renamer and thus will
    // never be found in the Android platform.
    // The $ indicates that the class was originally an inner class.
    // Some code, most notably android instrumentation runner, uses
    // this information to decide whether or not to classload the class.
    bool inner = strrchr(oldname->c_str(), '$');
    char descriptor[10];
    sprintf(descriptor, "LX%s%s;", inner ? "$" : "", clzname);
    auto dstring = DexString::make_string(descriptor);
    aliases[oldname] = dstring;
    dtype->assign_name_alias(dstring);
    std::string old_str(oldname->c_str());
    std::string new_str(descriptor);
    proguard_map.update_class_mapping(old_str, new_str);
    base_strings_size += strlen(oldname->c_str());
    base_strings_size += strlen(dstring->c_str());
    TRACE(RENAME, 4, "'%s'->'%s'\n", oldname->c_str(), descriptor);
    while (1) {
     std::string arrayop("[");
      arrayop += oldname->c_str();
      oldname = DexString::get_string(arrayop.c_str());
      if (oldname == nullptr) {
        break;
      }
      auto arraytype = DexType::get_type(oldname);
      if (arraytype == nullptr) {
        break;
      }
      std::string newarraytype("[");
      newarraytype += dstring->c_str();
      dstring = DexString::make_string(newarraytype.c_str());
      aliases[oldname] = dstring;
      arraytype->assign_name_alias(dstring);
    }
  }
  mgr.incr_metric(METRIC_RENAMED_CLASSES, match_short + match_long + match_inner);
  /* Now we need to re-write the Signature annotations.  They use
   * Strings rather than Type's, so they have to be explicitly
   * handled.
   */

  /* Generics of the form Type<> turn into the Type string
   * sans the ';'.  So, we have to alias those if they
   * exist.  Signature annotations suck.
   */
  for (auto apair : aliases) {
    char buf[MAX_DESCRIPTOR_LENGTH];
    const char *sourcestr = apair.first->c_str();
    size_t sourcelen = strlen(sourcestr);
    if (sourcestr[sourcelen - 1] != ';') continue;
    strcpy(buf, sourcestr);
    buf[sourcelen - 1] = '\0';
    auto dstring = DexString::get_string(buf);
    if (dstring == nullptr) continue;
    strcpy(buf, apair.second->c_str());
    buf[strlen(apair.second->c_str()) - 1] = '\0';
    auto target = DexString::make_string(buf);
    aliases[dstring] = target;
  }
  walk_annotations(scope, [&](DexAnnotation* anno) {
    static DexType *dalviksig =
      DexType::get_type("Ldalvik/annotation/Signature;");
    if (anno->type() != dalviksig) return;
    auto elems = anno->anno_elems();
    for (auto elem : elems) {
      auto ev = elem.encoded_value;
      if (ev->evtype() != DEVT_ARRAY) continue;
      auto arrayev = static_cast<DexEncodedValueArray*>(ev);
      auto const& evs = arrayev->evalues();
      for (auto strev : *evs) {
        if (strev->evtype() != DEVT_STRING) continue;
        auto stringev = static_cast<DexEncodedValueString*>(strev);
        if (aliases.count(stringev->string())) {
          TRACE(RENAME, 5, "Rewriting Signature from '%s' to '%s'\n",
              stringev->string()->c_str(),
              aliases[stringev->string()]->c_str());
          stringev->string(aliases[stringev->string()]);
        }
      }
    }
  });

  if (!path.empty()) {
    FILE* fd = fopen(path.c_str(), "w");
    if (fd == nullptr) {
      perror("Error writing rename file");
      return;
    }
    for (const auto &it : aliases) {
      // record for later processing and back map generation
      fprintf(fd, "%s -> %s\n",it.first->c_str(),
      it.second->c_str());
    }
    fclose(fd);
  }

  for (auto clazz : scope) {
    clazz->get_vmethods().sort(compare_dexmethods);
    clazz->get_dmethods().sort(compare_dexmethods);
    clazz->get_sfields().sort(compare_dexfields);
    clazz->get_ifields().sort(compare_dexfields);
  }
}

void RenameClassesPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(dexen);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeVector children;
      get_all_children(base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist, m_path,
      untouchables, cfg.get_proguard_map(), m_rename_annotations, mgr);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
<commit_msg>track reasons for not renaming as well<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */

#include "RenameClasses.h"

#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <unordered_set>
#include <unordered_map>

#include "walkers.h"
#include "DexClass.h"
#include "DexInstruction.h"
#include "DexUtil.h"
#include "ReachableClasses.h"

#define MAX_DESCRIPTOR_LENGTH (1024)
#define MAX_IDENT_CHAR (52)
#define MAX_IDENT (MAX_IDENT_CHAR * MAX_IDENT_CHAR * MAX_IDENT_CHAR)

#define METRIC_CLASSES_IN_SCOPE "num_classes_in_scope"
#define METRIC_RENAMED_CLASSES "**num_renamed**"
#define METRIC_CANT_RENAME_ANNOTATION "num_cant_rename_annotations"
#define METRIC_CANT_RENAME_UNTOUCHABLE "num_cant_rename_untouchable"
#define METRIC_CANT_RENAME_AND_CANT_DELETE "num_cant_rename_and_cant_delete"
#define METRIC_NOT_WHITELISTED "num_not_whitelisted"

int match_short = 0;
int match_long = 0;
int match_inner = 0;

int base_strings_size = 0;
int ren_strings_size = 0;

static char getident(int num) {
  if (num < 26) {
    return 'a' + num;
  } else {
    return 'A' + num - 26;
  }
}

void get_next_ident(char *out, int &num) {
  // *sigh* re-write when not tired.
  int low = num;
  int mid = (num / 52);
  int top = (mid / 52);
  always_assert_log(num <= MAX_IDENT,
                    "Bailing, Ident %d, greater than maximum\n", num);
  if (top) {
    *out++ = getident(top - 1);
    low -= (top *52*52);
  }
  if (mid) {
    mid -= (top * 52);
    *out++ = getident(mid);
    low -= (mid * 52);
  }
  *out++ = getident(low);
  *out++ = '\0';
  num++;
}

void unpackage_private(Scope &scope) {
  walk_methods(scope,
      [&](DexMethod *method) {
        if (is_package_protected(method)) set_public(method);
      });
  walk_fields(scope,
      [&](DexField *field) {
        if (is_package_protected(field)) set_public(field);
      });
  for (auto clazz : scope) {
    if (is_package_protected(clazz)) set_public(clazz);
  }
}

bool should_rename(DexClass *clazz,
    std::vector<std::string>& pre_patterns,
    std::vector<std::string>& post_patterns,
    std::unordered_set<const DexType*>& untouchables,
    bool rename_annotations,
    PassManager& mgr) {
  if (!rename_annotations && is_annotation(clazz)) {
    mgr.incr_metric(METRIC_CANT_RENAME_ANNOTATION, 1);
    return false;
  }
  if (untouchables.count(clazz->get_type())) {
    mgr.incr_metric(METRIC_CANT_RENAME_UNTOUCHABLE, 1);
    return false;
  }
  auto chstring = clazz->get_type()->get_name()->c_str();
  /* We're assuming anonymous classes are safe always safe to rename. */
  auto substr = strrchr(chstring, '$');
  if (substr != nullptr) {
    auto val = *++substr;
    if (val >= '0' && val <= '9') {
      match_inner++;
      return true;
    }
  }
  /* Check for more aggressive, but finer grained filters first */
  for (auto p : pre_patterns) {
    auto substr = strstr(chstring, p.c_str());
    if (substr != nullptr) {
      if (p.length() > 1) {
        match_long++;
      } else {
        match_short++;
      }
      return true;
    }
  }
  if (!can_rename(clazz) && !can_delete(clazz)) {
    mgr.incr_metric(METRIC_CANT_RENAME_AND_CANT_DELETE, 1);
    return false;
  }
  /* Check for wider, less precise filters */
  for (auto p : post_patterns) {
    auto substr = strstr(chstring, p.c_str());
    if (substr != nullptr) {
      if (p.length() > 1) {
        match_long++;
      } else {
        match_short++;
      }
      return true;
    }
  }
  mgr.incr_metric(METRIC_NOT_WHITELISTED, 1);
  return false;
}

void rename_classes(
    Scope& scope,
    std::vector<std::string>& pre_whitelist_patterns,
    std::vector<std::string>& post_whitelist_patterns,
    const std::string& path,
    std::unordered_set<const DexType*>& untouchables,
    ProguardMap& proguard_map,
    bool rename_annotations,
    PassManager& mgr) {
  unpackage_private(scope);
  int clazz_ident = 0;
  std::map<DexString*, DexString*> aliases;
  for(auto clazz: scope) {
    if (!should_rename(
        clazz, pre_whitelist_patterns, post_whitelist_patterns,
        untouchables, rename_annotations, mgr)) {
      continue;
    }
    char clzname[4];
    get_next_ident(clzname, clazz_ident);

    auto dtype = clazz->get_type();
    auto oldname = dtype->get_name();

    // The X helps our hacked Dalvik classloader recognize that a
    // class name is the output of the redex renamer and thus will
    // never be found in the Android platform.
    // The $ indicates that the class was originally an inner class.
    // Some code, most notably android instrumentation runner, uses
    // this information to decide whether or not to classload the class.
    bool inner = strrchr(oldname->c_str(), '$');
    char descriptor[10];
    sprintf(descriptor, "LX%s%s;", inner ? "$" : "", clzname);
    auto dstring = DexString::make_string(descriptor);
    aliases[oldname] = dstring;
    dtype->assign_name_alias(dstring);
    std::string old_str(oldname->c_str());
    std::string new_str(descriptor);
    proguard_map.update_class_mapping(old_str, new_str);
    base_strings_size += strlen(oldname->c_str());
    base_strings_size += strlen(dstring->c_str());
    TRACE(RENAME, 4, "'%s'->'%s'\n", oldname->c_str(), descriptor);
    while (1) {
     std::string arrayop("[");
      arrayop += oldname->c_str();
      oldname = DexString::get_string(arrayop.c_str());
      if (oldname == nullptr) {
        break;
      }
      auto arraytype = DexType::get_type(oldname);
      if (arraytype == nullptr) {
        break;
      }
      std::string newarraytype("[");
      newarraytype += dstring->c_str();
      dstring = DexString::make_string(newarraytype.c_str());
      aliases[oldname] = dstring;
      arraytype->assign_name_alias(dstring);
    }
  }
  mgr.incr_metric(METRIC_RENAMED_CLASSES, match_short + match_long + match_inner);
  /* Now we need to re-write the Signature annotations.  They use
   * Strings rather than Type's, so they have to be explicitly
   * handled.
   */

  /* Generics of the form Type<> turn into the Type string
   * sans the ';'.  So, we have to alias those if they
   * exist.  Signature annotations suck.
   */
  for (auto apair : aliases) {
    char buf[MAX_DESCRIPTOR_LENGTH];
    const char *sourcestr = apair.first->c_str();
    size_t sourcelen = strlen(sourcestr);
    if (sourcestr[sourcelen - 1] != ';') continue;
    strcpy(buf, sourcestr);
    buf[sourcelen - 1] = '\0';
    auto dstring = DexString::get_string(buf);
    if (dstring == nullptr) continue;
    strcpy(buf, apair.second->c_str());
    buf[strlen(apair.second->c_str()) - 1] = '\0';
    auto target = DexString::make_string(buf);
    aliases[dstring] = target;
  }
  walk_annotations(scope, [&](DexAnnotation* anno) {
    static DexType *dalviksig =
      DexType::get_type("Ldalvik/annotation/Signature;");
    if (anno->type() != dalviksig) return;
    auto elems = anno->anno_elems();
    for (auto elem : elems) {
      auto ev = elem.encoded_value;
      if (ev->evtype() != DEVT_ARRAY) continue;
      auto arrayev = static_cast<DexEncodedValueArray*>(ev);
      auto const& evs = arrayev->evalues();
      for (auto strev : *evs) {
        if (strev->evtype() != DEVT_STRING) continue;
        auto stringev = static_cast<DexEncodedValueString*>(strev);
        if (aliases.count(stringev->string())) {
          TRACE(RENAME, 5, "Rewriting Signature from '%s' to '%s'\n",
              stringev->string()->c_str(),
              aliases[stringev->string()]->c_str());
          stringev->string(aliases[stringev->string()]);
        }
      }
    }
  });

  if (!path.empty()) {
    FILE* fd = fopen(path.c_str(), "w");
    if (fd == nullptr) {
      perror("Error writing rename file");
      return;
    }
    for (const auto &it : aliases) {
      // record for later processing and back map generation
      fprintf(fd, "%s -> %s\n",it.first->c_str(),
      it.second->c_str());
    }
    fclose(fd);
  }

  for (auto clazz : scope) {
    clazz->get_vmethods().sort(compare_dexmethods);
    clazz->get_dmethods().sort(compare_dexmethods);
    clazz->get_sfields().sort(compare_dexfields);
    clazz->get_ifields().sort(compare_dexfields);
  }
}

void RenameClassesPass::run_pass(DexClassesVector& dexen, ConfigFiles& cfg, PassManager& mgr) {
  auto scope = build_class_scope(dexen);
  std::unordered_set<const DexType*> untouchables;
  for (const auto& base : m_untouchable_hierarchies) {
    auto base_type = DexType::get_type(base.c_str());
    if (base_type != nullptr) {
      untouchables.insert(base_type);
      TypeVector children;
      get_all_children(base_type, children);
      untouchables.insert(children.begin(), children.end());
    }
  }
  mgr.incr_metric(METRIC_CLASSES_IN_SCOPE, scope.size());
  rename_classes(
      scope, m_pre_filter_whitelist, m_post_filter_whitelist, m_path,
      untouchables, cfg.get_proguard_map(), m_rename_annotations, mgr);
  TRACE(RENAME, 1,
      "renamed classes: %d anon classes, %d from single char patterns, "
      "%d from multi char patterns\n",
      match_inner,
      match_short,
      match_long);
  TRACE(RENAME, 1, "String savings, at least %d bytes \n",
      base_strings_size - ren_strings_size);
}
<|endoftext|>


<commit_before>#include "LDAPCnx.h"

static struct timeval ldap_tv = { 0, 0 };

Nan::Persistent<v8::Function> LDAPCnx::constructor;

LDAPCnx::LDAPCnx(double value) {
}

LDAPCnx::~LDAPCnx() {
  delete this->callback;
}

void LDAPCnx::Init(v8::Local<v8::Object> exports) {
  Nan::HandleScope scope;

  // Prepare constructor template
  v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("LDAPCnx").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  Nan::SetPrototypeMethod(tpl, "search", Search);
  Nan::SetPrototypeMethod(tpl, "delete", Delete);
  Nan::SetPrototypeMethod(tpl, "bind", Bind);
  Nan::SetPrototypeMethod(tpl, "add", Add);
  Nan::SetPrototypeMethod(tpl, "modify", Modify);
  Nan::SetPrototypeMethod(tpl, "rename", Rename);
  Nan::SetPrototypeMethod(tpl, "initialize", Initialize);
  Nan::SetPrototypeMethod(tpl, "errorstring", GetErr);

  constructor.Reset(tpl->GetFunction());
  exports->Set(Nan::New("LDAPCnx").ToLocalChecked(), tpl->GetFunction());
}

void LDAPCnx::New(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  if (info.IsConstructCall()) {
    // Invoked as constructor: `new LDAPCnx(...)`
    double value = info[0]->IsUndefined() ? 0 : info[0]->NumberValue();
    LDAPCnx* obj = new LDAPCnx(value);
    obj->Wrap(info.Holder());

    obj->callback = new Nan::Callback(info[1].As<v8::Function>());

    info.GetReturnValue().Set(info.Holder());
  } else {
    // Invoked as plain function `LDAPCnx(...)`, turn into construct call.
    const int argc = 1;
    v8::Local<v8::Value> argv[argc] = { info[0] };
    v8::Local<v8::Function> cons = Nan::New<v8::Function>(constructor);

    info.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void LDAPCnx::Event(uv_poll_t* handle, int status, int events) {
  Nan::HandleScope scope;

  LDAPCnx *ld = (LDAPCnx *)handle->data;
  LDAPMessage * message = NULL;
  LDAPMessage * entry = NULL;
  v8::Local<v8::Value> errparam;

  switch(ldap_result(ld->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &ldap_tv, &message)) {
  case 0:
    // timeout occurred
  case -1:
    {
      // We can't really do much; we don't have a msgid...
      break;
    }
  default:
    {
      int err = ldap_result2error(ld->ld, message, 0);
      if (err) {
        errparam = Nan::Error(ldap_err2string(err));
      } else {
        errparam = Nan::Undefined();
      }

      switch ( ldap_msgtype( message ) ) {
      case LDAP_RES_SEARCH_REFERENCE:
        break;
      case LDAP_RES_SEARCH_ENTRY:
      case LDAP_RES_SEARCH_RESULT:
        {
          v8::Local<v8::Array> js_result_list = Nan::New<v8::Array>(ldap_count_entries(ld->ld, message));

          int j;

          for (entry = ldap_first_entry(ld->ld, message), j = 0 ; entry ;
               entry = ldap_next_entry(ld->ld, entry), j++) {
            v8::Local<v8::Object> js_result = Nan::New<v8::Object>();

            js_result_list->Set(Nan::New(j), js_result);

            char * dn = ldap_get_dn(ld->ld, entry);
            BerElement * berptr = NULL;
            for (char * attrname = ldap_first_attribute(ld->ld, entry, &berptr) ;
                 attrname ; attrname = ldap_next_attribute(ld->ld, entry, berptr)) {
              berval ** vals = ldap_get_values_len(ld->ld, entry, attrname);
              int num_vals = ldap_count_values_len(vals);
              v8::Local<v8::Array> js_attr_vals = Nan::New<v8::Array>(num_vals);
              js_result->Set(Nan::New(attrname).ToLocalChecked(), js_attr_vals);

              // int bin = ld->isBinary(attrname);
              int bin = 0;

              for (int i = 0 ; i < num_vals && vals[i] ; i++) {
                if (bin) {
                  // js_attr_vals->Set(Nan::New(i), ld->makeBuffer(vals[i]));
                } else {
                  js_attr_vals->Set(Nan::New(i), Nan::New(vals[i]->bv_val).ToLocalChecked());
                }
              } // all values for this attr added.
              ldap_value_free_len(vals);
              ldap_memfree(attrname);
            } // attrs for this entry added. Next entry.
            js_result->Set(Nan::New("dn").ToLocalChecked(), Nan::New(dn).ToLocalChecked());
            ber_free(berptr,0);
            ldap_memfree(dn);
          } // all entries done.

          v8::Local<v8::Value> argv[] = {
            errparam,
            Nan::New(ldap_msgid(message)),
            js_result_list
          };
          ld->callback->Call(3, argv);
          break;
        }
      case LDAP_RES_BIND:
      case LDAP_RES_MODIFY:
      case LDAP_RES_MODDN:
      case LDAP_RES_ADD:
      case LDAP_RES_DELETE:
        {
          v8::Local<v8::Value> argv[] = {
            errparam,
            Nan::New(ldap_msgid(message))
          };
          ld->callback->Call(2, argv);
          break;
        }
      default:
        {

          //emit an error
          // Nan::ThrowError("Unrecognized packet");
        }
      }
    }
  }
  ldap_msgfree(message);
  return;
}

void LDAPCnx::Initialize(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String url(info[0]);
  uv_poll_t * handle = new uv_poll_t;
  handle->data = ld;
  int fd = 0;
  int ver = 3;

  if (ldap_initialize(&(ld->ld), *url) != LDAP_SUCCESS) {
    Nan::ThrowError("Error init");
    return;
  }

   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);
   ldap_set_option(ld->ld, LDAP_OPT_PROTOCOL_VERSION, &ver);

   if ((ldap_simple_bind(ld->ld, NULL, NULL)) == -1) {
     Nan::ThrowError("Error anon bind");
     return;
   }
   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);

   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);

   if (fd < 0) {
     Nan::ThrowError("Connection issue");
     return;
   }

   uv_poll_init(uv_default_loop(), handle, fd);
   uv_poll_start(handle, UV_READABLE, Event);

   info.GetReturnValue().Set(info.This());
}

void LDAPCnx::GetErr(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  int err;
  ldap_get_option(ld->ld, LDAP_OPT_RESULT_CODE, &err);
  info.GetReturnValue().Set(Nan::New(ldap_err2string(err)).ToLocalChecked());
}

void LDAPCnx::Delete(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);

  info.GetReturnValue().Set(ldap_delete(ld->ld, *dn));
}

void LDAPCnx::Bind(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  Nan::Utf8String pw(info[1]);

  info.GetReturnValue().Set(ldap_simple_bind(ld->ld, *dn, *pw));
}

void LDAPCnx::Rename(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  Nan::Utf8String newrdn(info[1]);
  int res;

  ldap_rename(ld->ld, *dn, *newrdn, NULL, 1, NULL, NULL, &res);

  info.GetReturnValue().Set(res);
}

void LDAPCnx::Search(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String base(info[0]);
  Nan::Utf8String filter(info[1]);
  Nan::Utf8String attrs(info[2]);
  int msgid = 0;
  int res;
  char * attrlist[255];

  char *bufhead = strdup(*attrs);
  char *buf = bufhead;
  char **ap;
  for (ap = attrlist; (*ap = strsep(&buf, " \t,")) != NULL;)
    if (**ap != '\0')
      if (++ap >= &attrlist[255])
        break;

  res = ldap_search_ext(ld->ld, *base, 2, *filter , (char **)attrlist, 0,
                         NULL, NULL, NULL, 0, &msgid);

  free(bufhead);

  info.GetReturnValue().Set(msgid);
}

void LDAPCnx::Modify(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);

  v8::Handle<v8::Array> mods = v8::Handle<v8::Array>::Cast(info[1]);
  unsigned int nummods = mods->Length();

  LDAPMod **ldapmods = (LDAPMod **) malloc(sizeof(LDAPMod *) * (nummods + 1));

  for (unsigned int i = 0; i < nummods; i++) {
    v8::Local<v8::Object> modHandle =
      v8::Local<v8::Object>::Cast(mods->Get(Nan::New(i)));

    ldapmods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));

    v8::String::Utf8Value mod_op(modHandle->Get(Nan::New("op").ToLocalChecked()));

    if (!strcmp(*mod_op, "add")) {
      ldapmods[i]->mod_op = LDAP_MOD_ADD;
    } else if (!strcmp(*mod_op, "delete")) {
      ldapmods[i]->mod_op = LDAP_MOD_DELETE;
    } else {
      ldapmods[i]->mod_op = LDAP_MOD_REPLACE;
    }

    v8::String::Utf8Value mod_type(modHandle->Get(Nan::New("attr").ToLocalChecked()));
    ldapmods[i]->mod_type = strdup(*mod_type);

    v8::Local<v8::Array> modValsHandle =
      v8::Local<v8::Array>::Cast(modHandle->Get(Nan::New("vals").ToLocalChecked()));

    int modValsLength = modValsHandle->Length();
    ldapmods[i]->mod_values = (char **) malloc(sizeof(char *) *
                                               (modValsLength + 1));
    for (int j = 0; j < modValsLength; j++) {
      Nan::Utf8String modValue(modValsHandle->Get(Nan::New(j)));
      ldapmods[i]->mod_values[j] = strdup(*modValue);
    }
    ldapmods[i]->mod_values[modValsLength] = NULL;
  }
  ldapmods[nummods] = NULL;

  int msgid = ldap_modify(ld->ld, *dn, ldapmods);

  // TODO: free?

  info.GetReturnValue().Set(msgid);
}

void LDAPCnx::Add(const Nan::FunctionCallbackInfo<v8::Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  if (info[1]->IsArray()) {
    v8::Handle<v8::Array> attrs = v8::Handle<v8::Array>::Cast(info[1]);
    unsigned int numattrs = attrs->Length();

    LDAPMod **ldapmods = (LDAPMod **) malloc(sizeof(LDAPMod *) * (numattrs + 1));
    for (unsigned int i = 0; i < numattrs; i++) {
      v8::Local<v8::Object> attrHandle =
        v8::Local<v8::Object>::Cast(attrs->Get(Nan::New(i)));

      ldapmods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));

      // Step 1: mod_op
      ldapmods[i]->mod_op = LDAP_MOD_ADD;

      // Step 2: mod_type
      v8::String::Utf8Value mod_type(attrHandle->Get(Nan::New("attr").ToLocalChecked()));
      ldapmods[i]->mod_type = strdup(*mod_type);

      // Step 3: mod_vals
      v8::Local<v8::Array> attrValsHandle =
        v8::Local<v8::Array>::Cast(attrHandle->Get(Nan::New("vals").ToLocalChecked()));
      int attrValsLength = attrValsHandle->Length();
      ldapmods[i]->mod_values = (char **) malloc(sizeof(char *) *
                                                 (attrValsLength + 1));
      for (int j = 0; j < attrValsLength; j++) {
        Nan::Utf8String modValue(attrValsHandle->Get(Nan::New(j)));
        ldapmods[i]->mod_values[j] = strdup(*modValue);
      }
      ldapmods[i]->mod_values[attrValsLength] = NULL;
    }

    ldapmods[numattrs] = NULL;

    int msgid = ldap_add(ld->ld, *dn, ldapmods);

    info.GetReturnValue().Set(msgid);
    // TODO: free?
  } else {

 }

}
<commit_msg>Added namespace v8<commit_after>#include "LDAPCnx.h"

static struct timeval ldap_tv = { 0, 0 };

using namespace v8;

Nan::Persistent<Function> LDAPCnx::constructor;

LDAPCnx::LDAPCnx(double value) {
}

LDAPCnx::~LDAPCnx() {
  delete this->callback;
}

void LDAPCnx::Init(Local<Object> exports) {
  Nan::HandleScope scope;

  // Prepare constructor template
  Local<FunctionTemplate> tpl = Nan::New<FunctionTemplate>(New);
  tpl->SetClassName(Nan::New("LDAPCnx").ToLocalChecked());
  tpl->InstanceTemplate()->SetInternalFieldCount(1);

  // Prototype
  Nan::SetPrototypeMethod(tpl, "search", Search);
  Nan::SetPrototypeMethod(tpl, "delete", Delete);
  Nan::SetPrototypeMethod(tpl, "bind", Bind);
  Nan::SetPrototypeMethod(tpl, "add", Add);
  Nan::SetPrototypeMethod(tpl, "modify", Modify);
  Nan::SetPrototypeMethod(tpl, "rename", Rename);
  Nan::SetPrototypeMethod(tpl, "initialize", Initialize);
  Nan::SetPrototypeMethod(tpl, "errorstring", GetErr);

  constructor.Reset(tpl->GetFunction());
  exports->Set(Nan::New("LDAPCnx").ToLocalChecked(), tpl->GetFunction());
}

void LDAPCnx::New(const Nan::FunctionCallbackInfo<Value>& info) {
  if (info.IsConstructCall()) {
    // Invoked as constructor: `new LDAPCnx(...)`
    double value = info[0]->IsUndefined() ? 0 : info[0]->NumberValue();
    LDAPCnx* obj = new LDAPCnx(value);
    obj->Wrap(info.Holder());

    obj->callback = new Nan::Callback(info[1].As<Function>());

    info.GetReturnValue().Set(info.Holder());
  } else {
    // Invoked as plain function `LDAPCnx(...)`, turn into construct call.
    const int argc = 1;
    Local<Value> argv[argc] = { info[0] };
    Local<Function> cons = Nan::New<Function>(constructor);

    info.GetReturnValue().Set(cons->NewInstance(argc, argv));
  }
}

void LDAPCnx::Event(uv_poll_t* handle, int status, int events) {
  Nan::HandleScope scope;

  LDAPCnx *ld = (LDAPCnx *)handle->data;
  LDAPMessage * message = NULL;
  LDAPMessage * entry = NULL;
  Local<Value> errparam;

  switch(ldap_result(ld->ld, LDAP_RES_ANY, LDAP_MSG_ALL, &ldap_tv, &message)) {
  case 0:
    // timeout occurred
  case -1:
    {
      // We can't really do much; we don't have a msgid...
      break;
    }
  default:
    {
      int err = ldap_result2error(ld->ld, message, 0);
      if (err) {
        errparam = Nan::Error(ldap_err2string(err));
      } else {
        errparam = Nan::Undefined();
      }

      switch ( ldap_msgtype( message ) ) {
      case LDAP_RES_SEARCH_REFERENCE:
        break;
      case LDAP_RES_SEARCH_ENTRY:
      case LDAP_RES_SEARCH_RESULT:
        {
          Local<Array> js_result_list = Nan::New<Array>(ldap_count_entries(ld->ld, message));

          int j;

          for (entry = ldap_first_entry(ld->ld, message), j = 0 ; entry ;
               entry = ldap_next_entry(ld->ld, entry), j++) {
            Local<Object> js_result = Nan::New<Object>();

            js_result_list->Set(Nan::New(j), js_result);

            char * dn = ldap_get_dn(ld->ld, entry);
            BerElement * berptr = NULL;
            for (char * attrname = ldap_first_attribute(ld->ld, entry, &berptr) ;
                 attrname ; attrname = ldap_next_attribute(ld->ld, entry, berptr)) {
              berval ** vals = ldap_get_values_len(ld->ld, entry, attrname);
              int num_vals = ldap_count_values_len(vals);
              Local<Array> js_attr_vals = Nan::New<Array>(num_vals);
              js_result->Set(Nan::New(attrname).ToLocalChecked(), js_attr_vals);

              // int bin = ld->isBinary(attrname);
              int bin = 0;

              for (int i = 0 ; i < num_vals && vals[i] ; i++) {
                if (bin) {
                  // js_attr_vals->Set(Nan::New(i), ld->makeBuffer(vals[i]));
                } else {
                  js_attr_vals->Set(Nan::New(i), Nan::New(vals[i]->bv_val).ToLocalChecked());
                }
              } // all values for this attr added.
              ldap_value_free_len(vals);
              ldap_memfree(attrname);
            } // attrs for this entry added. Next entry.
            js_result->Set(Nan::New("dn").ToLocalChecked(), Nan::New(dn).ToLocalChecked());
            ber_free(berptr,0);
            ldap_memfree(dn);
          } // all entries done.

          Local<Value> argv[] = {
            errparam,
            Nan::New(ldap_msgid(message)),
            js_result_list
          };
          ld->callback->Call(3, argv);
          break;
        }
      case LDAP_RES_BIND:
      case LDAP_RES_MODIFY:
      case LDAP_RES_MODDN:
      case LDAP_RES_ADD:
      case LDAP_RES_DELETE:
        {
          Local<Value> argv[] = {
            errparam,
            Nan::New(ldap_msgid(message))
          };
          ld->callback->Call(2, argv);
          break;
        }
      default:
        {

          //emit an error
          // Nan::ThrowError("Unrecognized packet");
        }
      }
    }
  }
  ldap_msgfree(message);
  return;
}

void LDAPCnx::Initialize(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String url(info[0]);
  uv_poll_t * handle = new uv_poll_t;
  handle->data = ld;
  int fd = 0;
  int ver = 3;

  if (ldap_initialize(&(ld->ld), *url) != LDAP_SUCCESS) {
    Nan::ThrowError("Error init");
    return;
  }

   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);
   ldap_set_option(ld->ld, LDAP_OPT_PROTOCOL_VERSION, &ver);

   if ((ldap_simple_bind(ld->ld, NULL, NULL)) == -1) {
     Nan::ThrowError("Error anon bind");
     return;
   }
   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);

   ldap_get_option(ld->ld, LDAP_OPT_DESC, &fd);

   if (fd < 0) {
     Nan::ThrowError("Connection issue");
     return;
   }

   uv_poll_init(uv_default_loop(), handle, fd);
   uv_poll_start(handle, UV_READABLE, Event);

   info.GetReturnValue().Set(info.This());
}

void LDAPCnx::GetErr(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  int err;
  ldap_get_option(ld->ld, LDAP_OPT_RESULT_CODE, &err);
  info.GetReturnValue().Set(Nan::New(ldap_err2string(err)).ToLocalChecked());
}

void LDAPCnx::Delete(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);

  info.GetReturnValue().Set(ldap_delete(ld->ld, *dn));
}

void LDAPCnx::Bind(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  Nan::Utf8String pw(info[1]);

  info.GetReturnValue().Set(ldap_simple_bind(ld->ld, *dn, *pw));
}

void LDAPCnx::Rename(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  Nan::Utf8String newrdn(info[1]);
  int res;

  ldap_rename(ld->ld, *dn, *newrdn, NULL, 1, NULL, NULL, &res);

  info.GetReturnValue().Set(res);
}

void LDAPCnx::Search(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String base(info[0]);
  Nan::Utf8String filter(info[1]);
  Nan::Utf8String attrs(info[2]);
  int msgid = 0;
  int res;
  char * attrlist[255];

  char *bufhead = strdup(*attrs);
  char *buf = bufhead;
  char **ap;
  for (ap = attrlist; (*ap = strsep(&buf, " \t,")) != NULL;)
    if (**ap != '\0')
      if (++ap >= &attrlist[255])
        break;

  res = ldap_search_ext(ld->ld, *base, 2, *filter , (char **)attrlist, 0,
                         NULL, NULL, NULL, 0, &msgid);

  free(bufhead);

  info.GetReturnValue().Set(msgid);
}

void LDAPCnx::Modify(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);

  Handle<Array> mods = Handle<Array>::Cast(info[1]);
  unsigned int nummods = mods->Length();

  LDAPMod **ldapmods = (LDAPMod **) malloc(sizeof(LDAPMod *) * (nummods + 1));

  for (unsigned int i = 0; i < nummods; i++) {
    Local<Object> modHandle =
      Local<Object>::Cast(mods->Get(Nan::New(i)));

    ldapmods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));

    String::Utf8Value mod_op(modHandle->Get(Nan::New("op").ToLocalChecked()));

    if (!strcmp(*mod_op, "add")) {
      ldapmods[i]->mod_op = LDAP_MOD_ADD;
    } else if (!strcmp(*mod_op, "delete")) {
      ldapmods[i]->mod_op = LDAP_MOD_DELETE;
    } else {
      ldapmods[i]->mod_op = LDAP_MOD_REPLACE;
    }

    String::Utf8Value mod_type(modHandle->Get(Nan::New("attr").ToLocalChecked()));
    ldapmods[i]->mod_type = strdup(*mod_type);

    Local<Array> modValsHandle =
      Local<Array>::Cast(modHandle->Get(Nan::New("vals").ToLocalChecked()));

    int modValsLength = modValsHandle->Length();
    ldapmods[i]->mod_values = (char **) malloc(sizeof(char *) *
                                               (modValsLength + 1));
    for (int j = 0; j < modValsLength; j++) {
      Nan::Utf8String modValue(modValsHandle->Get(Nan::New(j)));
      ldapmods[i]->mod_values[j] = strdup(*modValue);
    }
    ldapmods[i]->mod_values[modValsLength] = NULL;
  }
  ldapmods[nummods] = NULL;

  int msgid = ldap_modify(ld->ld, *dn, ldapmods);

  // TODO: free?

  info.GetReturnValue().Set(msgid);
}

void LDAPCnx::Add(const Nan::FunctionCallbackInfo<Value>& info) {
  LDAPCnx* ld = ObjectWrap::Unwrap<LDAPCnx>(info.Holder());
  Nan::Utf8String dn(info[0]);
  if (info[1]->IsArray()) {
    Handle<Array> attrs = Handle<Array>::Cast(info[1]);
    unsigned int numattrs = attrs->Length();

    LDAPMod **ldapmods = (LDAPMod **) malloc(sizeof(LDAPMod *) * (numattrs + 1));
    for (unsigned int i = 0; i < numattrs; i++) {
      Local<Object> attrHandle =
        Local<Object>::Cast(attrs->Get(Nan::New(i)));

      ldapmods[i] = (LDAPMod *) malloc(sizeof(LDAPMod));

      // Step 1: mod_op
      ldapmods[i]->mod_op = LDAP_MOD_ADD;

      // Step 2: mod_type
      String::Utf8Value mod_type(attrHandle->Get(Nan::New("attr").ToLocalChecked()));
      ldapmods[i]->mod_type = strdup(*mod_type);

      // Step 3: mod_vals
      Local<Array> attrValsHandle =
        Local<Array>::Cast(attrHandle->Get(Nan::New("vals").ToLocalChecked()));
      int attrValsLength = attrValsHandle->Length();
      ldapmods[i]->mod_values = (char **) malloc(sizeof(char *) *
                                                 (attrValsLength + 1));
      for (int j = 0; j < attrValsLength; j++) {
        Nan::Utf8String modValue(attrValsHandle->Get(Nan::New(j)));
        ldapmods[i]->mod_values[j] = strdup(*modValue);
      }
      ldapmods[i]->mod_values[attrValsLength] = NULL;
    }

    ldapmods[numattrs] = NULL;

    int msgid = ldap_add(ld->ld, *dn, ldapmods);

    info.GetReturnValue().Set(msgid);
    // TODO: free?
  } else {

 }

}
<|endoftext|>


<commit_before>#include "Iop_Stdio.h"
#include <boost/lexical_cast.hpp>
#include "lexical_cast_ex.h"
#include "../Log.h"

#define LOG_NAME			"iop_stdio"

#define FUNCTION_PRINTF		"printf"

using namespace Iop;

CStdio::CStdio(uint8* ram)
: m_ram(ram)
{

}

CStdio::~CStdio()
{

}

std::string CStdio::GetId() const
{
	return "stdio";
}

std::string CStdio::GetFunctionName(unsigned int functionId) const
{
	switch(functionId)
	{
	case 4:
		return FUNCTION_PRINTF;
		break;
	default:
		return "unknown";
		break;
	}
}

void CStdio::Invoke(CMIPS& context, unsigned int functionId)
{
	switch(functionId)
	{
	case 4:
		__printf(context);
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Unknown function (%d) called. PC = (%0.8X).",
			functionId, context.m_State.nPC);
		break;
	}
}

std::string CStdio::PrintFormatted(CArgumentIterator& args)
{
	std::string output;
	const char* format = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
	while(*format != 0)
	{
		char character = *(format++);
		if(character == '%')
		{
			bool paramDone = false;
			bool inPrecision = false;
			char fillChar = ' ';
			std::string precision;
			while(!paramDone && *format != 0)
			{
				char type = *(format++);
				if(type == 's')
				{
					const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
					output += text;
					paramDone = true;
				}
				else if(type == 'c')
				{
					char character = static_cast<char>(args.GetNext());
					output += character;
					paramDone = true;
				}
				else if(type == 'd' || type == 'i')
				{
					int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
					paramDone = true;
				}
				else if(type == 'u')
				{
					unsigned int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_uint<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'x' || type == 'X')
				{
					uint32 number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 0;
					output += lexical_cast_hex<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'l')
				{
					//Length specifier, don't bother about it.
				}
				else if(type == '.')
				{
					inPrecision = true;
				}
				else
				{
					assert(isdigit(type));
					if(inPrecision)
					{
						precision += type;
					}
					else
					{
						fillChar = type;
						inPrecision = true;
					}
				}
			}
		}
		else
		{
			output += character;
		}
	}
	return output;
}

void CStdio::__printf(CMIPS& context)
{
	CArgumentIterator args(context);
	std::string output = PrintFormatted(args);
	printf("%s", output.c_str());
}
<commit_msg>Added support for %p in Iop_Stdio printf.<commit_after>#include "Iop_Stdio.h"
#include <boost/lexical_cast.hpp>
#include "lexical_cast_ex.h"
#include "../Log.h"

#define LOG_NAME			"iop_stdio"

#define FUNCTION_PRINTF		"printf"

using namespace Iop;

CStdio::CStdio(uint8* ram)
: m_ram(ram)
{

}

CStdio::~CStdio()
{

}

std::string CStdio::GetId() const
{
	return "stdio";
}

std::string CStdio::GetFunctionName(unsigned int functionId) const
{
	switch(functionId)
	{
	case 4:
		return FUNCTION_PRINTF;
		break;
	default:
		return "unknown";
		break;
	}
}

void CStdio::Invoke(CMIPS& context, unsigned int functionId)
{
	switch(functionId)
	{
	case 4:
		__printf(context);
		break;
	default:
		CLog::GetInstance().Print(LOG_NAME, "Unknown function (%d) called. PC = (%0.8X).",
			functionId, context.m_State.nPC);
		break;
	}
}

std::string CStdio::PrintFormatted(CArgumentIterator& args)
{
	std::string output;
	const char* format = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
	while(*format != 0)
	{
		char character = *(format++);
		if(character == '%')
		{
			bool paramDone = false;
			bool inPrecision = false;
			char fillChar = ' ';
			std::string precision;
			while(!paramDone && *format != 0)
			{
				char type = *(format++);
				if(type == 's')
				{
					const char* text = reinterpret_cast<const char*>(&m_ram[args.GetNext()]);
					output += text;
					paramDone = true;
				}
				else if(type == 'c')
				{
					char character = static_cast<char>(args.GetNext());
					output += character;
					paramDone = true;
				}
				else if(type == 'd' || type == 'i')
				{
					int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_int<std::string>(number, precisionValue, fillChar);
					paramDone = true;
				}
				else if(type == 'u')
				{
					unsigned int number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 1;
					output += lexical_cast_uint<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'x' || type == 'X' || type == 'p')
				{
					uint32 number = args.GetNext();
					unsigned int precisionValue = precision.length() ? boost::lexical_cast<unsigned int>(precision) : 0;
					output += lexical_cast_hex<std::string>(number, precisionValue);
					paramDone = true;
				}
				else if(type == 'l')
				{
					//Length specifier, don't bother about it.
				}
				else if(type == '.')
				{
					inPrecision = true;
				}
				else
				{
					assert(isdigit(type));
					if(inPrecision)
					{
						precision += type;
					}
					else
					{
						fillChar = type;
						inPrecision = true;
					}
				}
			}
		}
		else
		{
			output += character;
		}
	}
	return output;
}

void CStdio::__printf(CMIPS& context)
{
	CArgumentIterator args(context);
	std::string output = PrintFormatted(args);
	printf("%s", output.c_str());
}
<|endoftext|>


<commit_before>/* Copyright 2013-2019 Barefoot Networks, Inc.
 * Copyright 2019 VMware, Inc.
 *
 * 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.
 */

/*
 * Antonin Bas
 *
 */

#include <gtest/gtest.h>

#include <bm/bm_sim/expressions.h>
#include <bm/bm_sim/phv.h>

// expressions are mostly tested in test_conditionals.cpp. This file is only
// used for some edge case testing.

using namespace::bm;

class ExpressionsTest : public ::testing::Test {
 protected:
  PHVFactory phv_factory;
  std::unique_ptr<PHV> phv;

  HeaderType testHeaderType;
  header_id_t testHeader1{0}, testHeader2{1};

  header_stack_id_t testHeaderStack{0};

  ExpressionsTest()
      : testHeaderType("test_t", 0) {
    testHeaderType.push_back_field("f32", 32);
    testHeaderType.push_back_field("f48", 48);
    testHeaderType.push_back_field("f8", 8);
    testHeaderType.push_back_field("f16", 16);
    testHeaderType.push_back_field("f128", 128);
    phv_factory.push_back_header("test1", testHeader1, testHeaderType);
    phv_factory.push_back_header("test2", testHeader2, testHeaderType);

    phv_factory.push_back_header_stack(
        "test_stack", testHeaderStack, testHeaderType,
        {testHeader1, testHeader2});
  }

  virtual void SetUp() {
    phv = phv_factory.create();
  }

  // virtual void TearDown() {}
};

TEST_F(ExpressionsTest, EmptyArith) {
  Expression expr;
  expr.build();
  ASSERT_TRUE(expr.empty());
  const auto data = expr.eval_arith(*phv.get());
  EXPECT_EQ(0, data.get<int>());
}

TEST_F(ExpressionsTest, EmptyBool) {
  Expression expr;
  expr.build();
  ASSERT_TRUE(expr.empty());
  const auto b = expr.eval_bool(*phv.get());
  EXPECT_FALSE(b);
}

// TODO(antonin): test the union variants

TEST_F(ExpressionsTest, HeaderRef) {
  Expression expr;
  expr.push_back_load_header(testHeader1);
  expr.build();

  auto &hdr = expr.eval_header(phv.get());
  EXPECT_EQ(&phv->get_header(testHeader1), &hdr);
}

TEST_F(ExpressionsTest, HeaderStackRef) {
  Expression expr;
  expr.push_back_load_header_stack(testHeaderStack);
  expr.build();

  auto &stack = expr.eval_header_stack(phv.get());
  EXPECT_EQ(&phv->get_header_stack(testHeaderStack), &stack);
}

TEST_F(ExpressionsTest, FieldRef) {
  Expression expr;
  expr.push_back_load_header_stack(testHeaderStack);
  expr.push_back_load_const(Data(1));  // testHeader2
  expr.push_back_op(ExprOpcode::DEREFERENCE_HEADER_STACK);
  expr.push_back_access_field(3);  // f16
  expr.build();

  auto &data = expr.eval_arith_lvalue(phv.get());
  EXPECT_EQ(&phv->get_field(testHeader2, 3), &data);
}
<commit_msg>Add test case for out-of-bounds stack access in expressions<commit_after>/* Copyright 2013-2019 Barefoot Networks, Inc.
 * Copyright 2019 VMware, Inc.
 *
 * 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.
 */

/*
 * Antonin Bas
 *
 */

#include <gtest/gtest.h>

#include <bm/bm_sim/expressions.h>
#include <bm/bm_sim/phv.h>

#include <memory>
#include <stdexcept>

// expressions are mostly tested in test_conditionals.cpp. This file is only
// used for some edge case testing.

using namespace::bm;

class ExpressionsTest : public ::testing::Test {
 protected:
  PHVFactory phv_factory;
  std::unique_ptr<PHV> phv;

  HeaderType testHeaderType;
  header_id_t testHeader1{0}, testHeader2{1};

  header_stack_id_t testHeaderStack{0};

  ExpressionsTest()
      : testHeaderType("test_t", 0) {
    testHeaderType.push_back_field("f32", 32);
    testHeaderType.push_back_field("f48", 48);
    testHeaderType.push_back_field("f8", 8);
    testHeaderType.push_back_field("f16", 16);
    testHeaderType.push_back_field("f128", 128);
    phv_factory.push_back_header("test1", testHeader1, testHeaderType);
    phv_factory.push_back_header("test2", testHeader2, testHeaderType);

    phv_factory.push_back_header_stack(
        "test_stack", testHeaderStack, testHeaderType,
        {testHeader1, testHeader2});
  }

  virtual void SetUp() {
    phv = phv_factory.create();
  }

  // virtual void TearDown() {}
};

TEST_F(ExpressionsTest, EmptyArith) {
  Expression expr;
  expr.build();
  ASSERT_TRUE(expr.empty());
  const auto data = expr.eval_arith(*phv.get());
  EXPECT_EQ(0, data.get<int>());
}

TEST_F(ExpressionsTest, EmptyBool) {
  Expression expr;
  expr.build();
  ASSERT_TRUE(expr.empty());
  const auto b = expr.eval_bool(*phv.get());
  EXPECT_FALSE(b);
}

// TODO(antonin): test the union variants

TEST_F(ExpressionsTest, HeaderRef) {
  Expression expr;
  expr.push_back_load_header(testHeader1);
  expr.build();

  auto &hdr = expr.eval_header(phv.get());
  EXPECT_EQ(&phv->get_header(testHeader1), &hdr);
}

TEST_F(ExpressionsTest, HeaderStackRef) {
  Expression expr;
  expr.push_back_load_header_stack(testHeaderStack);
  expr.build();

  auto &stack = expr.eval_header_stack(phv.get());
  EXPECT_EQ(&phv->get_header_stack(testHeaderStack), &stack);
}

TEST_F(ExpressionsTest, FieldRef) {
  Expression expr;
  expr.push_back_load_header_stack(testHeaderStack);
  expr.push_back_load_const(Data(1));  // testHeader2
  expr.push_back_op(ExprOpcode::DEREFERENCE_HEADER_STACK);
  expr.push_back_access_field(3);  // f16
  expr.build();

  auto &data = expr.eval_arith_lvalue(phv.get());
  EXPECT_EQ(&phv->get_field(testHeader2, 3), &data);
}

TEST_F(ExpressionsTest, OutOfBoundsStackAccess) {
  Expression expr;
  expr.push_back_load_header_stack(testHeaderStack);
  expr.push_back_load_const(Data(2));  // out-of-bounds access
  expr.push_back_op(ExprOpcode::DEREFERENCE_HEADER_STACK);
  expr.build();

  // At the moment, we simply throw an exception which should crash the bmv2
  // process unless it is caught somewhere (e.g. in the target code). In the
  // future, we may log an error message as well.
  EXPECT_THROW(expr.eval_header(phv.get()), std::out_of_range);
}
<|endoftext|>


<commit_before>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qi/signal.hpp>
#include <qi/future.hpp>
#include <qi/signalspy.hpp>
#include <qi/anyobject.hpp>
#include <qi/application.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include <qi/type/dynamicobjectbuilder.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(qi::Atomic<int>* r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); ++*r;
  }
  void func2(qi::Atomic<int>* r, int, int) { ++*r; }
};
void foo(qi::Atomic<int>* r, int, int)     { ++*r; }
void foo2(qi::Atomic<int>* r, char, char)  { ++*r; }
void foo3(qi::Atomic<int>* r, Foo *)       { ++*r; }
void foolast(int, qi::Promise<void> prom, qi::Atomic<int>* r) { prom.setValue(0); ++*r; }

TEST(TestSignal, TestCompilation)
{
  qi::Atomic<int>        res{0};
  qi::Signal<int> s;
  Foo*                   f = (Foo*)1;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::AnyFunction::from(&Foo::func, f));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);

  while (res.load() != 6)
    qi::os::msleep(10);

  ASSERT_EQ(6, res.load());
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<boost::shared_ptr<int> > sig;
  sig.connect(qi::AnyFunction::from(&write42)).setCallType(qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  qi::Atomic<int> r{0};
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<qi::Atomic<int>*, int> sig;
  sig.connect(&Foo::func1, boost::weak_ptr<Foo>(foo), _1, _2).setCallType(qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
}

void waitFuture(qi::Atomic<int>& cnt, qi::Promise<void> start, qi::Future<void> f)
{
  if (++cnt == 2)
    start.setValue(0);
  f.wait();

  // force disconnection, may trigger a segfault
  throw qi::PointerLockException();
}

TEST(TestSignal, NonBlockingDestroy)
{
  // disconnect is blocking, but signal destruction should not be

  qi::Promise<void> start;
  qi::Promise<void> finish;
  qi::Atomic<int> cnt{0};

  {
    qi::Signal<void> sig;
    sig.connect(boost::bind(waitFuture, boost::ref(cnt), start, finish.future()));

    sig();
    sig();

    start.future().wait();
    // now that the callback is running, destroy the signal
  }

  // all went well, unblock the callback
  finish.setValue(0);
}

TEST(TestSignal, BadArity)
{
  // Test runtime detection of arity errors
  qi::Signal<> s;
  // avoid using s.connect() which will catch the problem at compile-time
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo))));
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo2))));
  EXPECT_ANY_THROW(s.connect(qi::AnyFunction::from((boost::function<void(qi::Atomic<int>*, int)>)boost::bind(&Foo::func1, (Foo*)0, _1, _2))));
}

void lol(int v, int& target)
{
  target = v;
}
TEST(TestSignal, SignalSignal)
{
  qi::SignalF<void (int)> sig1;
  qi::SignalF<void (int)> *sig2 = new  qi::SignalF<void (int)>();
  sig1.connect(*sig2);
  qi::SignalSpy spy(*sig2);
  sig1(10);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(10, spy.record(0).arg<int>(0));

  // Test autodisconnect
  delete sig2;
  sig1(20);
  ASSERT_FALSE(spy.waitUntil(2, qi::MilliSeconds(300)));
}

class SignalTest {
public:
  qi::Signal<int> sig;
  qi::Signal<int> sig2;
};

TEST(TestSignal, SignalSignal2)
{
  SignalTest st;
  qi::SignalSpy spy(st.sig2);
  st.sig.connect(st.sig2);
  qiLogDebug() << "sigptrs are " << &st.sig << " " << &st.sig2;
  st.sig(4242);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  assert(spy.recordCount() == 1u);
  EXPECT_EQ(4242, spy.lastRecord().arg<int>(0));
}

TEST(TestSignal, SignalN)
{
  qi::Signal<int> sig;
  qi::SignalSpy spy(sig);
  sig(5);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(5, spy.lastRecord().arg<int>(0));
}

class SigHolder
{
public:
  qi::Signal<> s0;
  qi::Signal<int> s1;
  qi::Signal<int, int> s2;
  void fire0() { s0();}
  void fire1(int i) { s1(i); }
  void fire2(int i, int j) { s2(i, j);}
};

QI_REGISTER_OBJECT(SigHolder, s0, s1, s2, fire0, fire1, fire2)

TEST(TestSignal, SignalNBind)
{
  int res = 0;
  boost::shared_ptr<SigHolder> so(new SigHolder);
  qi::AnyObject op = qi::AnyReference::from(so).to<qi::AnyObject>();
  qi::detail::printMetaObject(std::cerr, op.metaObject());
  op.connect("s1", (boost::function<void(int)>)boost::bind<void>(&lol, _1, boost::ref(res)));
  op.post("s1", 2);
  for (unsigned i=0; i<30 && res!=2; ++i) qi::os::msleep(10);
  ASSERT_EQ(2, res);
  so->s1(3);
  for (unsigned i=0; i<30 && res!=3; ++i) qi::os::msleep(10);
  ASSERT_EQ(3, res);
  so->s0.connect( boost::bind<void>(&lol, 42, boost::ref(res)));
  op.post("s0");
  for (unsigned i=0; i<30 && res!=42; ++i) qi::os::msleep(10);
  ASSERT_EQ(42, res);
}

void foothrow() {
  throw 42;
}

TEST(TestSignal, SignalThrow)
{
  qi::Signal<> sig;
  sig.connect(boost::bind<void>(&foothrow));
  ASSERT_NO_THROW(sig());
  qi::os::msleep(50);
}

void dynTest0(int& tgt)                     { tgt |= 1;}
void dynTest1(int& tgt, int)                { tgt |= 2;}
void dynTest2(int& tgt, int, int)           { tgt |= 4;}
void dynTest3(int& tgt, int, std::string)   { tgt |= 8;}
void dynTestN(int& tgt, const qi::AnyArguments& a)   { tgt |= 32;}
qi::AnyReference dynTestN2(int& tgt, const std::vector<qi::AnyReference>& a)   { tgt |= 16; return qi::AnyReference();}

TEST(TestSignal, Dynamic)
{
  qi::SignalBase s(qi::Signature("m"));
  int trig = 0;
  s.setCallType(qi::MetaCallType_Direct);
  s.connect((boost::function<void()>) boost::bind(&dynTest0, boost::ref(trig)));
  s.connect((boost::function<void(int)>) boost::bind(&dynTest1, boost::ref(trig), _1));
  s.connect((boost::function<void(int, int)>) boost::bind(&dynTest2, boost::ref(trig), _1, _2));
  s.connect((boost::function<void(int, std::string)>) boost::bind(&dynTest3, boost::ref(trig), _1, _2));
  s.connect(qi::AnyFunction::fromDynamicFunction(boost::bind(&dynTestN2, boost::ref(trig), _1)));
  s.connect((boost::function<void(const qi::AnyArguments&)>)(boost::bind(&dynTestN, boost::ref(trig), _1)));
  int a, b;
  std::string c;
  qi::GenericFunctionParameters params;
  s.trigger(params);
  EXPECT_EQ(49, trig);
  params.push_back(qi::AnyReference::from(a));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(50, trig);
  params.push_back(qi::AnyReference::from(b));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(52, trig);
  params[1] = qi::AnyReference::from(c);
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(56, trig);
}

void onSubs(std::atomic<bool>& var, bool subs)
{
  var = subs;
}

void callback(int i)
{}

TEST(TestSignal, OnSubscriber)
{
  std::atomic<bool> subscribers(false);

  qi::Signal<int> sig(boost::bind(onSubs, boost::ref(subscribers), _1));
  ASSERT_FALSE(subscribers);
  qi::SignalLink l = sig.connect(&callback);
  ASSERT_TRUE(subscribers);
  ASSERT_TRUE(sig.disconnect(l));
  ASSERT_FALSE(subscribers);
}

void store2(qi::Promise<int> variable1, qi::Promise<int> variable2, int value1, int value2)
{
  variable1.setValue(value1);
  variable2.setValue(value2);
}

TEST(TestSignal, SignalToSignalWithExtraArgument)
{
  qi::Promise<int> target1, target2;
  qi::Signal<int> signal1;
  qi::Signal<int, int> signal2;
  signal1.connect(boost::bind(boost::ref(signal2), _1, 42));
  signal2.connect(store2, target1, target2, _1, _2);
  signal1(12);
  EXPECT_EQ(12, target1.future().value());
  EXPECT_EQ(42, target2.future().value());
}

TEST(TestSignalSpy, Counter)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp.getCounter(), 2u);

  qi::DynamicObjectBuilder ob;
  ob.advertiseSignal("signal", &sig);
  qi::AnyObject obj(ob.object());
  qi::SignalSpy sp2(obj, "signal");
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp2.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp2.getCounter(), 2u);
}

TEST(TestSignalSpy, Async)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  qi::async(boost::bind(boost::ref(sig), 1));
  qi::async(boost::bind(boost::ref(sig), 1));
  ASSERT_TRUE(sp.waitUntil(2, qi::Seconds(1)));
  ASSERT_EQ(sp.recordCount(), 2u);
}

TEST(TestSignalSpy, StoringTypedValueRecords)
{
  const std::vector<int> ints{ 1, 42, 13, 2016 };
  const std::vector<std::string> strings{ "poil", "slip", "banane", "pancréas" };
  qi::Signal<int, std::string> signal;
  qi::SignalSpy spy(signal);

  signal(ints[0], strings[0]);
  ASSERT_EQ(1u, spy.recordCount());
  auto record = spy.record(0);
  ASSERT_EQ(ints[0], record.arg<int>(0));
  ASSERT_EQ(strings[0], record.arg<std::string>(1));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    signal(ints[i], strings[i]);
  }
  spy.waitUntil(ints.size(), qi::MilliSeconds(300));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    record = spy.record(i);
    EXPECT_EQ(ints[i], record.arg<int>(0));
    EXPECT_EQ(strings[i], record.arg<std::string>(1));
  }

  auto records = spy.allRecords();
  ASSERT_EQ(ints.size(), records.size());
  for(auto i = 0u; i < records.size(); ++i)
  {
    EXPECT_EQ(ints[i], records[i].arg<int>(0));
    EXPECT_EQ(strings[i], records[i].arg<std::string>(1));
  }
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  qi::log::addFilter("*", qi::LogLevel_Debug);
  return RUN_ALL_TESTS();
}
<commit_msg>Signal: add a test to demonstrate a property of the signal subscriber<commit_after>/*
** Author(s):
**  - Cedric GESTES <gestes@aldebaran-robotics.com>
**
** Copyright (C) 2012 Aldebaran Robotics
*/

#include <gtest/gtest.h>
#include <qi/signal.hpp>
#include <qi/future.hpp>
#include <qi/signalspy.hpp>
#include <qi/anyobject.hpp>
#include <qi/application.hpp>
#include <qi/type/objecttypebuilder.hpp>
#include <qi/type/dynamicobjectbuilder.hpp>

qiLogCategory("test");

class Foo
{
public:
  void func(int)               { }
  void func1(qi::Atomic<int>* r, int)
  {
    // hackish sleep so that asynchronous trigger detection is safer
    qi::os::msleep(1); ++*r;
  }
  void func2(qi::Atomic<int>* r, int, int) { ++*r; }
};
void foo(qi::Atomic<int>* r, int, int)     { ++*r; }
void foo2(qi::Atomic<int>* r, char, char)  { ++*r; }
void foo3(qi::Atomic<int>* r, Foo *)       { ++*r; }
void foolast(int, qi::Promise<void> prom, qi::Atomic<int>* r) { prom.setValue(0); ++*r; }

TEST(TestSignal, TestCompilation)
{
  qi::Atomic<int>        res{0};
  qi::Signal<int> s;
  Foo*                   f = (Foo*)1;
  qi::Promise<void>      prom;

  //do not count
  s.connect(qi::AnyFunction::from(&Foo::func, f));
  s.connect(boost::bind<void>(&Foo::func, f, _1));

  s.connect(boost::bind(&foo, &res, 12, _1));
  s.connect(boost::bind(&foo2, &res, 12, _1));
  s.connect(boost::bind<void>(&Foo::func1, f, &res, _1));
  s.connect(boost::bind<void>(&Foo::func2, f, &res, 5, _1));
  s.connect(boost::bind(&foo3, &res, f));
  s.connect(boost::bind(&foolast, _1, prom, &res));

  s(42);

  while (res.load() != 6)
    qi::os::msleep(10);

  ASSERT_EQ(6, res.load());
  ASSERT_TRUE(prom.future().isFinished());
  ASSERT_FALSE(prom.future().hasError());
}

void write42(boost::shared_ptr<int> ptr)
{
  *ptr = 42;
}

TEST(TestSignal, SharedPtr)
{
  // Redundant with Copy test, but just to be sure, check that shared_ptr
  // is correctly transmited.
  qi::Signal<boost::shared_ptr<int> > sig;
  sig.connect(qi::AnyFunction::from(&write42)).setCallType(qi::MetaCallType_Queued);
  {
    boost::shared_ptr<int> ptr(new int(12));
    sig(ptr);
  };
}

void byRef(int& i, bool* done)
{
  qiLogDebug() <<"byRef " << &i << ' ' << done;
  i = 12;
  *done = true;
}

TEST(TestSignal, AutoDisconnect)
{
  // Test automatic disconnection when passing shared_ptrs
  qi::Atomic<int> r{0};
  boost::shared_ptr<Foo> foo(new Foo());
  qi::Signal<qi::Atomic<int>*, int> sig;
  sig.connect(&Foo::func1, boost::weak_ptr<Foo>(foo), _1, _2).setCallType(qi::MetaCallType_Direct);
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
  foo.reset();
  sig(&r, 0);
  ASSERT_EQ(1, r.load());
}

void waitFuture(qi::Atomic<int>& cnt, qi::Promise<void> start, qi::Future<void> f)
{
  if (++cnt == 2)
    start.setValue(0);
  f.wait();

  // force disconnection, may trigger a segfault
  throw qi::PointerLockException();
}

TEST(TestSignal, NonBlockingDestroy)
{
  // disconnect is blocking, but signal destruction should not be

  qi::Promise<void> start;
  qi::Promise<void> finish;
  qi::Atomic<int> cnt{0};

  {
    qi::Signal<void> sig;
    sig.connect(boost::bind(waitFuture, boost::ref(cnt), start, finish.future()));

    sig();
    sig();

    start.future().wait();
    // now that the callback is running, destroy the signal
  }

  // all went well, unblock the callback
  finish.setValue(0);
}

TEST(TestSignal, BadArity)
{
  // Test runtime detection of arity errors
  qi::Signal<> s;
  // avoid using s.connect() which will catch the problem at compile-time
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo))));
  EXPECT_ANY_THROW(s.connect(qi::SignalSubscriber(qi::AnyFunction::from(&foo2))));
  EXPECT_ANY_THROW(s.connect(qi::AnyFunction::from((boost::function<void(qi::Atomic<int>*, int)>)boost::bind(&Foo::func1, (Foo*)0, _1, _2))));
}

void lol(int v, int& target)
{
  target = v;
}
TEST(TestSignal, SignalSignal)
{
  qi::SignalF<void (int)> sig1;
  qi::SignalF<void (int)> *sig2 = new  qi::SignalF<void (int)>();
  sig1.connect(*sig2);
  qi::SignalSpy spy(*sig2);
  sig1(10);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(10, spy.record(0).arg<int>(0));

  // Test autodisconnect
  delete sig2;
  sig1(20);
  ASSERT_FALSE(spy.waitUntil(2, qi::MilliSeconds(300)));
}

class SignalTest {
public:
  qi::Signal<int> sig;
  qi::Signal<int> sig2;
};

TEST(TestSignal, SignalSignal2)
{
  SignalTest st;
  qi::SignalSpy spy(st.sig2);
  st.sig.connect(st.sig2);
  qiLogDebug() << "sigptrs are " << &st.sig << " " << &st.sig2;
  st.sig(4242);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  assert(spy.recordCount() == 1u);
  EXPECT_EQ(4242, spy.lastRecord().arg<int>(0));
}

TEST(TestSignal, SignalN)
{
  qi::Signal<int> sig;
  qi::SignalSpy spy(sig);
  sig(5);
  ASSERT_TRUE(spy.waitUntil(1, qi::MilliSeconds(300)));
  ASSERT_EQ(5, spy.lastRecord().arg<int>(0));
}

class SigHolder
{
public:
  qi::Signal<> s0;
  qi::Signal<int> s1;
  qi::Signal<int, int> s2;
  void fire0() { s0();}
  void fire1(int i) { s1(i); }
  void fire2(int i, int j) { s2(i, j);}
};

QI_REGISTER_OBJECT(SigHolder, s0, s1, s2, fire0, fire1, fire2)

TEST(TestSignal, SignalNBind)
{
  int res = 0;
  boost::shared_ptr<SigHolder> so(new SigHolder);
  qi::AnyObject op = qi::AnyReference::from(so).to<qi::AnyObject>();
  qi::detail::printMetaObject(std::cerr, op.metaObject());
  op.connect("s1", (boost::function<void(int)>)boost::bind<void>(&lol, _1, boost::ref(res)));
  op.post("s1", 2);
  for (unsigned i=0; i<30 && res!=2; ++i) qi::os::msleep(10);
  ASSERT_EQ(2, res);
  so->s1(3);
  for (unsigned i=0; i<30 && res!=3; ++i) qi::os::msleep(10);
  ASSERT_EQ(3, res);
  so->s0.connect( boost::bind<void>(&lol, 42, boost::ref(res)));
  op.post("s0");
  for (unsigned i=0; i<30 && res!=42; ++i) qi::os::msleep(10);
  ASSERT_EQ(42, res);
}

void foothrow() {
  throw 42;
}

TEST(TestSignal, SignalThrow)
{
  qi::Signal<> sig;
  sig.connect(boost::bind<void>(&foothrow));
  ASSERT_NO_THROW(sig());
  qi::os::msleep(50);
}

void dynTest0(int& tgt)                     { tgt |= 1;}
void dynTest1(int& tgt, int)                { tgt |= 2;}
void dynTest2(int& tgt, int, int)           { tgt |= 4;}
void dynTest3(int& tgt, int, std::string)   { tgt |= 8;}
void dynTestN(int& tgt, const qi::AnyArguments& a)   { tgt |= 32;}
qi::AnyReference dynTestN2(int& tgt, const std::vector<qi::AnyReference>& a)   { tgt |= 16; return qi::AnyReference();}

TEST(TestSignal, Dynamic)
{
  qi::SignalBase s(qi::Signature("m"));
  int trig = 0;
  s.setCallType(qi::MetaCallType_Direct);
  s.connect((boost::function<void()>) boost::bind(&dynTest0, boost::ref(trig)));
  s.connect((boost::function<void(int)>) boost::bind(&dynTest1, boost::ref(trig), _1));
  s.connect((boost::function<void(int, int)>) boost::bind(&dynTest2, boost::ref(trig), _1, _2));
  s.connect((boost::function<void(int, std::string)>) boost::bind(&dynTest3, boost::ref(trig), _1, _2));
  s.connect(qi::AnyFunction::fromDynamicFunction(boost::bind(&dynTestN2, boost::ref(trig), _1)));
  s.connect((boost::function<void(const qi::AnyArguments&)>)(boost::bind(&dynTestN, boost::ref(trig), _1)));
  int a, b;
  std::string c;
  qi::GenericFunctionParameters params;
  s.trigger(params);
  EXPECT_EQ(49, trig);
  params.push_back(qi::AnyReference::from(a));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(50, trig);
  params.push_back(qi::AnyReference::from(b));
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(52, trig);
  params[1] = qi::AnyReference::from(c);
  trig = 0;
  s.trigger(params);
  EXPECT_EQ(56, trig);
}

void onSubs(std::atomic<bool>& var, bool subs)
{
  var = subs;
}

void callback(int i)
{}

TEST(TestSignal, OnSubscriber)
{
  std::atomic<bool> subscribers(false);

  qi::Signal<int> sig(boost::bind(onSubs, boost::ref(subscribers), _1));
  ASSERT_FALSE(subscribers);
  qi::SignalLink l = sig.connect(&callback);
  ASSERT_TRUE(subscribers);
  ASSERT_TRUE(sig.disconnect(l));
  ASSERT_FALSE(subscribers);
}

void store2(qi::Promise<int> variable1, qi::Promise<int> variable2, int value1, int value2)
{
  variable1.setValue(value1);
  variable2.setValue(value2);
}

TEST(TestSignal, SignalToSignalWithExtraArgument)
{
  qi::Promise<int> target1, target2;
  qi::Signal<int> signal1;
  qi::Signal<int, int> signal2;
  signal1.connect(boost::bind(boost::ref(signal2), _1, 42));
  signal2.connect(store2, target1, target2, _1, _2);
  signal1(12);
  EXPECT_EQ(12, target1.future().value());
  EXPECT_EQ(42, target2.future().value());
}

TEST(TestSignal, SignalSubscriberDoesNotUnsubscribeAtDestruction)
{
  int count = 0;
  qi::Signal<void> signal;
  auto subscriber = signal.connect([&]{ ++count; })
      .setCallType(qi::MetaCallType_Direct)
      .shared_from_this();
  signal();
  ASSERT_EQ(1, count);

  subscriber.reset();
  signal();
  ASSERT_EQ(2, count);
}

// ===========================================================
// Signal Spy
// -----------------------------------------------------------
TEST(TestSignalSpy, Counter)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp.getCounter(), 2u);

  qi::DynamicObjectBuilder ob;
  ob.advertiseSignal("signal", &sig);
  qi::AnyObject obj(ob.object());
  qi::SignalSpy sp2(obj, "signal");
  QI_EMIT sig(1);
  QI_EMIT sig(1);
  ASSERT_TRUE(sp2.waitUntil(2, qi::MilliSeconds(300)));
  ASSERT_EQ(sp2.getCounter(), 2u);
}

TEST(TestSignalSpy, Async)
{
  qi::Signal<int> sig;
  qi::SignalSpy sp(sig);
  qi::async(boost::bind(boost::ref(sig), 1));
  qi::async(boost::bind(boost::ref(sig), 1));
  ASSERT_TRUE(sp.waitUntil(2, qi::Seconds(1)));
  ASSERT_EQ(sp.recordCount(), 2u);
}

TEST(TestSignalSpy, StoringTypedValueRecords)
{
  const std::vector<int> ints{ 1, 42, 13, 2016 };
  const std::vector<std::string> strings{ "poil", "slip", "banane", "pancréas" };
  qi::Signal<int, std::string> signal;
  qi::SignalSpy spy(signal);

  signal(ints[0], strings[0]);
  ASSERT_EQ(1u, spy.recordCount());
  auto record = spy.record(0);
  ASSERT_EQ(ints[0], record.arg<int>(0));
  ASSERT_EQ(strings[0], record.arg<std::string>(1));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    signal(ints[i], strings[i]);
  }
  spy.waitUntil(ints.size(), qi::MilliSeconds(300));

  for(auto i = 1u; i < ints.size(); ++i)
  {
    record = spy.record(i);
    EXPECT_EQ(ints[i], record.arg<int>(0));
    EXPECT_EQ(strings[i], record.arg<std::string>(1));
  }

  auto records = spy.allRecords();
  ASSERT_EQ(ints.size(), records.size());
  for(auto i = 0u; i < records.size(); ++i)
  {
    EXPECT_EQ(ints[i], records[i].arg<int>(0));
    EXPECT_EQ(strings[i], records[i].arg<std::string>(1));
  }
}

int main(int argc, char **argv) {
  qi::Application app(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  qi::log::addFilter("*", qi::LogLevel_Debug);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>// Implementation file for String functions, include this file in string.h
// DO NOT INCLUDE/COMPILE THIS FILE SEPARATELY.
#ifdef CODE_STRING_H

/*******************************
* 1. Constructors and operator =
*******************************/

// empty constructor.
String::String() {
	_len = 0;
	_data = 0;
}

// copy contructors : assignment is copy
String::String(const String& s) {
	_len = s.length();
	_data = 0;
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s.charAt(i);
}

String::String(const char *s) {
	_len = strlen(s);
	_data = 0;
	_data = new char[ _len ];
	if( !_data ) forcequit(10);
	for( __SIZETYPE i=0; i<_len; i++)
		_data[i] = s[i];
}

String::String(char ch) {
	_len = 1;
	_data = 0;
	_data = new char[1];
	if( !_data ) forcequit(10);
	_data[0] = ch;
}

// operator =
String& String::operator= (const String& s) {
	_len = s.length();
	delete[] _data;
	_data = 0;
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s.charAt(i);
	return *this;
}

String& String::operator= (const char* s ) {
	_len = strlen(s);
	delete[] _data;
	_data = 0;
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s[i];
	return *this;
}

String& String::operator=(char ch ) {
	_len = 1;
	delete[] _data;
	_data = 0;
	_data = new char[1];
	if( !_data ) forcequit(10);
	_data[0] = ch;
	return *this;
}
// Destructor : free some space
String::~String() {
	clear();
}
// clears all data.
bool String::clear() {
	_len = 0;
	delete[] _data;
	delete[] _data2;
	_data = 0;
	return 1;
}

// Typecast to string constant : char *
char* String::c_str() {
	delete []_data2;
	_data2 = new char[_len + 1];
	for(__SIZETYPE i=0; i<_len; i++) _data2[i] = _data[i];
	_data2[_len] = '\0';
	return _data2;
}

/**************************
* 2. Read properties/data of a given string
**************************/

//size() : returns the size of the string
__SIZETYPE String::length() const {
	return _len;
}

// return the character at an index
char String::charAt(__SIZETYPE index) const {
	if( index < 0 ) index += _len;
	if( index > _len || index < 0 ) return 0;
	return _data[index];
}

// operator [] : gives reference to char at index .
char String::zerochar = 0; // returned on erraneous requests(out of bounds)
char& String::operator[] (__SIZETYPE index ) const {
	if( index < 0 ) index += _len;
	if( index > _len || index < 0 ) {
		zerochar = 0;
		return zerochar;
	}
	return _data[index];
}

/*******************************
* 3. Manipulations
********************************/

// Operator +
String String::operator+ (const String& r ) const {
	int tlen = r.length();
	char tmp[_len+ tlen +1];
	for(__SIZETYPE i=0; i<_len; i++)
		tmp[i] = _data[i];
	for(__SIZETYPE j=0; j<tlen; j++)
		tmp[j+_len] = r[j];
	tmp[_len+ tlen]= '\0';

	String c(tmp);
	return c;
}

// shorthand operator +=
String String::operator+= (const String& s) {
	return ( *this = *this + s );
}

// substring : returns the substring from index st , and length len.
// if len is -1 (default), the substring from st till the end is returned.
// if st is negative, it is counted from the end of the string.
String String::substr(__SIZETYPE st, __SIZETYPE  len) const {
	String ret;
	if( st < 0 ) st += _len;
	if( st < 0 ) st = 0;
	if( st + len > _len || len == -1 ) len = _len - st;

	char s[ len+1 ];

	for( __SIZETYPE i=0 ; i<len ; ++i ){
		s[i] = _data[ st+i ];
	}
	s[len] = '\0';
	ret = s;
	return ret;
}

// replace : replaces all occurences of <find> with <rep>
String String::replace(const String& find, const String& rep) const {
	String tmp , ch(*this);

	__SIZETYPE repPos = ch.indexOf(find),
	           flen = find.length();
	while( repPos >= 0 ) {
		tmp += ch.substr(0,repPos) + rep;
		ch = ch.substr(repPos+flen);
		repPos = ch.indexOf(find);
	}
	tmp += ch;
	return tmp;
}

// tolower : converts all alphabet values to lower case.
String String::tolower() const {
	String ret(*this );
	for( __SIZETYPE i=0; i<ret.length(); i++)
		if( ret[i] >= 'A' && ret[i] <= 'Z' )
			ret[i] = ret[i] - 'A' + 'a';
	return ret;
}

// toupper : converts all alphabet values to upper case.
String String::toupper() const {
	String ret( *this );
	for( __SIZETYPE i=0; i<ret.length(); i++)
		if( ret[i] >= 'a' && ret[i] <= 'z' )
			ret[i] = ret[i] - 'a' + 'A';
	return ret;
}

// trim : removes all preceding and trailing spaces
String String::trim() const {
	__SIZETYPE st,en;
	for( st = 0; _data[st] == ' ' && st < _len; st++);
	if( st == _len ) return String();

	for( en = _len-1; _data[en] == ' ' && en >= 0; en--);
	return this->substr( st, en-st+1 );
}

// indexOf :  gives index of first occurrance of s
__SIZETYPE String::indexOf(const String& s ) const {
	__SIZETYPE tlen = s.length();
	bool isfound ;

	for( __SIZETYPE i = 0; i < _len-tlen+1 ; ++i ){
		isfound = true;
		for( __SIZETYPE j = 0; j < tlen ; ++j ){
			if( s[j] != _data[i+j] ){
				isfound = false;
				break;
			}
		}
		if( isfound ) return i;
	}
	return -1;
}

// numOccurences : gives the number of times s appears in the given string ( without overlaps )
__SIZETYPE String::countOccurences(const String& find ) const {
	__SIZETYPE tot = 0;
	int flen = find.length();
	for( int i = 0; i<_len-flen ; i++ ){
		bool match = false;
		for( int j = 0; j<flen ; j++ )
			if( _data[i+j] != find[j] ){
				match = false;
				break;
			}
		if( match ){
			tot++;
			i += flen-1;
		}
	}
	return tot;
}

/**********************************
* 3.2. Advanced type checks and
*      conversions
**********************************/

bool String::isInteger() const {
	__SIZETYPE i;
	for (i = 0; i < _len; i++) {
		if (_data[i] == '-') {
			if (i != 0) return false;
			else continue;
		}
		else if (!(_data[i] >= '0' && _data[i] <= '9')) return false;
	}
	return true;
}
bool String::isNumber() const {
	__SIZETYPE i;
	bool isDeci = false;
	for (i = 0; i < _len; i++) {
		if (_data[i] == '-') {
			if (i != 0) return false;
			else continue;
		}
		if (_data[i] == '.') {
			if (isDeci) return false;
			isDeci = true;
		}
		else if (!(_data[i] >= '0' && _data[i] <= '9')) return false;
	}
	return true;
}

long String::toInteger() const {
	String tmp(*this);
	return atol(tmp.c_str());
}
double String::toNumber() const {
	String tmp(*this);
	return atof(tmp.c_str());
}

/***********************************
* 4. Relational Operators
************************************/

// operator ! : returns true if string is empty
bool String::operator!() const {
	return !_len;
}
bool String::equals(const String& s) const {
	if( _len != s.length() ) return false;
	for( __SIZETYPE it = 0; it < _len ; it++ )
		if( _data[it] != s[it] )
			return false;
	return true;
}
// operator == : returns true if both strings are equal( each char matches )
bool String::operator==(const String& s) const {
	return equals(s);
}

// operator != : returns true if both strings are not equal
bool String::operator!=(const String& s ) const {
	return !(equals(s));
}

/************************************
* 5. Stream IO operators : >> <<
************************************/
ostream& operator<<(ostream& output, const String& str) {
	str.print(output);
	return output;
}
bool String::print(ostream& output) const {
	for( __SIZETYPE i=0; i<_len; ++i) output<<_data[i];
	return true;
}

// this is the global input buffer for all strings.
char *String::stringInputBuffer = new char[ MAX_STRING_LENGTH ];

bool String::get(istream& input, char delim) {
	input.getline(stringInputBuffer, MAX_STRING_LENGTH, delim);
	*this = stringInputBuffer;
	return true;
}
istream& operator>>(istream& input, String& str) {
	str.get(input);
	return input;
}

#endif /* CODE_STRING_H */
<commit_msg>fixes #2<commit_after>// Implementation file for String functions, include this file in string.h
// DO NOT INCLUDE/COMPILE THIS FILE SEPARATELY.
#ifdef CODE_STRING_H

/*******************************
* 1. Constructors and operator =
*******************************/

// empty constructor.
String::String() {
	_len = 0;
	_data = _data2 = NULL;
}

// copy contructors : assignment is copy
String::String(const String& s) {
	_data2 = NULL;
	_len = s.length();
	_data = NULL;
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s.charAt(i);
}

String::String(const char *s) {
	_data2 = NULL;
	_len = strlen(s);
	_data = NULL;
	_data = new char[ _len ];
	if( !_data ) forcequit(10);
	for( __SIZETYPE i=0; i<_len; i++)
		_data[i] = s[i];
}

String::String(char ch) {
	_data2 = NULL;
	_len = 1;
	_data = NULL;
	_data = new char[1];
	if( !_data ) forcequit(10);
	_data[0] = ch;
}

// operator =
String& String::operator= (const String& s) {
	clear();
	_len = s.length();
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s.charAt(i);
	return *this;
}

String& String::operator= (const char* s ) {
	clear();
	_len = strlen(s);
	_data = new char[_len];
	if( !_data ) forcequit(10);
	for(int i=0; i<_len; i++)
		_data[i] = s[i];
	return *this;
}

String& String::operator=(char ch ) {
	clear();
	_len = 1;
	_data = new char[1];
	if( !_data ) forcequit(10);
	_data[0] = ch;
	return *this;
}
// Destructor : free some space
String::~String() {
	clear();
}
// clears all data.
bool String::clear() {
	_len = 0;
	delete[] _data;
	_data = NULL;
	delete[] _data2;
	_data2 = NULL;
	return 1;
}

// Typecast to string constant : char *
char* String::c_str() {
	delete []_data2;
	_data2 = NULL;
	_data2 = new char[_len + 1];
	for(__SIZETYPE i=0; i<_len; i++) _data2[i] = _data[i];
	_data2[_len] = '\0';
	return _data2;
}

/**************************
* 2. Read properties/data of a given string
**************************/

//size() : returns the size of the string
__SIZETYPE String::length() const {
	return _len;
}

// return the character at an index
char String::charAt(__SIZETYPE index) const {
	if( index < 0 ) index += _len;
	if( index > _len || index < 0 ) return 0;
	return _data[index];
}

// operator [] : gives reference to char at index .
char String::zerochar = 0; // returned on erraneous requests(out of bounds)
char& String::operator[] (__SIZETYPE index ) const {
	if( index < 0 ) index += _len;
	if( index > _len || index < 0 ) {
		zerochar = 0;
		return zerochar;
	}
	return _data[index];
}

/*******************************
* 3. Manipulations
********************************/

// Operator +
String String::operator+ (const String& r ) const {
	int tlen = r.length();
	char tmp[_len+ tlen +1];
	for(__SIZETYPE i=0; i<_len; i++)
		tmp[i] = _data[i];
	for(__SIZETYPE j=0; j<tlen; j++)
		tmp[j+_len] = r[j];
	tmp[_len+ tlen]= '\0';

	String c(tmp);
	return c;
}

// shorthand operator +=
String String::operator+= (const String& s) {
	return ( *this = *this + s );
}

// substring : returns the substring from index st , and length len.
// if len is -1 (default), the substring from st till the end is returned.
// if st is negative, it is counted from the end of the string.
String String::substr(__SIZETYPE st, __SIZETYPE  len) const {
	String ret;
	if( st < 0 ) st += _len;
	if( st < 0 ) st = 0;
	if( st + len > _len || len == -1 ) len = _len - st;

	char s[ len+1 ];

	for( __SIZETYPE i=0 ; i<len ; ++i ){
		s[i] = _data[ st+i ];
	}
	s[len] = '\0';
	ret = s;
	return ret;
}

// replace : replaces all occurences of <find> with <rep>
String String::replace(const String& find, const String& rep) const {
	String tmp , ch(*this);

	__SIZETYPE repPos = ch.indexOf(find),
	           flen = find.length();
	while( repPos >= 0 ) {
		tmp += ch.substr(0,repPos) + rep;
		ch = ch.substr(repPos+flen);
		repPos = ch.indexOf(find);
	}
	tmp += ch;
	return tmp;
}

// tolower : converts all alphabet values to lower case.
String String::tolower() const {
	String ret(*this );
	for( __SIZETYPE i=0; i<ret.length(); i++)
		if( ret[i] >= 'A' && ret[i] <= 'Z' )
			ret[i] = ret[i] - 'A' + 'a';
	return ret;
}

// toupper : converts all alphabet values to upper case.
String String::toupper() const {
	String ret( *this );
	for( __SIZETYPE i=0; i<ret.length(); i++)
		if( ret[i] >= 'a' && ret[i] <= 'z' )
			ret[i] = ret[i] - 'a' + 'A';
	return ret;
}

// trim : removes all preceding and trailing spaces
String String::trim() const {
	__SIZETYPE st,en;
	for( st = 0; _data[st] == ' ' && st < _len; st++);
	if( st == _len ) return String();

	for( en = _len-1; _data[en] == ' ' && en >= 0; en--);
	return this->substr( st, en-st+1 );
}

// indexOf :  gives index of first occurrance of s
__SIZETYPE String::indexOf(const String& s ) const {
	__SIZETYPE tlen = s.length();
	bool isfound ;

	for( __SIZETYPE i = 0; i < _len-tlen+1 ; ++i ){
		isfound = true;
		for( __SIZETYPE j = 0; j < tlen ; ++j ){
			if( s[j] != _data[i+j] ){
				isfound = false;
				break;
			}
		}
		if( isfound ) return i;
	}
	return -1;
}

// numOccurences : gives the number of times s appears in the given string ( without overlaps )
__SIZETYPE String::countOccurences(const String& find ) const {
	__SIZETYPE tot = 0;
	int flen = find.length();
	for( int i = 0; i<_len-flen ; i++ ){
		bool match = false;
		for( int j = 0; j<flen ; j++ )
			if( _data[i+j] != find[j] ){
				match = false;
				break;
			}
		if( match ){
			tot++;
			i += flen-1;
		}
	}
	return tot;
}

/**********************************
* 3.2. Advanced type checks and
*      conversions
**********************************/

bool String::isInteger() const {
	__SIZETYPE i;
	for (i = 0; i < _len; i++) {
		if (_data[i] == '-') {
			if (i != 0) return false;
			else continue;
		}
		else if (!(_data[i] >= '0' && _data[i] <= '9')) return false;
	}
	return true;
}
bool String::isNumber() const {
	__SIZETYPE i;
	bool isDeci = false;
	for (i = 0; i < _len; i++) {
		if (_data[i] == '-') {
			if (i != 0) return false;
			else continue;
		}
		if (_data[i] == '.') {
			if (isDeci) return false;
			isDeci = true;
		}
		else if (!(_data[i] >= '0' && _data[i] <= '9')) return false;
	}
	return true;
}

long String::toInteger() const {
	String tmp(*this);
	return atol(tmp.c_str());
}
double String::toNumber() const {
	String tmp(*this);
	return atof(tmp.c_str());
}

/***********************************
* 4. Relational Operators
************************************/

// operator ! : returns true if string is empty
bool String::operator!() const {
	return !_len;
}
bool String::equals(const String& s) const {
	if( _len != s.length() ) return false;
	for( __SIZETYPE it = 0; it < _len ; it++ )
		if( _data[it] != s[it] )
			return false;
	return true;
}
// operator == : returns true if both strings are equal( each char matches )
bool String::operator==(const String& s) const {
	return equals(s);
}

// operator != : returns true if both strings are not equal
bool String::operator!=(const String& s ) const {
	return !(equals(s));
}

/************************************
* 5. Stream IO operators : >> <<
************************************/
ostream& operator<<(ostream& output, const String& str) {
	str.print(output);
	return output;
}
bool String::print(ostream& output) const {
	for( __SIZETYPE i=0; i<_len; ++i) output<<_data[i];
	return true;
}

// this is the global input buffer for all strings.
char *String::stringInputBuffer = new char[ MAX_STRING_LENGTH ];

bool String::get(istream& input, char delim) {
	input.getline(stringInputBuffer, MAX_STRING_LENGTH, delim);
	*this = stringInputBuffer;
	return true;
}
istream& operator>>(istream& input, String& str) {
	str.get(input);
	return input;
}

#endif /* CODE_STRING_H */
<|endoftext|>


<commit_before>/// @example next_prime.cpp
/// Iterate over primes using a primesieve::iterator object.

#include <primesieve.hpp>
#include <iostream>

int main()
{
  primesieve::iterator pi;
  uint64_t sum = 0;

  // iterate over primes below 10^10
  while (pi.next_prime() < 10000000000ull)
    sum += pi.prime();

  std::cout << "Sum of the primes below 10^10 = " << sum << std::endl;
  return 0;
}
<commit_msg>Delete next_prime.cpp<commit_after><|endoftext|>


<commit_before>#include "ros/ros.h"
#include "boost/asio.hpp"
#include "jaws_msgs/Thrusters.h"

#define FEEDBACK
#define RESET

class Arbotix
{
  private:
    ros::NodeHandle nh;
    ros::Subscriber sub;
    boost::asio::io_service i_o;
    boost::asio::serial_port s_p;
    std::string port_name;
    int br;
    char c;
    int timeout;
    std::string feedback;
  public:
    Arbotix() : nh(), i_o(), s_p(i_o)
    {
      nh.getParam("/arbotix_node/port_name",port_name);
      nh.getParam("/arbotix_node/baud_rate",br);
      nh.param("/arbotix_node/timeout",timeout,2000);
      s_p.open(port_name);
      s_p.set_option(boost::asio::serial_port_base::baud_rate(br));

      sub = nh.subscribe<jaws_msgs::Thrusters>("thrusters", 1, &Arbotix::callback, this);
    }
    void restartPort()
    {
	nh.getParam("/arbotix_node/port_name",port_name);
	nh.getParam("/arbotix_node/baud_rate",br);
	s_p.close();
        s_p.open(port_name);
	s_p.set_option(boost::asio::serial_port_base::baud_rate(br));
    }
    void callback(const jaws_msgs::Thrusters::ConstPtr& thrusters)
    {
      const int SIZE = 11;
      unsigned char packet[SIZE];

      unsigned int start=clock();
      packet[0] = '-';

      packet[1] = (thrusters->port_angle >> 8) & 0xFF;
      packet[2] = thrusters->port_angle & 0xFF;

      packet[3] = (thrusters->stbd_angle >> 8) & 0xFF;
      packet[4] = thrusters->stbd_angle & 0xFF;

      packet[5] = (thrusters->aft_power >> 8) & 0xFF;
      packet[6] = thrusters->aft_power & 0xFF;

      packet[7] = (thrusters->port_power >> 8) & 0xFF;
      packet[8] = thrusters->port_power & 0xFF;
      packet[9] = (thrusters->stbd_power >> 8) & 0xFF;
      packet[10] = thrusters->stbd_power & 0xFF;

      s_p.write_some(boost::asio::buffer(&packet, SIZE));
      c='a';
      nh.getParam("/arbotix_node/timeout",timeout);
      #ifdef FEEDBACK
      while(c!='\n'){
         c=s_p.read_some(boost::asio::buffer(&c,1));
         if(c!='\n'){
 	   feedback+=c;
	 }
	else{
	   break;
	}
        #ifdef RESET
	if((clock()-start/CLOCKS_PER_SEC)>timeout){
	   restartPort();
	   feedback="Port reset, resuming";
	   break;
	}
        #endif
      }
     ROS_INFO("%s",feedback.c_str());
     #endif
    }
    void loop()
    {
      ros::spin();
    }
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "arbotix_node");
  Arbotix arbotix;
  arbotix.loop();
}
<commit_msg>Made string publisher, add to diagnostic node<commit_after>#include "ros/ros.h"
#include "boost/asio.hpp"
#include "jaws_msgs/Thrusters.h"
#include "std_msgs/String.h"

#define FEEDBACK
#define RESET
#define DIAGNOSTIC_PUBLISH

class Arbotix
{
  private:
    ros::NodeHandle nh;
    ros::Subscriber sub;
    ros::Publisher pub;
    boost::asio::io_service i_o;
    boost::asio::serial_port s_p;
    std::string port_name;
    int br;
    char c;
    int timeout;
    std::string feedback;
  public:
    Arbotix() : nh(), i_o(), s_p(i_o)
    {
      nh.getParam("/arbotix_node/port_name",port_name);
      nh.getParam("/arbotix_node/baud_rate",br);
      nh.param("/arbotix_node/timeout",timeout,2000);
      s_p.open(port_name);
      s_p.set_option(boost::asio::serial_port_base::baud_rate(br));

      pub=nh.advertise<std_msgs::String>("arbotix_diagnostic",2);
      sub = nh.subscribe<jaws_msgs::Thrusters>("thrusters", 1, &Arbotix::callback, this);
    }
    void restartPort()
    {
	nh.getParam("/arbotix_node/port_name",port_name);
	nh.getParam("/arbotix_node/baud_rate",br);
	s_p.close();
        s_p.open(port_name);
	s_p.set_option(boost::asio::serial_port_base::baud_rate(br));
    }
    void callback(const jaws_msgs::Thrusters::ConstPtr& thrusters)
    {
      const int SIZE = 11;
      unsigned char packet[SIZE];

      unsigned int start=clock();
      packet[0] = '-';

      packet[1] = (thrusters->port_angle >> 8) & 0xFF;
      packet[2] = thrusters->port_angle & 0xFF;

      packet[3] = (thrusters->stbd_angle >> 8) & 0xFF;
      packet[4] = thrusters->stbd_angle & 0xFF;

      packet[5] = (thrusters->aft_power >> 8) & 0xFF;
      packet[6] = thrusters->aft_power & 0xFF;

      packet[7] = (thrusters->port_power >> 8) & 0xFF;
      packet[8] = thrusters->port_power & 0xFF;
      packet[9] = (thrusters->stbd_power >> 8) & 0xFF;
      packet[10] = thrusters->stbd_power & 0xFF;

      s_p.write_some(boost::asio::buffer(&packet, SIZE));
      c='a';
      nh.getParam("/arbotix_node/timeout",timeout);
      #ifdef FEEDBACK
      while(c!='\n'){
         c=s_p.read_some(boost::asio::buffer(&c,1));
         if(c!='\n'){
 	   feedback+=c;
	 }
	else{
	   break;
	   #ifdef DIAGNOTIS_PUBLISH
	    pub.publish(feedback);
	   #endif
	}
        #ifdef RESET
	if((clock()-start/CLOCKS_PER_SEC)>timeout){
	   restartPort();
	   feedback="Port reset, resuming";
	   break;
	}
        #endif
      }
     ROS_INFO("%s",feedback.c_str());
     #endif
    }
    void loop()
    {
      ros::spin();
    }
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "arbotix_node");
  Arbotix arbotix;
  arbotix.loop();
}
<|endoftext|>