<commit_before>//===-- ApplyReplacements.cpp - Apply and deduplicate replacements --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file provides the implementation for deduplicating, detecting
/// conflicts in, and applying collections of Replacements.
///
/// FIXME: Use Diagnostics for output instead of llvm::errs().
///
//===----------------------------------------------------------------------===//
#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/ReplacementsYaml.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace clang;

static void eatDiagnostics(const SMDiagnostic &, void *) {}

namespace clang {
namespace replace {

std::error_code
collectReplacementsFromDirectory(const llvm::StringRef Directory,
                                 TUReplacements &TUs,
                                 TUReplacementFiles & TURFiles,
                                 clang::DiagnosticsEngine &Diagnostics) {
  using namespace llvm::sys::fs;
  using namespace llvm::sys::path;

  std::error_code ErrorCode;

  for (recursive_directory_iterator I(Directory, ErrorCode), E;
       I != E && !ErrorCode; I.increment(ErrorCode)) {
    if (filename(I->path())[0] == '.') {
      // Indicate not to descend into directories beginning with '.'
      I.no_push();
      continue;
    }

    if (extension(I->path()) != ".yaml")
      continue;

    TURFiles.push_back(I->path());

    ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
        MemoryBuffer::getFile(I->path());
    if (std::error_code BufferError = Out.getError()) {
      errs() << "Error reading " << I->path() << ": " << BufferError.message()
             << "\n";
      continue;
    }

    yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
    tooling::TranslationUnitReplacements TU;
    YIn >> TU;
    if (YIn.error()) {
      // File doesn't appear to be a header change description. Ignore it.
      continue;
    }

    // Only keep files that properly parse.
    TUs.push_back(TU);
  }

  return ErrorCode;
}

/// \brief Dumps information for a sequence of conflicting Replacements.
///
/// \param[in] File FileEntry for the file the conflicting Replacements are
/// for.
/// \param[in] ConflictingReplacements List of conflicting Replacements.
/// \param[in] SM SourceManager used for reporting.
static void reportConflict(
    const FileEntry *File,
    const llvm::ArrayRef<clang::tooling::Replacement> ConflictingReplacements,
    SourceManager &SM) {
  FileID FID = SM.translateFile(File);
  if (FID.isInvalid())
    FID = SM.createFileID(File, SourceLocation(), SrcMgr::C_User);

  // FIXME: Output something a little more user-friendly (e.g. unified diff?)
  errs() << "The following changes conflict:\n";
  for (const tooling::Replacement &R : ConflictingReplacements) {
    if (R.getLength() == 0) {
      errs() << "  Insert at " << SM.getLineNumber(FID, R.getOffset()) << ":"
             << SM.getColumnNumber(FID, R.getOffset()) << " "
             << R.getReplacementText() << "\n";
    } else {
      if (R.getReplacementText().empty())
        errs() << "  Remove ";
      else
        errs() << "  Replace ";

      errs() << SM.getLineNumber(FID, R.getOffset()) << ":"
             << SM.getColumnNumber(FID, R.getOffset()) << "-"
             << SM.getLineNumber(FID, R.getOffset() + R.getLength() - 1) << ":"
             << SM.getColumnNumber(FID, R.getOffset() + R.getLength() - 1);

      if (R.getReplacementText().empty())
        errs() << "\n";
      else
        errs() << " with \"" << R.getReplacementText() << "\"\n";
    }
  }
}

/// \brief Deduplicates and tests for conflicts among the replacements for each
/// file in \c Replacements. Any conflicts found are reported.
///
/// \post Replacements[i].getOffset() <= Replacements[i+1].getOffset().
///
/// \param[in,out] Replacements Container of all replacements grouped by file
/// to be deduplicated and checked for conflicts.
/// \param[in] SM SourceManager required for conflict reporting.
///
/// \returns \parblock
///          \li true if conflicts were detected
///          \li false if no conflicts were detected
static bool deduplicateAndDetectConflicts(FileToReplacementsMap &Replacements,
                                          SourceManager &SM) {
  bool conflictsFound = false;

  for (auto &FileAndReplacements : Replacements) {
    const FileEntry *Entry = FileAndReplacements.first;
    auto &Replacements = FileAndReplacements.second;
    assert(Entry != nullptr && "No file entry!");

    std::vector<tooling::Range> Conflicts;
    tooling::deduplicate(FileAndReplacements.second, Conflicts);

    if (Conflicts.empty())
      continue;

    conflictsFound = true;

    errs() << "There are conflicting changes to " << Entry->getName() << ":\n";

    for (const tooling::Range &Conflict : Conflicts) {
      auto ConflictingReplacements = llvm::makeArrayRef(
          &Replacements[Conflict.getOffset()], Conflict.getLength());
      reportConflict(Entry, ConflictingReplacements, SM);
    }
  }

  return conflictsFound;
}

bool mergeAndDeduplicate(const TUReplacements &TUs,
                         FileToReplacementsMap &GroupedReplacements,
                         clang::SourceManager &SM) {

  // Group all replacements by target file.
  std::set<StringRef> Warned;
  for (const auto &TU : TUs) {
    for (const tooling::Replacement &R : TU.Replacements) {
      // Use the file manager to deduplicate paths. FileEntries are
      // automatically canonicalized.
      const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath());
      if (!Entry && Warned.insert(R.getFilePath()).second) {
        errs() << "Described file '" << R.getFilePath()
               << "' doesn't exist. Ignoring...\n";
        continue;
      }
      GroupedReplacements[Entry].push_back(R);
    }
  }

  // Ask clang to deduplicate and report conflicts.
  return !deduplicateAndDetectConflicts(GroupedReplacements, SM);
}

bool applyReplacements(const FileToReplacementsMap &GroupedReplacements,
                       clang::Rewriter &Rewrites) {

  // Apply all changes
  //
  // FIXME: No longer certain GroupedReplacements is really the best kind of
  // data structure for applying replacements. Rewriter certainly doesn't care.
  // However, until we nail down the design of ReplacementGroups, might as well
  // leave this as is.
  for (const auto &FileAndReplacements : GroupedReplacements) {
    if (!tooling::applyAllReplacements(FileAndReplacements.second, Rewrites))
      return false;
  }

  return true;
}

RangeVector calculateChangedRanges(
    const std::vector<clang::tooling::Replacement> &Replaces) {
  RangeVector ChangedRanges;

  // Generate the new ranges from the replacements.
  //
  // NOTE: This is O(n^2) in the number of replacements. If this starts to
  // become a problem inline shiftedCodePosition() here and do shifts in a
  // single run through this loop.
  for (const tooling::Replacement &R : Replaces) {
    unsigned Offset = tooling::shiftedCodePosition(Replaces, R.getOffset());
    unsigned Length = R.getReplacementText().size();

    ChangedRanges.push_back(tooling::Range(Offset, Length));
  }

  return ChangedRanges;
}

bool writeFiles(const clang::Rewriter &Rewrites) {

  for (Rewriter::const_buffer_iterator BufferI = Rewrites.buffer_begin(),
                                       BufferE = Rewrites.buffer_end();
       BufferI != BufferE; ++BufferI) {
    const char *FileName =
        Rewrites.getSourceMgr().getFileEntryForID(BufferI->first)->getName();

    std::error_code EC;
    llvm::raw_fd_ostream FileStream(FileName, EC, llvm::sys::fs::F_Text);
    if (EC) {
      errs() << "Warning: Could not write to " << EC.message() << "\n";
      continue;
    }
    BufferI->second.write(FileStream);
  }

  return true;
}

bool deleteReplacementFiles(const TUReplacementFiles &Files,
                            clang::DiagnosticsEngine &Diagnostics) {
  bool Success = true;
  for (const auto &Filename : Files) {
    std::error_code Error = llvm::sys::fs::remove(Filename);
    if (Error) {
      Success = false;
      // FIXME: Use Diagnostics for outputting errors.
      errs() << "Error deleting file: " << Filename << "\n";
      errs() << Error.message() << "\n";
      errs() << "Please delete the file manually\n";
    }
  }
  return Success;
}

} // end namespace replace
} // end namespace clang
<commit_msg>Fix test failure introduced by r253859. I believe that the new behavior in r253859 makes sense in many cases and thus, I have fixed the implementation of calculateChangedRanges instead. It had a FIXME anyway saying that it was unecessarily using shiftedCodePosition which resulted in O(N^2) runtime.<commit_after>//===-- ApplyReplacements.cpp - Apply and deduplicate replacements --------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief This file provides the implementation for deduplicating, detecting
/// conflicts in, and applying collections of Replacements.
///
/// FIXME: Use Diagnostics for output instead of llvm::errs().
///
//===----------------------------------------------------------------------===//
#include "clang-apply-replacements/Tooling/ApplyReplacements.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Format/Format.h"
#include "clang/Lex/Lexer.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/ReplacementsYaml.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace clang;

static void eatDiagnostics(const SMDiagnostic &, void *) {}

