<commit_before>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.06
 * @brief Implementation of the GameDiscoverer class
 */

#include <cstring>

#include <SDL.h>

#include "game_discoverer.hxx"
#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "src/globals.hxx"

using namespace std;

#define BROADCAST_INTERVAL 128
#define CYCLE_COUNT 8
static const byte trigger[] = {
  'A', 'b', 'e', 'n', 'd', 's', 'p', 'i', 'e', 'l',
};

GameDiscoverer::GameDiscoverer(Tuner* tuner) {
  tuner->trigger(trigger, sizeof(trigger), this);
}

void GameDiscoverer::start() noth {
  nextBroadcast = SDL_GetTicks();
  currentTry = 0;
  results.clear();
}

void GameDiscoverer::poll(Antenna* antenna) noth {
  if (SDL_GetTicks() >= nextBroadcast && currentTry < CYCLE_COUNT) {
    ++currentTry;
    static const byte pack[] = {
      'A', 'b', 'e', 'n', 'd', 's', 'u', 'c', 'h'
    };
    static const asio::ip::address v4addr(
      asio::ip::address_v4::from_string("255.255.255.255"));
    static const asio::ip::address v6addr(
      asio::ip::address_v6::from_string("ff02::1"));
    for (unsigned isV6=0; isV6 < 2; ++isV6) {
      for (unsigned port=0; port < lenof(Antenna::wellKnownPorts); ++port) {
        try {
          if (isV6) {
            //IPv6
            if (antenna->hasV6()) {
              asio::ip::udp::endpoint dest(v6addr,
                                           Antenna::wellKnownPorts[port]);
              antenna->send(dest, pack, sizeof(pack));
            }
          } else {
            if (antenna->hasV4()) {
              asio::ip::udp::endpoint dest(v4addr,
                                           Antenna::wellKnownPorts[port]);
              antenna->send(dest, pack, sizeof(pack));
            }
          }
        } catch (asio::system_error e) {
          cerr << "Unable to broadcast to port "
               << Antenna::wellKnownPorts[port]
               << " with protocol " << (isV6? "IPv6" : "IPv4")
               << ": " << e.what() << endl;
        }
      }
    }

    nextBroadcast = SDL_GetTicks() + BROADCAST_INTERVAL;
  }
}

float GameDiscoverer::progress() const noth {
  if (currentTry == 0) return 0;
  if (currentTry == CYCLE_COUNT && SDL_GetTicks() >= nextBroadcast)
    return 1;

  return (currentTry +
          (SDL_GetTicks()-nextBroadcast)/(float)BROADCAST_INTERVAL)/
         (float)CYCLE_COUNT;
}

void GameDiscoverer::process(const Antenna::endpoint& source,
                             Antenna* antenna, Tuner* tuner,
                             const byte* data, unsigned len)
noth {
  //Past trigger
  data += sizeof(trigger);
  len -= sizeof(trigger);
  if (len != 4+1+1+4) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring Abendspiel of unexpected length: "
         << len << ", from " << source << endl;
    #endif
    return;
  }

  Uint32 oid;
  byte peercnt, pwprot;
  char mode[4];
  io::read(data, oid);
  io::read(data, peercnt);
  io::read(data, pwprot);
  strncpy((char*)mode, (const char*)data, 4);

  //Don't add result if the overseer has the same ID as another
  for (unsigned i=0; i<results.size(); ++i)
    if (results[i].overseer == oid)
      return;

  //OK, add result
  Result res;
  res.peer = source;
  res.overseer = oid;
  res.passwordProtected = pwprot;
  res.peerCount = peercnt;
  memcpy(res.gameMode, mode, sizeof(mode));
  results.push_back(res);
}

void GameDiscoverer::dumpResults() const noth {
  cout << "GameDiscoverer results:" << endl;
  cout << "#\toid\tprot?\tcnt\tmode\tpeer" << endl;
  for (unsigned i=0; i<results.size(); ++i) {
    const Result& res(results[i]);
    cout << i << '\t'
         << (res.passwordProtected? "yes" : "no") << '\t'
         << (unsigned)res.peerCount << '\t'
         << res.gameMode << '\t'
         << res.peer << endl;
  }
}
<commit_msg>Correct trying to use gameMode as a C-String.<commit_after>/**
 * @file
 * @author Jason Lingle
 * @date 2012.02.06
 * @brief Implementation of the GameDiscoverer class
 */

#include <cstring>

#include <SDL.h>

#include "game_discoverer.hxx"
#include "antenna.hxx"
#include "tuner.hxx"
#include "io.hxx"
#include "src/globals.hxx"

using namespace std;

#define BROADCAST_INTERVAL 128
#define CYCLE_COUNT 8
static const byte trigger[] = {
  'A', 'b', 'e', 'n', 'd', 's', 'p', 'i', 'e', 'l',
};

GameDiscoverer::GameDiscoverer(Tuner* tuner) {
  tuner->trigger(trigger, sizeof(trigger), this);
}

void GameDiscoverer::start() noth {
  nextBroadcast = SDL_GetTicks();
  currentTry = 0;
  results.clear();
}

void GameDiscoverer::poll(Antenna* antenna) noth {
  if (SDL_GetTicks() >= nextBroadcast && currentTry < CYCLE_COUNT) {
    ++currentTry;
    static const byte pack[] = {
      'A', 'b', 'e', 'n', 'd', 's', 'u', 'c', 'h'
    };
    static const asio::ip::address v4addr(
      asio::ip::address_v4::from_string("255.255.255.255"));
    static const asio::ip::address v6addr(
      asio::ip::address_v6::from_string("ff02::1"));
    for (unsigned isV6=0; isV6 < 2; ++isV6) {
      for (unsigned port=0; port < lenof(Antenna::wellKnownPorts); ++port) {
        try {
          if (isV6) {
            //IPv6
            if (antenna->hasV6()) {
              asio::ip::udp::endpoint dest(v6addr,
                                           Antenna::wellKnownPorts[port]);
              antenna->send(dest, pack, sizeof(pack));
            }
          } else {
            if (antenna->hasV4()) {
              asio::ip::udp::endpoint dest(v4addr,
                                           Antenna::wellKnownPorts[port]);
              antenna->send(dest, pack, sizeof(pack));
            }
          }
        } catch (asio::system_error e) {
          cerr << "Unable to broadcast to port "
               << Antenna::wellKnownPorts[port]
               << " with protocol " << (isV6? "IPv6" : "IPv4")
               << ": " << e.what() << endl;
        }
      }
    }

    nextBroadcast = SDL_GetTicks() + BROADCAST_INTERVAL;
  }
}

float GameDiscoverer::progress() const noth {
  if (currentTry == 0) return 0;
  if (currentTry == CYCLE_COUNT && SDL_GetTicks() >= nextBroadcast)
    return 1;

  return (currentTry +
          (SDL_GetTicks()-nextBroadcast)/(float)BROADCAST_INTERVAL)/
         (float)CYCLE_COUNT;
}

void GameDiscoverer::process(const Antenna::endpoint& source,
                             Antenna* antenna, Tuner* tuner,
                             const byte* data, unsigned len)
noth {
  //Past trigger
  data += sizeof(trigger);
  len -= sizeof(trigger);
  if (len != 4+1+1+4) {
    #ifdef DEBUG
    cerr << "Warning: Ignoring Abendspiel of unexpected length: "
         << len << ", from " << source << endl;
    #endif
    return;
  }

  Uint32 oid;
  byte peercnt, pwprot;
  char mode[4];
  io::read(data, oid);
  io::read(data, peercnt);
  io::read(data, pwprot);
  strncpy((char*)mode, (const char*)data, 4);

  //Don't add result if the overseer has the same ID as another
  for (unsigned i=0; i<results.size(); ++i)
    if (results[i].overseer == oid)
      return;

  //OK, add result
  Result res;
  res.peer = source;
  res.overseer = oid;
  res.passwordProtected = pwprot;
  res.peerCount = peercnt;
  memcpy(res.gameMode, mode, sizeof(mode));
  results.push_back(res);
}

void GameDiscoverer::dumpResults() const noth {
  cout << "GameDiscoverer results:" << endl;
  cout << "#\toid\tprot?\tcnt\tmode\tpeer" << endl;
  for (unsigned i=0; i<results.size(); ++i) {
    const Result& res(results[i]);
    cout << i << '\t'
         << (res.passwordProtected? "yes" : "no") << '\t'
         << (unsigned)res.peerCount << '\t'
         << string(res.gameMode, res.gameMode+4) << '\t'
         << res.peer << endl;
  }
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <stego-crypt-lib/stego-crypt-lib.hh>

TEST(StegStub, oneEqualsone) {
  int one = 1;
  EXPECT_EQ(1, one);
}

TEST(BMPTests, BmpValidation) {
  std::ifstream ifs("test/stego-crypt/test.bmp", std::ios::binary);
  std::ostringstream ost;
  ost << ifs.rdbuf();
  std::string bmp(ost.str());
  EXPECT_EQ(true, is_bmp_valid(bmp));
}
<commit_msg>Changed test case name to BmpTests<commit_after>#include <gtest/gtest.h>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <stego-crypt-lib/stego-crypt-lib.hh>

TEST(StegStub, oneEqualsone) {
  int one = 1;
  EXPECT_EQ(1, one);
}

TEST(BmpTests, BmpValidation) {
  std::ifstream ifs("test/stego-crypt/test.bmp", std::ios::binary);
  std::ostringstream ost;
  ost << ifs.rdbuf();
  std::string bmp(ost.str());
  EXPECT_EQ(true, is_bmp_valid(bmp));
}
<|endoftext|>


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

#include "ClangdUnit.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Tooling/CompilationDatabase.h"

using namespace clang::clangd;
using namespace clang;

ClangdUnit::ClangdUnit(PathRef FileName, StringRef Contents,
                       std::shared_ptr<PCHContainerOperations> PCHs,
                       std::vector<tooling::CompileCommand> Commands)
    : FileName(FileName), PCHs(PCHs) {
  assert(!Commands.empty() && "No compile commands provided");

  // Inject the resource dir.
  // FIXME: Don't overwrite it if it's already there.
  static int Dummy; // Just an address in this process.
  std::string ResourceDir =
      CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
  Commands.front().CommandLine.push_back("-resource-dir=" + ResourceDir);

  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
      CompilerInstance::createDiagnostics(new DiagnosticOptions);

  std::vector<const char *> ArgStrs;
  for (const auto &S : Commands.front().CommandLine)
    ArgStrs.push_back(S.c_str());

  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  auto ArgP = &*ArgStrs.begin();
  Unit = std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true, RemappedSource,
      /*RemappedFilesKeepOriginalName=*/true,
      /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Complete,
      /*CacheCodeCompletionResults=*/true,
      /*IncludeBriefCommentsInCodeCompletion=*/true,
      /*AllowPCHWithCompilerErrors=*/true));
}

void ClangdUnit::reparse(StringRef Contents) {
  // Do a reparse if this wasn't the first parse.
  // FIXME: This might have the wrong working directory if it changed in the
  // meantime.
  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  Unit->Reparse(PCHs, RemappedSource);
}

