<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/diagnostics/recon_diagnostics.h"

#include <string>

#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/path_service.h"
#include "chrome/browser/diagnostics/diagnostics_test.h"
#include "chrome/browser/platform_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/json_value_serializer.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "chrome/browser/enumerate_modules_model_win.h"
#include "chrome/installer/util/install_util.h"
#endif

// Reconnaissance diagnostics. These are the first and most critical
// diagnostic tests. Here we check for the existence of critical files.
// TODO(cpu): Define if it makes sense to localize strings.

// TODO(cpu): There are a few maximum file sizes hardcoded in this file
// that have little or no theoretical or experimental ground. Find a way
// to justify them.

namespace {

class InstallTypeTest;
InstallTypeTest* g_install_type = 0;

// Check that the flavor of the operating system is supported.
class OperatingSystemTest : public DiagnosticTest {
 public:
  OperatingSystemTest() : DiagnosticTest(ASCIIToUTF16("Operating System")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    int version = 0;
    int major = 0;
    int minor = 0;
#if defined(OS_WIN)
    version = base::win::GetVersion();
    if (version < base::win::VERSION_XP) {
      RecordFailure(ASCIIToUTF16("Windows 2000 or earlier"));
      return false;
    }
    base::win::GetServicePackLevel(&major, &minor);
    if ((version == base::win::VERSION_XP) && (major < 2)) {
      RecordFailure(ASCIIToUTF16("XP Service Pack 1 or earlier"));
      return false;
    }
#else
    // TODO(port): define the OS criteria for Linux and Mac.
#endif  // defined(OS_WIN)
    RecordSuccess(ASCIIToUTF16(StringPrintf("%s %s (%d [%d:%d])",
        base::SysInfo::OperatingSystemName().c_str(),
        base::SysInfo::OperatingSystemVersion().c_str(),
        version, major, minor)));
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(OperatingSystemTest);
};

// Check if any conflicting DLLs are loaded.
class ConflictingDllsTest : public DiagnosticTest {
 public:
  ConflictingDllsTest() : DiagnosticTest(ASCIIToUTF16("Conflicting modules")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
#if defined(OS_WIN)
    EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
    model->set_limited_mode(true);
    model->ScanNow();
    ListValue* list = model->GetModuleList();
    if (!model->confirmed_bad_modules_detected() &&
        !model->suspected_bad_modules_detected()) {
      RecordSuccess(ASCIIToUTF16("No conflicting modules found"));
      return true;
    }

    string16 failures = ASCIIToUTF16("Possibly conflicting modules:");
    DictionaryValue* dictionary;
    for (size_t i = 0; i < list->GetSize(); ++i) {
      list->GetDictionary(i, &dictionary);
      int status;
      string16 location;
      string16 name;
      if (!dictionary->GetInteger("status", &status))
        RecordFailure(ASCIIToUTF16("No 'status' field found"));
      if (status < ModuleEnumerator::SUSPECTED_BAD)
        continue;

      if (!dictionary->GetString("location", &location)) {
        RecordFailure(ASCIIToUTF16("No 'location' field found"));
        return true;
      }
      if (!dictionary->GetString("name", &name)) {
        RecordFailure(ASCIIToUTF16("No 'name' field found"));
        return true;
      }

      failures += ASCIIToUTF16("\n") + location + name;
    }
    RecordFailure(failures);
    return true;
#else
    RecordFailure(ASCIIToUTF16("Not implemented"));
    return true;
#endif  // defined(OS_WIN)
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ConflictingDllsTest);
};

// Check if it is system install or per-user install.
class InstallTypeTest : public DiagnosticTest {
 public:
  InstallTypeTest() : DiagnosticTest(ASCIIToUTF16("Install Type")),
                      user_level_(false) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
#if defined(OS_WIN)
    FilePath chrome_exe;
    if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
      RecordFailure(ASCIIToUTF16("Path provider failure"));
      return false;
    }
    user_level_ = InstallUtil::IsPerUserInstall(
        chrome_exe.ToWStringHack().c_str());
    const char* type = user_level_ ? "User Level" : "System Level";
    string16 install_type(ASCIIToUTF16(type));
#else
    string16 install_type(ASCIIToUTF16("System Level"));
#endif  // defined(OS_WIN)
    RecordSuccess(install_type);
    g_install_type = this;
    return true;
  }

  bool system_level() const { return !user_level_; }

 private:
  bool user_level_;
  DISALLOW_COPY_AND_ASSIGN(InstallTypeTest);
};

// Check the version of Chrome.
class VersionTest : public DiagnosticTest {
 public:
  VersionTest() : DiagnosticTest(ASCIIToUTF16("Browser Version")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    chrome::VersionInfo version_info;
    if (!version_info.is_valid()) {
      RecordFailure(ASCIIToUTF16("No Version"));
      return true;
    }
    std::string current_version = version_info.Version();
    if (current_version.empty()) {
      RecordFailure(ASCIIToUTF16("Empty Version"));
      return true;
    }
    std::string version_modifier = platform_util::GetVersionStringModifier();
    if (!version_modifier.empty())
      current_version += " " + version_modifier;
#if defined(GOOGLE_CHROME_BUILD)
    current_version += " GCB";
#endif  // defined(GOOGLE_CHROME_BUILD)
    RecordSuccess(ASCIIToUTF16(current_version));
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(VersionTest);
};

struct TestPathInfo {
  const char* test_name;
  int  path_id;
  bool is_directory;
  bool is_optional;
  bool test_writable;
  int64 max_size;
};

const int64 kOneKilo = 1024;
const int64 kOneMeg = 1024 * kOneKilo;

const TestPathInfo kPathsToTest[] = {
  {"User data Directory", chrome::DIR_USER_DATA,
      true, false, true, 850 * kOneMeg},
  {"Local state file", chrome::FILE_LOCAL_STATE,
      false, false, true, 500 * kOneKilo},
  {"Dictionaries Directory", chrome::DIR_APP_DICTIONARIES,
      true, true, false, 0},
  {"Inspector Directory", chrome::DIR_INSPECTOR,
      true, false, false, 0}
};

// Check that the user's data directory exists and the paths are writable.
// If it is a systemwide install some paths are not expected to be writable.
// This test depends on |InstallTypeTest| having run successfully.
class PathTest : public DiagnosticTest {
 public:
  explicit PathTest(const TestPathInfo& path_info)
      : DiagnosticTest(ASCIIToUTF16(path_info.test_name)),
        path_info_(path_info) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    if (!g_install_type) {
      RecordStopFailure(ASCIIToUTF16("dependency failure"));
      return false;
    }
    FilePath dir_or_file;
    if (!PathService::Get(path_info_.path_id, &dir_or_file)) {
      RecordStopFailure(ASCIIToUTF16("Path provider failure"));
      return false;
    }
    if (!file_util::PathExists(dir_or_file)) {
      RecordFailure(ASCIIToUTF16("Path not found"));
      return true;
    }

    int64 dir_or_file_size = 0;
    if (path_info_.is_directory) {
      dir_or_file_size = file_util::ComputeDirectorySize(dir_or_file);
    } else {
      file_util::GetFileSize(dir_or_file, &dir_or_file_size);
    }
    if (!dir_or_file_size && !path_info_.is_optional) {
      RecordFailure(ASCIIToUTF16("Cannot obtain size"));
      return true;
    }
    DataUnits units = GetByteDisplayUnits(dir_or_file_size);
    string16 printable_size = FormatBytes(dir_or_file_size, units, true);

    if (path_info_.max_size > 0) {
      if (dir_or_file_size > path_info_.max_size) {
        RecordFailure(ASCIIToUTF16("Path is too big: ") + printable_size);
        return true;
      }
    }
    if (g_install_type->system_level() && !path_info_.test_writable) {
      RecordSuccess(ASCIIToUTF16("Path exists"));
      return true;
    }
    if (!file_util::PathIsWritable(dir_or_file)) {
      RecordFailure(ASCIIToUTF16("Path is not writable"));
      return true;
    }
    RecordSuccess(ASCIIToUTF16("Path exists and is writable: ")
                  + printable_size);
    return true;
  }

 private:
  TestPathInfo path_info_;
  DISALLOW_COPY_AND_ASSIGN(PathTest);
};

// Check that the disk space in the volume where the user data dir normally
// lives is not dangerously low.
class DiskSpaceTest : public DiagnosticTest {
 public:
  DiskSpaceTest() : DiagnosticTest(ASCIIToUTF16("Disk Space")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    FilePath data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &data_dir))
      return false;
    int64 disk_space = base::SysInfo::AmountOfFreeDiskSpace(data_dir);
    if (disk_space < 0) {
      RecordFailure(ASCIIToUTF16("Unable to query free space"));
      return true;
    }
    DataUnits units = GetByteDisplayUnits(disk_space);
    string16 printable_size = FormatBytes(disk_space, units, true);
    if (disk_space < 80 * kOneMeg) {
      RecordFailure(ASCIIToUTF16("Low disk space : ") + printable_size);
      return true;
    }
    RecordSuccess(ASCIIToUTF16("Free space : ") + printable_size);
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DiskSpaceTest);
};

// Checks that a given json file can be correctly parsed.
class JSONTest : public DiagnosticTest {
 public:
  JSONTest(const FilePath& path, const string16 name, int64 max_file_size)
      : DiagnosticTest(name), path_(path), max_file_size_(max_file_size) {
  }

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    if (!file_util::PathExists(path_)) {
      RecordFailure(ASCIIToUTF16("File not found"));
      return true;
    }
    int64 file_size;
    file_util::GetFileSize(path_, &file_size);
    if (file_size > max_file_size_) {
      RecordFailure(ASCIIToUTF16("File too big"));
      return true;
    }
    // Being small enough, we can process it in-memory.
    std::string json_data;
    if (!file_util::ReadFileToString(path_, &json_data)) {
      RecordFailure(ASCIIToUTF16(
          "Could not open file. Possibly locked by other process"));
      return true;
    }

    JSONStringValueSerializer json(json_data);
    int error_code = base::JSONReader::JSON_NO_ERROR;
    std::string error_message;
    scoped_ptr<Value> json_root(json.Deserialize(&error_code, &error_message));
    if (base::JSONReader::JSON_NO_ERROR != error_code) {
      if (error_message.empty()) {
        error_message = "Parse error " + base::IntToString(error_code);
      }
      RecordFailure(UTF8ToUTF16(error_message));
      return true;
    }

    RecordSuccess(ASCIIToUTF16("File parsed OK"));
    return true;
  }

 private:
  FilePath path_;
  int64 max_file_size_;
  DISALLOW_COPY_AND_ASSIGN(JSONTest);
};

}  // namespace

DiagnosticTest* MakeUserDirTest() {
  return new PathTest(kPathsToTest[0]);
}

DiagnosticTest* MakeLocalStateFileTest() {
  return new PathTest(kPathsToTest[1]);
}

DiagnosticTest* MakeDictonaryDirTest() {
  return new PathTest(kPathsToTest[2]);
}

DiagnosticTest* MakeInspectorDirTest() {
  return new PathTest(kPathsToTest[3]);
}

DiagnosticTest* MakeVersionTest() {
  return new VersionTest();
}

DiagnosticTest* MakeDiskSpaceTest() {
  return new DiskSpaceTest();
}

DiagnosticTest* MakeOperatingSystemTest() {
  return new OperatingSystemTest();
}

DiagnosticTest* MakeConflictingDllsTest() {
  return new ConflictingDllsTest();
}

DiagnosticTest* MakeInstallTypeTest() {
  return new InstallTypeTest();
}

DiagnosticTest* MakePreferencesTest() {
  FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
  path = path.Append(chrome::kPreferencesFilename);
  return new JSONTest(path, ASCIIToUTF16("Profile JSON"), 100 * kOneKilo);
}

DiagnosticTest* MakeBookMarksTest() {
  FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
  path = path.Append(chrome::kBookmarksFileName);
  return new JSONTest(path, ASCIIToUTF16("BookMarks JSON"), 2 * kOneMeg);
}