namespace clang {
namespace replace {

std::error_code
collectReplacementsFromDirectory(const llvm::StringRef Directory,
                                 TUReplacements &TUs,
                                 TUReplacementFiles & TURFiles,
                                 clang::DiagnosticsEngine &Diagnostics) {
  using namespace llvm::sys::fs;
  using namespace llvm::sys::path;

  std::error_code ErrorCode;

  for (recursive_directory_iterator I(Directory, ErrorCode), E;
       I != E && !ErrorCode; I.increment(ErrorCode)) {
    if (filename(I->path())[0] == '.') {
      // Indicate not to descend into directories beginning with '.'
      I.no_push();
      continue;
    }

    if (extension(I->path()) != ".yaml")
      continue;

    TURFiles.push_back(I->path());

    ErrorOr<std::unique_ptr<MemoryBuffer>> Out =
        MemoryBuffer::getFile(I->path());
    if (std::error_code BufferError = Out.getError()) {
      errs() << "Error reading " << I->path() << ": " << BufferError.message()
             << "\n";
      continue;
    }

    yaml::Input YIn(Out.get()->getBuffer(), nullptr, &eatDiagnostics);
    tooling::TranslationUnitReplacements TU;
    YIn >> TU;
    if (YIn.error()) {
      // File doesn't appear to be a header change description. Ignore it.
      continue;
    }

    // Only keep files that properly parse.
    TUs.push_back(TU);
  }

  return ErrorCode;
}

/// \brief Dumps information for a sequence of conflicting Replacements.
///
/// \param[in] File FileEntry for the file the conflicting Replacements are
/// for.
/// \param[in] ConflictingReplacements List of conflicting Replacements.
/// \param[in] SM SourceManager used for reporting.
static void reportConflict(
    const FileEntry *File,
    const llvm::ArrayRef<clang::tooling::Replacement> ConflictingReplacements,
    SourceManager &SM) {
  FileID FID = SM.translateFile(File);
  if (FID.isInvalid())
    FID = SM.createFileID(File, SourceLocation(), SrcMgr::C_User);

  // FIXME: Output something a little more user-friendly (e.g. unified diff?)
  errs() << "The following changes conflict:\n";
  for (const tooling::Replacement &R : ConflictingReplacements) {
    if (R.getLength() == 0) {
      errs() << "  Insert at " << SM.getLineNumber(FID, R.getOffset()) << ":"
             << SM.getColumnNumber(FID, R.getOffset()) << " "
             << R.getReplacementText() << "\n";
    } else {
      if (R.getReplacementText().empty())
        errs() << "  Remove ";
      else
        errs() << "  Replace ";

      errs() << SM.getLineNumber(FID, R.getOffset()) << ":"
             << SM.getColumnNumber(FID, R.getOffset()) << "-"
             << SM.getLineNumber(FID, R.getOffset() + R.getLength() - 1) << ":"
             << SM.getColumnNumber(FID, R.getOffset() + R.getLength() - 1);

      if (R.getReplacementText().empty())
        errs() << "\n";
      else
        errs() << " with \"" << R.getReplacementText() << "\"\n";
    }
  }
}

/// \brief Deduplicates and tests for conflicts among the replacements for each
/// file in \c Replacements. Any conflicts found are reported.
///
/// \post Replacements[i].getOffset() <= Replacements[i+1].getOffset().
///
/// \param[in,out] Replacements Container of all replacements grouped by file
/// to be deduplicated and checked for conflicts.
/// \param[in] SM SourceManager required for conflict reporting.
///
/// \returns \parblock
///          \li true if conflicts were detected
///          \li false if no conflicts were detected
static bool deduplicateAndDetectConflicts(FileToReplacementsMap &Replacements,
                                          SourceManager &SM) {
  bool conflictsFound = false;

  for (auto &FileAndReplacements : Replacements) {
    const FileEntry *Entry = FileAndReplacements.first;
    auto &Replacements = FileAndReplacements.second;
    assert(Entry != nullptr && "No file entry!");

    std::vector<tooling::Range> Conflicts;
    tooling::deduplicate(FileAndReplacements.second, Conflicts);

    if (Conflicts.empty())
      continue;

    conflictsFound = true;

    errs() << "There are conflicting changes to " << Entry->getName() << ":\n";

    for (const tooling::Range &Conflict : Conflicts) {
      auto ConflictingReplacements = llvm::makeArrayRef(
          &Replacements[Conflict.getOffset()], Conflict.getLength());
      reportConflict(Entry, ConflictingReplacements, SM);
    }
  }

  return conflictsFound;
}

bool mergeAndDeduplicate(const TUReplacements &TUs,
                         FileToReplacementsMap &GroupedReplacements,
                         clang::SourceManager &SM) {

  // Group all replacements by target file.
  std::set<StringRef> Warned;
  for (const auto &TU : TUs) {
    for (const tooling::Replacement &R : TU.Replacements) {
      // Use the file manager to deduplicate paths. FileEntries are
      // automatically canonicalized.
      const FileEntry *Entry = SM.getFileManager().getFile(R.getFilePath());
      if (!Entry && Warned.insert(R.getFilePath()).second) {
        errs() << "Described file '" << R.getFilePath()
               << "' doesn't exist. Ignoring...\n";
        continue;
      }
      GroupedReplacements[Entry].push_back(R);
    }
  }

  // Ask clang to deduplicate and report conflicts.
  return !deduplicateAndDetectConflicts(GroupedReplacements, SM);
}

bool applyReplacements(const FileToReplacementsMap &GroupedReplacements,
                       clang::Rewriter &Rewrites) {

  // Apply all changes
  //
  // FIXME: No longer certain GroupedReplacements is really the best kind of
  // data structure for applying replacements. Rewriter certainly doesn't care.
  // However, until we nail down the design of ReplacementGroups, might as well
  // leave this as is.
  for (const auto &FileAndReplacements : GroupedReplacements) {
    if (!tooling::applyAllReplacements(FileAndReplacements.second, Rewrites))
      return false;
  }

  return true;
}

RangeVector calculateChangedRanges(
    const std::vector<clang::tooling::Replacement> &Replaces) {
  RangeVector ChangedRanges;

  // Generate the new ranges from the replacements.
  int Shift = 0;
  for (const tooling::Replacement &R : Replaces) {
    unsigned Offset = R.getOffset() + Shift;
    unsigned Length = R.getReplacementText().size();
    Shift += Length - R.getLength();
    ChangedRanges.push_back(tooling::Range(Offset, Length));
  }

  return ChangedRanges;
}

bool writeFiles(const clang::Rewriter &Rewrites) {

  for (Rewriter::const_buffer_iterator BufferI = Rewrites.buffer_begin(),
                                       BufferE = Rewrites.buffer_end();
       BufferI != BufferE; ++BufferI) {
    const char *FileName =
        Rewrites.getSourceMgr().getFileEntryForID(BufferI->first)->getName();

    std::error_code EC;
    llvm::raw_fd_ostream FileStream(FileName, EC, llvm::sys::fs::F_Text);
    if (EC) {
      errs() << "Warning: Could not write to " << EC.message() << "\n";
      continue;
    }
    BufferI->second.write(FileStream);
  }

  return true;
}

bool deleteReplacementFiles(const TUReplacementFiles &Files,
                            clang::DiagnosticsEngine &Diagnostics) {
  bool Success = true;
  for (const auto &Filename : Files) {
    std::error_code Error = llvm::sys::fs::remove(Filename);
    if (Error) {
      Success = false;
      // FIXME: Use Diagnostics for outputting errors.
      errs() << "Error deleting file: " << Filename << "\n";
      errs() << Error.message() << "\n";
      errs() << "Please delete the file manually\n";
    }
  }
  return Success;
}

} // end namespace replace
} // end namespace clang
<|endoftext|>


<commit_before>//
//  database.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/23/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include "database.h"

Database::~Database()
{
	delete db;
}

DatabaseQueue::~DatabaseQueue()
{
	//		std::queue<Database *>::const_iterator i(queue.begin());
	//		for (; i != databases.end(); ++i) {
	//			(*i).second.finish();
	//		}
}

DatabasePool::DatabasePool()
{
	pthread_mutex_init(&qmtx, 0);
}

DatabasePool::~DatabasePool()
{
	finish();
	pthread_mutex_destroy(&qmtx);
}

void DatabasePool::finish() {
	pthread_mutex_lock(&qmtx);

	finished = true;

	pthread_mutex_unlock(&qmtx);
}

bool
DatabasePool::checkout(Database **database, Endpoints &endpoints, bool writable)
{
	Database *database_ = NULL;

	pthread_mutex_lock(&qmtx);

	if (!finished && *database == NULL) {
		size_t hash = endpoints.hash(writable);
		DatabaseQueue &queue = databases[hash];

		if (!queue.pop(database_, 0)) {
			database_ = new Database();
			database_->endpoints = endpoints;
			database_->hash = hash;
			if (writable) {
				database_->db = new Xapian::WritableDatabase(endpoints[0].path, Xapian::DB_CREATE_OR_OPEN);
			} else {
				database_->db = new Xapian::Database(endpoints[0].path, Xapian::DB_CREATE_OR_OPEN);
				if (!writable) {
					std::vector<Endpoint>::const_iterator i(endpoints.begin());
					for (++i; i != endpoints.end(); ++i) {
						database_->db->add_database(Xapian::Database((*i).path));
					}
				} else if (endpoints.size() != 1) {
					printf("ERROR: Expecting exactly one database.");
				}
			}
		}
		*database = database_;
	}

	pthread_mutex_unlock(&qmtx);

	return database_ != NULL;
}

void
DatabasePool::checkin(Database **database)
{
	pthread_mutex_lock(&qmtx);

	DatabaseQueue &queue = databases[(*database)->hash];

	queue.push(*database);

	*database = NULL;

	pthread_mutex_unlock(&qmtx);
}
<commit_msg>Added reopen() and comments<commit_after>//
//  database.cpp
//  Xapiand
//
//  Created by Germán M. Bravo on 2/23/15.
//  Copyright (c) 2015 Germán M. Bravo. All rights reserved.
//

#include "database.h"

Database::Database(Endpoints &endpoints_, bool writable_)
	: endpoints(endpoints_),
	  writable(writable_)
{
	hash = endpoints.hash(writable);
	reopen();
}

void
Database::reopen()
{
	// FIXME: Handle remote endpoints and figure out if the endpoint is a local database
	if (writable) {
		db = new Xapian::WritableDatabase(endpoints[0].path, Xapian::DB_CREATE_OR_OPEN);
	} else {
		db = new Xapian::Database(endpoints[0].path, Xapian::DB_CREATE_OR_OPEN);
		if (!writable) {
			std::vector<Endpoint>::const_iterator i(endpoints.begin());
			for (++i; i != endpoints.end(); ++i) {
				db->add_database(Xapian::Database((*i).path));
			}
		} else if (endpoints.size() != 1) {
			printf("ERROR: Expecting exactly one database.");
		}
	}
}

Database::~Database()
{
	delete db;
}

DatabaseQueue::~DatabaseQueue()
{
	//		std::queue<Database *>::const_iterator i(queue.begin());
	//		for (; i != databases.end(); ++i) {
	//			(*i).second.finish();
	//		}
}