namespace {

CompletionItemKind getKind(CXCursorKind K) {
  switch (K) {
  case CXCursor_MacroInstantiation:
  case CXCursor_MacroDefinition:
    return CompletionItemKind::Text;
  case CXCursor_CXXMethod:
    return CompletionItemKind::Method;
  case CXCursor_FunctionDecl:
  case CXCursor_FunctionTemplate:
    return CompletionItemKind::Function;
  case CXCursor_Constructor:
  case CXCursor_Destructor:
    return CompletionItemKind::Constructor;
  case CXCursor_FieldDecl:
    return CompletionItemKind::Field;
  case CXCursor_VarDecl:
  case CXCursor_ParmDecl:
    return CompletionItemKind::Variable;
  case CXCursor_ClassDecl:
  case CXCursor_StructDecl:
  case CXCursor_UnionDecl:
  case CXCursor_ClassTemplate:
  case CXCursor_ClassTemplatePartialSpecialization:
    return CompletionItemKind::Class;
  case CXCursor_Namespace:
  case CXCursor_NamespaceAlias:
  case CXCursor_NamespaceRef:
    return CompletionItemKind::Module;
  case CXCursor_EnumConstantDecl:
    return CompletionItemKind::Value;
  case CXCursor_EnumDecl:
    return CompletionItemKind::Enum;
  case CXCursor_TypeAliasDecl:
  case CXCursor_TypeAliasTemplateDecl:
  case CXCursor_TypedefDecl:
  case CXCursor_MemberRef:
  case CXCursor_TypeRef:
    return CompletionItemKind::Reference;
  default:
    return CompletionItemKind::Missing;
  }
}

class CompletionItemsCollector : public CodeCompleteConsumer {
  std::vector<CompletionItem> *Items;
  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
  CodeCompletionTUInfo CCTUInfo;

public:
  CompletionItemsCollector(std::vector<CompletionItem> *Items,
                           const CodeCompleteOptions &CodeCompleteOpts)
      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
        Items(Items),
        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
        CCTUInfo(Allocator) {}

  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
                                  CodeCompletionResult *Results,
                                  unsigned NumResults) override {
    for (unsigned I = 0; I != NumResults; ++I) {
      CodeCompletionResult &Result = Results[I];
      CodeCompletionString *CCS = Result.CreateCodeCompletionString(
          S, Context, *Allocator, CCTUInfo,
          CodeCompleteOpts.IncludeBriefComments);
      if (CCS) {
        CompletionItem Item;
        assert(CCS->getTypedText());
        Item.label = CCS->getTypedText();
        Item.kind = getKind(Result.CursorKind);
        if (CCS->getBriefComment())
          Item.documentation = CCS->getBriefComment();
        Items->push_back(std::move(Item));
      }
    }
  }

  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }

  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
};
} // namespace

std::vector<CompletionItem> ClangdUnit::codeComplete(StringRef Contents,
                                                     Position Pos) {
  CodeCompleteOptions CCO;
  CCO.IncludeBriefComments = 1;
  // This is where code completion stores dirty buffers. Need to free after
  // completion.
  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
  std::vector<CompletionItem> Items;
  CompletionItemsCollector Collector(&Items, CCO);

  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  IntrusiveRefCntPtr<SourceManager> SourceMgr(
      new SourceManager(*DiagEngine, Unit->getFileManager()));
  // CodeComplete seems to require fresh LangOptions.
  LangOptions LangOpts = Unit->getLangOpts();
  // The language server protocol uses zero-based line and column numbers.
  // The clang code completion uses one-based numbers.
  Unit->CodeComplete(FileName, Pos.line + 1, Pos.character + 1, RemappedSource,
                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
                     LangOpts, *SourceMgr, Unit->getFileManager(),
                     StoredDiagnostics, OwnedBuffers);
  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
    delete Buffer;
  return Items;
}

namespace {
/// Convert from clang diagnostic level to LSP severity.
static int getSeverity(DiagnosticsEngine::Level L) {
  switch (L) {
  case DiagnosticsEngine::Remark:
    return 4;
  case DiagnosticsEngine::Note:
    return 3;
  case DiagnosticsEngine::Warning:
    return 2;
  case DiagnosticsEngine::Fatal:
  case DiagnosticsEngine::Error:
    return 1;
  case DiagnosticsEngine::Ignored:
    return 0;
  }
  llvm_unreachable("Unknown diagnostic level!");
}
} // namespace

std::vector<DiagWithFixIts> ClangdUnit::getLocalDiagnostics() const {
  std::vector<DiagWithFixIts> Result;
  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
                                     DEnd = Unit->stored_diag_end();
       D != DEnd; ++D) {
    if (!D->getLocation().isValid() ||
        !D->getLocation().getManager().isInMainFile(D->getLocation()))
      continue;
    Position P;
    P.line = D->getLocation().getSpellingLineNumber() - 1;
    P.character = D->getLocation().getSpellingColumnNumber();
    Range R = {P, P};
    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};

    llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
    for (const FixItHint &Fix : D->getFixIts()) {
      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
    }
    Result.push_back({Diag, std::move(FixItsForDiagnostic)});
  }
  return Result;
}
<commit_msg>[clangd] Switch to incomplete translation units<commit_after>//===--- ClangdUnit.cpp -----------------------------------------*- C++-*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//

#include "ClangdUnit.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Tooling/CompilationDatabase.h"

using namespace clang::clangd;
using namespace clang;

ClangdUnit::ClangdUnit(PathRef FileName, StringRef Contents,
                       std::shared_ptr<PCHContainerOperations> PCHs,
                       std::vector<tooling::CompileCommand> Commands)
    : FileName(FileName), PCHs(PCHs) {
  assert(!Commands.empty() && "No compile commands provided");

  // Inject the resource dir.
  // FIXME: Don't overwrite it if it's already there.
  static int Dummy; // Just an address in this process.
  std::string ResourceDir =
      CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy);
  Commands.front().CommandLine.push_back("-resource-dir=" + ResourceDir);

  IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
      CompilerInstance::createDiagnostics(new DiagnosticOptions);

  std::vector<const char *> ArgStrs;
  for (const auto &S : Commands.front().CommandLine)
    ArgStrs.push_back(S.c_str());

  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  auto ArgP = &*ArgStrs.begin();
  Unit = std::unique_ptr<ASTUnit>(ASTUnit::LoadFromCommandLine(
      ArgP, ArgP + ArgStrs.size(), PCHs, Diags, ResourceDir,
      /*OnlyLocalDecls=*/false, /*CaptureDiagnostics=*/true, RemappedSource,
      /*RemappedFilesKeepOriginalName=*/true,
      /*PrecompilePreambleAfterNParses=*/1, /*TUKind=*/TU_Prefix,
      /*CacheCodeCompletionResults=*/true,
      /*IncludeBriefCommentsInCodeCompletion=*/true,
      /*AllowPCHWithCompilerErrors=*/true));
}

void ClangdUnit::reparse(StringRef Contents) {
  // Do a reparse if this wasn't the first parse.
  // FIXME: This might have the wrong working directory if it changed in the
  // meantime.
  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  Unit->Reparse(PCHs, RemappedSource);
}

namespace {

CompletionItemKind getKind(CXCursorKind K) {
  switch (K) {
  case CXCursor_MacroInstantiation:
  case CXCursor_MacroDefinition:
    return CompletionItemKind::Text;
  case CXCursor_CXXMethod:
    return CompletionItemKind::Method;
  case CXCursor_FunctionDecl:
  case CXCursor_FunctionTemplate:
    return CompletionItemKind::Function;
  case CXCursor_Constructor:
  case CXCursor_Destructor:
    return CompletionItemKind::Constructor;
  case CXCursor_FieldDecl:
    return CompletionItemKind::Field;
  case CXCursor_VarDecl:
  case CXCursor_ParmDecl:
    return CompletionItemKind::Variable;
  case CXCursor_ClassDecl:
  case CXCursor_StructDecl:
  case CXCursor_UnionDecl:
  case CXCursor_ClassTemplate:
  case CXCursor_ClassTemplatePartialSpecialization:
    return CompletionItemKind::Class;
  case CXCursor_Namespace:
  case CXCursor_NamespaceAlias:
  case CXCursor_NamespaceRef:
    return CompletionItemKind::Module;
  case CXCursor_EnumConstantDecl:
    return CompletionItemKind::Value;
  case CXCursor_EnumDecl:
    return CompletionItemKind::Enum;
  case CXCursor_TypeAliasDecl:
  case CXCursor_TypeAliasTemplateDecl:
  case CXCursor_TypedefDecl:
  case CXCursor_MemberRef:
  case CXCursor_TypeRef:
    return CompletionItemKind::Reference;
  default:
    return CompletionItemKind::Missing;
  }
}

class CompletionItemsCollector : public CodeCompleteConsumer {
  std::vector<CompletionItem> *Items;
  std::shared_ptr<clang::GlobalCodeCompletionAllocator> Allocator;
  CodeCompletionTUInfo CCTUInfo;

public:
  CompletionItemsCollector(std::vector<CompletionItem> *Items,
                           const CodeCompleteOptions &CodeCompleteOpts)
      : CodeCompleteConsumer(CodeCompleteOpts, /*OutputIsBinary=*/false),
        Items(Items),
        Allocator(std::make_shared<clang::GlobalCodeCompletionAllocator>()),
        CCTUInfo(Allocator) {}

  void ProcessCodeCompleteResults(Sema &S, CodeCompletionContext Context,
                                  CodeCompletionResult *Results,
                                  unsigned NumResults) override {
    for (unsigned I = 0; I != NumResults; ++I) {
      CodeCompletionResult &Result = Results[I];
      CodeCompletionString *CCS = Result.CreateCodeCompletionString(
          S, Context, *Allocator, CCTUInfo,
          CodeCompleteOpts.IncludeBriefComments);
      if (CCS) {
        CompletionItem Item;
        assert(CCS->getTypedText());
        Item.label = CCS->getTypedText();
        Item.kind = getKind(Result.CursorKind);
        if (CCS->getBriefComment())
          Item.documentation = CCS->getBriefComment();
        Items->push_back(std::move(Item));
      }
    }
  }

  GlobalCodeCompletionAllocator &getAllocator() override { return *Allocator; }

  CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
};
} // namespace

std::vector<CompletionItem> ClangdUnit::codeComplete(StringRef Contents,
                                                     Position Pos) {
  CodeCompleteOptions CCO;
  CCO.IncludeBriefComments = 1;
  // This is where code completion stores dirty buffers. Need to free after
  // completion.
  SmallVector<const llvm::MemoryBuffer *, 4> OwnedBuffers;
  SmallVector<StoredDiagnostic, 4> StoredDiagnostics;
  IntrusiveRefCntPtr<DiagnosticsEngine> DiagEngine(
      new DiagnosticsEngine(new DiagnosticIDs, new DiagnosticOptions));
  std::vector<CompletionItem> Items;
  CompletionItemsCollector Collector(&Items, CCO);

  ASTUnit::RemappedFile RemappedSource(
      FileName,
      llvm::MemoryBuffer::getMemBufferCopy(Contents, FileName).release());

  IntrusiveRefCntPtr<SourceManager> SourceMgr(
      new SourceManager(*DiagEngine, Unit->getFileManager()));
  // CodeComplete seems to require fresh LangOptions.
  LangOptions LangOpts = Unit->getLangOpts();
  // The language server protocol uses zero-based line and column numbers.
  // The clang code completion uses one-based numbers.
  Unit->CodeComplete(FileName, Pos.line + 1, Pos.character + 1, RemappedSource,
                     CCO.IncludeMacros, CCO.IncludeCodePatterns,
                     CCO.IncludeBriefComments, Collector, PCHs, *DiagEngine,
                     LangOpts, *SourceMgr, Unit->getFileManager(),
                     StoredDiagnostics, OwnedBuffers);
  for (const llvm::MemoryBuffer *Buffer : OwnedBuffers)
    delete Buffer;
  return Items;
}

namespace {
/// Convert from clang diagnostic level to LSP severity.
static int getSeverity(DiagnosticsEngine::Level L) {
  switch (L) {
  case DiagnosticsEngine::Remark:
    return 4;
  case DiagnosticsEngine::Note:
    return 3;
  case DiagnosticsEngine::Warning:
    return 2;
  case DiagnosticsEngine::Fatal:
  case DiagnosticsEngine::Error:
    return 1;
  case DiagnosticsEngine::Ignored:
    return 0;
  }
  llvm_unreachable("Unknown diagnostic level!");
}
} // namespace