DiagnosticTest* MakeLocalStateTest() {
  FilePath path;
  PathService::Get(chrome::DIR_USER_DATA, &path);
  path = path.Append(chrome::kLocalStateFilename);
  return new JSONTest(path, ASCIIToUTF16("Local State JSON"), 50 * kOneKilo);
}
<commit_msg>Fix minor CHECKED_RETURN Coverity complaint in code I added to the --diagnostics code.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/diagnostics/recon_diagnostics.h"

#include <string>

#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/string_util.h"
#include "base/string_number_conversions.h"
#include "base/utf_string_conversions.h"
#include "base/sys_info.h"
#include "base/path_service.h"
#include "chrome/browser/diagnostics/diagnostics_test.h"
#include "chrome/browser/platform_util.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_version_info.h"
#include "chrome/common/json_value_serializer.h"

#if defined(OS_WIN)
#include "base/win/windows_version.h"
#include "chrome/browser/enumerate_modules_model_win.h"
#include "chrome/installer/util/install_util.h"
#endif

// Reconnaissance diagnostics. These are the first and most critical
// diagnostic tests. Here we check for the existence of critical files.
// TODO(cpu): Define if it makes sense to localize strings.

// TODO(cpu): There are a few maximum file sizes hardcoded in this file
// that have little or no theoretical or experimental ground. Find a way
// to justify them.

namespace {

class InstallTypeTest;
InstallTypeTest* g_install_type = 0;

// Check that the flavor of the operating system is supported.
class OperatingSystemTest : public DiagnosticTest {
 public:
  OperatingSystemTest() : DiagnosticTest(ASCIIToUTF16("Operating System")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    int version = 0;
    int major = 0;
    int minor = 0;
#if defined(OS_WIN)
    version = base::win::GetVersion();
    if (version < base::win::VERSION_XP) {
      RecordFailure(ASCIIToUTF16("Windows 2000 or earlier"));
      return false;
    }
    base::win::GetServicePackLevel(&major, &minor);
    if ((version == base::win::VERSION_XP) && (major < 2)) {
      RecordFailure(ASCIIToUTF16("XP Service Pack 1 or earlier"));
      return false;
    }
#else
    // TODO(port): define the OS criteria for Linux and Mac.
#endif  // defined(OS_WIN)
    RecordSuccess(ASCIIToUTF16(StringPrintf("%s %s (%d [%d:%d])",
        base::SysInfo::OperatingSystemName().c_str(),
        base::SysInfo::OperatingSystemVersion().c_str(),
        version, major, minor)));
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(OperatingSystemTest);
};

// Check if any conflicting DLLs are loaded.
class ConflictingDllsTest : public DiagnosticTest {
 public:
  ConflictingDllsTest() : DiagnosticTest(ASCIIToUTF16("Conflicting modules")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
#if defined(OS_WIN)
    EnumerateModulesModel* model = EnumerateModulesModel::GetInstance();
    model->set_limited_mode(true);
    model->ScanNow();
    ListValue* list = model->GetModuleList();
    if (!model->confirmed_bad_modules_detected() &&
        !model->suspected_bad_modules_detected()) {
      RecordSuccess(ASCIIToUTF16("No conflicting modules found"));
      return true;
    }

    string16 failures = ASCIIToUTF16("Possibly conflicting modules:");
    DictionaryValue* dictionary;
    for (size_t i = 0; i < list->GetSize(); ++i) {
      if (!list->GetDictionary(i, &dictionary))
        RecordFailure(ASCIIToUTF16("Dictionary lookup failed"));
      int status;
      string16 location;
      string16 name;
      if (!dictionary->GetInteger("status", &status))
        RecordFailure(ASCIIToUTF16("No 'status' field found"));
      if (status < ModuleEnumerator::SUSPECTED_BAD)
        continue;

      if (!dictionary->GetString("location", &location)) {
        RecordFailure(ASCIIToUTF16("No 'location' field found"));
        return true;
      }
      if (!dictionary->GetString("name", &name)) {
        RecordFailure(ASCIIToUTF16("No 'name' field found"));
        return true;
      }

      failures += ASCIIToUTF16("\n") + location + name;
    }
    RecordFailure(failures);
    return true;
#else
    RecordFailure(ASCIIToUTF16("Not implemented"));
    return true;
#endif  // defined(OS_WIN)
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ConflictingDllsTest);
};

// Check if it is system install or per-user install.
class InstallTypeTest : public DiagnosticTest {
 public:
  InstallTypeTest() : DiagnosticTest(ASCIIToUTF16("Install Type")),
                      user_level_(false) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
#if defined(OS_WIN)
    FilePath chrome_exe;
    if (!PathService::Get(base::FILE_EXE, &chrome_exe)) {
      RecordFailure(ASCIIToUTF16("Path provider failure"));
      return false;
    }
    user_level_ = InstallUtil::IsPerUserInstall(
        chrome_exe.ToWStringHack().c_str());
    const char* type = user_level_ ? "User Level" : "System Level";
    string16 install_type(ASCIIToUTF16(type));
#else
    string16 install_type(ASCIIToUTF16("System Level"));
#endif  // defined(OS_WIN)
    RecordSuccess(install_type);
    g_install_type = this;
    return true;
  }

  bool system_level() const { return !user_level_; }

 private:
  bool user_level_;
  DISALLOW_COPY_AND_ASSIGN(InstallTypeTest);
};

// Check the version of Chrome.
class VersionTest : public DiagnosticTest {
 public:
  VersionTest() : DiagnosticTest(ASCIIToUTF16("Browser Version")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    chrome::VersionInfo version_info;
    if (!version_info.is_valid()) {
      RecordFailure(ASCIIToUTF16("No Version"));
      return true;
    }
    std::string current_version = version_info.Version();
    if (current_version.empty()) {
      RecordFailure(ASCIIToUTF16("Empty Version"));
      return true;
    }
    std::string version_modifier = platform_util::GetVersionStringModifier();
    if (!version_modifier.empty())
      current_version += " " + version_modifier;
#if defined(GOOGLE_CHROME_BUILD)
    current_version += " GCB";
#endif  // defined(GOOGLE_CHROME_BUILD)
    RecordSuccess(ASCIIToUTF16(current_version));
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(VersionTest);
};

struct TestPathInfo {
  const char* test_name;
  int  path_id;
  bool is_directory;
  bool is_optional;
  bool test_writable;
  int64 max_size;
};

const int64 kOneKilo = 1024;
const int64 kOneMeg = 1024 * kOneKilo;

const TestPathInfo kPathsToTest[] = {
  {"User data Directory", chrome::DIR_USER_DATA,
      true, false, true, 850 * kOneMeg},
  {"Local state file", chrome::FILE_LOCAL_STATE,
      false, false, true, 500 * kOneKilo},
  {"Dictionaries Directory", chrome::DIR_APP_DICTIONARIES,
      true, true, false, 0},
  {"Inspector Directory", chrome::DIR_INSPECTOR,
      true, false, false, 0}
};

// Check that the user's data directory exists and the paths are writable.
// If it is a systemwide install some paths are not expected to be writable.
// This test depends on |InstallTypeTest| having run successfully.
class PathTest : public DiagnosticTest {
 public:
  explicit PathTest(const TestPathInfo& path_info)
      : DiagnosticTest(ASCIIToUTF16(path_info.test_name)),
        path_info_(path_info) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    if (!g_install_type) {
      RecordStopFailure(ASCIIToUTF16("dependency failure"));
      return false;
    }
    FilePath dir_or_file;
    if (!PathService::Get(path_info_.path_id, &dir_or_file)) {
      RecordStopFailure(ASCIIToUTF16("Path provider failure"));
      return false;
    }
    if (!file_util::PathExists(dir_or_file)) {
      RecordFailure(ASCIIToUTF16("Path not found"));
      return true;
    }

    int64 dir_or_file_size = 0;
    if (path_info_.is_directory) {
      dir_or_file_size = file_util::ComputeDirectorySize(dir_or_file);
    } else {
      file_util::GetFileSize(dir_or_file, &dir_or_file_size);
    }
    if (!dir_or_file_size && !path_info_.is_optional) {
      RecordFailure(ASCIIToUTF16("Cannot obtain size"));
      return true;
    }
    DataUnits units = GetByteDisplayUnits(dir_or_file_size);
    string16 printable_size = FormatBytes(dir_or_file_size, units, true);

    if (path_info_.max_size > 0) {
      if (dir_or_file_size > path_info_.max_size) {
        RecordFailure(ASCIIToUTF16("Path is too big: ") + printable_size);
        return true;
      }
    }
    if (g_install_type->system_level() && !path_info_.test_writable) {
      RecordSuccess(ASCIIToUTF16("Path exists"));
      return true;
    }
    if (!file_util::PathIsWritable(dir_or_file)) {
      RecordFailure(ASCIIToUTF16("Path is not writable"));
      return true;
    }
    RecordSuccess(ASCIIToUTF16("Path exists and is writable: ")
                  + printable_size);
    return true;
  }

 private:
  TestPathInfo path_info_;
  DISALLOW_COPY_AND_ASSIGN(PathTest);
};

// Check that the disk space in the volume where the user data dir normally
// lives is not dangerously low.
class DiskSpaceTest : public DiagnosticTest {
 public:
  DiskSpaceTest() : DiagnosticTest(ASCIIToUTF16("Disk Space")) {}

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    FilePath data_dir;
    if (!PathService::Get(chrome::DIR_USER_DATA, &data_dir))
      return false;
    int64 disk_space = base::SysInfo::AmountOfFreeDiskSpace(data_dir);
    if (disk_space < 0) {
      RecordFailure(ASCIIToUTF16("Unable to query free space"));
      return true;
    }
    DataUnits units = GetByteDisplayUnits(disk_space);
    string16 printable_size = FormatBytes(disk_space, units, true);
    if (disk_space < 80 * kOneMeg) {
      RecordFailure(ASCIIToUTF16("Low disk space : ") + printable_size);
      return true;
    }
    RecordSuccess(ASCIIToUTF16("Free space : ") + printable_size);
    return true;
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(DiskSpaceTest);
};

// Checks that a given json file can be correctly parsed.
class JSONTest : public DiagnosticTest {
 public:
  JSONTest(const FilePath& path, const string16 name, int64 max_file_size)
      : DiagnosticTest(name), path_(path), max_file_size_(max_file_size) {
  }

  virtual int GetId() { return 0; }

  virtual bool ExecuteImpl(DiagnosticsModel::Observer* observer) {
    if (!file_util::PathExists(path_)) {
      RecordFailure(ASCIIToUTF16("File not found"));
      return true;
    }
    int64 file_size;
    file_util::GetFileSize(path_, &file_size);
    if (file_size > max_file_size_) {
      RecordFailure(ASCIIToUTF16("File too big"));
      return true;
    }
    // Being small enough, we can process it in-memory.
    std::string json_data;
    if (!file_util::ReadFileToString(path_, &json_data)) {
      RecordFailure(ASCIIToUTF16(
          "Could not open file. Possibly locked by other process"));
      return true;
    }

    JSONStringValueSerializer json(json_data);
    int error_code = base::JSONReader::JSON_NO_ERROR;
    std::string error_message;
    scoped_ptr<Value> json_root(json.Deserialize(&error_code, &error_message));
    if (base::JSONReader::JSON_NO_ERROR != error_code) {
      if (error_message.empty()) {
        error_message = "Parse error " + base::IntToString(error_code);
      }
      RecordFailure(UTF8ToUTF16(error_message));
      return true;
    }

    RecordSuccess(ASCIIToUTF16("File parsed OK"));
    return true;
  }

 private:
  FilePath path_;
  int64 max_file_size_;
  DISALLOW_COPY_AND_ASSIGN(JSONTest);
};

}  // namespace

DiagnosticTest* MakeUserDirTest() {
  return new PathTest(kPathsToTest[0]);
}