DatabasePool::DatabasePool()
{
	pthread_mutex_init(&qmtx, 0);
}

DatabasePool::~DatabasePool()
{
	finish();
	pthread_mutex_destroy(&qmtx);
}

void DatabasePool::finish() {
	pthread_mutex_lock(&qmtx);

	finished = true;

	pthread_mutex_unlock(&qmtx);
}

bool
DatabasePool::checkout(Database **database, Endpoints &endpoints, bool writable)
{
	Database *database_ = NULL;

	pthread_mutex_lock(&qmtx);

	if (!finished && *database == NULL) {
		size_t hash = endpoints.hash(writable);
		DatabaseQueue &queue = databases[hash];

		if (!queue.pop(database_, 0)) {
			if (!writable || queue.instances_count == 0) {
				database_ = new Database(endpoints, writable);
				queue.instances_count++;
			}
			// FIXME: lock until a database is available if it can't get one
		}
		*database = database_;
	}

	pthread_mutex_unlock(&qmtx);

	return database_ != NULL;
}

void
DatabasePool::checkin(Database **database)
{
	pthread_mutex_lock(&qmtx);

	DatabaseQueue &queue = databases[(*database)->hash];

	queue.push(*database);

	*database = NULL;

	pthread_mutex_unlock(&qmtx);
}
<|endoftext|>


<commit_before>//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "SymbolVendorMacOSX.h"

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>

#include <AvailabilityMacros.h>

#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Symbol/ObjectFile.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// SymbolVendorMacOSX constructor
//----------------------------------------------------------------------
SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) :
    SymbolVendor (module_sp)
{
}

//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
SymbolVendorMacOSX::~SymbolVendorMacOSX()
{
}

static bool
UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm)
{
    if (module && ofile)
    {
        // Make sure the UUIDs match
        lldb_private::UUID dsym_uuid;

        if (!ofile->GetUUID(&dsym_uuid))
        {
            if (feedback_strm)
            {
                feedback_strm->PutCString("warning: failed to get the uuid for object file: '");
                ofile->GetFileSpec().Dump(feedback_strm);
                feedback_strm->PutCString("\n");
            }
            return false;
        }

        if (dsym_uuid == module->GetUUID())
            return true;

        // Emit some warning messages since the UUIDs do not match!
        if (feedback_strm)
        {
            feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n    ");
            module->GetUUID().Dump(feedback_strm);
            feedback_strm->PutChar(' ');
            module->GetFileSpec().Dump(feedback_strm);
            feedback_strm->PutCString("\n    ");
            dsym_uuid.Dump(feedback_strm);
            feedback_strm->PutChar(' ');
            ofile->GetFileSpec().Dump(feedback_strm);
            feedback_strm->EOL();
        }
    }
    return false;
}

static void
ReplaceDSYMSectionsWithExecutableSections (ObjectFile *exec_objfile, ObjectFile *dsym_objfile)
{
    // We need both the executable and the dSYM to live off of the
    // same section lists. So we take all of the sections from the
    // executable, and replace them in the dSYM. This allows section
    // offset addresses that come from the dSYM to automatically
    // get updated as images (shared libraries) get loaded and
    // unloaded.
    SectionList *exec_section_list = exec_objfile->GetSectionList();
    SectionList *dsym_section_list = dsym_objfile->GetSectionList();
    if (exec_section_list && dsym_section_list)
    {
        const uint32_t num_exec_sections = dsym_section_list->GetSize();
        uint32_t exec_sect_idx;
        for (exec_sect_idx = 0; exec_sect_idx < num_exec_sections; ++exec_sect_idx)
        {
            SectionSP exec_sect_sp(exec_section_list->GetSectionAtIndex(exec_sect_idx));
            if (exec_sect_sp.get())
            {
                // Try and replace any sections that exist in both the executable
                // and in the dSYM with those from the executable. If we fail to
                // replace the one in the dSYM, then add the executable section to
                // the dSYM.
                if (dsym_section_list->ReplaceSection(exec_sect_sp->GetID(), exec_sect_sp, 0) == false)
                    dsym_section_list->AddSection(exec_sect_sp);
            }
        }

        dsym_section_list->Finalize(); // Now that we're done adding sections, finalize to build fast-lookup caches
    }
}

void
SymbolVendorMacOSX::Initialize()
{
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
                                   GetPluginDescriptionStatic(),
                                   CreateInstance);
}

void
SymbolVendorMacOSX::Terminate()
{
    PluginManager::UnregisterPlugin (CreateInstance);
}

const char *
SymbolVendorMacOSX::GetPluginNameStatic()
{
    return "symbol-vendor.macosx";
}

const char *
SymbolVendorMacOSX::GetPluginDescriptionStatic()
{
    return "Symbol vendor for MacOSX that looks for dSYM files that match executables.";
}

//----------------------------------------------------------------------
// CreateInstance
//
// Platforms can register a callback to use when creating symbol
// vendors to allow for complex debug information file setups, and to
// also allow for finding separate debug information files.
//----------------------------------------------------------------------
SymbolVendor*
SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
{
    if (!module_sp)
        return NULL;

    Timer scoped_timer (__PRETTY_FUNCTION__,
                        "SymbolVendorMacOSX::CreateInstance (module = %s)",
                        module_sp->GetFileSpec().GetPath().c_str());
    SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp);
    if (symbol_vendor)
    {
        char path[PATH_MAX];
        path[0] = '\0';

        // Try and locate the dSYM file on Mac OS X
        ObjectFile * obj_file = module_sp->GetObjectFile();
        if (obj_file)
        {
            Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
                                 "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM",
                                 module_sp->GetFileSpec().GetPath().c_str());

            // First check to see if the module has a symbol file in mind already.
            // If it does, then we MUST use that.
            FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec());

            ObjectFileSP dsym_objfile_sp;
            if (!dsym_fspec)
            {
                // No symbol file was specified in the module, lets try and find
                // one ourselves.
                FileSpec file_spec = obj_file->GetFileSpec();
                if (!file_spec)
                    file_spec = module_sp->GetFileSpec();

                ModuleSpec module_spec(file_spec, module_sp->GetArchitecture());
                module_spec.GetUUID() = module_sp->GetUUID();
                dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
                if (module_spec.GetSourceMappingList().GetSize())
                    module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true);
            }

            if (dsym_fspec)
            {
                DataBufferSP dsym_file_data_sp;
                lldb::offset_t dsym_file_data_offset = 0;
                dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
                if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm))
                {
                    char dsym_path[PATH_MAX];
                    if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path)))
                    {
                        lldb_private::UUID dsym_uuid;
                        if (dsym_objfile_sp->GetUUID(&dsym_uuid))
                        {
                            std::string uuid_str = dsym_uuid.GetAsString ();
                            if (!uuid_str.empty())
                            {
                                char *resources = strstr (dsym_path, "/Contents/Resources/");
                                if (resources)
                                {
                                    char dsym_uuid_plist_path[PATH_MAX];
                                    resources[strlen("/Contents/Resources/")] = '\0';
                                    snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str());
                                    FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false);
                                    if (dsym_uuid_plist_spec.Exists())
                                    {
                                        xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0);
                                        if (doc)
                                        {
                                            char DBGBuildSourcePath[PATH_MAX];
                                            char DBGSourcePath[PATH_MAX];
                                            DBGBuildSourcePath[0] = '\0';
                                            DBGSourcePath[0] = '\0';
                                            for (xmlNode *node = doc->children; node; node = node ? node->next : NULL)
                                            {
                                                if (node->type == XML_ELEMENT_NODE)
                                                {
                                                    if (node->name && strcmp((const char*)node->name, "plist") == 0)
                                                    {
                                                        xmlNode *dict_node = node->children;
                                                        while (dict_node && dict_node->type != XML_ELEMENT_NODE)
                                                            dict_node = dict_node->next;
                                                        if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0)
                                                        {
                                                            for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next)
                                                            {
                                                                if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name)
                                                                {
                                                                    if (strcmp((const char *)key_node->name, "key") == 0)
                                                                    {
                                                                        const char *key_name = (const char *)::xmlNodeGetContent(key_node);
                                                                        if (strcmp(key_name, "DBGBuildSourcePath") == 0)
                                                                        {
                                                                            xmlNode *value_node = key_node->next;
                                                                            while (value_node && value_node->type != XML_ELEMENT_NODE)
                                                                                value_node = value_node->next;
                                                                            if (value_node && value_node->name)
                                                                            {
                                                                                if (strcmp((const char *)value_node->name, "string") == 0)
                                                                                {
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
                                                                                if (node_content)
                                                                                {
                                                                                strncpy(DBGBuildSourcePath, node_content, sizeof(DBGBuildSourcePath));
                                                                                }
                                                                                }
                                                                                key_node = value_node;
                                                                            }
                                                                        }
                                                                        else if (strcmp(key_name, "DBGSourcePath") == 0)
                                                                        {
                                                                            xmlNode *value_node = key_node->next;
                                                                            while (value_node && value_node->type != XML_ELEMENT_NODE)
                                                                                value_node = value_node->next;
                                                                            if (value_node && value_node->name)
                                                                            {
                                                                                if (strcmp((const char *)value_node->name, "string") == 0)
                                                                                {
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
                                                                                if (node_content)
                                                                                {
                                                                                FileSpec resolved_source_path(node_content, true);
                                                                                resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath));
                                                                                }
                                                                                }
                                                                                key_node = value_node;
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            ::xmlFreeDoc (doc);

                                            if (DBGBuildSourcePath[0] && DBGSourcePath[0])
                                            {
                                                module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    ReplaceDSYMSectionsWithExecutableSections (obj_file, dsym_objfile_sp.get());
                    symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
                    return symbol_vendor;
                }
            }

            // Just create our symbol vendor using the current objfile as this is either
            // an executable with no dSYM (that we could locate), an executable with
            // a dSYM that has a UUID that doesn't match.
            symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this());
        }
    }
    return symbol_vendor;
}

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
const char *
SymbolVendorMacOSX::GetPluginName()
{
    return "SymbolVendorMacOSX";
}

const char *
SymbolVendorMacOSX::GetShortPluginName()
{
    return GetPluginNameStatic();
}

uint32_t
SymbolVendorMacOSX::GetPluginVersion()
{
    return 1;
}

<commit_msg>Add code to ReplaceDSYMSectionsWithExecutableSections() to handle the case where a new section is added to the executable after the dSYM has been created, e.g. the CTF segment added to mach_kernel after all other linking and processing has been finished. <rdar://problem/13258780> <commit_after>//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "SymbolVendorMacOSX.h"

#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>

#include <AvailabilityMacros.h>

#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Section.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Symbols.h"
#include "lldb/Symbol/ObjectFile.h"

using namespace lldb;
using namespace lldb_private;

//----------------------------------------------------------------------
// SymbolVendorMacOSX constructor
//----------------------------------------------------------------------
SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) :
    SymbolVendor (module_sp)
{
}

//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
SymbolVendorMacOSX::~SymbolVendorMacOSX()
{
}

static bool
UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm)
{
    if (module && ofile)
    {
        // Make sure the UUIDs match
        lldb_private::UUID dsym_uuid;

        if (!ofile->GetUUID(&dsym_uuid))
        {
            if (feedback_strm)
            {
                feedback_strm->PutCString("warning: failed to get the uuid for object file: '");
                ofile->GetFileSpec().Dump(feedback_strm);
                feedback_strm->PutCString("\n");
            }
            return false;
        }

        if (dsym_uuid == module->GetUUID())
            return true;

        // Emit some warning messages since the UUIDs do not match!
        if (feedback_strm)
        {
            feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n    ");
            module->GetUUID().Dump(feedback_strm);
            feedback_strm->PutChar(' ');
            module->GetFileSpec().Dump(feedback_strm);
            feedback_strm->PutCString("\n    ");
            dsym_uuid.Dump(feedback_strm);
            feedback_strm->PutChar(' ');
            ofile->GetFileSpec().Dump(feedback_strm);
            feedback_strm->EOL();
        }
    }
    return false;
}