std::vector<DiagWithFixIts> ClangdUnit::getLocalDiagnostics() const {
  std::vector<DiagWithFixIts> Result;
  for (ASTUnit::stored_diag_iterator D = Unit->stored_diag_begin(),
                                     DEnd = Unit->stored_diag_end();
       D != DEnd; ++D) {
    if (!D->getLocation().isValid() ||
        !D->getLocation().getManager().isInMainFile(D->getLocation()))
      continue;
    Position P;
    P.line = D->getLocation().getSpellingLineNumber() - 1;
    P.character = D->getLocation().getSpellingColumnNumber();
    Range R = {P, P};
    clangd::Diagnostic Diag = {R, getSeverity(D->getLevel()), D->getMessage()};

    llvm::SmallVector<tooling::Replacement, 1> FixItsForDiagnostic;
    for (const FixItHint &Fix : D->getFixIts()) {
      FixItsForDiagnostic.push_back(clang::tooling::Replacement(
          Unit->getSourceManager(), Fix.RemoveRange, Fix.CodeToInsert));
    }
    Result.push_back({Diag, std::move(FixItsForDiagnostic)});
  }
  return Result;
}
<|endoftext|>


<commit_before>//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.

// eth_fbsd.cc - A FreeBSD packet filter implementation of
// an ethernet pktmover. There are some problems and limitations
// with FreeBSD:
//   - the source address of the frame is overwritten by
//    the hosts's source address. This causes problems with
//    learning bridges - since they cannot determine where
//    BOCHS 'is', they broadcast the frame to all ports.
//   - packets cannot be sent from BOCHS to the host
//   - TCP performance seems to be abysmal; I think this is
//     a timing problem somewhere.
//   - I haven't handled the case where multiple frames arrive
//     in a single BPF read.
//
//   The /dev/bpf* devices need to be set up with the appropriate
//  permissions for this to work.
//
//   The config line in .bochsrc should look something like:
//
//  ne2k: ioaddr=0x280, irq=9, mac=00:a:b:c:1:2, ethmod=fbsd, ethdev=fxp0
//

#include "bochs.h"
#ifdef ETH_FBSD
#define LOG_THIS this->

extern "C" {
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/bpf.h>
};

#define BX_BPF_POLL  1000    // Poll for a frame every 1000 usecs

#define BX_BPF_BUFSIZ 2048   // enough for an ether frame + bpf hdr

#define BX_BPF_INSNSIZ  8    // number of bpf insns

// template filter for a unicast mac address and all
// multicast/broadcast frames
static const struct bpf_insn macfilter[] = {
  BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
  BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
  BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
  BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
  BPF_STMT(BPF_RET, 1514),
  BPF_STMT(BPF_RET, 0),
};

// template filter for all frames
static const struct bpf_insn promiscfilter[] = {
  BPF_STMT(BPF_RET, 1514)
};

//
//  Define the class. This is private to this module
//
class bx_fbsd_pktmover_c : public eth_pktmover_c {
public:
  bx_fbsd_pktmover_c(const char *netif,
		     const char *macaddr,
		     eth_rx_handler_t rxh,
		     void *rxarg);
  void sendpkt(void *buf, unsigned io_len);

private:
  char *fbsd_macaddr[6];
  int bpf_fd;
  static void rx_timer_handler(void *);
  void rx_timer(void);
  int rx_timer_index;
  struct bpf_insn filter[BX_BPF_INSNSIZ];
  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
};

//
//  Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_fbsd_locator_c : public eth_locator_c {
public:
  bx_fbsd_locator_c(void) : eth_locator_c("fbsd") {}
protected:
  eth_pktmover_c *allocate(const char *netif,
			   const char *macaddr,
			   eth_rx_handler_t rxh,
			   void *rxarg) {
    return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, rxarg));
  }
} bx_fbsd_match;

//
// Define the methods for the bx_fbsd_pktmover derived class
//