DiagnosticTest* MakeLocalStateFileTest() {
  return new PathTest(kPathsToTest[1]);
}

DiagnosticTest* MakeDictonaryDirTest() {
  return new PathTest(kPathsToTest[2]);
}

DiagnosticTest* MakeInspectorDirTest() {
  return new PathTest(kPathsToTest[3]);
}

DiagnosticTest* MakeVersionTest() {
  return new VersionTest();
}

DiagnosticTest* MakeDiskSpaceTest() {
  return new DiskSpaceTest();
}

DiagnosticTest* MakeOperatingSystemTest() {
  return new OperatingSystemTest();
}

DiagnosticTest* MakeConflictingDllsTest() {
  return new ConflictingDllsTest();
}

DiagnosticTest* MakeInstallTypeTest() {
  return new InstallTypeTest();
}

DiagnosticTest* MakePreferencesTest() {
  FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
  path = path.Append(chrome::kPreferencesFilename);
  return new JSONTest(path, ASCIIToUTF16("Profile JSON"), 100 * kOneKilo);
}

DiagnosticTest* MakeBookMarksTest() {
  FilePath path = DiagnosticTest::GetUserDefaultProfileDir();
  path = path.Append(chrome::kBookmarksFileName);
  return new JSONTest(path, ASCIIToUTF16("BookMarks JSON"), 2 * kOneMeg);
}

DiagnosticTest* MakeLocalStateTest() {
  FilePath path;
  PathService::Get(chrome::DIR_USER_DATA, &path);
  path = path.Append(chrome::kLocalStateFilename);
  return new JSONTest(path, ASCIIToUTF16("Local State JSON"), 50 * kOneKilo);
}
<|endoftext|>


<commit_before><commit_msg>Add HKLM + HKCU lookup for COM history indexer - slight refactor<commit_after><|endoftext|>


<commit_before>#include "InputManager.hpp"
#include "EntityManager.hpp"

#include "components/InputComponent.hpp"
#include "imgui.h"

InputManager::InputManager(kengine::EntityManager & em, OgreBites::ApplicationContext & app) : _em(em) {
	app.addInputListener(this);
}

static putils::vector<OgreBites::KeyboardEvent, 128> g_keyPressedEvents;
static putils::vector<OgreBites::KeyboardEvent, 128> g_keyReleasedEvents;
static putils::vector<OgreBites::MouseMotionEvent, 128> g_mouseMovedEvents;
static putils::vector<OgreBites::MouseButtonEvent, 128> g_mousePressedEvents;
static putils::vector<OgreBites::MouseButtonEvent, 128> g_mouseReleasedEvents;
static putils::vector<OgreBites::MouseWheelEvent, 128> g_mouseWheelEvents;

void InputManager::execute() noexcept {
	const auto & imgui = ImGui::GetIO();
	for (const auto & [e, input] : _em.getEntities<kengine::InputComponent>()) {
		if (!imgui.WantCaptureKeyboard && input.onKey != nullptr) {
			for (const auto & event : g_keyPressedEvents)
				input.onKey(event.keysym.sym, true);
			for (const auto & event : g_keyReleasedEvents)
				input.onKey(event.keysym.sym, false);
		}

		if (!imgui.WantCaptureMouse) {
			if (imgui.WantCaptureMouse && input.onMouseMove != nullptr)
				for (const auto & event : g_mouseMovedEvents)
					input.onMouseMove((float)event.x, (float)event.y);

			if (input.onMouseButton != nullptr) {
				for (const auto & event : g_mousePressedEvents)
					input.onMouseButton(event.button, (float)event.x, (float)event.y, true);
				for (const auto & event : g_mouseReleasedEvents)
					input.onMouseButton(event.button, (float)event.x, (float)event.y, false);
			}

			if (input.onMouseWheel != nullptr)
				for (const auto & event : g_mouseWheelEvents)
					input.onMouseWheel((float)event.y, 0.f, 0.f);
		}
	}

	g_keyPressedEvents.clear();
	g_keyReleasedEvents.clear();
	g_mouseMovedEvents.clear();
	g_mousePressedEvents.clear();
	g_mouseReleasedEvents.clear();
	g_mouseWheelEvents.clear();
}

bool InputManager::keyPressed(const OgreBites::KeyboardEvent & event) {
	g_keyPressedEvents.push_back(event);
	return true;
}

bool InputManager::keyReleased(const OgreBites::KeyboardEvent & event) {
	g_keyReleasedEvents.push_back(event);
	return true;
}

bool InputManager::mouseMoved(const OgreBites::MouseMotionEvent & event) {
	g_mouseMovedEvents.push_back(event);
	return true;
}

bool InputManager::mousePressed(const OgreBites::MouseButtonEvent & event) {
	g_mousePressedEvents.push_back(event);
	return true;
}

bool InputManager::mouseReleased(const OgreBites::MouseButtonEvent & event) {
	g_mouseReleasedEvents.push_back(event);
	return true;
}

bool InputManager::mouseWheelRolled(const OgreBites::MouseWheelEvent & event) {
	g_mouseWheelEvents.push_back(event);
	return true;
}
<commit_msg>ogre -- fix bad condition in InputManager<commit_after>#include "InputManager.hpp"
#include "EntityManager.hpp"

#include "components/InputComponent.hpp"
#include "imgui.h"

InputManager::InputManager(kengine::EntityManager & em, OgreBites::ApplicationContext & app) : _em(em) {
	app.addInputListener(this);
}

static putils::vector<OgreBites::KeyboardEvent, 128> g_keyPressedEvents;
static putils::vector<OgreBites::KeyboardEvent, 128> g_keyReleasedEvents;
static putils::vector<OgreBites::MouseMotionEvent, 128> g_mouseMovedEvents;
static putils::vector<OgreBites::MouseButtonEvent, 128> g_mousePressedEvents;
static putils::vector<OgreBites::MouseButtonEvent, 128> g_mouseReleasedEvents;
static putils::vector<OgreBites::MouseWheelEvent, 128> g_mouseWheelEvents;

void InputManager::execute() noexcept {
	const auto & imgui = ImGui::GetIO();
	for (const auto & [e, input] : _em.getEntities<kengine::InputComponent>()) {
		if (!imgui.WantCaptureKeyboard && input.onKey != nullptr) {
			for (const auto & event : g_keyPressedEvents)
				input.onKey(event.keysym.sym, true);
			for (const auto & event : g_keyReleasedEvents)
				input.onKey(event.keysym.sym, false);
		}

		if (!imgui.WantCaptureMouse) {
			if (input.onMouseMove != nullptr)
				for (const auto & event : g_mouseMovedEvents)
					input.onMouseMove((float)event.x, (float)event.y);

			if (input.onMouseButton != nullptr) {
				for (const auto & event : g_mousePressedEvents)
					input.onMouseButton(event.button, (float)event.x, (float)event.y, true);
				for (const auto & event : g_mouseReleasedEvents)
					input.onMouseButton(event.button, (float)event.x, (float)event.y, false);
			}

			if (input.onMouseWheel != nullptr)
				for (const auto & event : g_mouseWheelEvents)
					input.onMouseWheel((float)event.y, 0.f, 0.f);
		}
	}

	g_keyPressedEvents.clear();
	g_keyReleasedEvents.clear();
	g_mouseMovedEvents.clear();
	g_mousePressedEvents.clear();
	g_mouseReleasedEvents.clear();
	g_mouseWheelEvents.clear();
}

bool InputManager::keyPressed(const OgreBites::KeyboardEvent & event) {
	g_keyPressedEvents.push_back(event);
	return true;
}

bool InputManager::keyReleased(const OgreBites::KeyboardEvent & event) {
	g_keyReleasedEvents.push_back(event);
	return true;
}

bool InputManager::mouseMoved(const OgreBites::MouseMotionEvent & event) {
	g_mouseMovedEvents.push_back(event);
	return true;
}

bool InputManager::mousePressed(const OgreBites::MouseButtonEvent & event) {
	g_mousePressedEvents.push_back(event);
	return true;
}

bool InputManager::mouseReleased(const OgreBites::MouseButtonEvent & event) {
	g_mouseReleasedEvents.push_back(event);
	return true;
}

bool InputManager::mouseWheelRolled(const OgreBites::MouseWheelEvent & event) {
	g_mouseWheelEvents.push_back(event);
	return true;
}
<|endoftext|>


<commit_before>#include <IOKit/hid/IOHIDKeys.h>

#include "Config.hpp"
#include "IOLogWrapper.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedDevice.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "Params.hpp"
#include "PressingPhysicalKeys.hpp"
#include "TimerWrapper.hpp"
#include "strlcpy_utf8.hpp"

namespace org_pqrs_Karabiner {
TimerWrapper ListHookedDevice::refreshInProgressDevices_timer_;

// ======================================================================
ListHookedDevice::Item::Item(IOHIDevice* d) : device_(d),
                                              deviceType_(DeviceType::UNKNOWN),
                                              inProgress_(false) {
  setDeviceIdentifier();
  setDeviceType();
}

void
ListHookedDevice::Item::setDeviceIdentifier(void) {
  if (!device_) return;

  IORegistryEntry* dev = device_;

  while (dev) {
    const OSNumber* vid = NULL;
    vid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDVendorIDKey));

    const OSNumber* pid = NULL;
    pid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDProductIDKey));

    if (vid && pid) {
      deviceIdentifier_.setVendor(DeviceVendor(vid->unsigned32BitValue()));
      deviceIdentifier_.setProduct(DeviceProduct(pid->unsigned32BitValue()));

      goto finish;

    } else {
      // ApplePS2Keyboard does not have ProductID,
      // so we check for Manufacturer and Product strings
      const char* name = dev->getName();

      if (name && strcmp(name, "ApplePS2Keyboard") == 0) {
        // kIOHIDManufacturerKey == "Manufacturer"
        // kIOHIDProductKey == "Product"
        const OSString* manufacturer = OSDynamicCast(OSString, dev->getProperty(kIOHIDManufacturerKey));
        const OSString* product = OSDynamicCast(OSString, dev->getProperty(kIOHIDProductKey));

        if (manufacturer && product) {
          if (manufacturer->isEqualTo("Apple") &&
              product->isEqualTo("Keyboard")) {
            deviceIdentifier_.setVendor(DeviceVendor::APPLE_COMPUTER);
            deviceIdentifier_.setProduct(DeviceProduct::APPLE_INTERNAL_KEYBOARD_TRACKPAD_0x0218);
            goto finish;
          }
        }
      }
    }

    // check parent property.
    dev = dev->getParentEntry(IORegistryEntry::getPlane(kIOServicePlane));
  }

finish:
  // Set LocationID
  if (dev) {
    const OSNumber* locationid = NULL;
    locationid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDLocationIDKey));
    if (locationid) {
      deviceIdentifier_.setLocation(DeviceLocation(locationid->unsigned32BitValue()));
    }
  }

  IOLOG_DEBUG("HookedDevice::setVendorProductLocation device_:%p, vendor:0x%04x, product:0x%04x location:0x%04x\n",
              device_,
              deviceIdentifier_.getVendor().get(),
              deviceIdentifier_.getProduct().get(),
              deviceIdentifier_.getLocation().get());
}