static void
ReplaceDSYMSectionsWithExecutableSections (ObjectFile *exec_objfile, ObjectFile *dsym_objfile)
{
    // We need both the executable and the dSYM to live off of the
    // same section lists. So we take all of the sections from the
    // executable, and replace them in the dSYM. This allows section
    // offset addresses that come from the dSYM to automatically
    // get updated as images (shared libraries) get loaded and
    // unloaded.
    SectionList *exec_section_list = exec_objfile->GetSectionList();
    SectionList *dsym_section_list = dsym_objfile->GetSectionList();
    if (exec_section_list && dsym_section_list)
    {
        const uint32_t num_exec_sections = dsym_section_list->GetSize();
        uint32_t exec_sect_idx;
        for (exec_sect_idx = 0; exec_sect_idx < num_exec_sections; ++exec_sect_idx)
        {
            SectionSP exec_sect_sp(exec_section_list->GetSectionAtIndex(exec_sect_idx));
            if (exec_sect_sp.get())
            {
                // Try and replace any sections that exist in both the executable
                // and in the dSYM with those from the executable. If we fail to
                // replace the one in the dSYM, then add the executable section to
                // the dSYM.
                SectionSP dsym_sect_sp(dsym_section_list->FindSectionByID(exec_sect_sp->GetID()));
                if (dsym_sect_sp.get() && dsym_sect_sp->GetName() != exec_sect_sp->GetName())
                {
                    // The sections in a dSYM are normally a superset of the sections in an executable.
                    // If we find a section # in the exectuable & dSYM that don't have the same name,
                    // something has changed since the dSYM was written.  The mach_kernel DSTROOT binary
                    // has a CTF segment added, for instance, and it's easiest to simply not add that to
                    // the dSYM - none of the nlist entries are going to have references to that section.
                    continue;
                }
                if (dsym_section_list->ReplaceSection(exec_sect_sp->GetID(), exec_sect_sp, 0) == false)
                    dsym_section_list->AddSection(exec_sect_sp);
            }
        }

        dsym_section_list->Finalize(); // Now that we're done adding sections, finalize to build fast-lookup caches
    }
}

void
SymbolVendorMacOSX::Initialize()
{
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
                                   GetPluginDescriptionStatic(),
                                   CreateInstance);
}

void
SymbolVendorMacOSX::Terminate()
{
    PluginManager::UnregisterPlugin (CreateInstance);
}

const char *
SymbolVendorMacOSX::GetPluginNameStatic()
{
    return "symbol-vendor.macosx";
}

const char *
SymbolVendorMacOSX::GetPluginDescriptionStatic()
{
    return "Symbol vendor for MacOSX that looks for dSYM files that match executables.";
}