// the constructor
//
// Open a bpf file descriptor, and attempt to bind to
// the specified netif (Replicates libpcap open code)
//
bx_fbsd_pktmover_c::bx_fbsd_pktmover_c(const char *netif,
				       const char *macaddr,
				       eth_rx_handler_t rxh,
				       void *rxarg)
{
  char device[sizeof "/dev/bpf000"];
  int tmpfd;
  int n = 0;
  struct ifreq ifr;
  struct bpf_version bv;
  struct bpf_program bp;
  u_int v;

  memcpy(fbsd_macaddr, macaddr, 6);

  do {
    (void)sprintf(device, "/dev/bpf%d", n++);
    this->bpf_fd = open(device, O_RDWR);
  } while (this->bpf_fd < 0);

  if (this->bpf_fd < 0) {
    BX_INFO(("eth_freebsd: could not open packet filter"));
    return;
  }

  if (ioctl(this->bpf_fd, BIOCVERSION, (caddr_t)&bv) < 0) {
    BX_INFO(("eth_freebsd: could not retrieve bpf version"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }
  if (bv.bv_major != BPF_MAJOR_VERSION ||
      bv.bv_minor < BPF_MINOR_VERSION) {
    BX_INFO(("eth_freebsd: bpf version mismatch"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Set buffer size
  v = BX_BPF_BUFSIZ;
  if (ioctl(this->bpf_fd, BIOCSBLEN, (caddr_t)&v) < 0) {
    BX_INFO(("eth_freebsd: could not set buffer size"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  (void)strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
  if (ioctl(this->bpf_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
    BX_INFO(("eth_freebsd: could not enable interface %s", netif));
    close(this->bpf_fd);
    this->bpf_fd == -1;
  }

  // Verify that the device is an ethernet.
  if (ioctl(this->bpf_fd, BIOCGDLT, (caddr_t)&v) < 0) {
    BX_INFO(("eth_freebsd: could not retrieve datalink type"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }
  if (v != DLT_EN10MB) {
    BX_INFO(("eth_freebsd: incorrect datalink type %d", v));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Put the device into promisc mode. This could be optimised
  // to filter on a MAC address, broadcast, and all-multi,
  // but this will do for now.
  //
  if (ioctl(this->bpf_fd, BIOCPROMISC, NULL) < 0) {
    BX_INFO(("eth_freebsd: could not enable promisc mode"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Set up non-blocking i/o
  v = 1;
  if (ioctl(this->bpf_fd, FIONBIO, &v) < 0) {
    BX_INFO(("eth_freebsd: could not enable non-blocking i/o"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Install a filter
#ifdef notdef
  memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
  bp.bf_len   = 1;
#endif
  memcpy(&this->filter, macfilter, sizeof(macfilter));
  this->filter[1].k = (macaddr[2] & 0xff) << 24 |
    (macaddr[3] & 0xff) << 16 |
    (macaddr[4] & 0xff) << 8  |
    (macaddr[5] & 0xff);
  this->filter[3].k = (macaddr[0] & 0xff) << 8 |
    (macaddr[1] & 0xff);
  bp.bf_len   = 8;
  bp.bf_insns = &this->filter[0];
  if (ioctl(this->bpf_fd, BIOCSETF, &bp) < 0) {
    BX_INFO(("eth_freebsd: could not set filter"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Start the rx poll
  this->rx_timer_index =
    bx_pc_system.register_timer(this, this->rx_timer_handler, BX_BPF_POLL,
				1, 1); // continuous, active

  this->rxh   = rxh;
  this->rxarg = rxarg;

#if BX_ETH_FBSD_LOGGING
  // eventually Bryce wants txlog to dump in pcap format so that
  // tcpdump -r FILE can read it and interpret packets.
  txlog = fopen ("ne2k-tx.log", "wb");
  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
  fprintf (txlog_txt, "null packetmover readable log file\n");
  fprintf (txlog_txt, "net IF = %s\n", netif);
  fprintf (txlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (txlog_txt, "\n--\n");
  fflush (txlog_txt);
#endif
}

// the output routine - called with pre-formatted ethernet frame.
void
bx_fbsd_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#if BX_ETH_FBSD_LOGGING
  BX_DEBUG (("sendpkt length %u", io_len));
  // dump raw bytes to a file, eventually dump in pcap format so that
  // tcpdump -r FILE can interpret them for us.
  int n = fwrite (buf, io_len, 1, txlog);
  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
  // dump packet in hex into an ascii log file
  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
  Bit8u *charbuf = (Bit8u *)buf;
  for (n=0; n<io_len; n++) {
    if (((n % 16) == 0) && n>0)
      fprintf (txlog_txt, "\n");
    fprintf (txlog_txt, "%02x ", charbuf[n]);
  }
  fprintf (txlog_txt, "\n--\n");
  // flush log so that we see the packets as they arrive w/o buffering
  fflush (txlog);
  fflush (txlog_txt);
#endif
  int status;

  if (this->bpf_fd != -1)
    status = write(this->bpf_fd, buf, io_len);
}

// The receive poll process
void
bx_fbsd_pktmover_c::rx_timer_handler(void *this_ptr)
{
  bx_fbsd_pktmover_c *class_ptr = (bx_fbsd_pktmover_c *) this_ptr;

  class_ptr->rx_timer();
}

void
bx_fbsd_pktmover_c::rx_timer(void)
{
  int nbytes = 0;
  Bit8u rxbuf[BX_BPF_BUFSIZ];
  struct bpf_hdr *bhdr;

  nbytes = read(this->bpf_fd, rxbuf, sizeof(rxbuf));

  if (nbytes > 0) {
    bhdr = (struct bpf_hdr *) rxbuf;

    // filter out packets sourced from this node
    if (memcmp(rxbuf + bhdr->bh_hdrlen + 6, this->fbsd_macaddr, 6)) {
      (*rxh)(rxarg, rxbuf + bhdr->bh_hdrlen, bhdr->bh_caplen);
    }
#if BX_ETH_FBSD_LOGGING
  /// hey wait there is no receive data with a NULL ethernet, is there....
  if (nbytes > 0) {
    BX_DEBUG (("receive packet length %u", nbytes));
    // dump raw bytes to a file, eventually dump in pcap format so that
    // tcpdump -r FILE can interpret them for us.
    int n = fwrite (rxbuf, nbytes, 1, this->rxlog);
    if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
    // dump packet in hex into an ascii log file
    fprintf (this->rxlog_txt, "NE2K transmitting a packet, length %u\n", nbytes);
    Bit8u *charrxbuf = (Bit8u *)rxbuf;
    for (n=0; n<nbytes; n++) {
      if (((n % 16) == 0) && n>0)
	fprintf (this->rxlog_txt, "\n");
      fprintf (this->rxlog_txt, "%02x ", charbuf[n]);
    }
    fprintf (this->rxlog_txt, "\n--\n");
    // flush log so that we see the packets as they arrive w/o buffering
    fflush (this->rxlog);
    fflush (this->rxlog_txt);
  }
#endif

  }
}
#endif

<commit_msg>- oops, renamed charbuf to rxbuf<commit_after>//  Copyright (C) 2001  MandrakeSoft S.A.
//
//    MandrakeSoft S.A.
//    43, rue d'Aboukir
//    75002 Paris - France
//    http://www.linux-mandrake.com/
//    http://www.mandrakesoft.com/
//
//  This library is free software; you can redistribute it and/or
//  modify it under the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either
//  version 2 of the License, or (at your option) any later version.
//
//  This library is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//  Lesser General Public License for more details.
//
//  You should have received a copy of the GNU Lesser General Public
//  License along with this library; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

// Peter Grehan (grehan@iprg.nokia.com) coded all of this
// NE2000/ether stuff.

// eth_fbsd.cc - A FreeBSD packet filter implementation of
// an ethernet pktmover. There are some problems and limitations
// with FreeBSD:
//   - the source address of the frame is overwritten by
//    the hosts's source address. This causes problems with
//    learning bridges - since they cannot determine where
//    BOCHS 'is', they broadcast the frame to all ports.
//   - packets cannot be sent from BOCHS to the host
//   - TCP performance seems to be abysmal; I think this is
//     a timing problem somewhere.
//   - I haven't handled the case where multiple frames arrive
//     in a single BPF read.
//
//   The /dev/bpf* devices need to be set up with the appropriate
//  permissions for this to work.
//
//   The config line in .bochsrc should look something like:
//
//  ne2k: ioaddr=0x280, irq=9, mac=00:a:b:c:1:2, ethmod=fbsd, ethdev=fxp0
//

#include "bochs.h"
#ifdef ETH_FBSD
#define LOG_THIS this->

extern "C" {
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/bpf.h>
};

#define BX_BPF_POLL  1000    // Poll for a frame every 1000 usecs

#define BX_BPF_BUFSIZ 2048   // enough for an ether frame + bpf hdr

#define BX_BPF_INSNSIZ  8    // number of bpf insns

// template filter for a unicast mac address and all
// multicast/broadcast frames
static const struct bpf_insn macfilter[] = {
  BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2),
  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0xaaaaaaaa, 0, 2),
  BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 0),
  BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0000aaaa, 2, 0),
  BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 0),
  BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x01, 0, 1),
  BPF_STMT(BPF_RET, 1514),
  BPF_STMT(BPF_RET, 0),
};

// template filter for all frames
static const struct bpf_insn promiscfilter[] = {
  BPF_STMT(BPF_RET, 1514)
};

//
//  Define the class. This is private to this module
//
class bx_fbsd_pktmover_c : public eth_pktmover_c {
public:
  bx_fbsd_pktmover_c(const char *netif,
		     const char *macaddr,
		     eth_rx_handler_t rxh,
		     void *rxarg);
  void sendpkt(void *buf, unsigned io_len);

private:
  char *fbsd_macaddr[6];
  int bpf_fd;
  static void rx_timer_handler(void *);
  void rx_timer(void);
  int rx_timer_index;
  struct bpf_insn filter[BX_BPF_INSNSIZ];
  FILE *txlog, *txlog_txt, *rxlog, *rxlog_txt;
};

//
//  Define the static class that registers the derived pktmover class,
// and allocates one on request.
//
class bx_fbsd_locator_c : public eth_locator_c {
public:
  bx_fbsd_locator_c(void) : eth_locator_c("fbsd") {}
protected:
  eth_pktmover_c *allocate(const char *netif,
			   const char *macaddr,
			   eth_rx_handler_t rxh,
			   void *rxarg) {
    return (new bx_fbsd_pktmover_c(netif, macaddr, rxh, rxarg));
  }
} bx_fbsd_match;

//
// Define the methods for the bx_fbsd_pktmover derived class
//

// the constructor
//
// Open a bpf file descriptor, and attempt to bind to
// the specified netif (Replicates libpcap open code)
//
bx_fbsd_pktmover_c::bx_fbsd_pktmover_c(const char *netif,
				       const char *macaddr,
				       eth_rx_handler_t rxh,
				       void *rxarg)
{
  char device[sizeof "/dev/bpf000"];
  int tmpfd;
  int n = 0;
  struct ifreq ifr;
  struct bpf_version bv;
  struct bpf_program bp;
  u_int v;

  memcpy(fbsd_macaddr, macaddr, 6);

  do {
    (void)sprintf(device, "/dev/bpf%d", n++);
    this->bpf_fd = open(device, O_RDWR);
  } while (this->bpf_fd < 0);

  if (this->bpf_fd < 0) {
    BX_INFO(("eth_freebsd: could not open packet filter"));
    return;
  }

  if (ioctl(this->bpf_fd, BIOCVERSION, (caddr_t)&bv) < 0) {
    BX_INFO(("eth_freebsd: could not retrieve bpf version"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }
  if (bv.bv_major != BPF_MAJOR_VERSION ||
      bv.bv_minor < BPF_MINOR_VERSION) {
    BX_INFO(("eth_freebsd: bpf version mismatch"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Set buffer size
  v = BX_BPF_BUFSIZ;
  if (ioctl(this->bpf_fd, BIOCSBLEN, (caddr_t)&v) < 0) {
    BX_INFO(("eth_freebsd: could not set buffer size"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  (void)strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name));
  if (ioctl(this->bpf_fd, BIOCSETIF, (caddr_t)&ifr) < 0) {
    BX_INFO(("eth_freebsd: could not enable interface %s", netif));
    close(this->bpf_fd);
    this->bpf_fd == -1;
  }

  // Verify that the device is an ethernet.
  if (ioctl(this->bpf_fd, BIOCGDLT, (caddr_t)&v) < 0) {
    BX_INFO(("eth_freebsd: could not retrieve datalink type"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }
  if (v != DLT_EN10MB) {
    BX_INFO(("eth_freebsd: incorrect datalink type %d", v));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Put the device into promisc mode. This could be optimised
  // to filter on a MAC address, broadcast, and all-multi,
  // but this will do for now.
  //
  if (ioctl(this->bpf_fd, BIOCPROMISC, NULL) < 0) {
    BX_INFO(("eth_freebsd: could not enable promisc mode"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Set up non-blocking i/o
  v = 1;
  if (ioctl(this->bpf_fd, FIONBIO, &v) < 0) {
    BX_INFO(("eth_freebsd: could not enable non-blocking i/o"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Install a filter
#ifdef notdef
  memcpy(&this->filter, promiscfilter, sizeof(promiscfilter));
  bp.bf_len   = 1;
#endif
  memcpy(&this->filter, macfilter, sizeof(macfilter));
  this->filter[1].k = (macaddr[2] & 0xff) << 24 |
    (macaddr[3] & 0xff) << 16 |
    (macaddr[4] & 0xff) << 8  |
    (macaddr[5] & 0xff);
  this->filter[3].k = (macaddr[0] & 0xff) << 8 |
    (macaddr[1] & 0xff);
  bp.bf_len   = 8;
  bp.bf_insns = &this->filter[0];
  if (ioctl(this->bpf_fd, BIOCSETF, &bp) < 0) {
    BX_INFO(("eth_freebsd: could not set filter"));
    close(this->bpf_fd);
    this->bpf_fd = -1;
    return;
  }

  // Start the rx poll
  this->rx_timer_index =
    bx_pc_system.register_timer(this, this->rx_timer_handler, BX_BPF_POLL,
				1, 1); // continuous, active

  this->rxh   = rxh;
  this->rxarg = rxarg;

#if BX_ETH_FBSD_LOGGING
  // eventually Bryce wants txlog to dump in pcap format so that
  // tcpdump -r FILE can read it and interpret packets.
  txlog = fopen ("ne2k-tx.log", "wb");
  if (!txlog) BX_PANIC (("open ne2k-tx.log failed"));
  txlog_txt = fopen ("ne2k-txdump.txt", "wb");
  if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed"));
  fprintf (txlog_txt, "null packetmover readable log file\n");
  fprintf (txlog_txt, "net IF = %s\n", netif);
  fprintf (txlog_txt, "MAC address = ");
  for (int i=0; i<6; i++)
    fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : "");
  fprintf (txlog_txt, "\n--\n");
  fflush (txlog_txt);
#endif
}

// the output routine - called with pre-formatted ethernet frame.
void
bx_fbsd_pktmover_c::sendpkt(void *buf, unsigned io_len)
{
#if BX_ETH_FBSD_LOGGING
  BX_DEBUG (("sendpkt length %u", io_len));
  // dump raw bytes to a file, eventually dump in pcap format so that
  // tcpdump -r FILE can interpret them for us.
  int n = fwrite (buf, io_len, 1, txlog);
  if (n != 1) BX_ERROR (("fwrite to txlog failed", io_len));
  // dump packet in hex into an ascii log file
  fprintf (txlog_txt, "NE2K transmitting a packet, length %u\n", io_len);
  Bit8u *charbuf = (Bit8u *)buf;
  for (n=0; n<io_len; n++) {
    if (((n % 16) == 0) && n>0)
      fprintf (txlog_txt, "\n");
    fprintf (txlog_txt, "%02x ", charbuf[n]);
  }
  fprintf (txlog_txt, "\n--\n");
  // flush log so that we see the packets as they arrive w/o buffering
  fflush (txlog);
  fflush (txlog_txt);
#endif
  int status;

  if (this->bpf_fd != -1)
    status = write(this->bpf_fd, buf, io_len);
}

// The receive poll process
void
bx_fbsd_pktmover_c::rx_timer_handler(void *this_ptr)
{
  bx_fbsd_pktmover_c *class_ptr = (bx_fbsd_pktmover_c *) this_ptr;

  class_ptr->rx_timer();
}

void
bx_fbsd_pktmover_c::rx_timer(void)
{
  int nbytes = 0;
  Bit8u rxbuf[BX_BPF_BUFSIZ];
  struct bpf_hdr *bhdr;

  nbytes = read(this->bpf_fd, rxbuf, sizeof(rxbuf));

  if (nbytes > 0) {
    bhdr = (struct bpf_hdr *) rxbuf;

    // filter out packets sourced from this node
    if (memcmp(rxbuf + bhdr->bh_hdrlen + 6, this->fbsd_macaddr, 6)) {
      (*rxh)(rxarg, rxbuf + bhdr->bh_hdrlen, bhdr->bh_caplen);
    }
#if BX_ETH_FBSD_LOGGING
  /// hey wait there is no receive data with a NULL ethernet, is there....
  if (nbytes > 0) {
    BX_DEBUG (("receive packet length %u", nbytes));
    // dump raw bytes to a file, eventually dump in pcap format so that
    // tcpdump -r FILE can interpret them for us.
    int n = fwrite (rxbuf, nbytes, 1, this->rxlog);
    if (n != 1) BX_ERROR (("fwrite to rxlog failed", nbytes));
    // dump packet in hex into an ascii log file
    fprintf (this->rxlog_txt, "NE2K transmitting a packet, length %u\n", nbytes);
    Bit8u *charrxbuf = (Bit8u *)rxbuf;
    for (n=0; n<nbytes; n++) {
      if (((n % 16) == 0) && n>0)
	fprintf (this->rxlog_txt, "\n");
      fprintf (this->rxlog_txt, "%02x ", rxbuf[n]);
    }
    fprintf (this->rxlog_txt, "\n--\n");
    // flush log so that we see the packets as they arrive w/o buffering
    fflush (this->rxlog);
    fflush (this->rxlog_txt);
  }
#endif

  }
}
#endif

<|endoftext|>


<commit_before>#include "stdsneezy.h"
#include "database.h"
#include "shop.h"
#include "shopowned.h"

void calcBankInterest()
{
  TDatabase db(DB_SNEEZY), in(DB_SNEEZY);
  float profit_sell;
  unsigned int shop_nr;
  int pretalens=0, posttalens=0;

  db.query("select shop_nr, keeper from shop");

  while(db.fetchRow()){
    if(mob_index[real_mobile(convertTo<int>(db["keeper"]))].spec==SPEC_BANKER){
      shop_nr=convertTo<int>(db["shop_nr"]);
      profit_sell=shop_index[shop_nr].profit_sell;

      if(profit_sell==1.0)
	continue;

      in.query("select sum(talens) as talens from shopownedbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	pretalens=convertTo<int>(in["talens"]);

      in.query("select sum(talens) as talens from shopownedcorpbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	pretalens+=convertTo<int>(in["talens"]);

      in.query("update shopownedbank set talens=talens * %f where shop_nr=%i",
	       1.0+(profit_sell/365.0), shop_nr);
      in.query("update shopownedcorpbank set talens=talens * %f where shop_nr=%i",
	       1.0+(profit_sell/365.0), shop_nr);

      in.query("select sum(talens) as talens from shopownedbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	posttalens=convertTo<int>(in["talens"]);

      in.query("select sum(talens) as talens from shopownedcorpbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	posttalens+=convertTo<int>(in["talens"]);

      if((posttalens-pretalens) !=0)
	in.query("insert into shoplog values (%i, 'unknown', 'paying interest', 'all', %i, 0, 0, now(), 0)", shop_nr, posttalens-pretalens);

    }
  }
}

int bankWithdraw(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  if (!ch->isPc() || dynamic_cast<TMonster *>(ch)) {
    teller->doTell(ch->getName(), "Stupid monster can't bank here!");
    return TRUE;
  }

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return FALSE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  if (money > bankmoney) {
    teller->doTell(ch->getName(), "You don't have enough in the bank for that!");
    return TRUE;
  } else if(myself->getMoney() < money){
    teller->doTell(ch->getName(), "The bank doesn't have your funds available right now!");
    return TRUE;
  } else if (money <= 0) {
    teller->doTell(ch->getName(), "Go away, you bother me.");
    return TRUE;
  }

  teller->doTell(ch->getName(), "Thank you.");
  myself->giveMoney(ch, money, GOLD_XFER);
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  db.query("update shopownedbank set talens=talens-%i where player_id=%i and shop_nr=%i", money, ch->getPlayerID(), shop_nr);

  shoplog(shop_nr, ch, myself, "talens", -money, "withdrawal");

  return TRUE;
}

int bankDeposit(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  if (!ch->isPc() || dynamic_cast<TMonster *>(ch)) {
    teller->doTell(ch->getName(), "Stupid monster can't bank here!");
    return TRUE;
  }

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return TRUE;
  }

  if (money <= 0) {
    teller->doTell(ch->getName(), "Go away, you bother me.");
    return TRUE;
  } else if (money > ch->getMoney()) {
    teller->doTell(ch->getName(), "You don't have enough for that!");
    return TRUE;
  }

  teller->doTell(ch->getName(), "Thank you.");
  ch->giveMoney(myself, money, GOLD_XFER);
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  db.query("update shopownedbank set talens=talens+%i where player_id=%i and shop_nr=%i", money, ch->getPlayerID(), shop_nr);

  shoplog(shop_nr, ch, myself, "talens", money, "deposit");

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if (!db.fetchRow()) {
    teller->doTell(ch->getName(), "You really should not see me, this is an error...");
    vlogf(LOG_BUG, fmt("Banking error, was unable to retrieve balance after a deposit: %s") % ch->getName());

    return TRUE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  teller->doTell(ch->getName(), fmt("...Your new balance is %i") % bankmoney);

  return TRUE;
}

int bankBalance(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return TRUE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  teller->doTell(ch->getName(), fmt("Your balance is %i.") % bankmoney);

  return TRUE;
}

int bankBuyAccount(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);

  if(ch->getMoney() < 100){
    teller->doTell(ch->getName(), "You don't have enough money to open an account.");
    return TRUE;
  }

  db.query("select talens from shopownedbank where player_id=%i and shop_nr=%i", ch->getPlayerID(), shop_nr);

  if(db.fetchRow()){
    teller->doTell(ch->getName(), "You already have an account.");
    return TRUE;
  }

  db.query("insert into shopownedbank (player_id, shop_nr, talens) values (%i, %i, 0)", ch->getPlayerID(), shop_nr);
  ch->giveMoney(myself, 100, GOLD_XFER);
  shoplog(shop_nr, ch, myself, "talens", 100, "new account");
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  teller->doTell(ch->getName(), "Your account is now open and ready for use.");

  return TRUE;
}

int banker(TBeing *ch, cmdTypeT cmd, const char *arg, TMonster *myself, TObj *)
{
  int shop_nr, money=0;
  TDatabase db(DB_SNEEZY);

  if((cmd!=CMD_WITHDRAW &&
      cmd!=CMD_DEPOSIT &&
      cmd!=CMD_BUY &&
      cmd!=CMD_LIST &&
      cmd!=CMD_BALANCE &&
      cmd!=CMD_WHISPER) ||
     !ch || !myself)
    return FALSE;

  if(!(shop_nr=find_shop_nr(myself->number)))
    return FALSE;

  if(cmd==CMD_WHISPER)
    return shopWhisper(ch, myself, shop_nr, arg);

  if(cmd==CMD_LIST){
    TShopOwned tso(shop_nr, myself, ch);

    if(!tso.hasAccess(SHOPACCESS_LOGS)){
      myself->doTell(ch->getName(), "Sorry, you don't have access to do that.");
      return FALSE;
    }

    db.query("select p.name, b.talens from player p, shopownedbank b where b.shop_nr=%i and b.player_id=p.id union select c.name, b.talens from corporation c, shopownedcorpbank b where b.shop_nr=c.bank and b.shop_nr=%i and b.corp_id=c.corp_id order by talens desc", shop_nr, shop_nr);

    sstring buf;
    while(db.fetchRow()){
      buf += fmt("<c>%s - %s talens.<1>\n\r") % db["name"] %
	talenDisplay(convertTo<int>(db["talens"]));
    }

    db.query("select (sb.c+sbc.c) as c, (sb.t+sbc.t) as t from (select count(*) as c, sum(talens) as t from shopownedbank where shop_nr=%i) sb, (select count(*) as c, sum(talens) as t from shopownedcorpbank where shop_nr=%i) sbc", shop_nr, shop_nr);

    if(db.fetchRow()){
      buf += fmt("%i accounts, %s talens.\n\r") %
	convertTo<int>(db["c"]) %
	talenDisplay(convertTo<int>(db["t"]));
    }

    ch->desc->page_string(buf);

    return TRUE;
  }

  if(cmd==CMD_BUY && sstring(arg).lower()=="account"){
    money=convertTo<int>(arg);
    return bankBuyAccount(ch, myself, myself, shop_nr, money);
  } else if(cmd==CMD_BALANCE){
    return bankBalance(ch, myself, myself, shop_nr);
  } else if(cmd==CMD_WITHDRAW){
    if(!strcmp(arg, "all"))
      money=ch->getBank();
    else
      money=convertTo<int>(arg);

    return bankWithdraw(ch, myself, myself, shop_nr, money);
  } else if(cmd==CMD_DEPOSIT){
    if(!strcmp(arg, "all"))
      money=ch->getMoney();
    else
      money=convertTo<int>(arg);
    return bankDeposit(ch, myself, myself, shop_nr, money);
  }

  return TRUE;
}

int bankRoom(TBeing *ch, cmdTypeT cmd, const char *arg, TRoom *rp)
{
  TMonster *teller, *banker;
  TBeing *t;
  int tmp=130, money, shop_nr;

  // tellers/branches can only do these commands
  if(cmd!=CMD_WITHDRAW &&
     cmd!=CMD_DEPOSIT &&
     cmd!=CMD_BALANCE &&
     cmd!=CMD_BUY)
    return FALSE;

  // find out which teller for this room
  switch(rp->number){
    case 31751:
    case 31756:
    case 2351:
      tmp=31750;
      break;
    case 1295:
      tmp=1295;
      break;
    case 3755:
      tmp=3755;
      break;
    case 8756:
      tmp=8756;
      break;
  }

  // find the teller
  for(t=character_list;t;t=t->next){
    if(t->mobVnum()==tmp)
      break;
  }

  if(!t || !(teller=dynamic_cast<TMonster *>(t)))
    return FALSE;

  // find out which banker for this room
  switch(rp->number){
    case 31751:
    case 31756:
    case 2351:
      tmp=31765;
      break;
    case 1295:
      tmp=1295;
      break;
    case 3755:
      tmp=3755;
      break;
    case 8756:
      tmp=8756;
      break;
  }

  // find the banker
  for(t=character_list;t;t=t->next){
    if(t->mobVnum()==tmp)
      break;
  }

  if(!t || !(banker=dynamic_cast<TMonster *>(t)))
    return FALSE;

  if(!(shop_nr=find_shop_nr(banker->number)))
    return FALSE;

  if(cmd==CMD_BUY && sstring(arg).lower()=="account"){
    money=convertTo<int>(arg);
    return bankBuyAccount(ch, banker, teller, shop_nr, money);
  } else if(cmd==CMD_BALANCE){
    return bankBalance(ch, banker, teller, shop_nr);
  } else if(cmd==CMD_WITHDRAW){
    if(!strcmp(arg, "all"))
      money=ch->getBank();
    else
      money=convertTo<int>(arg);
    return bankWithdraw(ch, banker, teller, shop_nr, money);
  } else if(cmd==CMD_DEPOSIT){
    if(!strcmp(arg, "all"))
      money=ch->getMoney();
    else
      money=convertTo<int>(arg);
    return bankDeposit(ch, banker, teller, shop_nr, money);
  }

  return FALSE;
}

<commit_msg>added empty account tallie<commit_after>#include "stdsneezy.h"
#include "database.h"
#include "shop.h"
#include "shopowned.h"

void calcBankInterest()
{
  TDatabase db(DB_SNEEZY), in(DB_SNEEZY);
  float profit_sell;
  unsigned int shop_nr;
  int pretalens=0, posttalens=0;

  db.query("select shop_nr, keeper from shop");

  while(db.fetchRow()){
    if(mob_index[real_mobile(convertTo<int>(db["keeper"]))].spec==SPEC_BANKER){
      shop_nr=convertTo<int>(db["shop_nr"]);
      profit_sell=shop_index[shop_nr].profit_sell;

      if(profit_sell==1.0)
	continue;

      in.query("select sum(talens) as talens from shopownedbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	pretalens=convertTo<int>(in["talens"]);

      in.query("select sum(talens) as talens from shopownedcorpbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	pretalens+=convertTo<int>(in["talens"]);

      in.query("update shopownedbank set talens=talens * %f where shop_nr=%i",
	       1.0+(profit_sell/365.0), shop_nr);
      in.query("update shopownedcorpbank set talens=talens * %f where shop_nr=%i",
	       1.0+(profit_sell/365.0), shop_nr);

      in.query("select sum(talens) as talens from shopownedbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	posttalens=convertTo<int>(in["talens"]);

      in.query("select sum(talens) as talens from shopownedcorpbank where shop_nr=%i",
	       shop_nr);
      if(in.fetchRow())
	posttalens+=convertTo<int>(in["talens"]);

      if((posttalens-pretalens) !=0)
	in.query("insert into shoplog values (%i, 'unknown', 'paying interest', 'all', %i, 0, 0, now(), 0)", shop_nr, posttalens-pretalens);

    }
  }
}

int bankWithdraw(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  if (!ch->isPc() || dynamic_cast<TMonster *>(ch)) {
    teller->doTell(ch->getName(), "Stupid monster can't bank here!");
    return TRUE;
  }

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return FALSE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  if (money > bankmoney) {
    teller->doTell(ch->getName(), "You don't have enough in the bank for that!");
    return TRUE;
  } else if(myself->getMoney() < money){
    teller->doTell(ch->getName(), "The bank doesn't have your funds available right now!");
    return TRUE;
  } else if (money <= 0) {
    teller->doTell(ch->getName(), "Go away, you bother me.");
    return TRUE;
  }

  teller->doTell(ch->getName(), "Thank you.");
  myself->giveMoney(ch, money, GOLD_XFER);
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  db.query("update shopownedbank set talens=talens-%i where player_id=%i and shop_nr=%i", money, ch->getPlayerID(), shop_nr);

  shoplog(shop_nr, ch, myself, "talens", -money, "withdrawal");

  return TRUE;
}

int bankDeposit(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  if (!ch->isPc() || dynamic_cast<TMonster *>(ch)) {
    teller->doTell(ch->getName(), "Stupid monster can't bank here!");
    return TRUE;
  }

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return TRUE;
  }

  if (money <= 0) {
    teller->doTell(ch->getName(), "Go away, you bother me.");
    return TRUE;
  } else if (money > ch->getMoney()) {
    teller->doTell(ch->getName(), "You don't have enough for that!");
    return TRUE;
  }

  teller->doTell(ch->getName(), "Thank you.");
  ch->giveMoney(myself, money, GOLD_XFER);
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  db.query("update shopownedbank set talens=talens+%i where player_id=%i and shop_nr=%i", money, ch->getPlayerID(), shop_nr);

  shoplog(shop_nr, ch, myself, "talens", money, "deposit");

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if (!db.fetchRow()) {
    teller->doTell(ch->getName(), "You really should not see me, this is an error...");
    vlogf(LOG_BUG, fmt("Banking error, was unable to retrieve balance after a deposit: %s") % ch->getName());

    return TRUE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  teller->doTell(ch->getName(), fmt("...Your new balance is %i") % bankmoney);

  return TRUE;
}

int bankBalance(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr)
{
  TDatabase db(DB_SNEEZY);
  int bankmoney;

  db.query("select talens from shopownedbank where shop_nr=%i and player_id=%i", shop_nr, ch->getPlayerID());

  if(!db.fetchRow()){
    teller->doTell(ch->getName(), "You don't have an account here.");
    teller->doTell(ch->getName(), "To open an account, type 'buy account'.");
    teller->doTell(ch->getName(), "The new account fee is 100 talens.");
    return TRUE;
  } else
    bankmoney = convertTo<int>(db["talens"]);

  teller->doTell(ch->getName(), fmt("Your balance is %i.") % bankmoney);

  return TRUE;
}

int bankBuyAccount(TBeing *ch, TMonster *myself, TMonster *teller, int shop_nr, int money)
{
  TDatabase db(DB_SNEEZY);

  if(ch->getMoney() < 100){
    teller->doTell(ch->getName(), "You don't have enough money to open an account.");
    return TRUE;
  }

  db.query("select talens from shopownedbank where player_id=%i and shop_nr=%i", ch->getPlayerID(), shop_nr);

  if(db.fetchRow()){
    teller->doTell(ch->getName(), "You already have an account.");
    return TRUE;
  }

  db.query("insert into shopownedbank (player_id, shop_nr, talens) values (%i, %i, 0)", ch->getPlayerID(), shop_nr);
  ch->giveMoney(myself, 100, GOLD_XFER);
  shoplog(shop_nr, ch, myself, "talens", 100, "new account");
  myself->saveItems(fmt("%s/%d") % SHOPFILE_PATH % shop_nr);

  teller->doTell(ch->getName(), "Your account is now open and ready for use.");

  return TRUE;
}

int banker(TBeing *ch, cmdTypeT cmd, const char *arg, TMonster *myself, TObj *)
{
  int shop_nr, money=0;
  TDatabase db(DB_SNEEZY);

  if((cmd!=CMD_WITHDRAW &&
      cmd!=CMD_DEPOSIT &&
      cmd!=CMD_BUY &&
      cmd!=CMD_LIST &&
      cmd!=CMD_BALANCE &&
      cmd!=CMD_WHISPER) ||
     !ch || !myself)
    return FALSE;

  if(!(shop_nr=find_shop_nr(myself->number)))
    return FALSE;

  if(cmd==CMD_WHISPER)
    return shopWhisper(ch, myself, shop_nr, arg);

  if(cmd==CMD_LIST){
    TShopOwned tso(shop_nr, myself, ch);

    if(!tso.hasAccess(SHOPACCESS_LOGS)){
      myself->doTell(ch->getName(), "Sorry, you don't have access to do that.");
      return FALSE;
    }

    db.query("select p.name, b.talens from player p, shopownedbank b where b.shop_nr=%i and b.player_id=p.id union select c.name, b.talens from corporation c, shopownedcorpbank b where b.shop_nr=c.bank and b.shop_nr=%i and b.corp_id=c.corp_id order by talens desc", shop_nr, shop_nr);

    sstring buf;
    int empty=0;
    while(db.fetchRow()){
      if(convertTo<int>(db["talens"]) == 0)
	empty++;
      else
	buf += fmt("<c>%s - %s talens.<1>\n\r") % db["name"] %
	  talenDisplay(convertTo<int>(db["talens"]));
    }
    buf += fmt("%i empty accounts.\n\r") % empty;

    db.query("select (sb.c+sbc.c) as c, (sb.t+sbc.t) as t from (select count(*) as c, sum(talens) as t from shopownedbank where shop_nr=%i) sb, (select count(*) as c, sum(talens) as t from shopownedcorpbank where shop_nr=%i) sbc", shop_nr, shop_nr);

    if(db.fetchRow()){
      buf += fmt("%i total accounts, %s talens.\n\r") %
	convertTo<int>(db["c"]) %
	talenDisplay(convertTo<int>(db["t"]));
    }

    ch->desc->page_string(buf);

    return TRUE;
  }

  if(cmd==CMD_BUY && sstring(arg).lower()=="account"){
    money=convertTo<int>(arg);
    return bankBuyAccount(ch, myself, myself, shop_nr, money);
  } else if(cmd==CMD_BALANCE){
    return bankBalance(ch, myself, myself, shop_nr);
  } else if(cmd==CMD_WITHDRAW){
    if(!strcmp(arg, "all"))
      money=ch->getBank();
    else
      money=convertTo<int>(arg);

    return bankWithdraw(ch, myself, myself, shop_nr, money);
  } else if(cmd==CMD_DEPOSIT){
    if(!strcmp(arg, "all"))
      money=ch->getMoney();
    else
      money=convertTo<int>(arg);
    return bankDeposit(ch, myself, myself, shop_nr, money);
  }

  return TRUE;
}

int bankRoom(TBeing *ch, cmdTypeT cmd, const char *arg, TRoom *rp)
{
  TMonster *teller, *banker;
  TBeing *t;
  int tmp=130, money, shop_nr;

  // tellers/branches can only do these commands
  if(cmd!=CMD_WITHDRAW &&
     cmd!=CMD_DEPOSIT &&
     cmd!=CMD_BALANCE &&
     cmd!=CMD_BUY)
    return FALSE;

  // find out which teller for this room
  switch(rp->number){
    case 31751:
    case 31756:
    case 2351:
      tmp=31750;
      break;
    case 1295:
      tmp=1295;
      break;
    case 3755:
      tmp=3755;
      break;
    case 8756:
      tmp=8756;
      break;
  }

  // find the teller
  for(t=character_list;t;t=t->next){
    if(t->mobVnum()==tmp)
      break;
  }

  if(!t || !(teller=dynamic_cast<TMonster *>(t)))
    return FALSE;

  // find out which banker for this room
  switch(rp->number){
    case 31751:
    case 31756:
    case 2351:
      tmp=31765;
      break;
    case 1295:
      tmp=1295;
      break;
    case 3755:
      tmp=3755;
      break;
    case 8756:
      tmp=8756;
      break;
  }

  // find the banker
  for(t=character_list;t;t=t->next){
    if(t->mobVnum()==tmp)
      break;
  }

  if(!t || !(banker=dynamic_cast<TMonster *>(t)))
    return FALSE;

  if(!(shop_nr=find_shop_nr(banker->number)))
    return FALSE;

  if(cmd==CMD_BUY && sstring(arg).lower()=="account"){
    money=convertTo<int>(arg);
    return bankBuyAccount(ch, banker, teller, shop_nr, money);
  } else if(cmd==CMD_BALANCE){
    return bankBalance(ch, banker, teller, shop_nr);
  } else if(cmd==CMD_WITHDRAW){
    if(!strcmp(arg, "all"))
      money=ch->getBank();
    else
      money=convertTo<int>(arg);
    return bankWithdraw(ch, banker, teller, shop_nr, money);
  } else if(cmd==CMD_DEPOSIT){
    if(!strcmp(arg, "all"))
      money=ch->getMoney();
    else
      money=convertTo<int>(arg);
    return bankDeposit(ch, banker, teller, shop_nr, money);
  }

  return FALSE;
}

<|endoftext|>


<commit_before>#pragma once

#include <iostream>
#include <chrono>
#include <mutex>

#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>

// Helpers
namespace
{
	// For differences between quaternions.
	struct AngleAxis
	{
		float     angle;
		glm::vec3 axis;

		AngleAxis( float _angle=0.0f, glm::vec3 _axis={} ) : angle(_angle), axis(_axis) {}
	};

	AngleAxis operator* ( const AngleAxis& lhs, float rhs )
	{
		AngleAxis result{ lhs.angle, lhs.axis };
		result.angle *= rhs;
		return result;
	}

	AngleAxis operator/ ( const AngleAxis& lhs, float rhs )
	{
		AngleAxis result{ lhs.angle, lhs.axis };
		result.angle /= rhs;
		return result;
	}

	// Difference
	template <typename T>
	inline T _minus( const T& lhs={}, const T& rhs={} )
	{
		return lhs - rhs;
	}

	// Difference between quaternions
	inline AngleAxis _minus( const glm::quat& lhs, const glm::quat& rhs )
	{
		auto quatDelta = lhs * glm::inverse(rhs);
		return AngleAxis{ glm::angle( quatDelta ), glm::axis( quatDelta ) };;
	}

	// Addition
	template <typename T, typename RHT=T>
	inline T _plus( const T& lhs={}, const RHT& rhs={} )
	{
		return lhs + rhs;
	}

	template <>
	inline glm::quat _plus( const glm::quat& lhs, const AngleAxis& rhs )
	{
		auto rot = glm::angleAxis( rhs.angle, rhs.axis );
		return lhs * rot;
	}

	// Division
	template <typename T, typename S=float>
	inline T _scalarDivide( const T& lhs={}, S rhs={1.f} )
	{
		if( rhs == 0.0 ) rhs = S{ 1.f };
		return lhs / rhs;
	}

	// Multiplying
	template <typename T, typename S=float>
	inline T _scalarMultiply( const T& lhs={}, S rhs={1.f} )
	{
		return lhs * rhs;
	}
}

template <typename T, typename DeltaType=decltype( _minus( T{}, T{} ) )>
struct Smooth
{
	typedef std::chrono::high_resolution_clock::time_point HiResTimePoint;
	typedef T ValueType;

	Smooth( T startValue={} )
	{
		value = startValue;
		guess = startValue;
	}

	Smooth( T&& startValue )
	{
		value = T{ std::forward( startValue ) };
		guess = value;
	}

	Smooth& operator=( const T& startValue )
	{
		value = startValue;
		guess = value;
		return *this;
	}

	void Update( const T& newValue )
	{
		std::lock_guard<mutex> valueLock( mut );
		auto currentTime = HiResTimePoint::clock::now();
		auto deltaTime   = DeltaTime( currentTime );
		DeltaType deltaValue = _minus( newValue, value );

		lastUpdate = currentTime;
		speed = _scalarDivide( deltaValue, deltaTime );

		value = newValue;
		guess = newValue;
	}

	void Calculate( const float& stepMultiplier={1.f} )
	{
		std::lock_guard<mutex> valueLock( mut );
		auto deltaTime = DeltaTime( HiResTimePoint::clock::now() );
		auto sum = _scalarMultiply( speed, deltaTime*stepMultiplier );
		guess    = _plus<ValueType>( value, sum );
	}

	inline T Get()
	{
		std::lock_guard<mutex> valueLock( mut );
		return guess;
	}

 protected:
	HiResTimePoint lastUpdate = HiResTimePoint::clock::now();

	inline float DeltaTime( const HiResTimePoint& currentTime )
	{
		return std::chrono::duration_cast<std::chrono::milliseconds>( currentTime - lastUpdate ).count() / 1000.f;
	}

	T value;
	T guess;
	DeltaType speed;
	std::mutex mut;
};

<commit_msg>Swapped definition lines.<commit_after>#pragma once

#include <iostream>
#include <chrono>
#include <mutex>

#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>

// Helpers
namespace
{
	// For differences between quaternions.
	struct AngleAxis
	{
		float     angle;
		glm::vec3 axis;

		AngleAxis( float _angle=0.0f, glm::vec3 _axis={} ) : angle(_angle), axis(_axis) {}
	};

	AngleAxis operator* ( const AngleAxis& lhs, float rhs )
	{
		AngleAxis result{ lhs.angle, lhs.axis };
		result.angle *= rhs;
		return result;
	}

	AngleAxis operator/ ( const AngleAxis& lhs, float rhs )
	{
		AngleAxis result{ lhs.angle, lhs.axis };
		result.angle /= rhs;
		return result;
	}

	// Difference
	template <typename T>
	inline T _minus( const T& lhs={}, const T& rhs={} )
	{
		return lhs - rhs;
	}

	// Difference between quaternions
	inline AngleAxis _minus( const glm::quat& lhs, const glm::quat& rhs )
	{
		auto quatDelta = lhs * glm::inverse(rhs);
		return AngleAxis{ glm::angle( quatDelta ), glm::axis( quatDelta ) };;
	}

	// Addition
	template <typename T, typename RHT=T>
	inline T _plus( const T& lhs={}, const RHT& rhs={} )
	{
		return lhs + rhs;
	}

	template <>
	inline glm::quat _plus( const glm::quat& lhs, const AngleAxis& rhs )
	{
		auto rot = glm::angleAxis( rhs.angle, rhs.axis );
		return lhs * rot;
	}

	// Division
	template <typename T, typename S=float>
	inline T _scalarDivide( const T& lhs={}, S rhs={1.f} )
	{
		if( rhs == 0.0 ) rhs = S{ 1.f };
		return lhs / rhs;
	}

	// Multiplying
	template <typename T, typename S=float>
	inline T _scalarMultiply( const T& lhs={}, S rhs={1.f} )
	{
		return lhs * rhs;
	}
}

template <typename T, typename DeltaType=decltype( _minus( T{}, T{} ) )>
struct Smooth
{
	typedef std::chrono::high_resolution_clock::time_point HiResTimePoint;
	typedef T ValueType;

	Smooth( T startValue={} )
	{
		value = startValue;
		guess = startValue;
	}

	Smooth( T&& startValue )
	{
		value = T{ std::forward( startValue ) };
		guess = value;
	}

	Smooth& operator=( const T& startValue )
	{
		value = startValue;
		guess = value;
		return *this;
	}

	void Update( const T& newValue )
	{
		std::lock_guard<mutex> valueLock( mut );
		auto currentTime = HiResTimePoint::clock::now();
		auto deltaTime   = DeltaTime( currentTime );
		DeltaType deltaValue = _minus( newValue, value );

		lastUpdate = currentTime;
		speed = _scalarDivide( deltaValue, deltaTime );

		value = newValue;
		guess = newValue;
	}

	void Calculate( const float& stepMultiplier={1.f} )
	{
		std::lock_guard<mutex> valueLock( mut );
		auto deltaTime = DeltaTime( HiResTimePoint::clock::now() );
		auto sum = _scalarMultiply( speed, deltaTime*stepMultiplier );
		guess    = _plus<ValueType>( value, sum );
	}

	inline T Get()
	{
		std::lock_guard<mutex> valueLock( mut );
		return guess;
	}

 protected:
	inline float DeltaTime( const HiResTimePoint& currentTime )
	{
		return std::chrono::duration_cast<std::chrono::milliseconds>( currentTime - lastUpdate ).count() / 1000.f;
	}

	HiResTimePoint lastUpdate = HiResTimePoint::clock::now();

	T value;
	T guess;
	DeltaType speed;
	std::mutex mut;
};

<|endoftext|>


<commit_before>/******************************************************************************
 * This file is part of the Mula project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "offsetcachefile.h"

#include "file.h"
#include "wordentry.h"

#include <QtCore/QVector>
#include <QtCore/QFile>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QPair>
#include <QtGui/QDesktopServices>

#include <arpa/inet.h>

using namespace MulaPluginStarDict;

class OffsetCacheFile::Private
{
    public:
        Private()
            : wordCount(0)
            , cacheMagicString("StarDict's Cache, Version: 0.1")
            , mappedData(0)
        {
        }

        ~Private()
        {
        }

        void fill(QByteArray data, int entryCount, long index);

        static const int entriesPerPage = 32;
        QString cacheMagic;

        QVector<quint32> wordOffset;
        QFile indexFile;
        ulong wordCount;

        QByteArray wordEntryBuffer; // 256 + sizeof(quint32)*2) - The length of "word_str" should be less than 256. See src/tools/DICTFILE_FORMAT.

        QPair<int, QByteArray> first;
        QPair<int, QByteArray> last;
        QPair<int, QByteArray> middle;
        QPair<int, QByteArray> realLast;

        QByteArray pageData;

        long entryIndex;
        QList<WordEntry> entries;

        QByteArray cacheMagicString;
        QFile mapFile;
        uchar *mappedData;
};

void
OffsetCacheFile::Private::fill(QByteArray data, int entryCount, long index)
{
    entryIndex = index;
    ulong position = 0;
    for (int i = 0; i < entryCount; ++i)
    {
        entries[i].setData(data.mid(position));
        position = qstrlen(data.mid(position)) + 1;
        entries[i].setDataOffset(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
        entries[i].setDataSize(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
    }
}

OffsetCacheFile::OffsetCacheFile()
    : d(new Private)
{
}

OffsetCacheFile::~OffsetCacheFile()
{
}

QByteArray
OffsetCacheFile::readFirstOnPageKey(long pageIndex)
{
    d->indexFile.seek(d->wordOffset.at(pageIndex));
    int pageSize = d->wordOffset.at(pageIndex + 1) - d->wordOffset.at(pageIndex);
    d->wordEntryBuffer = d->indexFile.read(qMin(d->wordEntryBuffer.size(), pageSize)); //TODO: check returned values, deal with word entry that strlen>255.
    return d->wordEntryBuffer;
}

QByteArray
OffsetCacheFile::firstOnPageKey(long pageIndex)
{
    if (pageIndex < d->middle.first)
    {
        if (pageIndex == d->first.first)
            return d->first.second;

        return readFirstOnPageKey(pageIndex);
    }
    else if (pageIndex > d->middle.first)
    {
        if (pageIndex == d->last.first)
            return d->last.second;

        return readFirstOnPageKey(pageIndex);
    }
    else
    {
        return d->middle.second;
    }
}

QStringList
OffsetCacheFile::cacheLocations(const QString& url)
{
    QStringList result;
    result.append(url + ".oft");

    QString cacheLocation = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
    QFileInfo cacheLocationFileInfo(cacheLocation);
    QDir cacheLocationDir;

    if (!cacheLocationFileInfo.exists() && cacheLocationDir.mkdir(cacheLocation) == false)
        return result;

    if (!cacheLocationFileInfo.isDir())
        return result;

    result.append(cacheLocation + QDir::separator() + "sdcv" + QDir::separator() + QFileInfo(url).fileName() + ".oft");
    return result;
}

bool
OffsetCacheFile::loadCache(const QString& url)
{
    foreach (const QString& cacheLocation, cacheLocations(url))
    {
        QFileInfo fileInfoIndex(url);
        QFileInfo fileInfoCache(cacheLocation);

        if (fileInfoCache.lastModified() < fileInfoIndex.lastModified())
            continue;

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (d->cacheMagicString != d->mappedData)
            continue;

        memcpy(d->wordOffset.data(), d->mappedData + d->cacheMagicString.size(), d->wordOffset.size()*sizeof(d->wordOffset.at(0)));
        return true;
    }

    return false;
}

bool
OffsetCacheFile::saveCache(const QString& url)
{
    foreach (const QString& cacheLocation, cacheLocations(url))
    {
        QFile file(cacheLocation);
        if( !file.open( QIODevice::WriteOnly ) )
        {
            qDebug() << "Failed to open file for writing:" << cacheLocation;
            return -1;
        }

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (file.write(d->cacheMagicString) != d->cacheMagicString.size())
            continue;

        if (file.write(reinterpret_cast<const char*>(d->wordOffset.data()), sizeof(d->wordOffset.at(0))*d->wordOffset.size())
                != d->wordOffset.at(0)*d->wordOffset.size())
            continue;

        file.close();

        qDebug() << "Save to cache" << url;

        return true;
    }

    return false;
}

bool
OffsetCacheFile::load(const QString& url, int wc, qulonglong fileSize)
{
    Q_UNUSED(fileSize);

    d->wordCount = wc;
    qulonglong npages = (wc - 1) / d->entriesPerPage + 2;
    d->wordOffset.resize(npages);

    if (!loadCache(url))
    { //map file will close after finish of block
        d->mapFile.setFileName(url);
        if (!d->mapFile.open(QIODevice::ReadOnly))
        {
            qDebug() << "Failed to open file:" << url;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(url);
            return false;
        }

        QByteArray byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(d->mappedData), d->mapFile.size());

        int position = 0;
        int j = 0;
        for (int i = 0; i < wc; i++)
        {
            if (i % d->entriesPerPage == 0)
            {
                d->wordOffset[j] = position;
                ++j;
            }

            position += qstrlen(byteArray.mid(position)) + 1 + 2 * sizeof(quint32);
        }

        d->wordOffset[j] = position;

        if (!saveCache(url))
            qDebug() << "Cache update failed";
    }

    d->indexFile.setFileName(url);
    if (!d->indexFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open file:" << url;
        d->wordOffset.resize(0);
        return false;
    }

    d->first = qMakePair(0, readFirstOnPageKey(0));
    d->last = qMakePair(d->wordOffset.size() - 2, readFirstOnPageKey(d->wordOffset.size() - 2));
    d->middle = qMakePair((d->wordOffset.size() - 2) / 2, readFirstOnPageKey((d->wordOffset.size() - 2) / 2));
    d->realLast = qMakePair(wc - 1, key(wc - 1));

    return true;
}

ulong
OffsetCacheFile::loadPage(long pageIndex)
{
    ulong entryCount = d->entriesPerPage;
    if (pageIndex == ulong(d->wordOffset.size() - 2) && (entryCount = d->wordCount % d->entriesPerPage) == 0)
    {
        entryCount = d->entriesPerPage;
    }

    if (pageIndex != d->entryIndex)
    {
        d->indexFile.seek(d->wordOffset.at(pageIndex));

        d->pageData = d->indexFile.read(d->wordOffset[pageIndex + 1] - d->wordOffset[pageIndex]);
        d->fill(d->pageData, entryCount, pageIndex);
    }

    return entryCount;
}

QByteArray
OffsetCacheFile::key(long index)
{
    loadPage(index / d->entriesPerPage);
    ulong indexInPage = index % d->entriesPerPage;
    setWordEntryOffset(d->entries.at(indexInPage).dataOffset());
    setWordEntrySize(d->entries.at(indexInPage).dataSize());

    return d->entries.at(indexInPage).data();
}

bool
OffsetCacheFile::lookup(const QByteArray& word, long &index)
{
    bool found = false;
    long indexFrom;
    long indexTo = d->wordOffset.size() - 2;
    int cmpint;
    long indexThisIndex;
    if (stardictStringCompare(word, d->first.second) < 0)
    {
        index = 0;
        return false;
    }
    else if (stardictStringCompare(word, d->realLast.second) > 0)
    {
        index = invalidIndex;
        return false;
    }
    else
    {
        indexFrom = 0;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, firstOnPageKey(indexThisIndex));
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }
        if (!found)
            index = indexTo;    //prev
        else
            index = indexThisIndex;
    }

    if (!found)
    {
        ulong netr = loadPage(index);
        indexFrom = 1; // Needn't search the first word anymore.
        indexTo = netr - 1;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, d->entries.at(indexThisIndex).data());
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }

        index *= d->entriesPerPage;
        if (!found)
            index += indexFrom;    //next
        else
            index += indexThisIndex;
    }
    else
    {
        index *= d->entriesPerPage;
    }

    return found;
}

quint32
OffsetCacheFile::wordEntryOffset() const
{
    return AbstractIndexFile::wordEntryOffset();
}

void
OffsetCacheFile::setWordEntryOffset(quint32 wordEntryOffset)
{
    AbstractIndexFile::setWordEntryOffset(wordEntryOffset);
}

quint32
OffsetCacheFile::wordEntrySize() const
{
    return AbstractIndexFile::wordEntrySize();
}

void
OffsetCacheFile::setWordEntrySize(quint32 wordEntrySize)
{
    AbstractIndexFile::setWordEntrySize(wordEntrySize);
}
<commit_msg>Eliminate the unused cacheMagic public private class member<commit_after>/******************************************************************************
 * This file is part of the Mula project
 * Copyright (c) 2011 Laszlo Papp <lpapp@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "offsetcachefile.h"

#include "file.h"
#include "wordentry.h"

#include <QtCore/QVector>
#include <QtCore/QFile>
#include <QtCore/QtGlobal>
#include <QtCore/QDir>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QPair>
#include <QtGui/QDesktopServices>

#include <arpa/inet.h>

using namespace MulaPluginStarDict;

class OffsetCacheFile::Private
{
    public:
        Private()
            : wordCount(0)
            , cacheMagicString("StarDict's Cache, Version: 0.1")
            , mappedData(0)
        {
        }

        ~Private()
        {
        }

        void fill(QByteArray data, int entryCount, long index);

        static const int entriesPerPage = 32;

        QVector<quint32> wordOffset;
        QFile indexFile;
        ulong wordCount;

        QByteArray wordEntryBuffer; // 256 + sizeof(quint32)*2) - The length of "word_str" should be less than 256. See src/tools/DICTFILE_FORMAT.

        QPair<int, QByteArray> first;
        QPair<int, QByteArray> last;
        QPair<int, QByteArray> middle;
        QPair<int, QByteArray> realLast;

        QByteArray pageData;

        long entryIndex;
        QList<WordEntry> entries;

        QByteArray cacheMagicString;
        QFile mapFile;
        uchar *mappedData;
};

void
OffsetCacheFile::Private::fill(QByteArray data, int entryCount, long index)
{
    entryIndex = index;
    ulong position = 0;
    for (int i = 0; i < entryCount; ++i)
    {
        entries[i].setData(data.mid(position));
        position = qstrlen(data.mid(position)) + 1;
        entries[i].setDataOffset(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
        entries[i].setDataSize(ntohl(*reinterpret_cast<quint32 *>(data.mid(position).data())));
        position += sizeof(quint32);
    }
}

OffsetCacheFile::OffsetCacheFile()
    : d(new Private)
{
}

OffsetCacheFile::~OffsetCacheFile()
{
}

QByteArray
OffsetCacheFile::readFirstOnPageKey(long pageIndex)
{
    d->indexFile.seek(d->wordOffset.at(pageIndex));
    int pageSize = d->wordOffset.at(pageIndex + 1) - d->wordOffset.at(pageIndex);
    d->wordEntryBuffer = d->indexFile.read(qMin(d->wordEntryBuffer.size(), pageSize)); //TODO: check returned values, deal with word entry that strlen>255.
    return d->wordEntryBuffer;
}

QByteArray
OffsetCacheFile::firstOnPageKey(long pageIndex)
{
    if (pageIndex < d->middle.first)
    {
        if (pageIndex == d->first.first)
            return d->first.second;

        return readFirstOnPageKey(pageIndex);
    }
    else if (pageIndex > d->middle.first)
    {
        if (pageIndex == d->last.first)
            return d->last.second;

        return readFirstOnPageKey(pageIndex);
    }
    else
    {
        return d->middle.second;
    }
}

QStringList
OffsetCacheFile::cacheLocations(const QString& url)
{
    QStringList result;
    result.append(url + ".oft");

    QString cacheLocation = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
    QFileInfo cacheLocationFileInfo(cacheLocation);
    QDir cacheLocationDir;

    if (!cacheLocationFileInfo.exists() && cacheLocationDir.mkdir(cacheLocation) == false)
        return result;

    if (!cacheLocationFileInfo.isDir())
        return result;

    result.append(cacheLocation + QDir::separator() + "sdcv" + QDir::separator() + QFileInfo(url).fileName() + ".oft");
    return result;
}

bool
OffsetCacheFile::loadCache(const QString& url)
{
    foreach (const QString& cacheLocation, cacheLocations(url))
    {
        QFileInfo fileInfoIndex(url);
        QFileInfo fileInfoCache(cacheLocation);

        if (fileInfoCache.lastModified() < fileInfoIndex.lastModified())
            continue;

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (d->cacheMagicString != d->mappedData)
            continue;

        memcpy(d->wordOffset.data(), d->mappedData + d->cacheMagicString.size(), d->wordOffset.size()*sizeof(d->wordOffset.at(0)));
        return true;
    }

    return false;
}

bool
OffsetCacheFile::saveCache(const QString& url)
{
    foreach (const QString& cacheLocation, cacheLocations(url))
    {
        QFile file(cacheLocation);
        if( !file.open( QIODevice::WriteOnly ) )
        {
            qDebug() << "Failed to open file for writing:" << cacheLocation;
            return -1;
        }

        d->mapFile.unmap(d->mappedData);
        d->mapFile.setFileName(cacheLocation);
        if( !d->mapFile.open( QIODevice::ReadOnly ) )
        {
            qDebug() << "Failed to open file:" << cacheLocation;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(cacheLocation);
            return false;
        }

        if (file.write(d->cacheMagicString) != d->cacheMagicString.size())
            continue;

        if (file.write(reinterpret_cast<const char*>(d->wordOffset.data()), sizeof(d->wordOffset.at(0))*d->wordOffset.size())
                != d->wordOffset.at(0)*d->wordOffset.size())
            continue;

        file.close();

        qDebug() << "Save to cache" << url;

        return true;
    }

    return false;
}

bool
OffsetCacheFile::load(const QString& url, int wc, qulonglong fileSize)
{
    Q_UNUSED(fileSize);

    d->wordCount = wc;
    qulonglong npages = (wc - 1) / d->entriesPerPage + 2;
    d->wordOffset.resize(npages);

    if (!loadCache(url))
    { //map file will close after finish of block
        d->mapFile.setFileName(url);
        if (!d->mapFile.open(QIODevice::ReadOnly))
        {
            qDebug() << "Failed to open file:" << url;
            return -1;
        }

        d->mappedData = d->mapFile.map(0, d->mapFile.size());
        if (d->mappedData == NULL)
        {
            qDebug() << Q_FUNC_INFO << QString("Mapping the file %1 failed!").arg(url);
            return false;
        }

        QByteArray byteArray = QByteArray::fromRawData(reinterpret_cast<const char*>(d->mappedData), d->mapFile.size());

        int position = 0;
        int j = 0;
        for (int i = 0; i < wc; i++)
        {
            if (i % d->entriesPerPage == 0)
            {
                d->wordOffset[j] = position;
                ++j;
            }

            position += qstrlen(byteArray.mid(position)) + 1 + 2 * sizeof(quint32);
        }

        d->wordOffset[j] = position;

        if (!saveCache(url))
            qDebug() << "Cache update failed";
    }

    d->indexFile.setFileName(url);
    if (!d->indexFile.open(QIODevice::ReadOnly))
    {
        qDebug() << "Failed to open file:" << url;
        d->wordOffset.resize(0);
        return false;
    }

    d->first = qMakePair(0, readFirstOnPageKey(0));
    d->last = qMakePair(d->wordOffset.size() - 2, readFirstOnPageKey(d->wordOffset.size() - 2));
    d->middle = qMakePair((d->wordOffset.size() - 2) / 2, readFirstOnPageKey((d->wordOffset.size() - 2) / 2));
    d->realLast = qMakePair(wc - 1, key(wc - 1));

    return true;
}

ulong
OffsetCacheFile::loadPage(long pageIndex)
{
    ulong entryCount = d->entriesPerPage;
    if (pageIndex == ulong(d->wordOffset.size() - 2) && (entryCount = d->wordCount % d->entriesPerPage) == 0)
    {
        entryCount = d->entriesPerPage;
    }

    if (pageIndex != d->entryIndex)
    {
        d->indexFile.seek(d->wordOffset.at(pageIndex));

        d->pageData = d->indexFile.read(d->wordOffset[pageIndex + 1] - d->wordOffset[pageIndex]);
        d->fill(d->pageData, entryCount, pageIndex);
    }

    return entryCount;
}

QByteArray
OffsetCacheFile::key(long index)
{
    loadPage(index / d->entriesPerPage);
    ulong indexInPage = index % d->entriesPerPage;
    setWordEntryOffset(d->entries.at(indexInPage).dataOffset());
    setWordEntrySize(d->entries.at(indexInPage).dataSize());

    return d->entries.at(indexInPage).data();
}

bool
OffsetCacheFile::lookup(const QByteArray& word, long &index)
{
    bool found = false;
    long indexFrom;
    long indexTo = d->wordOffset.size() - 2;
    int cmpint;
    long indexThisIndex;
    if (stardictStringCompare(word, d->first.second) < 0)
    {
        index = 0;
        return false;
    }
    else if (stardictStringCompare(word, d->realLast.second) > 0)
    {
        index = invalidIndex;
        return false;
    }
    else
    {
        indexFrom = 0;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, firstOnPageKey(indexThisIndex));
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }
        if (!found)
            index = indexTo;    //prev
        else
            index = indexThisIndex;
    }

    if (!found)
    {
        ulong netr = loadPage(index);
        indexFrom = 1; // Needn't search the first word anymore.
        indexTo = netr - 1;
        indexThisIndex = 0;
        while (indexFrom <= indexTo)
        {
            indexThisIndex = (indexFrom + indexTo) / 2;
            cmpint = stardictStringCompare(word, d->entries.at(indexThisIndex).data());
            if (cmpint > 0)
                indexFrom = indexThisIndex + 1;
            else if (cmpint < 0)
                indexTo = indexThisIndex - 1;
            else
            {
                found = true;
                break;
            }
        }

        index *= d->entriesPerPage;
        if (!found)
            index += indexFrom;    //next
        else
            index += indexThisIndex;
    }
    else
    {
        index *= d->entriesPerPage;
    }

    return found;
}

quint32
OffsetCacheFile::wordEntryOffset() const
{
    return AbstractIndexFile::wordEntryOffset();
}

void
OffsetCacheFile::setWordEntryOffset(quint32 wordEntryOffset)
{
    AbstractIndexFile::setWordEntryOffset(wordEntryOffset);
}

quint32
OffsetCacheFile::wordEntrySize() const
{
    return AbstractIndexFile::wordEntrySize();
}

void
OffsetCacheFile::setWordEntrySize(quint32 wordEntrySize)
{
    AbstractIndexFile::setWordEntrySize(wordEntrySize);
}
<|endoftext|>