void
ListHookedDevice::Item::setDeviceType(void) {
  if (!device_) return;

  const char* name = NULL;

  name = device_->getName();
  if (!name) goto finish;

  // Apple device
  if (strcmp(name, "IOHIDKeyboard") == 0 ||
      strcmp(name, "AppleADBKeyboard") == 0 ||
      strcmp(name, "IOHIDConsumer") == 0 ||
      strcmp(name, "IOHIDPointing") == 0 ||
      strcmp(name, "ApplePS2Mouse") == 0 ||
      strcmp(name, "ApplePS2Trackpad") == 0 ||
      strcmp(name, "AppleUSBGrIIITrackpad") == 0 ||
      strcmp(name, "AppleADBMouseType4") == 0) {

    deviceType_ = DeviceType::APPLE_EXTERNAL;

    // ------------------------------------------------------------
    // Judge internal device or external device.
    //
    // We judge it from a product name whether it is internal device.
    // At keyboard, we cannot use the KeyboardType,
    // because some external keyboard has the same KeyboardType as Apple internal keyboard.
    const OSString* productname = NULL;
    productname = OSDynamicCast(OSString, device_->getProperty(kIOHIDProductKey));
    if (productname) {
      const char* pname = productname->getCStringNoCopy();
      if (pname) {
        const char* internalname = "Apple Internal ";
        if (strncmp(internalname, pname, strlen(internalname)) == 0) {
          deviceType_ = DeviceType::APPLE_INTERNAL;
        }

        const char* mikeyname = "Apple Mikey HID Driver";
        if (strcmp(mikeyname, pname) == 0) {
          deviceType_ = DeviceType::APPLE_MIKEY_HID_DRIVER;
        }
      }
    }

    goto finish;
  }

  if (strcmp(name, "ApplePS2Keyboard") == 0) {
    deviceType_ = DeviceType::APPLE_INTERNAL;
    goto finish;
  }

  // USB Overdrive
  if (strcmp(name, "OverdriveHIDKeyboard") == 0 ||
      strcmp(name, "OverdriveHIDPointer") == 0) {
    deviceType_ = DeviceType::USB_OVERDRIVE;
    goto finish;
  }

finish:
  IOLOG_DEBUG("HookedDevice::setDeviceType device_:%p, name:%s, deviceType_:%d\n",
              device_,
              name ? name : "null",
              deviceType_);
}

bool
ListHookedDevice::Item::isConsumer(const char* name) {
  if (!name) return false;

  if (strcmp(name, "IOHIDConsumer") == 0) return true;
  if (strcmp(name, "com_Logitech_HISpecialKeys") == 0) return true;

  return false;
}

// ======================================================================
namespace {
void
reset(void) {
  PressingPhysicalKeys::clear();
}
}

bool
ListHookedDevice::initialize(void) {
  return true;
}

void
ListHookedDevice::terminate(void) {
  list_.clear();

  reset();
}

void
ListHookedDevice::push_back(ListHookedDevice::Item* newp) {
  if (!newp) return;

  last_ = newp->device_;
  list_.push_back(newp);

  // Call reset whenever the device status is changed.
  reset();

  IOLOG_DEVEL("ListHookedDevice::push_back list_.size = %d\n", static_cast<int>(list_.size()));

  refresh();
  start_refreshInProgressDevices_timer();
}

void
ListHookedDevice::erase(IOHIDevice* p) {
  ListHookedDevice::Item* item = get(p);
  if (!item) return;

  list_.erase_and_delete(item);

  // Call reset whenever the device status is changed.
  reset();

  IOLOG_DEVEL("ListHookedDevice::erase list_.size = %d\n", static_cast<int>(list_.size()));

  refresh();
}

ListHookedDevice::Item*
ListHookedDevice::get(const IOHIDevice* device) {
  last_ = device;

  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->device_ == device) return p;
  }

  return NULL;
}

ListHookedDevice::Item*
ListHookedDevice::get_replaced(void) {
  // ----------------------------------------------------------------------
  // Search a last_ device first.
  ListHookedDevice::Item* p = get(last_);
  if (p && p->isReplaced()) return p;

  // ----------------------------------------------------------------------
  // Using a first matched device.
  for (p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->isReplaced()) return p;
  }

  return NULL;
}

void
ListHookedDevice::refresh(void) {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->refresh()) {
      // Call reset whenever the device status is changed.
      reset();
    }
  }
}

bool
ListHookedDevice::isInProgress(void) const {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->inProgress_) {
      return true;
    }
  }

  return false;
}

bool
ListHookedDevice::isExternalDevicesConnected(void) const {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->deviceType_ != DeviceType::APPLE_INTERNAL) {
      return true;
    }
  }

  return false;
}

void
ListHookedDevice::getDeviceInformation(BridgeDeviceInformation& out, size_t index) const {
  out.isFound = 0;
  out.manufacturer[0] = '\0';
  out.product[0] = '\0';
  out.vendorID = 0;
  out.productID = 0;
  out.locationID = 0;

  Item* p = static_cast<Item*>(list_.safe_front());

  for (;;) {
    if (!p) return;

    if (p->isReplaced()) {
      if (index == 0) {
        break;
      } else {
        --index;
      }
    }

    p = static_cast<Item*>(p->getnext());
  }

  if (!p) return;

  if (p->device_) {
    const OSString* manufacturer = OSDynamicCast(OSString, p->device_->getProperty(kIOHIDManufacturerKey));
    if (manufacturer) {
      const char* cstr = manufacturer->getCStringNoCopy();
      if (cstr) {
        pqrs::strlcpy_utf8::strlcpy(out.manufacturer, cstr, sizeof(out.manufacturer));
      }
    }

    const OSString* product = OSDynamicCast(OSString, p->device_->getProperty(kIOHIDProductKey));
    if (product) {
      const char* cstr = product->getCStringNoCopy();
      if (cstr) {
        pqrs::strlcpy_utf8::strlcpy(out.product, cstr, sizeof(out.product));
      }
    }
  }
  out.vendorID = (p->deviceIdentifier_).getVendor().get();
  out.productID = (p->deviceIdentifier_).getProduct().get();
  out.locationID = (p->deviceIdentifier_).getLocation().get();
  out.isFound = 1;
}

void
ListHookedDevice::initializeAll(IOWorkLoop& workloop) {
  ListHookedKeyboard::instance().initialize();
  ListHookedConsumer::instance().initialize();
  ListHookedPointing::instance().initialize();

  refreshInProgressDevices_timer_.initialize(&workloop, NULL, ListHookedDevice::refreshInProgressDevices_timer_callback);
}

void
ListHookedDevice::terminateAll(void) {
  refreshInProgressDevices_timer_.terminate();

  ListHookedKeyboard::instance().terminate();
  ListHookedConsumer::instance().terminate();
  ListHookedPointing::instance().terminate();
}

void
ListHookedDevice::refreshAll(void) {
  ListHookedKeyboard::instance().refresh();
  ListHookedConsumer::instance().refresh();
  ListHookedPointing::instance().refresh();
}

void
ListHookedDevice::start_refreshInProgressDevices_timer(void) {
  refreshInProgressDevices_timer_.setTimeoutMS(REFRESH_INPROGRESS_DEVICES_TIMER_INTERVAL);
}

void
ListHookedDevice::refreshInProgressDevices_timer_callback(OSObject* owner, IOTimerEventSource* sender) {
  IOLOG_DEBUG("refreshInProgressDevices_timer_callback\n");

  if (ListHookedKeyboard::instance().isInProgress()) {
    ListHookedKeyboard::instance().refresh();
  }
  if (ListHookedConsumer::instance().isInProgress()) {
    ListHookedConsumer::instance().refresh();
  }
  if (ListHookedPointing::instance().isInProgress()) {
    ListHookedPointing::instance().refresh();
  }

  if (ListHookedKeyboard::instance().isInProgress() ||
      ListHookedConsumer::instance().isInProgress() ||
      ListHookedPointing::instance().isInProgress()) {
    IOLOG_DEBUG("Restarting refreshInProgressDevices_timer because some devices are in progress.\n");
    refreshInProgressDevices_timer_.setTimeoutMS(REFRESH_INPROGRESS_DEVICES_TIMER_INTERVAL);
  }
}
}
<commit_msg>fix ListHookedDevice::isExternalDevicesConnected<commit_after>#include <IOKit/hid/IOHIDKeys.h>

#include "Config.hpp"
#include "IOLogWrapper.hpp"
#include "ListHookedConsumer.hpp"
#include "ListHookedDevice.hpp"
#include "ListHookedKeyboard.hpp"
#include "ListHookedPointing.hpp"
#include "Params.hpp"
#include "PressingPhysicalKeys.hpp"
#include "TimerWrapper.hpp"
#include "strlcpy_utf8.hpp"

namespace org_pqrs_Karabiner {
TimerWrapper ListHookedDevice::refreshInProgressDevices_timer_;

// ======================================================================
ListHookedDevice::Item::Item(IOHIDevice* d) : device_(d),
                                              deviceType_(DeviceType::UNKNOWN),
                                              inProgress_(false) {
  setDeviceIdentifier();
  setDeviceType();
}

void
ListHookedDevice::Item::setDeviceIdentifier(void) {
  if (!device_) return;

  IORegistryEntry* dev = device_;

  while (dev) {
    const OSNumber* vid = NULL;
    vid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDVendorIDKey));

    const OSNumber* pid = NULL;
    pid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDProductIDKey));

    if (vid && pid) {
      deviceIdentifier_.setVendor(DeviceVendor(vid->unsigned32BitValue()));
      deviceIdentifier_.setProduct(DeviceProduct(pid->unsigned32BitValue()));

      goto finish;

    } else {
      // ApplePS2Keyboard does not have ProductID,
      // so we check for Manufacturer and Product strings
      const char* name = dev->getName();

      if (name && strcmp(name, "ApplePS2Keyboard") == 0) {
        // kIOHIDManufacturerKey == "Manufacturer"
        // kIOHIDProductKey == "Product"
        const OSString* manufacturer = OSDynamicCast(OSString, dev->getProperty(kIOHIDManufacturerKey));
        const OSString* product = OSDynamicCast(OSString, dev->getProperty(kIOHIDProductKey));

        if (manufacturer && product) {
          if (manufacturer->isEqualTo("Apple") &&
              product->isEqualTo("Keyboard")) {
            deviceIdentifier_.setVendor(DeviceVendor::APPLE_COMPUTER);
            deviceIdentifier_.setProduct(DeviceProduct::APPLE_INTERNAL_KEYBOARD_TRACKPAD_0x0218);
            goto finish;
          }
        }
      }
    }

    // check parent property.
    dev = dev->getParentEntry(IORegistryEntry::getPlane(kIOServicePlane));
  }

finish:
  // Set LocationID
  if (dev) {
    const OSNumber* locationid = NULL;
    locationid = OSDynamicCast(OSNumber, dev->getProperty(kIOHIDLocationIDKey));
    if (locationid) {
      deviceIdentifier_.setLocation(DeviceLocation(locationid->unsigned32BitValue()));
    }
  }

  IOLOG_DEBUG("HookedDevice::setVendorProductLocation device_:%p, vendor:0x%04x, product:0x%04x location:0x%04x\n",
              device_,
              deviceIdentifier_.getVendor().get(),
              deviceIdentifier_.getProduct().get(),
              deviceIdentifier_.getLocation().get());
}

void
ListHookedDevice::Item::setDeviceType(void) {
  if (!device_) return;

  const char* name = NULL;

  name = device_->getName();
  if (!name) goto finish;

  // Apple device
  if (strcmp(name, "IOHIDKeyboard") == 0 ||
      strcmp(name, "AppleADBKeyboard") == 0 ||
      strcmp(name, "IOHIDConsumer") == 0 ||
      strcmp(name, "IOHIDPointing") == 0 ||
      strcmp(name, "ApplePS2Mouse") == 0 ||
      strcmp(name, "ApplePS2Trackpad") == 0 ||
      strcmp(name, "AppleUSBGrIIITrackpad") == 0 ||
      strcmp(name, "AppleADBMouseType4") == 0) {

    deviceType_ = DeviceType::APPLE_EXTERNAL;

    // ------------------------------------------------------------
    // Judge internal device or external device.
    //
    // We judge it from a product name whether it is internal device.
    // At keyboard, we cannot use the KeyboardType,
    // because some external keyboard has the same KeyboardType as Apple internal keyboard.
    const OSString* productname = NULL;
    productname = OSDynamicCast(OSString, device_->getProperty(kIOHIDProductKey));
    if (productname) {
      const char* pname = productname->getCStringNoCopy();
      if (pname) {
        const char* internalname = "Apple Internal ";
        if (strncmp(internalname, pname, strlen(internalname)) == 0) {
          deviceType_ = DeviceType::APPLE_INTERNAL;
        }

        const char* mikeyname = "Apple Mikey HID Driver";
        if (strcmp(mikeyname, pname) == 0) {
          deviceType_ = DeviceType::APPLE_MIKEY_HID_DRIVER;
        }
      }
    }

    goto finish;
  }

  if (strcmp(name, "ApplePS2Keyboard") == 0) {
    deviceType_ = DeviceType::APPLE_INTERNAL;
    goto finish;
  }

  // USB Overdrive
  if (strcmp(name, "OverdriveHIDKeyboard") == 0 ||
      strcmp(name, "OverdriveHIDPointer") == 0) {
    deviceType_ = DeviceType::USB_OVERDRIVE;
    goto finish;
  }

finish:
  IOLOG_DEBUG("HookedDevice::setDeviceType device_:%p, name:%s, deviceType_:%d\n",
              device_,
              name ? name : "null",
              deviceType_);
}