//----------------------------------------------------------------------
// CreateInstance
//
// Platforms can register a callback to use when creating symbol
// vendors to allow for complex debug information file setups, and to
// also allow for finding separate debug information files.
//----------------------------------------------------------------------
SymbolVendor*
SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
{
    if (!module_sp)
        return NULL;

    Timer scoped_timer (__PRETTY_FUNCTION__,
                        "SymbolVendorMacOSX::CreateInstance (module = %s)",
                        module_sp->GetFileSpec().GetPath().c_str());
    SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp);
    if (symbol_vendor)
    {
        char path[PATH_MAX];
        path[0] = '\0';

        // Try and locate the dSYM file on Mac OS X
        ObjectFile * obj_file = module_sp->GetObjectFile();
        if (obj_file)
        {
            Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM",
                                 "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM",
                                 module_sp->GetFileSpec().GetPath().c_str());

            // First check to see if the module has a symbol file in mind already.
            // If it does, then we MUST use that.
            FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec());

            ObjectFileSP dsym_objfile_sp;
            if (!dsym_fspec)
            {
                // No symbol file was specified in the module, lets try and find
                // one ourselves.
                FileSpec file_spec = obj_file->GetFileSpec();
                if (!file_spec)
                    file_spec = module_sp->GetFileSpec();

                ModuleSpec module_spec(file_spec, module_sp->GetArchitecture());
                module_spec.GetUUID() = module_sp->GetUUID();
                dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
                if (module_spec.GetSourceMappingList().GetSize())
                    module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true);
            }

            if (dsym_fspec)
            {
                DataBufferSP dsym_file_data_sp;
                lldb::offset_t dsym_file_data_offset = 0;
                dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
                if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm))
                {
                    char dsym_path[PATH_MAX];
                    if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path)))
                    {
                        lldb_private::UUID dsym_uuid;
                        if (dsym_objfile_sp->GetUUID(&dsym_uuid))
                        {
                            std::string uuid_str = dsym_uuid.GetAsString ();
                            if (!uuid_str.empty())
                            {
                                char *resources = strstr (dsym_path, "/Contents/Resources/");
                                if (resources)
                                {
                                    char dsym_uuid_plist_path[PATH_MAX];
                                    resources[strlen("/Contents/Resources/")] = '\0';
                                    snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str());
                                    FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false);
                                    if (dsym_uuid_plist_spec.Exists())
                                    {
                                        xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0);
                                        if (doc)
                                        {
                                            char DBGBuildSourcePath[PATH_MAX];
                                            char DBGSourcePath[PATH_MAX];
                                            DBGBuildSourcePath[0] = '\0';
                                            DBGSourcePath[0] = '\0';
                                            for (xmlNode *node = doc->children; node; node = node ? node->next : NULL)
                                            {
                                                if (node->type == XML_ELEMENT_NODE)
                                                {
                                                    if (node->name && strcmp((const char*)node->name, "plist") == 0)
                                                    {
                                                        xmlNode *dict_node = node->children;
                                                        while (dict_node && dict_node->type != XML_ELEMENT_NODE)
                                                            dict_node = dict_node->next;
                                                        if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0)
                                                        {
                                                            for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next)
                                                            {
                                                                if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name)
                                                                {
                                                                    if (strcmp((const char *)key_node->name, "key") == 0)
                                                                    {
                                                                        const char *key_name = (const char *)::xmlNodeGetContent(key_node);
                                                                        if (strcmp(key_name, "DBGBuildSourcePath") == 0)
                                                                        {
                                                                            xmlNode *value_node = key_node->next;
                                                                            while (value_node && value_node->type != XML_ELEMENT_NODE)
                                                                                value_node = value_node->next;
                                                                            if (value_node && value_node->name)
                                                                            {
                                                                                if (strcmp((const char *)value_node->name, "string") == 0)
                                                                                {
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
                                                                                if (node_content)
                                                                                {
                                                                                strncpy(DBGBuildSourcePath, node_content, sizeof(DBGBuildSourcePath));
                                                                                }
                                                                                }
                                                                                key_node = value_node;
                                                                            }
                                                                        }
                                                                        else if (strcmp(key_name, "DBGSourcePath") == 0)
                                                                        {
                                                                            xmlNode *value_node = key_node->next;
                                                                            while (value_node && value_node->type != XML_ELEMENT_NODE)
                                                                                value_node = value_node->next;
                                                                            if (value_node && value_node->name)
                                                                            {
                                                                                if (strcmp((const char *)value_node->name, "string") == 0)
                                                                                {
                                                                                const char *node_content = (const char *)::xmlNodeGetContent(value_node);
                                                                                if (node_content)
                                                                                {
                                                                                FileSpec resolved_source_path(node_content, true);
                                                                                resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath));
                                                                                }
                                                                                }
                                                                                key_node = value_node;
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                            ::xmlFreeDoc (doc);

                                            if (DBGBuildSourcePath[0] && DBGSourcePath[0])
                                            {
                                                module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    ReplaceDSYMSectionsWithExecutableSections (obj_file, dsym_objfile_sp.get());
                    symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp);
                    return symbol_vendor;
                }
            }

            // Just create our symbol vendor using the current objfile as this is either
            // an executable with no dSYM (that we could locate), an executable with
            // a dSYM that has a UUID that doesn't match.
            symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this());
        }
    }
    return symbol_vendor;
}

//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
const char *
SymbolVendorMacOSX::GetPluginName()
{
    return "SymbolVendorMacOSX";
}

const char *
SymbolVendorMacOSX::GetShortPluginName()
{
    return GetPluginNameStatic();
}

uint32_t
SymbolVendorMacOSX::GetPluginVersion()
{
    return 1;
}

<|endoftext|>


<commit_before>/*
    pluginloader.cpp - Kopete Plugin Loader

    Copyright (c) 2002 by Duncan Mac-Vicar Prett       <duncan@kde.org>

    Portions of this code based in Noatun plugin code:
    Copyright (c) 2000-2002 The Noatun Developers

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "pluginloader.h"

#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>

#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <knotifyclient.h>
#include <kparts/componentfactory.h>
#include <ksimpleconfig.h>
#include <kstaticdeleter.h>
#include <kstddirs.h>
#include <kurl.h>

#include "kopeteplugin.h"

class KopeteLibraryInfo;

// Put the static deleter in its anonymous namespace
namespace
{
	KStaticDeleter<LibraryLoader> sd;
}

bool operator ==(const KopeteLibraryInfo &a, const KopeteLibraryInfo &b)
{
	// Feels like cheating, doesn't it?
	return a.specfile == b.specfile;
}

LibraryLoader* LibraryLoader::s_pluginLoader = 0L;

LibraryLoader* LibraryLoader::pluginLoader()
{
	if( !s_pluginLoader )
		sd.setObject( s_pluginLoader, new LibraryLoader() );

	return s_pluginLoader;
}

LibraryLoader::LibraryLoader()
: QObject( qApp )
{
}

LibraryLoader::~LibraryLoader()
{
	QDictIterator<KopetePlugin> i( mLibHash );
	while( i.current() )
	{
		// Remove causes the iterator to auto-increment, so
		// only increment explicitly when not removing
		if( getInfo( i.currentKey() ).type != "protocol" )
			remove( i.current() );
		else
			++i;
	}
	i.toFirst();
	while( i.current() )
		remove( i.current() );

	kdDebug() << "LibraryLoader::~LibraryLoader(): all plugins removed" << endl;
}

QPtrList<KopetePlugin> LibraryLoader::plugins() const
{
	QPtrList<KopetePlugin> list;
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
		list.append( i.current() );

	return list;
}

QValueList<KopeteLibraryInfo> LibraryLoader::loaded() const
{
	QValueList<KopeteLibraryInfo> items;

	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( mLibHash[ i.currentKey() ] )
			items.append( getInfo( i.currentKey() ) );
	}

	return items;
}

bool LibraryLoader::loadAll()
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	QStringList modules = config->readListEntry("Modules");

	// Session management...
/*
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("sm"))
			continue;
		loadPlugin( *i );
	}
*/
	// load all the protocols in the first
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("protocol"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	// load all misc plugins
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("other"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	return true;
}

KopeteLibraryInfo LibraryLoader::getInfo(const QString &spec) const
{
	QMap<QString, KopeteLibraryInfo>::iterator cached = m_cachedInfo.find(spec);
	if (cached != m_cachedInfo.end() )
		return *cached;

	KopeteLibraryInfo info;
	QString specPath = ( spec[ 0 ] == '/' ) ? spec : KGlobal::dirs()->findResource( "appdata", spec );
	if( !QFile::exists( specPath ) )
		return info;

	KSimpleConfig file( specPath );
	if( spec.find( '/' ) >= 0 )
		info.specfile = KURL( spec ).fileName();
	else
		info.specfile = spec;

	info.filename = file.readEntry( "Filename" );
	info.author   = file.readEntry( "Author" );
	info.site     = file.readEntry( "Site" );
	info.email    = file.readEntry( "Email" );
	info.type     = file.readEntry( "Type" );
	info.name     = file.readEntry( "Name" );
	info.comment  = file.readEntry( "Comment" );
	info.license  = file.readEntry( "License" );
	info.icon     = file.readEntry( "Icon" );

	m_cachedInfo[ spec ] = info;
	return info;
}

bool LibraryLoader::isLoaded( const QString &spec ) const
{
	KopetePlugin *p = mLibHash[ spec ];
	return p;
}

void LibraryLoader::setModules(const QStringList &mods)
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	config->writeEntry("Modules", mods);
	KGlobal::config()->sync();
}

QValueList<KopeteLibraryInfo> LibraryLoader::available() const
{
	QValueList<KopeteLibraryInfo> items;
	QStringList files=KGlobal::dirs()->findAllResources("appdata", "*.plugin", false, true);
	for (QStringList::Iterator i=files.begin(); i!=files.end(); ++i)
		items.append(getInfo(*i));

	return items;
}

bool LibraryLoader::loadPlugin( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
	{
		KopeteLibraryInfo info = getInfo( spec );
		if( info.specfile != spec )
			return false;

		// Get the library loader instance
		KLibLoader *loader = KLibLoader::self();

		KLibrary *lib = loader->library( QFile::encodeName( info.filename) );
		if( !lib )
		{
			kdDebug() << "LibraryLoader::loadPlugin: Error while loading plugin: " << loader->lastErrorMessage() << endl;
			return false;
		}
		plugin = KParts::ComponentFactory::createInstanceFromFactory<KopetePlugin> ( lib->factory(), this );
		mLibHash.insert( spec, plugin );

		connect( plugin, SIGNAL( destroyed( QObject * ) ),
			SLOT( slotPluginDestroyed( QObject * ) ) );

		// Automatically load the i18n catalogue for the plugin
		KGlobal::locale()->insertCatalogue( info.filename );

		plugin->init();

		m_addressBookFields.insert( plugin, plugin->addressBookFields() );

		kdDebug() << "LibraryLoader::loadPlugin: Successfully loaded plugin '" << spec << "'."<< endl;
		emit pluginLoaded( plugin );
		return true;
	}
	else
	{
		kdDebug() << "LibraryLoader::loadPlugin: Plugin '" << spec << "' is already loaded!" << endl;
		return false;
	}
}

bool LibraryLoader::remove( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
		return false;

	remove( plugin );
	return true;
}

bool LibraryLoader::remove( KopetePlugin *p )
{
	if( !p )
		return false;

	kdDebug() << "LibraryLoader::remove: Removing plugin: " << p->pluginId() << endl;

	// Added by Duncan 20/01/2002
	// We need to call unload function for the plugin
	p->unload();
	delete p;

	return false;
}

void LibraryLoader::slotPluginDestroyed( QObject *o )
{
	m_addressBookFields.remove( static_cast<KopetePlugin *>( o ) );

	QDictIterator<KopetePlugin> it( mLibHash );
	for( ; it.current() && it.current() == o; ++it )
	{
		mLibHash.remove( it.currentKey() );
		break;
	}

	// FIXME: Most likely most data structures here leak and are bound
	// to cause crashes. Find and identify those.
}

QStringList LibraryLoader::addressBookFields( KopetePlugin *p ) const
{
	if( m_addressBookFields.contains( p ) )
		return m_addressBookFields[ p ];
	else
		return QStringList();
}

KopetePlugin * LibraryLoader::searchByName(const QString &name)
{
	for( QDictIterator<KopetePlugin> i( mLibHash ); i.current(); ++i )
	{
		if (getInfo(i.currentKey()).name==name)
			return (*i);
	}
	return 0L;
}

QString LibraryLoader::pluginIcon( const QString &pluginId ) const
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( i.currentKey() == pluginId );
			return getInfo( i.currentKey() ).icon;
	}

	return QString::null;
}

#include <pluginloader.moc>

// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>hmm, should have committed this long ago. sorry, olivier!<commit_after>/*
    pluginloader.cpp - Kopete Plugin Loader

    Copyright (c) 2002 by Duncan Mac-Vicar Prett       <duncan@kde.org>

    Portions of this code based in Noatun plugin code:
    Copyright (c) 2000-2002 The Noatun Developers

    Kopete    (c) 2002 by the Kopete developers  <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "pluginloader.h"

#include <qapplication.h>
#include <qdir.h>
#include <qfile.h>

#include <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <knotifyclient.h>
#include <kparts/componentfactory.h>
#include <ksimpleconfig.h>
#include <kstaticdeleter.h>
#include <kstddirs.h>
#include <kurl.h>

#include "kopeteplugin.h"

class KopeteLibraryInfo;

// Put the static deleter in its anonymous namespace
namespace
{
	KStaticDeleter<LibraryLoader> sd;
}

bool operator ==(const KopeteLibraryInfo &a, const KopeteLibraryInfo &b)
{
	// Feels like cheating, doesn't it?
	return a.specfile == b.specfile;
}

LibraryLoader* LibraryLoader::s_pluginLoader = 0L;

LibraryLoader* LibraryLoader::pluginLoader()
{
	if( !s_pluginLoader )
		sd.setObject( s_pluginLoader, new LibraryLoader() );

	return s_pluginLoader;
}

LibraryLoader::LibraryLoader()
: QObject( qApp )
{
}

LibraryLoader::~LibraryLoader()
{
	QDictIterator<KopetePlugin> i( mLibHash );
	while( i.current() )
	{
		// Remove causes the iterator to auto-increment, so
		// only increment explicitly when not removing
		if( getInfo( i.currentKey() ).type != "protocol" )
			remove( i.current() );
		else
			++i;
	}
	i.toFirst();
	while( i.current() )
		remove( i.current() );

	kdDebug() << "LibraryLoader::~LibraryLoader(): all plugins removed" << endl;
}

QPtrList<KopetePlugin> LibraryLoader::plugins() const
{
	QPtrList<KopetePlugin> list;
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
		list.append( i.current() );

	return list;
}

QValueList<KopeteLibraryInfo> LibraryLoader::loaded() const
{
	QValueList<KopeteLibraryInfo> items;

	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( mLibHash[ i.currentKey() ] )
			items.append( getInfo( i.currentKey() ) );
	}

	return items;
}

bool LibraryLoader::loadAll()
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	QStringList modules = config->readListEntry("Modules");

	// Session management...