bool
ListHookedDevice::Item::isConsumer(const char* name) {
  if (!name) return false;

  if (strcmp(name, "IOHIDConsumer") == 0) return true;
  if (strcmp(name, "com_Logitech_HISpecialKeys") == 0) return true;

  return false;
}

// ======================================================================
namespace {
void
reset(void) {
  PressingPhysicalKeys::clear();
}
}

bool
ListHookedDevice::initialize(void) {
  return true;
}

void
ListHookedDevice::terminate(void) {
  list_.clear();

  reset();
}

void
ListHookedDevice::push_back(ListHookedDevice::Item* newp) {
  if (!newp) return;

  last_ = newp->device_;
  list_.push_back(newp);

  // Call reset whenever the device status is changed.
  reset();

  IOLOG_DEVEL("ListHookedDevice::push_back list_.size = %d\n", static_cast<int>(list_.size()));

  refresh();
  start_refreshInProgressDevices_timer();
}

void
ListHookedDevice::erase(IOHIDevice* p) {
  ListHookedDevice::Item* item = get(p);
  if (!item) return;

  list_.erase_and_delete(item);

  // Call reset whenever the device status is changed.
  reset();

  IOLOG_DEVEL("ListHookedDevice::erase list_.size = %d\n", static_cast<int>(list_.size()));

  refresh();
}

ListHookedDevice::Item*
ListHookedDevice::get(const IOHIDevice* device) {
  last_ = device;

  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->device_ == device) return p;
  }

  return NULL;
}

ListHookedDevice::Item*
ListHookedDevice::get_replaced(void) {
  // ----------------------------------------------------------------------
  // Search a last_ device first.
  ListHookedDevice::Item* p = get(last_);
  if (p && p->isReplaced()) return p;

  // ----------------------------------------------------------------------
  // Using a first matched device.
  for (p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->isReplaced()) return p;
  }

  return NULL;
}

void
ListHookedDevice::refresh(void) {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->refresh()) {
      // Call reset whenever the device status is changed.
      reset();
    }
  }
}

bool
ListHookedDevice::isInProgress(void) const {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->inProgress_) {
      return true;
    }
  }

  return false;
}

bool
ListHookedDevice::isExternalDevicesConnected(void) const {
  for (Item* p = static_cast<Item*>(list_.safe_front()); p; p = static_cast<Item*>(p->getnext())) {
    if (p->inProgress_) continue;

    if (p->deviceType_ != DeviceType::APPLE_MIKEY_HID_DRIVER &&
        p->deviceType_ != DeviceType::APPLE_INTERNAL) {
      return true;
    }
  }

  return false;
}

void
ListHookedDevice::getDeviceInformation(BridgeDeviceInformation& out, size_t index) const {
  out.isFound = 0;
  out.manufacturer[0] = '\0';
  out.product[0] = '\0';
  out.vendorID = 0;
  out.productID = 0;
  out.locationID = 0;

  Item* p = static_cast<Item*>(list_.safe_front());

  for (;;) {
    if (!p) return;

    if (p->isReplaced()) {
      if (index == 0) {
        break;
      } else {
        --index;
      }
    }

    p = static_cast<Item*>(p->getnext());
  }

  if (!p) return;

  if (p->device_) {
    const OSString* manufacturer = OSDynamicCast(OSString, p->device_->getProperty(kIOHIDManufacturerKey));
    if (manufacturer) {
      const char* cstr = manufacturer->getCStringNoCopy();
      if (cstr) {
        pqrs::strlcpy_utf8::strlcpy(out.manufacturer, cstr, sizeof(out.manufacturer));
      }
    }

    const OSString* product = OSDynamicCast(OSString, p->device_->getProperty(kIOHIDProductKey));
    if (product) {
      const char* cstr = product->getCStringNoCopy();
      if (cstr) {
        pqrs::strlcpy_utf8::strlcpy(out.product, cstr, sizeof(out.product));
      }
    }
  }
  out.vendorID = (p->deviceIdentifier_).getVendor().get();
  out.productID = (p->deviceIdentifier_).getProduct().get();
  out.locationID = (p->deviceIdentifier_).getLocation().get();
  out.isFound = 1;
}

void
ListHookedDevice::initializeAll(IOWorkLoop& workloop) {
  ListHookedKeyboard::instance().initialize();
  ListHookedConsumer::instance().initialize();
  ListHookedPointing::instance().initialize();

  refreshInProgressDevices_timer_.initialize(&workloop, NULL, ListHookedDevice::refreshInProgressDevices_timer_callback);
}

void
ListHookedDevice::terminateAll(void) {
  refreshInProgressDevices_timer_.terminate();

  ListHookedKeyboard::instance().terminate();
  ListHookedConsumer::instance().terminate();
  ListHookedPointing::instance().terminate();
}

void
ListHookedDevice::refreshAll(void) {
  ListHookedKeyboard::instance().refresh();
  ListHookedConsumer::instance().refresh();
  ListHookedPointing::instance().refresh();
}

void
ListHookedDevice::start_refreshInProgressDevices_timer(void) {
  refreshInProgressDevices_timer_.setTimeoutMS(REFRESH_INPROGRESS_DEVICES_TIMER_INTERVAL);
}

void
ListHookedDevice::refreshInProgressDevices_timer_callback(OSObject* owner, IOTimerEventSource* sender) {
  IOLOG_DEBUG("refreshInProgressDevices_timer_callback\n");

  if (ListHookedKeyboard::instance().isInProgress()) {
    ListHookedKeyboard::instance().refresh();
  }
  if (ListHookedConsumer::instance().isInProgress()) {
    ListHookedConsumer::instance().refresh();
  }
  if (ListHookedPointing::instance().isInProgress()) {
    ListHookedPointing::instance().refresh();
  }

  if (ListHookedKeyboard::instance().isInProgress() ||
      ListHookedConsumer::instance().isInProgress() ||
      ListHookedPointing::instance().isInProgress()) {
    IOLOG_DEBUG("Restarting refreshInProgressDevices_timer because some devices are in progress.\n");
    refreshInProgressDevices_timer_.setTimeoutMS(REFRESH_INPROGRESS_DEVICES_TIMER_INTERVAL);
  }
}
}
<|endoftext|>


<commit_before>#ifndef __MW__MW_API__
#define __MW__MW_API__

#include "MW_API_Types.hpp"
#include "Work.hpp"
#include "Result.hpp"
#include <list>
#include <memory>

class MW_API {
public:
    virtual std::list<std::shared_ptr<Work>> &work() = 0;
    virtual int results(std::list<Result *> *) = 0;
};

void MW_Run(int argc, char* argv[], MW_API *app);

#endif
<commit_msg>added random failure mechanism<commit_after>#ifndef __MW__MW_API__
#define __MW__MW_API__

#include "MW_API_Types.hpp"
#include "Work.hpp"
#include "Result.hpp"
#include <list>
#include <memory>

class MW_API {
public:
    virtual std::list<std::shared_ptr<Work>> &work() = 0;
    virtual int results(std::list<Result *> *) = 0;
};

void MW_Run(int argc, char* argv[], MW_API *app);

#endif
<|endoftext|>