/*
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("sm"))
			continue;
		loadPlugin( *i );
	}
*/
	// load all the protocols in the first
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("protocol"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	// load all misc plugins
	for(QStringList::ConstIterator i=modules.begin(); i!=modules.end(); ++i)
	{
		KopeteLibraryInfo info=getInfo(*i);
		if (!info.type.contains("other"))
			continue;

		if ( !loadPlugin( *i ) )
			kdDebug() << "[LibraryLoader] loading " << (*i) << " failed!" << endl;
	}

	return true;
}

KopeteLibraryInfo LibraryLoader::getInfo(const QString &spec) const
{
	QMap<QString, KopeteLibraryInfo>::iterator cached = m_cachedInfo.find(spec);
	if (cached != m_cachedInfo.end() )
		return *cached;

	KopeteLibraryInfo info;
	QString specPath = ( spec[ 0 ] == '/' ) ? spec : KGlobal::dirs()->findResource( "appdata", spec );
	if( !QFile::exists( specPath ) )
		return info;

	KSimpleConfig file( specPath );
	if( spec.find( '/' ) >= 0 )
		info.specfile = KURL( spec ).fileName();
	else
		info.specfile = spec;

	info.filename = file.readEntry( "Filename" );
	info.author   = file.readEntry( "Author" );
	info.site     = file.readEntry( "Site" );
	info.email    = file.readEntry( "Email" );
	info.type     = file.readEntry( "Type" );
	info.name     = file.readEntry( "Name" );
	info.comment  = file.readEntry( "Comment" );
	info.license  = file.readEntry( "License" );
	info.icon     = file.readEntry( "Icon" );

	m_cachedInfo[ spec ] = info;
	return info;
}

bool LibraryLoader::isLoaded( const QString &spec ) const
{
	KopetePlugin *p = mLibHash[ spec ];
	return p;
}

void LibraryLoader::setModules(const QStringList &mods)
{
	KConfig *config=KGlobal::config();
	config->setGroup("");
	config->writeEntry("Modules", mods);
	KGlobal::config()->sync();
}

QValueList<KopeteLibraryInfo> LibraryLoader::available() const
{
	QValueList<KopeteLibraryInfo> items;
	QStringList files=KGlobal::dirs()->findAllResources("appdata", "*.plugin", false, true);
	for (QStringList::Iterator i=files.begin(); i!=files.end(); ++i)
		items.append(getInfo(*i));

	return items;
}

bool LibraryLoader::loadPlugin( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
	{
		KopeteLibraryInfo info = getInfo( spec );
		if( info.specfile != spec )
			return false;

		// Get the library loader instance
		KLibLoader *loader = KLibLoader::self();

		KLibrary *lib = loader->library( QFile::encodeName( info.filename) );
		if( !lib )
		{
			kdDebug() << "LibraryLoader::loadPlugin: Error while loading plugin: " << loader->lastErrorMessage() << endl;
			return false;
		}
		plugin = KParts::ComponentFactory::createInstanceFromFactory<KopetePlugin> ( lib->factory(), this );
		mLibHash.insert( spec, plugin );

		connect( plugin, SIGNAL( destroyed( QObject * ) ),
			SLOT( slotPluginDestroyed( QObject * ) ) );

		// Automatically load the i18n catalogue for the plugin
		KGlobal::locale()->insertCatalogue( info.filename );

		plugin->init();

		m_addressBookFields.insert( plugin, plugin->addressBookFields() );

		kdDebug() << "LibraryLoader::loadPlugin: Successfully loaded plugin '" << spec << "'."<< endl;
		emit pluginLoaded( plugin );
		return true;
	}
	else
	{
		kdDebug() << "LibraryLoader::loadPlugin: Plugin '" << spec << "' is already loaded!" << endl;
		return false;
	}
}

bool LibraryLoader::remove( const QString &spec )
{
	KopetePlugin *plugin = mLibHash[ spec ];
	if( !plugin )
		return false;

	remove( plugin );
	return true;
}

bool LibraryLoader::remove( KopetePlugin *p )
{
	if( !p )
		return false;

	kdDebug() << "LibraryLoader::remove: Removing plugin: " << p->pluginId() << endl;

	// Added by Duncan 20/01/2002
	// We need to call unload function for the plugin
	p->unload();
	delete p;

	return false;
}

void LibraryLoader::slotPluginDestroyed( QObject *o )
{
	m_addressBookFields.remove( static_cast<KopetePlugin *>( o ) );

	QDictIterator<KopetePlugin> it( mLibHash );
	for( ; it.current() ; ++it )
	{
		if( it.current() == o )
		{
			mLibHash.remove( it.currentKey() );
			break;
		}
	}

	// FIXME: Most likely most data structures here leak and are bound
	// to cause crashes. Find and identify those.
}

QStringList LibraryLoader::addressBookFields( KopetePlugin *p ) const
{
	if( m_addressBookFields.contains( p ) )
		return m_addressBookFields[ p ];
	else
		return QStringList();
}

KopetePlugin * LibraryLoader::searchByName(const QString &name)
{
	for( QDictIterator<KopetePlugin> i( mLibHash ); i.current(); ++i )
	{
		if (getInfo(i.currentKey()).name==name)
			return (*i);
	}
	return 0L;
}

QString LibraryLoader::pluginIcon( const QString &pluginId ) const
{
	QDictIterator<KopetePlugin> i( mLibHash );
	for( ; i.current(); ++i )
	{
		if( i.currentKey() == pluginId );
			return getInfo( i.currentKey() ).icon;
	}

	return QString::null;
}

#include <pluginloader.moc>

// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>#include <iostream>
#include <fstream>

using namespace std;

template <class T>
struct Node
{
	T element;
	Node<T> *left, *right, *pparent;
};

template <class T>
class BST {
private:
	Node<T> *root;
	int count;
public:
	BST();
	~BST();
	void deleteTree(Node<T> *Tree);
	void show(ostream&cout, const Node<T> *Tree) const;
	void add(const T&);
	bool search(const T&, Node<T> *Tree) const;
	void input(const string& file) const;
	void output(const string& file) const;
	Node<T>* MinElement(Node<T>* min);
	Node<T>* getroot() const;
	int getcount() const;
	Node<T>* del(Node<T>* parent, Node<T>* current, const T& val);
	bool delVal(const T& val);

};

template <typename T> BST<T>::BST() {
	root = NULL;
	count = 0;
}

template <typename T> BST<T>::~BST() {
	deleteTree(root);
}

template <typename T>void BST<T>::deleteTree(Node<T> *Tree) {
	if (!Tree)
		return;
	if (Tree->left) {
		deleteTree(Tree->left);
		Tree->left = nullptr;
	}

	if (Tree->right) {
		deleteTree(Tree->right);
		Tree->right = nullptr;
	}
	delete Tree;
}

template <typename T> void BST<T>::show(ostream&cout, const Node<T> *Tree) const{
	if (Tree != NULL) {

		cout << Tree->element << endl;;
		show(cout, Tree->left);
		show(cout, Tree->right);

	}
}

template <typename T> void BST<T>::add(const T &x) {
	Node<T>* daughter = new Node<T>;
	daughter->element = x;
	daughter->left = daughter->right = nullptr;
	Node<T>* parent = root;
	Node<T>* temp = root;

	while (temp)
	{
		parent = temp;
		if (x < temp->element)
			temp = temp->left;
		else temp = temp->right;
	}

	if (!parent)
		root = daughter;
	else {
		if (x < parent->element)
			parent->left = daughter;
		else
			parent->right = daughter;
	}
	count++;
}

template <typename T> Node<T>* BST<T>::getroot() const {
	return root;
}

template <typename T> int BST<T>::getcount() const {
	return count;
}

template <typename T> void BST<T>::input(const string& file) const {
	ifstream fin(file);
	try
	{
		int temp;
		while (!fin.eof()) throw 1;
		{

			fin >> temp;
			add(temp);

		}
		fin.close();
	}
	catch (int i)
	{
		cout << "This file don't find" << endl;
	}

}

template <typename T> void BST<T>::output(const string& file) const {
	ofstream fout(file);
	show(fout, root);
	fout.close();
}

template <typename T> bool BST<T>::search(const T&x, Node<T>* Tree) const {
	if (Tree == nullptr)
		return false;
	if (x == Tree->element) {
		return true;
	}
	else if (x < Tree->element) {
		search(x, Tree->left);
	}
	else search(x, Tree->right);
}

template <typename T> Node<T>* BST<T>::MinElement(Node<T>* min) {
	if (min->left == nullptr)
		return min;
	else
		return MinElement(min->left);

}

template <typename T>
Node<T>* BST<T>::del(Node<T>* parent, Node<T>* current, const T& val)
{
	if (!current) return false;

	if (current->element == val)
	{
		if (current->left == NULL || current->right == NULL)
		{
			Node<T>* temp = current->left;
			if (current->right) temp = current->right;
			if (parent)
			{
				if (parent->left == current)
				{
					parent->left = temp;
				}
				else
				{
					parent->right = temp;
				}
			}
			else
			{
				this->root = temp;
			}
		}

		else
		{
			Node<T>* validSubs = current->right;
			while (validSubs->left)
			{
				validSubs = validSubs->left;
			}
			T temp = current->element;
			current->element = validSubs->element;
			validSubs->element = temp;
			return del(current, current->right, temp);

		}
		delete current;
		count--;
		return true;
	}

	if (current->element > val)

		return del(current, current->left, val);

	else

		return del(current, current->right, val);
}

template <typename T>
bool BST<T>::delVal(const T& val) {
	return this->del(NULL, root, val);
}
<commit_msg>Create BST.hpp<commit_after>#include <iostream>
#include <fstream>

using namespace std;

template <class T>
struct Node
{
	T element;
	Node<T> *left, *right, *pparent;
};