<commit_before>/*
 * DesktopSessionLauncher.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopSessionLauncher.hpp"

#include <boost/bind.hpp>

#include <core/WaitUtils.hpp>
#include <core/system/ParentProcessMonitor.hpp>

#include <QProcess>
#include <QtNetwork/QTcpSocket>

#include "DesktopUtils.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"

using namespace core;

namespace desktop {

namespace {

void launchProcess(std::string absPath,
                   QStringList argList,
                   QProcess** ppProc)
{
   QProcess* pProcess = new QProcess();
   pProcess->setProcessChannelMode(QProcess::SeparateChannels);
   pProcess->start(QString::fromUtf8(absPath.c_str()), argList);
   *ppProc = pProcess;
}

core::WaitResult serverReady(QString host, QString port)
{
   QTcpSocket socket;
   socket.connectToHost(host, port.toInt());
   return WaitResult(socket.waitForConnected() ? WaitSuccess : WaitContinue,
                     Success());
}

} // anonymous namespace

Error SessionLauncher::launchFirstSession(const QString& filename,
                                          ApplicationLaunch* pAppLaunch)
{
   // save reference to app launch
   pAppLaunch_ = pAppLaunch;

   // build a new new launch context
   QString host, port;
   QStringList argList;
   QUrl url;
   buildLaunchContext(&host, &port, &argList, &url);

   // launch the process
   Error error = launchSession(argList, &pRSessionProcess_);
   if (error)
     return error;

   // jcheng 03/16/2011: Due to crashing caused by authenticating
   // proxies, bypass all proxies from Qt until we can get the problem
   // completely solved. This is only expected to affect CRAN mirror
   // selection (which falls back to local mirror list) and update
   // checking.
   //NetworkProxyFactory* pProxyFactory = new NetworkProxyFactory();
   //QNetworkProxyFactory::setApplicationProxyFactory(pProxyFactory);

   pMainWindow_ = new MainWindow(url);
   pMainWindow_->setSessionProcess(pRSessionProcess_);
   pAppLaunch->setActivationWindow(pMainWindow_);

   desktop::options().restoreMainWindowBounds(pMainWindow_);

   error = waitForSession(host, port);
   if (error)
      return error;

   // one-time workbench intiailized hook for startup file association
   if (!filename.isNull() && !filename.isEmpty())
   {
      StringSlotBinder* filenameBinder = new StringSlotBinder(filename);
      pMainWindow_->connect(pMainWindow_,
                            SIGNAL(firstWorkbenchInitialized()),
                            filenameBinder,
                            SLOT(trigger()));
      pMainWindow_->connect(filenameBinder,
                            SIGNAL(triggered(QString)),
                            pMainWindow_,
                            SLOT(openFileInRStudio(QString)));
   }

   pMainWindow_->connect(pAppLaunch_,
                         SIGNAL(openFileRequest(QString)),
                         pMainWindow_,
                         SLOT(openFileInRStudio(QString)));

   pMainWindow_->connect(pRSessionProcess_,
                         SIGNAL(finished(int,QProcess::ExitStatus)),
                         this, SLOT(onRSessionExited()));

   pMainWindow_->show();
   pMainWindow_->loadUrl(url);

   return Success();
}

void SessionLauncher::onRSessionExited()
{
   if (pMainWindow_->collectPendingSwitchToProjectRequest())
   {
      Error error = launchNextSession();
      if (error)
      {
         LOG_ERROR(error);

         showMessageBox(QMessageBox::Critical,
                        pMainWindow_,
                        QString::fromUtf8("RStudio"),
                        launchFailedErrorMessage());

         pMainWindow_->quit();
      }
   }
   else
   {
      pMainWindow_->quit();
   }
}

Error SessionLauncher::launchNextSession()
{
   // disconnect the firstWorkbenchInitialized event so it doesn't occur
   // again when we launch the next session
   pMainWindow_->disconnect(SIGNAL(firstWorkbenchInitialized()));

   // delete the old process object
   pMainWindow_->setSessionProcess(NULL);
   if (pRSessionProcess_)
   {
      delete pRSessionProcess_;
      pRSessionProcess_ = NULL;
   }

   // build a new new launch context
   QString host, port;
   QStringList argList;
   QUrl url;
   buildLaunchContext(&host, &port, &argList, &url);

   // launch the process
   Error error = launchSession(argList, &pRSessionProcess_);
   if (error)
     return error;

   // update the main window's reference to the process object
   pMainWindow_->setSessionProcess(pRSessionProcess_);

   // wait for it to be available
   error = waitForSession(host, port);
   if (error)
      return error;

   // connect to quit event
   pMainWindow_->connect(pRSessionProcess_,
                         SIGNAL(finished(int,QProcess::ExitStatus)),
                         this, SLOT(onRSessionExited()));

   // laod url -- use a delay because on occation we've seen the
   // mac client crash during switching of projects and this could
   // be some type of timing related issue
   nextSessionUrl_ = url;
   QTimer::singleShot(50, this, SLOT(onReloadFrameForNextSession()));

   return Success();
}

void SessionLauncher::onReloadFrameForNextSession()
{
   pMainWindow_->loadUrl(nextSessionUrl_);
   nextSessionUrl_.clear();
}

Error SessionLauncher::launchSession(const QStringList& argList,
                                     QProcess** ppRSessionProcess)
{
   return  parent_process_monitor::wrapFork(
         boost::bind(launchProcess,
                     sessionPath_.absolutePath(),
                     argList,
                     ppRSessionProcess));
}

Error SessionLauncher::waitForSession(const QString& host,
                                      const QString& port)
{
   return waitWithTimeout(boost::bind(serverReady, host, port),
                          50, 25, 10);
}

QString SessionLauncher::launchFailedErrorMessage() const
{
   QString errMsg = QString::fromUtf8("The R session failed to start.");

   if (pRSessionProcess_)
   {
      QString errmsgs = QString::fromLocal8Bit(
                              pRSessionProcess_->readAllStandardError());
      if (errmsgs.size())
      {
         errMsg = errMsg.append(
                           QString::fromAscii("\n\n")).append(errmsgs);
      }
   }

   return errMsg;
}

void SessionLauncher::cleanupAtExit()
{
   if (pMainWindow_)
      desktop::options().saveMainWindowBounds(pMainWindow_);
}

void SessionLauncher::buildLaunchContext(QString* pHost,
                                         QString* pPort,
                                         QStringList* pArgList,
                                         QUrl* pUrl) const
{
   *pHost = QString::fromAscii("127.0.0.1");
   *pPort = desktop::options().newPortNumber();
   *pUrl = QUrl(QString::fromAscii("http://") + *pHost +
                QString::fromAscii(":") + *pPort + QString::fromAscii("/"));

   if (!confPath_.empty())
   {
      *pArgList << QString::fromAscii("--config-file") <<
                   QString::fromUtf8(confPath_.absolutePath().c_str());
   }
   else
   {
      // explicitly pass "none" so that rsession doesn't read an
      // /etc/rstudio/rsession.conf file which may be sitting around
      // from a previous configuratin or install
      *pArgList << QString::fromAscii("--config-file") <<
                   QString::fromAscii("none");
   }

   *pArgList << QString::fromAscii("--program-mode") <<
                QString::fromAscii("desktop");

   *pArgList << QString::fromAscii("--www-port") << *pPort;
}

} // namespace desktop
<commit_msg>increase reload frame delay for new session<commit_after>/*
 * DesktopSessionLauncher.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include "DesktopSessionLauncher.hpp"

#include <boost/bind.hpp>

#include <core/WaitUtils.hpp>
#include <core/system/ParentProcessMonitor.hpp>

#include <QProcess>
#include <QtNetwork/QTcpSocket>

#include "DesktopUtils.hpp"
#include "DesktopOptions.hpp"
#include "DesktopSlotBinders.hpp"

using namespace core;

namespace desktop {

namespace {

void launchProcess(std::string absPath,
                   QStringList argList,
                   QProcess** ppProc)
{
   QProcess* pProcess = new QProcess();
   pProcess->setProcessChannelMode(QProcess::SeparateChannels);
   pProcess->start(QString::fromUtf8(absPath.c_str()), argList);
   *ppProc = pProcess;
}

core::WaitResult serverReady(QString host, QString port)
{
   QTcpSocket socket;
   socket.connectToHost(host, port.toInt());
   return WaitResult(socket.waitForConnected() ? WaitSuccess : WaitContinue,
                     Success());
}

} // anonymous namespace

Error SessionLauncher::launchFirstSession(const QString& filename,
                                          ApplicationLaunch* pAppLaunch)
{
   // save reference to app launch
   pAppLaunch_ = pAppLaunch;

   // build a new new launch context
   QString host, port;
   QStringList argList;
   QUrl url;
   buildLaunchContext(&host, &port, &argList, &url);

   // launch the process
   Error error = launchSession(argList, &pRSessionProcess_);
   if (error)
     return error;

   // jcheng 03/16/2011: Due to crashing caused by authenticating
   // proxies, bypass all proxies from Qt until we can get the problem
   // completely solved. This is only expected to affect CRAN mirror
   // selection (which falls back to local mirror list) and update
   // checking.
   //NetworkProxyFactory* pProxyFactory = new NetworkProxyFactory();
   //QNetworkProxyFactory::setApplicationProxyFactory(pProxyFactory);

   pMainWindow_ = new MainWindow(url);
   pMainWindow_->setSessionProcess(pRSessionProcess_);
   pAppLaunch->setActivationWindow(pMainWindow_);

   desktop::options().restoreMainWindowBounds(pMainWindow_);

   error = waitForSession(host, port);
   if (error)
      return error;

   // one-time workbench intiailized hook for startup file association
   if (!filename.isNull() && !filename.isEmpty())
   {
      StringSlotBinder* filenameBinder = new StringSlotBinder(filename);
      pMainWindow_->connect(pMainWindow_,
                            SIGNAL(firstWorkbenchInitialized()),
                            filenameBinder,
                            SLOT(trigger()));
      pMainWindow_->connect(filenameBinder,
                            SIGNAL(triggered(QString)),
                            pMainWindow_,
                            SLOT(openFileInRStudio(QString)));
   }

   pMainWindow_->connect(pAppLaunch_,
                         SIGNAL(openFileRequest(QString)),
                         pMainWindow_,
                         SLOT(openFileInRStudio(QString)));

   pMainWindow_->connect(pRSessionProcess_,
                         SIGNAL(finished(int,QProcess::ExitStatus)),
                         this, SLOT(onRSessionExited()));

   pMainWindow_->show();
   pMainWindow_->loadUrl(url);

   return Success();
}

void SessionLauncher::onRSessionExited()
{
   if (pMainWindow_->collectPendingSwitchToProjectRequest())
   {
      Error error = launchNextSession();
      if (error)
      {
         LOG_ERROR(error);

         showMessageBox(QMessageBox::Critical,
                        pMainWindow_,
                        QString::fromUtf8("RStudio"),
                        launchFailedErrorMessage());

         pMainWindow_->quit();
      }
   }
   else
   {
      pMainWindow_->quit();
   }
}

Error SessionLauncher::launchNextSession()
{
   // disconnect the firstWorkbenchInitialized event so it doesn't occur
   // again when we launch the next session
   pMainWindow_->disconnect(SIGNAL(firstWorkbenchInitialized()));

   // delete the old process object
   pMainWindow_->setSessionProcess(NULL);
   if (pRSessionProcess_)
   {
      delete pRSessionProcess_;
      pRSessionProcess_ = NULL;
   }

   // build a new new launch context
   QString host, port;
   QStringList argList;
   QUrl url;
   buildLaunchContext(&host, &port, &argList, &url);

   // launch the process
   Error error = launchSession(argList, &pRSessionProcess_);
   if (error)
     return error;

   // update the main window's reference to the process object
   pMainWindow_->setSessionProcess(pRSessionProcess_);

   // wait for it to be available
   error = waitForSession(host, port);
   if (error)
      return error;

   // connect to quit event
   pMainWindow_->connect(pRSessionProcess_,
                         SIGNAL(finished(int,QProcess::ExitStatus)),
                         this, SLOT(onRSessionExited()));

   // laod url -- use a delay because on occation we've seen the
   // mac client crash during switching of projects and this could
   // be some type of timing related issue
   nextSessionUrl_ = url;
   QTimer::singleShot(100, this, SLOT(onReloadFrameForNextSession()));

   return Success();
}

void SessionLauncher::onReloadFrameForNextSession()
{
   pMainWindow_->loadUrl(nextSessionUrl_);
   nextSessionUrl_.clear();
}

Error SessionLauncher::launchSession(const QStringList& argList,
                                     QProcess** ppRSessionProcess)
{
   return  parent_process_monitor::wrapFork(
         boost::bind(launchProcess,
                     sessionPath_.absolutePath(),
                     argList,
                     ppRSessionProcess));
}

Error SessionLauncher::waitForSession(const QString& host,
                                      const QString& port)
{
   return waitWithTimeout(boost::bind(serverReady, host, port),
                          50, 25, 10);
}

QString SessionLauncher::launchFailedErrorMessage() const
{
   QString errMsg = QString::fromUtf8("The R session failed to start.");

   if (pRSessionProcess_)
   {
      QString errmsgs = QString::fromLocal8Bit(
                              pRSessionProcess_->readAllStandardError());
      if (errmsgs.size())
      {
         errMsg = errMsg.append(
                           QString::fromAscii("\n\n")).append(errmsgs);
      }
   }

   return errMsg;
}

void SessionLauncher::cleanupAtExit()
{
   if (pMainWindow_)
      desktop::options().saveMainWindowBounds(pMainWindow_);
}

void SessionLauncher::buildLaunchContext(QString* pHost,
                                         QString* pPort,
                                         QStringList* pArgList,
                                         QUrl* pUrl) const
{
   *pHost = QString::fromAscii("127.0.0.1");
   *pPort = desktop::options().newPortNumber();
   *pUrl = QUrl(QString::fromAscii("http://") + *pHost +
                QString::fromAscii(":") + *pPort + QString::fromAscii("/"));

   if (!confPath_.empty())
   {
      *pArgList << QString::fromAscii("--config-file") <<
                   QString::fromUtf8(confPath_.absolutePath().c_str());
   }
   else
   {
      // explicitly pass "none" so that rsession doesn't read an
      // /etc/rstudio/rsession.conf file which may be sitting around
      // from a previous configuratin or install
      *pArgList << QString::fromAscii("--config-file") <<
                   QString::fromAscii("none");
   }

   *pArgList << QString::fromAscii("--program-mode") <<
                QString::fromAscii("desktop");

   *pArgList << QString::fromAscii("--www-port") << *pPort;
}

} // namespace desktop
<|endoftext|>


<commit_before>#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdio>
#include <sstream>
#include <cassert>
#include <vector>
#include <string>
#include <cstdlib>
#include <iomanip>
#include "bond_angle.h"

using namespace std;

extern int totalatoms;
extern vector< vector<string> > vector_coords;  //referring to vector "vector_coords" in extraction.cpp

void atom_distance(vector< vector<string> > & vector_coords) {

    ofstream log;
    log.open("log.txt", ios::app);

    cout <<"Interatomic distances (in Angstroms): " << endl;

    int i, j, k, l;
    string atom1, atom2, atom3, atom4;
    string x1_string, x2_string, y1_string, y2_string, z1_string, z2_string;
    double x1_double, x2_double, y1_double, y2_double, z1_double, z2_double;
    double distance;
    vector< vector<double> > R;
    vector<double> distance_vector;

    for(i = 0; i < totalatoms; i++) {
        for(j = i + 1; j < totalatoms; j++) {
            for(k = j + 1; k < totalatoms; k++) {
                for(l = k + 1; l < totalatoms; l++) {
                    atom1 = (vector_coords[i][0]);
                    atom2 = (vector_coords[j][0]);
                    atom3 = (vector_coords[k][0]);
                    atom4 = (vector_coords[l][0]);
                    x1_string = (vector_coords[i][2]);
                    x2_string = (vector_coords[j][2]);
                    y1_string = (vector_coords[i][3]);
                    y2_string = (vector_coords[j][3]);
                    z1_string = (vector_coords[i][4]);
                    z2_string = (vector_coords[j][4]);

                    x1_double = atof(x1_string.c_str());
                    x2_double = atof(x2_string.c_str());
                    y1_double = atof(y1_string.c_str());
                    y2_double = atof(y2_string.c_str());
                    z1_double = atof(z1_string.c_str());
                    z2_double = atof(z2_string.c_str());

                    distance = (sqrt(
                                    ((pow(x2_double - x1_double, 2))) +
                                    ((pow(y2_double - y1_double, 2))) +  //calculation of interatomic distances
                                    ((pow(z2_double - z1_double, 2)))));

                    distance_vector.push_back(distance);
                    R.push_back(distance_vector);

                    cout << atom1 << "  " << atom2 << "   " << distance << endl;
                }
            }
        }
    }
}

void unit_vects(int i, int j,
                double x1_double, double x2_double,
		double y1_double, double y2_double,
		double z1_double, double z2_double,
		vector< vector<double> > & R,
		vector< vector<string> > & vector_coords) {

    double ex_ij, ey_ij, ez_ij;
    double ex_jk, ey_jk, ez_jk;
    double ex_kl, ey_kl, ez_kl;
    vector<double> e_ij;
    vector<double> e_jk;
    vector<double> e_kl;
    vector< vector<double> > unit_vectors;

    cout << "Bond angles (in degrees): " << endl;

    for(i = 0; i < totalatoms; i++) {
        for(j = i + 1; j < totalatoms; j++) {
            if(R[i][j] < 1.55) {
                ex_ij = ((-(x2_double - x1_double)) / R[i][j]);
                    e_ij.push_back(ex_ij);
                ey_ij = ((-(y2_double - y1_double)) / R[i][j]);
                    e_ij.push_back(ey_ij);
                ez_ij = ((-(z2_double - z1_double)) / R[i][j]);
                    e_ij.push_back(ez_ij);

                unit_vectors.push_back(e_ij);

                ex_jk = ((-(x2_double - x1_double)) / R[i][j]);
                    e_jk.push_back(ex_jk);
                ey_jk = ((-(y2_double - y1_double)) / R[i][j]);
                    e_jk.push_back(ey_jk);
                ez_jk = ((-(z2_double - z1_double)) / R[i][j]);
                    e_jk.push_back(ez_jk);

                unit_vectors.push_back(e_jk);

                ex_kl = ((-(x2_double - x1_double)) / R[i][j]);
                    e_kl.push_back(ex_kl);
                ey_kl = ((-(y2_double - y1_double)) / R[i][j]);
                    e_kl.push_back(ey_kl);
                ez_kl = ((-(z2_double - z1_double)) / R[i][j]);
                    e_kl.push_back(ez_kl);

                unit_vectors.push_back(e_kl);
            }
        }
    }
}

void bond_angle(int i, int j, int k,
                string atom1, string atom2, string atom3,
		vector< vector<double> > & R,
		vector< vector<double> > & unit_vectors,
		vector< vector<string> > & vector_coords) {

    double x1_unit, x2_unit, y1_unit, y2_unit, z1_unit, z2_unit;
    double angle_phi;
    vector<double> angles_vector;

    for(i = 0; i < totalatoms; i ++) {
        for( j = i + 1; j < totalatoms; j++) {
            for(k = j + 1; k < totalatoms; k++) {
                if(R[i][j] < 1.55) {
                    x1_unit = (unit_vectors[0][i]);  //ex_ij unit vector
                    x2_unit = (unit_vectors[0][j]);  //ex_jk unit vector
                    y1_unit = (unit_vectors[1][i]);  //ey_ij unit vector
                    y2_unit = (unit_vectors[1][j]);  //ey_jk unit vector
                    z1_unit = (unit_vectors[2][i]);  //ez_ij unit vector
                    z2_unit = (unit_vectors[2][j]);  //ez_jk unit vector

                    angle_phi = (acos(
		                 x1_unit * x2_unit +
                                 y1_unit * y2_unit +  //calculation of bond angle
                                 z1_unit * z2_unit));

                    angles_vector.push_back(angle_phi);

                    cout << atom1 << "  " << atom2 << "  " << atom3 << "   " << angle_phi << endl;
                }
            }
        }
    }
}
<commit_msg>improvements and updates<commit_after>#include <iostream>
#include <cmath>
#include <fstream>
#include <cstdio>
#include <sstream>
#include <cassert>
#include <vector>
#include <string>
#include <cstdlib>
#include <iomanip>
#include "bond_angle.h"

using namespace std;

extern int totalatoms;  //int totalatoms in extraction.cpp
extern vector< vector<string> > vector_coords;  //2D vector "vector_coords" in extraction.cpp

typedef vector<int> Row;
typedef vector<double> dblRow;
typedef vector<Row> Matrix;
typedef vector<dblRow> dblMatrix;
    dblMatrix R(totalatoms,dblRow(totalatoms));
    Matrix bond_exist(totalatoms,Row(totalatoms));

vector<double> angRow;
vector< vector<double> > bond_angle_v;

void atom_distance(int number_atoms) {

    ofstream outputfile;
    ofstream log;
    outputfile.open("outputfile.txt", ios::app);
    log.open("log.txt", ios::app);

    cout << "Interatomic distances (in Angstroms): " << endl;
    log << "Interatomic distances (in Angstroms): " << endl;
    outputfile << "Interatomic distances (in Angstroms): " << endl;

    int i, j;
    string atom1, atom2;
    string x1_string, x2_string, y1_string, y2_string, z1_string, z2_string;
    double x1_double, x2_double, y1_double, y2_double, z1_double, z2_double;
    double distance;

    for(i = 0; i < number_atoms; i++) {
        for(j = i + 1; j < number_atoms; j++) {

            atom1 = (vector_coords[i][0]);
            atom2 = (vector_coords[j][0]);
            x1_string = (vector_coords[i][2]);
            x2_string = (vector_coords[j][2]);
            y1_string = (vector_coords[i][3]);
            y2_string = (vector_coords[j][3]);
            z1_string = (vector_coords[i][4]);
            z2_string = (vector_coords[j][4]);

            x1_double = atof(x1_string.c_str());
            x2_double = atof(x2_string.c_str());
            y1_double = atof(y1_string.c_str());
            y2_double = atof(y2_string.c_str());
            z1_double = atof(z1_string.c_str());
            z2_double = atof(z2_string.c_str());

            distance = (sqrt(
                            ((pow(x2_double - x1_double, 2))) +
                            ((pow(y2_double - y1_double, 2))) +  //calculation of interatomic distances
                            ((pow(z2_double - z1_double, 2)))));

            R[i][j] = distance;

	    if(distance < 1.55) {
	        bond_exist[i][j] = 1;
	    } else {
	        bond_exist[i][j] = 0;
              }

     	    cout << atom1 << "  " << atom2 << "    " << R[i][j] << endl;
            log << atom1 << "  " << atom2 << "    " << R[i][j] << endl;
            outputfile << atom1 << "  " << atom2 << "    " << R[i][j] << endl;
        }
    }

}

double unit_vectors(int a1, int a2, int col) {

    int number_atoms;
    string x1_string, x2_string;
    double x1_double, x2_double;
    double ex;

    x1_string = (vector_coords[a1][col]);
    x2_string = (vector_coords[a2][col]);
    x1_double = atof(x1_string.c_str());
    x2_double = atof(x2_string.c_str());

    ex = ((-(x2_double - x1_double)) / R[a1][a2]);

    return ex;

}

void bond_angle_f(int number_atoms) {

    ofstream outputfile;
    ofstream log;
    outputfile.open("outputfile.txt", ios::app);
    log.open("log.txt", ios::app);

    int z = 0;
    double ex_ij, ey_ij, ez_ij;
    double ex_ik, ey_ik, ez_ik;
    double angle_phi;

    cout << "Bond angles (in degrees): " << endl;
    log << "Bond angles (in degrees): " << endl;
    outputfile << "Bond angles (in degrees): " << endl;

    for(int i = 0; i < number_atoms; i++) {
        for(int j = i + 1; j < number_atoms; j++) {
	    if(bond_exist[i][j] == 1) {
	        for(int k = j + 1; k < number_atoms; k++) {
		    if(bond_exist[i][k] == 1) {

		        angRow.clear();

		        ex_ij = unit_vectors(i,j,2);
		        ey_ij = unit_vectors(i,j,3);
		        ez_ij = unit_vectors(i,j,4);

		        ex_ik = unit_vectors(i,k,2);
		        ey_ik = unit_vectors(i,k,3);
		        ez_ik = unit_vectors(i,k,4);

		        angle_phi = (acos(ex_ij * ex_ik +
			                  ey_ij * ey_ik +  //calculation of bond angle
			                  ez_ij * ez_ik));

		        angRow.push_back(i);
		        angRow.push_back(j);
		        angRow.push_back(k);

		        angRow.push_back(ex_ij);
		        angRow.push_back(ey_ij);
		        angRow.push_back(ez_ij);

		        angRow.push_back(ex_ik);
		        angRow.push_back(ey_ik);
		        angRow.push_back(ez_ik);

		        angRow.push_back(angle_phi);

		        bond_angle_v.push_back(angRow);

		        z++;
		    }
	        }
	    }
        }
    }

    for(int i = 0; i < bond_angle_v.size(); i++) {
        for(int j = 0; j < 10; j++) {
            cout << bond_angle_v[i][j] << "    ";
        }

	cout << endl;

    }

}
<|endoftext|>


<commit_before>// Copyright 2016 ct_common authors. See LICENSE file for details.

#include "ct_common/common/constraint_l_ivld.h"

#include "ct_common/base/class_name_utils.h"

#include "ct_common/common/exp_a.h"
#include "ct_common/common/exp_s.h"

namespace ct_common {

REGISTER_CLASS_NAME(Constraint_L_IVLD)

Constraint_L_IVLD::Constraint_L_IVLD()
    : Constraint_L_Atomic(), pid_(PID_BOUND) {}

Constraint_L_IVLD::~Constraint_L_IVLD() = default;

optional<bool> Constraint_L_IVLD::Evaluate(
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs,
    const Assignment& assignment) const {
  if (!assignment.IsContainParam(pid_)) {
    CT_EXCEPTION("parameter not found in the test case");
    return nullopt;
  }
  if (param_specs[pid_]->is_auto()) {
    CT_EXCEPTION("Error: auto value cannot be invalidated");
    return nullopt;
  }
  return param_specs[pid_]->IsVidInvalid(
      assignment.GetValue(pid_));
}

void Constraint_L_IVLD::InnerTouchLeafPids(
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs,
    std::set<std::size_t>* pids_to_touch) const {
  // auto and aux parameters cannot be invalidated, so no need to check
  pids_to_touch->insert(pid_);
}

void Constraint_L_IVLD::Dump(
    std::ostream& os,
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs) const {
  os << "#";
  os << "(";
  os << param_specs[pid_]->get_param_name();
  os << ")";
}

}  // namespace ct_common
<commit_msg>fix constraint_l_ivld<commit_after>// Copyright 2016 ct_common authors. See LICENSE file for details.

#include "ct_common/common/constraint_l_ivld.h"

#include "ct_common/base/class_name_utils.h"

#include "ct_common/common/exp_a.h"
#include "ct_common/common/exp_s.h"

namespace ct_common {

namespace {

bool IsTreeNodeValid(
    const std::vector<std::shared_ptr<ParamSpec> > & param_specs,
    const Assignment& assignment,
    const std::shared_ptr<TreeNode>& node) {
  if (std::dynamic_pointer_cast<Constraint>(node)) {
    std::shared_ptr<Constraint> c_node =
        std::dynamic_pointer_cast<Constraint>(node);
    return static_cast<bool>(c_node->Evaluate(param_specs, assignment));
  } else if (std::dynamic_pointer_cast<Exp_A>(node).get()) {
    std::shared_ptr<Exp_A> c_node = std::dynamic_pointer_cast<Exp_A>(node);
    if (c_node->get_type() == EAT_INT) {
      return static_cast<bool>(c_node->EvaluateInt(param_specs, assignment));
    } else if (c_node->get_type() == EAT_DOUBLE) {
      return static_cast<bool>(c_node->EvaluateDouble(param_specs, assignment));
    } else {
      CT_EXCEPTION("unrecognized arithmetic expression type");
    }
  } else if (std::dynamic_pointer_cast<Exp_S>(node)) {
    std::shared_ptr<Exp_S> c_node = std::dynamic_pointer_cast<Exp_S>(node);
    return static_cast<bool>(c_node->Evaluate(param_specs, assignment));
  } else {
    CT_EXCEPTION("unknown expression type");
  }
  return false;
}

}  // anonymous namespace

REGISTER_CLASS_NAME(Constraint_L_IVLD)

Constraint_L_IVLD::Constraint_L_IVLD()
    : Constraint_L_Atomic(), pid_(PID_BOUND) {}

Constraint_L_IVLD::~Constraint_L_IVLD() = default;

optional<bool> Constraint_L_IVLD::Evaluate(
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs,
    const Assignment& assignment) const {
  if (!assignment.IsContainParam(pid_)) {
    CT_EXCEPTION("parameter not found in the test case");
    return nullopt;
  }
  if (param_specs[pid_]->is_auto()) {
    for (const auto& auto_value_spec
             : param_specs[this->pid_]->auto_value_specs()) {
      std::shared_ptr<Constraint> cond =
          std::dynamic_pointer_cast<Constraint>(auto_value_spec.first);
      if (cond) {
        optional<bool> cond_value = cond->Evaluate(param_specs, assignment);
        if (cond_value && cond_value.value()) {
          // condition met, taking the value
          if (IsTreeNodeValid(
                  param_specs, assignment, auto_value_spec.second)) {
            return false;
          }
          return true;
        }
      } else {
        CT_EXCEPTION("Error: encountering invalid auto value condition");
        return nullopt;
      }
    }
    // FIXME: suppressing error
    // CT_EXCEPTION(std::string(
    //     "Error: encountering unhandled auto value condition for parameter ")+
    //     ptr->get_param_name());
    return true; // no conditions match
  }
  return param_specs[pid_]->IsVidInvalid(assignment.GetValue(pid_));
}

void Constraint_L_IVLD::InnerTouchLeafPids(
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs,
    std::set<std::size_t>* pids_to_touch) const {
  // auto and aux parameters cannot be invalidated, so no need to check
  pids_to_touch->insert(pid_);
}

void Constraint_L_IVLD::Dump(
    std::ostream& os,
    const std::vector<std::shared_ptr<ParamSpec> >& param_specs) const {
  os << "#";
  os << "(";
  os << param_specs[pid_]->get_param_name();
  os << ")";
}

}  // namespace ct_common
<|endoftext|>


<commit_before>// Module:  Log4CPLUS
// File:    fileappender.cxx
// Created: 6/2001
// Author:  Tad E. Smith
//
//
// Copyright (C) The Apache Software Foundation. All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//

#include <log4cplus/fileappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/loggingevent.h>
#include <algorithm>
#include <sstream>
#include <stdio.h>

using namespace std;
using namespace log4cplus::helpers;

#define MINIMUM_ROLLING_LOG_SIZE 200*1024L

log4cplus::FileAppender::FileAppender(const std::string& filename,
                                      std::ios::openmode mode)
: out(filename.c_str(), mode),
  filename(filename)
{
    if(!out.good()) {
        getErrorHandler()->error("Unable to open file: " + filename);
        return;
    }

    int columns = 80;
    std::string tmp;
    tmp.resize(columns);
    std::fill_n(tmp.begin(), columns, '#');

    out << tmp << std::endl
        << "#" << std::endl
        << "# Created Appender on: "
        << getFormattedTime(time(NULL), "%m-%d-%y %H:%M:%S") << std::endl
        << "#" << std::endl
        << tmp << std::endl;

}

log4cplus::FileAppender::~FileAppender()
{
    destructorImpl();
}

void
log4cplus::FileAppender::close()
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        out.close();
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

// This method does not need to be locked since it is called by
// doAppend() which performs the locking
void
log4cplus::FileAppender::append(const spi::InternalLoggingEvent& event)
{
    if(!out.is_open()) {
        getErrorHandler()->error("file is not open: " + filename);
        return;
    }

    layout->formatAndAppend(out, event);
}

log4cplus::RollingFileAppender::RollingFileAppender(const std::string& filename,
                                                    long maxFileSize,
                                                    int maxBackupIndex)
 : FileAppender(filename, std::ios::app),
   maxFileSize(max(maxFileSize, MINIMUM_ROLLING_LOG_SIZE)),
   maxBackupIndex(maxBackupIndex)
{
}

log4cplus::RollingFileAppender::~RollingFileAppender()
{
    destructorImpl();
}

// This method does not need to be locked since it is called by
// doAppend() which performs the locking
void
log4cplus::RollingFileAppender::append(const spi::InternalLoggingEvent& event)
{
    if(!out.is_open()) {
        getErrorHandler()->error("file is not open: " + filename);
        return;
    }

    layout->formatAndAppend(out, event);

    if(out.tellp() > maxFileSize) {
        rollover();
    }
}

void
log4cplus::RollingFileAppender::rollover()
{
    // If maxBackups <= 0, then there is no file renaming to be done.
    if(maxBackupIndex > 0) {
        // Delete the oldest file
        std::ostringstream buffer;
        buffer << filename << '.' << maxBackupIndex;
        remove(buffer.str().c_str());

        // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
        for(int i=maxBackupIndex - 1; i >= 1; i--) {
            std::ostringstream source;
            std::ostringstream target;

            source << filename << '.' << i;
            target << filename << '.' << (i+1);
            getLogLog().debug("Renaming file " + source.str() + " to " + target.str());
            rename(source.str().c_str(), target.str().c_str());
        }

        // Close the current file
        out.close();
        out.clear(); // reset flags since the C++ standard specified that all the
                     // flags should remain unchanged on a close

        // Rename fileName to fileName.1
        std::string target = filename + ".1";
        getLogLog().debug("Renaming file " + filename + " to " + target);
        rename(filename.c_str(), target.c_str());

        // Open a new file
        out.open(filename.c_str(), std::ios::out | std::ios::trunc);
    }
    else {
        getLogLog().debug(filename + " has no backups specified");
        // Close the current file
        out.close();
        out.clear(); // reset flags since the C++ standard specified that all the
                     // flags should remain unchanged on a close

        // Open it up again in truncation mode
        out.open(filename.c_str(), std::ios::out | std::ios::trunc);
    }
}

<commit_msg>Added the FileAppender(log4cplus::helpers::Properties properties) ctors.<commit_after>// Module:  Log4CPLUS
// File:    fileappender.cxx
// Created: 6/2001
// Author:  Tad E. Smith
//
//
// Copyright (C) The Apache Software Foundation. All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//

#include <log4cplus/fileappender.h>
#include <log4cplus/layout.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/spi/loggingevent.h>
#include <algorithm>
#include <sstream>
#include <stdio.h>

using namespace std;
using namespace log4cplus::helpers;

#define MINIMUM_ROLLING_LOG_SIZE 200*1024L

log4cplus::FileAppender::FileAppender(const std::string& filename,
                                      std::ios::openmode mode)
{
    init(filename, mode);
}

log4cplus::FileAppender::FileAppender(log4cplus::helpers::Properties properties,
                                      std::ios::openmode mode)
: Appender(properties)
{
     string filename = properties.getProperty("File");
     if(filename.length() == 0) {
         getErrorHandler()->error("Invalid filename");
         return;
     }

     init(filename, mode);
}

void
log4cplus::FileAppender::init(const std::string& filename,
                              std::ios::openmode mode)
{
    this->filename = filename;
    out.open(filename.c_str(), mode);

    if(!out.good()) {
        getErrorHandler()->error("Unable to open file: " + filename);
        return;
    }
    getLogLog().debug("Just opened file: " + filename);

    int columns = 80;
    std::string tmp;
    tmp.resize(columns);
    std::fill_n(tmp.begin(), columns, '#');

    out << tmp << std::endl
        << "#" << std::endl
        << "# Created Appender on: "
        << getFormattedTime(time(NULL), "%m-%d-%y %H:%M:%S") << std::endl
        << "#" << std::endl
        << tmp << std::endl;
}

log4cplus::FileAppender::~FileAppender()
{
    destructorImpl();
}

void
log4cplus::FileAppender::close()
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        out.close();
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

// This method does not need to be locked since it is called by
// doAppend() which performs the locking
void
log4cplus::FileAppender::append(const spi::InternalLoggingEvent& event)
{
    if(!out.is_open()) {
        getErrorHandler()->error("file is not open: " + filename);
        return;
    }

    layout->formatAndAppend(out, event);
}

log4cplus::RollingFileAppender::RollingFileAppender(const std::string& filename,
                                                    long maxFileSize,
                                                    int maxBackupIndex)
: FileAppender(filename, std::ios::app)
{
    init(maxFileSize, maxBackupIndex);
}

log4cplus::RollingFileAppender::RollingFileAppender(log4cplus::helpers::Properties properties)
: FileAppender(properties, std::ios::app)
{
    // TODO --> get maxFileSize and maxBackupIndex from properties
    init(10*1024*1024, 1);
}

log4cplus::RollingFileAppender::~RollingFileAppender()
{
    destructorImpl();
}

void
log4cplus::RollingFileAppender::init(long maxFileSize, int maxBackupIndex)
{
    this->maxFileSize = maxFileSize;
    this->maxBackupIndex = maxBackupIndex;
}

// This method does not need to be locked since it is called by
// doAppend() which performs the locking
void
log4cplus::RollingFileAppender::append(const spi::InternalLoggingEvent& event)
{
    if(!out.is_open()) {
        getErrorHandler()->error("file is not open: " + filename);
        return;
    }

    layout->formatAndAppend(out, event);

    if(out.tellp() > maxFileSize) {
        rollover();
    }
}

void
log4cplus::RollingFileAppender::rollover()
{
    // If maxBackups <= 0, then there is no file renaming to be done.
    if(maxBackupIndex > 0) {
        // Delete the oldest file
        std::ostringstream buffer;
        buffer << filename << '.' << maxBackupIndex;
        remove(buffer.str().c_str());

        // Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3, 2}
        for(int i=maxBackupIndex - 1; i >= 1; i--) {
            std::ostringstream source;
            std::ostringstream target;

            source << filename << '.' << i;
            target << filename << '.' << (i+1);
            getLogLog().debug("Renaming file " + source.str() + " to " + target.str());
            rename(source.str().c_str(), target.str().c_str());
        }

        // Close the current file
        out.close();
        out.clear(); // reset flags since the C++ standard specified that all the
                     // flags should remain unchanged on a close

        // Rename fileName to fileName.1
        std::string target = filename + ".1";
        getLogLog().debug("Renaming file " + filename + " to " + target);
        rename(filename.c_str(), target.c_str());

        // Open a new file
        out.open(filename.c_str(), std::ios::out | std::ios::trunc);
    }
    else {
        getLogLog().debug(filename + " has no backups specified");
        // Close the current file
        out.close();
        out.clear(); // reset flags since the C++ standard specified that all the
                     // flags should remain unchanged on a close

        // Open it up again in truncation mode
        out.open(filename.c_str(), std::ios::out | std::ios::trunc);
    }
}

<|endoftext|>