template <class T>
class BST {
private:
	Node<T> *root;
	int count;
public:
	BST();
	~BST();
	void deleteTree(Node<T> *Tree);
	void show(ostream&cout, const Node<T> *Tree) const;
	void add(const T&);
	bool search(const T&, Node<T> *Tree) const;
	void input(const string& file) const;
	void output(const string& file) const;
	Node<T>* MinElement(Node<T>* min);
	Node<T>* getroot() const;
	int getcount() const;
	Node<T>* del(Node<T>* parent, Node<T>* current, const T& val);
	bool delVal(const T& val);

};

template <typename T> BST<T>::BST() {
	root = NULL;
	count = 0;
}

template <typename T> BST<T>::~BST() {
	deleteTree(root);
}

template <typename T>void BST<T>::deleteTree(Node<T> *Tree) {
	if (!Tree)
		return;
	if (Tree->left) {
		deleteTree(Tree->left);
		Tree->left = nullptr;
	}

	if (Tree->right) {
		deleteTree(Tree->right);
		Tree->right = nullptr;
	}
	delete Tree;
}

template <typename T> void BST<T>::show(ostream&cout, const Node<T> *Tree) const{
	if (Tree != NULL) {

		cout << Tree->element << endl;;
		show(cout, Tree->left);
		show(cout, Tree->right);

	}
}

template <typename T> void BST<T>::add(const T &x) {
	Node<T>* daughter = new Node<T>;
	daughter->element = x;
	daughter->left = daughter->right = nullptr;
	Node<T>* parent = root;
	Node<T>* temp = root;

	while (temp)
	{
		parent = temp;
		if (x < temp->element)
			temp = temp->left;
		else temp = temp->right;
	}

	if (!parent)
		root = daughter;
	else {
		if (x < parent->element)
			parent->left = daughter;
		else
			parent->right = daughter;
	}
	count++;
}

template <typename T> Node<T>* BST<T>::getroot() const {
	return root;
}

template <typename T> int BST<T>::getcount() const {
	return count;
}

template <typename T> void BST<T>::input(const string& file){
	ifstream fin(file);
	try
	{
		int temp;
		while (!fin.eof()) throw 1;
		{

			fin >> temp;
			add(temp);

		}
		fin.close();
	}
	catch (int i)
	{
		cout << "This file don't find" << endl;
	}

}

template <typename T> void BST<T>::output(const string& file) const {
	ofstream fout(file);
	show(fout, root);
	fout.close();
}

template <typename T> bool BST<T>::search(const T&x, Node<T>* Tree) const {
	if (Tree == nullptr)
		return false;
	if (x == Tree->element) {
		return true;
	}
	else if (x < Tree->element) {
		search(x, Tree->left);
	}
	else search(x, Tree->right);
}

template <typename T> Node<T>* BST<T>::MinElement(Node<T>* min) {
	if (min->left == nullptr)
		return min;
	else
		return MinElement(min->left);

}

template <typename T>
Node<T>* BST<T>::del(Node<T>* parent, Node<T>* current, const T& val)
{
	if (!current) return false;

	if (current->element == val)
	{
		if (current->left == NULL || current->right == NULL)
		{
			Node<T>* temp = current->left;
			if (current->right) temp = current->right;
			if (parent)
			{
				if (parent->left == current)
				{
					parent->left = temp;
				}
				else
				{
					parent->right = temp;
				}
			}
			else
			{
				this->root = temp;
			}
		}

		else
		{
			Node<T>* validSubs = current->right;
			while (validSubs->left)
			{
				validSubs = validSubs->left;
			}
			T temp = current->element;
			current->element = validSubs->element;
			validSubs->element = temp;
			return del(current, current->right, temp);

		}
		delete current;
		count--;
		return true;
	}

	if (current->element > val)

		return del(current, current->left, val);

	else

		return del(current, current->right, val);
}

template <typename T>
bool BST<T>::delVal(const T& val) {
	return this->del(NULL, root, val);
}
<|endoftext|>


<commit_before>//-----------------------------------------------------------
//
//    Copyright (C) 2015 by the deal2lkit authors
//
//    This file is part of the deal2lkit library.
//
//    The deal2lkit library is free software; you can use it, redistribute
//    it, and/or modify it under the terms of the GNU Lesser General
//    Public License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//    The full text of the license can be found in the file LICENSE at
//    the top level of the deal2lkit distribution.
//
//-----------------------------------------------------------

#include <deal2lkit/sundials_interface.h>
#include <deal2lkit/imex_stepper.h>
#ifdef D2K_WITH_SUNDIALS

#include <deal.II/base/utilities.h>
#include <deal.II/lac/block_vector.h>
#ifdef DEAL_II_WITH_TRILINOS
#include <deal.II/lac/trilinos_block_vector.h>
#include <deal.II/lac/trilinos_parallel_block_vector.h>
#include <deal.II/lac/trilinos_vector.h>
#endif
#include <deal.II/base/utilities.h>

#include <iostream>
#include <iomanip>

#ifdef DEAL_II_WITH_MPI
#include <nvector/nvector_parallel.h>
#endif

using namespace dealii;

D2K_NAMESPACE_OPEN

template <typename VEC>
IMEXStepper<VEC>::IMEXStepper(SundialsInterface<VEC> &interface,
                              const double &step_size,
                              const double &initial_time,
                              const double &final_time) :
  ParameterAcceptor("IMEX Parameters"),
  interface(interface),
  step_size(step_size),
  initial_time(initial_time),
  final_time(final_time)
{
  abs_tol = 1e-6;
  rel_tol = 1e-8;
  output_period = 1;
  newton_alpha = 1.0;
  max_outer_non_linear_iterations = 5;
  max_inner_non_linear_iterations = 3;
  norm_res="l2";
}

template <typename VEC>
void IMEXStepper<VEC>::declare_parameters(ParameterHandler &prm)
{
  add_parameter(prm, &step_size,
                "Step size", std::to_string(step_size), Patterns::Double());

  add_parameter(prm, &abs_tol,
                "Absolute error tolerance", std::to_string(abs_tol),
                Patterns::Double());

  add_parameter(prm, &rel_tol,
                "Relative error tolerance", std::to_string(rel_tol),
                Patterns::Double());

  add_parameter(prm, &initial_time,
                "Initial time", std::to_string(initial_time),
                Patterns::Double());

  add_parameter(prm, &final_time,
                "Final time", std::to_string(final_time),
                Patterns::Double());

  add_parameter(prm, &output_period,
                "Intervals between outputs", std::to_string(output_period),
                Patterns::Integer());

  add_parameter(prm, &max_outer_non_linear_iterations,
                "Maximum number of outer nonlinear iterations", std::to_string(max_outer_non_linear_iterations),
                Patterns::Integer(),
                "At each outer iteration the Jacobian is updated if it is set that the \n"
                "Jacobian is continuously updated and a cycle of inner iterations is \n"
                "perfomed.");

  add_parameter(prm, &norm_res,
                "Norm used for non linear iterations", norm_res,
                Patterns::Selection("l2|linfty"));

  add_parameter(prm, &max_inner_non_linear_iterations,
                "Maximum number of inner nonlinear iterations", std::to_string(max_inner_non_linear_iterations),
                Patterns::Integer(),
                "At each inner iteration the Jacobian is NOT updated.");

  add_parameter(prm, &newton_alpha,
                "Newton relaxation parameter", std::to_string(newton_alpha),
                Patterns::Double());

  add_parameter(prm, &update_jacobian_continuously,
                "Update continuously Jacobian", "true",
                Patterns::Bool());
}

template <typename VEC>
unsigned int IMEXStepper<VEC>::start_ode(VEC &solution)
{
  AssertDimension(solution.size(), interface.n_dofs());

  unsigned int step_number = 0;

  auto previous_solution = interface.create_new_vector();
  auto solution_dot = interface.create_new_vector();
  auto solution_update = interface.create_new_vector();
  auto residual = interface.create_new_vector();
  auto rhs = interface.create_new_vector();

  *previous_solution = solution;

  double t = initial_time;
  double alpha;

  // check if it is a stationary problem
  if (initial_time == final_time)
    alpha = 0.0;
  else
    alpha = 1./step_size;

  interface.output_step( 0, solution, *solution_dot, 0, step_size);

  // Initialization of the state of the boolean variable
  // responsible to keep track of the requirement that the
  // system's Jacobian be updated.
  bool update_Jacobian = true;

  // The overall cycle over time begins here.
  for (; t<=final_time; t+= step_size, ++step_number)
    {
      std::cout << "Time = " << t << std::endl;
      // Implicit Euler scheme.
      *solution_dot = solution;
      *solution_dot -= *previous_solution;
      *solution_dot *= alpha;

      // Initialization of two counters for the monitoring of
      // progress of the nonlinear solver.
      unsigned int inner_iter = 0;
      unsigned int outer_iter = 0;
      unsigned int nonlin_iter = 0;
      interface.residual(t, solution, *solution_dot, *residual);
      double res_norm = 0.0;
      double solution_norm = 0.0;

      if (norm_res=="l2")
        {
          res_norm = residual->l2_norm();
          solution_norm = solution.l2_norm();
        }
      else if (norm_res=="linfty")
        {
          res_norm = residual->linfty_norm();
          solution_norm = solution.l2_norm();
        }

      // The nonlinear solver iteration cycle begins here.
      while (outer_iter < max_outer_non_linear_iterations &&
             res_norm > abs_tol &&
             res_norm > rel_tol*solution_norm)
        {
          outer_iter += 1;
          if (update_Jacobian == true)
            {
              interface.setup_jacobian(t, solution, *solution_dot,
                                       *residual, alpha);
            }

          inner_iter = 0;
          while (inner_iter < max_inner_non_linear_iterations &&
                 res_norm > abs_tol &&
                 res_norm > rel_tol*solution_norm)
            {
              inner_iter += 1;

              *rhs = *residual;
              *rhs *= -1.0;

              interface.solve_jacobian_system(t, solution, *solution_dot,
                                              *residual, alpha,
                                              *rhs, *solution_update);
              solution.sadd(1.0,
                            newton_alpha, *solution_update);

              // Implicit Euler scheme.
              *solution_dot = solution;
              *solution_dot -= *previous_solution;
              *solution_dot *= alpha;

              interface.residual(t, solution, *solution_dot, *residual);

              if (norm_res=="l2")
                {
                  res_norm = residual->l2_norm();
                  solution_norm = solution.l2_norm();
                }
              else if (norm_res=="linfty")
                {
                  res_norm = residual->linfty_norm();
                  solution_norm = solution.l2_norm();
                }

            }

          nonlin_iter += inner_iter;

          if (std::fabs(res_norm) < abs_tol)
            {
              std::printf("   %-16.3e (converged in %d iterations)\n\n", res_norm, nonlin_iter);
              break; // Break of the while cycle ... after this a time advancement happens.
            }
          else if (outer_iter == max_outer_non_linear_iterations)
            {
              std::printf("   %-16.3e (not converged in %d iterations)\n\n", res_norm, nonlin_iter);
              AssertThrow(false,
                          ExcMessage ("No convergence in nonlinear solver"));
            }

        } // The nonlinear solver iteration cycle ends here.

      *previous_solution = solution;

      if ((step_number % output_period) == 0)
        interface.output_step(t, solution, *solution_dot,  step_number, step_size);

      update_Jacobian = update_jacobian_continuously;

    } // End of the cycle over time.
  return 0;
}

D2K_NAMESPACE_CLOSE

template class deal2lkit::IMEXStepper<BlockVector<double> >;

#ifdef DEAL_II_WITH_MPI

#ifdef DEAL_II_WITH_TRILINOS
template class deal2lkit::IMEXStepper<TrilinosWrappers::MPI::Vector>;
template class deal2lkit::IMEXStepper<TrilinosWrappers::MPI::BlockVector>;
#endif

#endif

#endif
<commit_msg>avoid useless computation<commit_after>//-----------------------------------------------------------
//
//    Copyright (C) 2015 by the deal2lkit authors
//
//    This file is part of the deal2lkit library.
//
//    The deal2lkit library is free software; you can use it, redistribute
//    it, and/or modify it under the terms of the GNU Lesser General
//    Public License as published by the Free Software Foundation; either
//    version 2.1 of the License, or (at your option) any later version.
//    The full text of the license can be found in the file LICENSE at
//    the top level of the deal2lkit distribution.
//
//-----------------------------------------------------------

#include <deal2lkit/sundials_interface.h>
#include <deal2lkit/imex_stepper.h>
#ifdef D2K_WITH_SUNDIALS

#include <deal.II/base/utilities.h>
#include <deal.II/lac/block_vector.h>
#ifdef DEAL_II_WITH_TRILINOS
#include <deal.II/lac/trilinos_block_vector.h>
#include <deal.II/lac/trilinos_parallel_block_vector.h>
#include <deal.II/lac/trilinos_vector.h>
#endif
#include <deal.II/base/utilities.h>

#include <iostream>
#include <iomanip>

#ifdef DEAL_II_WITH_MPI
#include <nvector/nvector_parallel.h>
#endif

using namespace dealii;

D2K_NAMESPACE_OPEN

template <typename VEC>
IMEXStepper<VEC>::IMEXStepper(SundialsInterface<VEC> &interface,
                              const double &step_size,
                              const double &initial_time,
                              const double &final_time) :
  ParameterAcceptor("IMEX Parameters"),
  interface(interface),
  step_size(step_size),
  initial_time(initial_time),
  final_time(final_time)
{
  abs_tol = 1e-6;
  rel_tol = 1e-8;
  output_period = 1;
  newton_alpha = 1.0;
  max_outer_non_linear_iterations = 5;
  max_inner_non_linear_iterations = 3;
  norm_res="l2";
}

template <typename VEC>
void IMEXStepper<VEC>::declare_parameters(ParameterHandler &prm)
{
  add_parameter(prm, &step_size,
                "Step size", std::to_string(step_size), Patterns::Double());

  add_parameter(prm, &abs_tol,
                "Absolute error tolerance", std::to_string(abs_tol),
                Patterns::Double());

  add_parameter(prm, &rel_tol,
                "Relative error tolerance", std::to_string(rel_tol),
                Patterns::Double());

  add_parameter(prm, &initial_time,
                "Initial time", std::to_string(initial_time),
                Patterns::Double());

  add_parameter(prm, &final_time,
                "Final time", std::to_string(final_time),
                Patterns::Double());

  add_parameter(prm, &output_period,
                "Intervals between outputs", std::to_string(output_period),
                Patterns::Integer());

  add_parameter(prm, &max_outer_non_linear_iterations,
                "Maximum number of outer nonlinear iterations", std::to_string(max_outer_non_linear_iterations),
                Patterns::Integer(),
                "At each outer iteration the Jacobian is updated if it is set that the \n"
                "Jacobian is continuously updated and a cycle of inner iterations is \n"
                "perfomed.");

  add_parameter(prm, &norm_res,
                "Norm used for non linear iterations", norm_res,
                Patterns::Selection("l2|linfty"));

  add_parameter(prm, &max_inner_non_linear_iterations,
                "Maximum number of inner nonlinear iterations", std::to_string(max_inner_non_linear_iterations),
                Patterns::Integer(),
                "At each inner iteration the Jacobian is NOT updated.");

  add_parameter(prm, &newton_alpha,
                "Newton relaxation parameter", std::to_string(newton_alpha),
                Patterns::Double());

  add_parameter(prm, &update_jacobian_continuously,
                "Update continuously Jacobian", "true",
                Patterns::Bool());
}

template <typename VEC>
unsigned int IMEXStepper<VEC>::start_ode(VEC &solution)
{
  AssertDimension(solution.size(), interface.n_dofs());

  unsigned int step_number = 0;

  auto previous_solution = interface.create_new_vector();
  auto solution_dot = interface.create_new_vector();
  auto solution_update = interface.create_new_vector();
  auto residual = interface.create_new_vector();
  auto rhs = interface.create_new_vector();

  *previous_solution = solution;

  double t = initial_time;
  double alpha;

  // check if it is a stationary problem
  if (initial_time == final_time)
    alpha = 0.0;
  else
    alpha = 1./step_size;

  interface.output_step( 0, solution, *solution_dot, 0, step_size);

  // Initialization of the state of the boolean variable
  // responsible to keep track of the requirement that the
  // system's Jacobian be updated.
  bool update_Jacobian = true;

  // The overall cycle over time begins here.
  for (; t<=final_time; t+= step_size, ++step_number)
    {
      std::cout << "Time = " << t << std::endl;
      // Implicit Euler scheme.
      *solution_dot = solution;
      *solution_dot -= *previous_solution;
      *solution_dot *= alpha;

      // Initialization of two counters for the monitoring of
      // progress of the nonlinear solver.
      unsigned int inner_iter = 0;
      unsigned int outer_iter = 0;
      unsigned int nonlin_iter = 0;
      interface.residual(t, solution, *solution_dot, *residual);
      double res_norm = 0.0;
      double solution_norm = 0.0;

      if (norm_res=="l2")
        {
          if (abs_tol>0.0)
            res_norm = residual->l2_norm();
          if (rel_tol>0.0)
            solution_norm = solution.l2_norm();
        }
      else if (norm_res=="linfty")
        {
          if (abs_tol>0.0)
            res_norm = residual->linfty_norm();
          if (rel_tol>0.0)
            solution_norm = solution.linfty_norm();
        }

      // The nonlinear solver iteration cycle begins here.
      while (outer_iter < max_outer_non_linear_iterations &&
             res_norm > abs_tol &&
             res_norm > rel_tol*solution_norm)
        {
          outer_iter += 1;
          if (update_Jacobian == true)
            {
              interface.setup_jacobian(t, solution, *solution_dot,
                                       *residual, alpha);
            }

          inner_iter = 0;
          while (inner_iter < max_inner_non_linear_iterations &&
                 res_norm > abs_tol &&
                 res_norm > rel_tol*solution_norm)
            {
              inner_iter += 1;

              *rhs = *residual;
              *rhs *= -1.0;

              interface.solve_jacobian_system(t, solution, *solution_dot,
                                              *residual, alpha,
                                              *rhs, *solution_update);
              solution.sadd(1.0,
                            newton_alpha, *solution_update);

              // Implicit Euler scheme.
              *solution_dot = solution;
              *solution_dot -= *previous_solution;
              *solution_dot *= alpha;

              interface.residual(t, solution, *solution_dot, *residual);

              if (norm_res=="l2")
                {
                  if (abs_tol>0.0)
                    res_norm = residual->l2_norm();
                  if (rel_tol>0.0)
                    solution_norm = solution.l2_norm();
                }
              else if (norm_res=="linfty")
                {
                  if (abs_tol>0.0)
                    res_norm = residual->linfty_norm();
                  if (rel_tol>0.0)
                    solution_norm = solution.linfty_norm();
                }

            }

          nonlin_iter += inner_iter;

          if (std::fabs(res_norm) < abs_tol)
            {
              std::printf("   %-16.3e (converged in %d iterations)\n\n", res_norm, nonlin_iter);
              break; // Break of the while cycle ... after this a time advancement happens.
            }
          else if (outer_iter == max_outer_non_linear_iterations)
            {
              std::printf("   %-16.3e (not converged in %d iterations)\n\n", res_norm, nonlin_iter);
              AssertThrow(false,
                          ExcMessage ("No convergence in nonlinear solver"));
            }

        } // The nonlinear solver iteration cycle ends here.

      *previous_solution = solution;

      if ((step_number % output_period) == 0)
        interface.output_step(t, solution, *solution_dot,  step_number, step_size);

      update_Jacobian = update_jacobian_continuously;

    } // End of the cycle over time.
  return 0;
}

D2K_NAMESPACE_CLOSE

template class deal2lkit::IMEXStepper<BlockVector<double> >;

#ifdef DEAL_II_WITH_MPI

#ifdef DEAL_II_WITH_TRILINOS
template class deal2lkit::IMEXStepper<TrilinosWrappers::MPI::Vector>;
template class deal2lkit::IMEXStepper<TrilinosWrappers::MPI::BlockVector>;
#endif

#endif

#endif
<|endoftext|>