<commit_before>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <new>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
// Simplistic definitinos of these macros for use in getOpenFile.
#ifndef S_ISREG
#define S_ISREG(x) (1)
#endif
#ifndef S_ISBLK
#define S_ISBLK(x) (0)
#endif
#endif
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

namespace {
struct NamedBufferAlloc {
  StringRef Name;
  NamedBufferAlloc(StringRef Name) : Name(Name) {}
};
}

void *operator new(size_t N, const NamedBufferAlloc &Alloc) {
  char *Mem = static_cast<char *>(operator new(N + Alloc.Name.size() + 1));
  CopyStringRef(Mem + N, Alloc.Name);
  return Mem;
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return new (NamedBufferAlloc(BufferName))
      MemoryBufferMem(InputData, RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region.
///
/// This handles converting the offset into a legal offset on the platform.
class MemoryBufferMMapFile : public MemoryBuffer {
  sys::fs::mapped_file_region MFR;

  static uint64_t getLegalMapOffset(uint64_t Offset) {
    return Offset & ~(sys::fs::mapped_file_region::alignment() - 1);
  }

  static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) {
    return Len + (Offset - getLegalMapOffset(Offset));
  }

  const char *getStart(uint64_t Len, uint64_t Offset) {
    return MFR.const_data() + (Offset - getLegalMapOffset(Offset));
  }

public:
  MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len,
                       uint64_t Offset, error_code EC)
      : MFR(FD, false, sys::fs::mapped_file_region::readonly,
            getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) {
    if (!EC) {
      const char *Start = getStart(Len, Offset);
      init(Start, Start + Len, RequiresNullTerminator);
    }
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
    // The name is stored after the class itself.
    return reinterpret_cast<const char *>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_MMap;
  }
};
}

static error_code getMemoryBufferForStream(int FD,
                                           StringRef BufferName,
                                           OwningPtr<MemoryBuffer> &result) {
  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(FD, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName));
  return error_code::success();
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  int FD;
  error_code EC = sys::fs::openFileForRead(Filename, FD);
  if (EC)
    return EC;

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    struct stat FileInfo;
    // TODO: This should use fstat64 when available.
    if (fstat(FD, &FileInfo) == -1) {
      return error_code(errno, posix_category());
    }
    FileSize = FileInfo.st_size;
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::process::get_self()->page_size();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      struct stat FileInfo;
      // TODO: This should use fstat64 when available.
      if (fstat(FD, &FileInfo) == -1) {
        return error_code(errno, posix_category());
      }

      // If this not a file or a block device (e.g. it's a named pipe
      // or character device), we can't trust the size. Create the memory
      // buffer by copying off the stream.
      if (!S_ISREG(FileInfo.st_mode) && !S_ISBLK(FileInfo.st_mode)) {
        return getMemoryBufferForStream(FD, Filename, result);
      }

      FileSize = FileInfo.st_size;
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    error_code EC;
    result.reset(new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile(
        RequiresNullTerminator, FD, MapSize, Offset, EC));
    if (!EC)
      return error_code::success();
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::ChangeStdinToBinary();

  return getMemoryBufferForStream(0, "<stdin>", result);
}
<commit_msg>Convert two uses if fstat with sys::fs::status.<commit_after>//===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file implements the MemoryBuffer interface.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/MemoryBuffer.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Errno.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/system_error.h"
#include <cassert>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <new>
#include <sys/stat.h>
#include <sys/types.h>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
// Simplistic definitinos of these macros for use in getOpenFile.
#ifndef S_ISREG
#define S_ISREG(x) (1)
#endif
#ifndef S_ISBLK
#define S_ISBLK(x) (0)
#endif
#endif
using namespace llvm;

//===----------------------------------------------------------------------===//
// MemoryBuffer implementation itself.
//===----------------------------------------------------------------------===//

MemoryBuffer::~MemoryBuffer() { }

/// init - Initialize this MemoryBuffer as a reference to externally allocated
/// memory, memory that we know is already null terminated.
void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
                        bool RequiresNullTerminator) {
  assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
         "Buffer is not null terminated!");
  BufferStart = BufStart;
  BufferEnd = BufEnd;
}

//===----------------------------------------------------------------------===//
// MemoryBufferMem implementation.
//===----------------------------------------------------------------------===//

/// CopyStringRef - Copies contents of a StringRef into a block of memory and
/// null-terminates it.
static void CopyStringRef(char *Memory, StringRef Data) {
  memcpy(Memory, Data.data(), Data.size());
  Memory[Data.size()] = 0; // Null terminate string.
}

namespace {
struct NamedBufferAlloc {
  StringRef Name;
  NamedBufferAlloc(StringRef Name) : Name(Name) {}
};
}

void *operator new(size_t N, const NamedBufferAlloc &Alloc) {
  char *Mem = static_cast<char *>(operator new(N + Alloc.Name.size() + 1));
  CopyStringRef(Mem + N, Alloc.Name);
  return Mem;
}

namespace {
/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
class MemoryBufferMem : public MemoryBuffer {
public:
  MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
    init(InputData.begin(), InputData.end(), RequiresNullTerminator);
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
     // The name is stored after the class itself.
    return reinterpret_cast<const char*>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_Malloc;
  }
};
}

/// getMemBuffer - Open the specified memory range as a MemoryBuffer.  Note
/// that InputData must be a null terminated if RequiresNullTerminator is true!
MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData,
                                         StringRef BufferName,
                                         bool RequiresNullTerminator) {
  return new (NamedBufferAlloc(BufferName))
      MemoryBufferMem(InputData, RequiresNullTerminator);
}

/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer,
/// copying the contents and taking ownership of it.  This has no requirements
/// on EndPtr[0].
MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData,
                                             StringRef BufferName) {
  MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName);
  if (!Buf) return 0;
  memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(),
         InputData.size());
  return Buf;
}

/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size
/// that is not initialized.  Note that the caller should initialize the
/// memory allocated by this method.  The memory is owned by the MemoryBuffer
/// object.
MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size,
                                                  StringRef BufferName) {
  // Allocate space for the MemoryBuffer, the data and the name. It is important
  // that MemoryBuffer and data are aligned so PointerIntPair works with them.
  size_t AlignedStringLen =
    RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1,
                       sizeof(void*)); // TODO: Is sizeof(void*) enough?
  size_t RealLen = AlignedStringLen + Size + 1;
  char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow));
  if (!Mem) return 0;

  // The name is stored after the class itself.
  CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName);

  // The buffer begins after the name and must be aligned.
  char *Buf = Mem + AlignedStringLen;
  Buf[Size] = 0; // Null terminate buffer.

  return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true);
}

/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that
/// is completely initialized to zeros.  Note that the caller should
/// initialize the memory allocated by this method.  The memory is owned by
/// the MemoryBuffer object.
MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) {
  MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName);
  if (!SB) return 0;
  memset(const_cast<char*>(SB->getBufferStart()), 0, Size);
  return SB;
}

/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin
/// if the Filename is "-".  If an error occurs, this returns null and fills
/// in *ErrStr with a reason.  If stdin is empty, this API (unlike getSTDIN)
/// returns an empty buffer.
error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename,
                                        OwningPtr<MemoryBuffer> &result,
                                        int64_t FileSize) {
  if (Filename == "-")
    return getSTDIN(result);
  return getFile(Filename, result, FileSize);
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getFile implementation.
//===----------------------------------------------------------------------===//

namespace {
/// \brief Memorry maps a file descriptor using sys::fs::mapped_file_region.
///
/// This handles converting the offset into a legal offset on the platform.
class MemoryBufferMMapFile : public MemoryBuffer {
  sys::fs::mapped_file_region MFR;

  static uint64_t getLegalMapOffset(uint64_t Offset) {
    return Offset & ~(sys::fs::mapped_file_region::alignment() - 1);
  }

  static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) {
    return Len + (Offset - getLegalMapOffset(Offset));
  }

  const char *getStart(uint64_t Len, uint64_t Offset) {
    return MFR.const_data() + (Offset - getLegalMapOffset(Offset));
  }

public:
  MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len,
                       uint64_t Offset, error_code EC)
      : MFR(FD, false, sys::fs::mapped_file_region::readonly,
            getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) {
    if (!EC) {
      const char *Start = getStart(Len, Offset);
      init(Start, Start + Len, RequiresNullTerminator);
    }
  }

  virtual const char *getBufferIdentifier() const LLVM_OVERRIDE {
    // The name is stored after the class itself.
    return reinterpret_cast<const char *>(this + 1);
  }

  virtual BufferKind getBufferKind() const LLVM_OVERRIDE {
    return MemoryBuffer_MMap;
  }
};
}

static error_code getMemoryBufferForStream(int FD,
                                           StringRef BufferName,
                                           OwningPtr<MemoryBuffer> &result) {
  const ssize_t ChunkSize = 4096*4;
  SmallString<ChunkSize> Buffer;
  ssize_t ReadBytes;
  // Read into Buffer until we hit EOF.
  do {
    Buffer.reserve(Buffer.size() + ChunkSize);
    ReadBytes = read(FD, Buffer.end(), ChunkSize);
    if (ReadBytes == -1) {
      if (errno == EINTR) continue;
      return error_code(errno, posix_category());
    }
    Buffer.set_size(Buffer.size() + ReadBytes);
  } while (ReadBytes != 0);

  result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName));
  return error_code::success();
}

error_code MemoryBuffer::getFile(StringRef Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  // Ensure the path is null terminated.
  SmallString<256> PathBuf(Filename.begin(), Filename.end());
  return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize,
                               RequiresNullTerminator);
}

error_code MemoryBuffer::getFile(const char *Filename,
                                 OwningPtr<MemoryBuffer> &result,
                                 int64_t FileSize,
                                 bool RequiresNullTerminator) {
  int FD;
  error_code EC = sys::fs::openFileForRead(Filename, FD);
  if (EC)
    return EC;

  error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize,
                               0, RequiresNullTerminator);
  close(FD);
  return ret;
}

static bool shouldUseMmap(int FD,
                          size_t FileSize,
                          size_t MapSize,
                          off_t Offset,
                          bool RequiresNullTerminator,
                          int PageSize) {
  // We don't use mmap for small files because this can severely fragment our
  // address space.
  if (MapSize < 4096*4)
    return false;

  if (!RequiresNullTerminator)
    return true;

  // If we don't know the file size, use fstat to find out.  fstat on an open
  // file descriptor is cheaper than stat on a random path.
  // FIXME: this chunk of code is duplicated, but it avoids a fstat when
  // RequiresNullTerminator = false and MapSize != -1.
  if (FileSize == size_t(-1)) {
    sys::fs::file_status Status;
    error_code EC = sys::fs::status(FD, Status);
    if (EC)
      return EC;
    FileSize = Status.getSize();
  }

  // If we need a null terminator and the end of the map is inside the file,
  // we cannot use mmap.
  size_t End = Offset + MapSize;
  assert(End <= FileSize);
  if (End != FileSize)
    return false;

  // Don't try to map files that are exactly a multiple of the system page size
  // if we need a null terminator.
  if ((FileSize & (PageSize -1)) == 0)
    return false;

  return true;
}

error_code MemoryBuffer::getOpenFile(int FD, const char *Filename,
                                     OwningPtr<MemoryBuffer> &result,
                                     uint64_t FileSize, uint64_t MapSize,
                                     int64_t Offset,
                                     bool RequiresNullTerminator) {
  static int PageSize = sys::process::get_self()->page_size();

  // Default is to map the full file.
  if (MapSize == uint64_t(-1)) {
    // If we don't know the file size, use fstat to find out.  fstat on an open
    // file descriptor is cheaper than stat on a random path.
    if (FileSize == uint64_t(-1)) {
      sys::fs::file_status Status;
      error_code EC = sys::fs::status(FD, Status);
      if (EC)
        return EC;

      // If this not a file or a block device (e.g. it's a named pipe
      // or character device), we can't trust the size. Create the memory
      // buffer by copying off the stream.
      sys::fs::file_type Type = Status.type();
      if (Type != sys::fs::file_type::regular_file &&
          Type != sys::fs::file_type::block_file)
        return getMemoryBufferForStream(FD, Filename, result);

      FileSize = Status.getSize();
    }
    MapSize = FileSize;
  }

  if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
                    PageSize)) {
    error_code EC;
    result.reset(new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile(
        RequiresNullTerminator, FD, MapSize, Offset, EC));
    if (!EC)
      return error_code::success();
  }

  MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename);
  if (!Buf) {
    // Failed to create a buffer. The only way it can fail is if
    // new(std::nothrow) returns 0.
    return make_error_code(errc::not_enough_memory);
  }

  OwningPtr<MemoryBuffer> SB(Buf);
  char *BufPtr = const_cast<char*>(SB->getBufferStart());

  size_t BytesLeft = MapSize;
#ifndef HAVE_PREAD
  if (lseek(FD, Offset, SEEK_SET) == -1)
    return error_code(errno, posix_category());
#endif

  while (BytesLeft) {
#ifdef HAVE_PREAD
    ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset);
#else
    ssize_t NumRead = ::read(FD, BufPtr, BytesLeft);
#endif
    if (NumRead == -1) {
      if (errno == EINTR)
        continue;
      // Error while reading.
      return error_code(errno, posix_category());
    }
    if (NumRead == 0) {
      assert(0 && "We got inaccurate FileSize value or fstat reported an "
                   "invalid file size.");
      *BufPtr = '\0'; // null-terminate at the actual size.
      break;
    }
    BytesLeft -= NumRead;
    BufPtr += NumRead;
  }

  result.swap(SB);
  return error_code::success();
}

//===----------------------------------------------------------------------===//
// MemoryBuffer::getSTDIN implementation.
//===----------------------------------------------------------------------===//

error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) {
  // Read in all of the data from stdin, we cannot mmap stdin.
  //
  // FIXME: That isn't necessarily true, we should try to mmap stdin and
  // fallback if it fails.
  sys::ChangeStdinToBinary();

  return getMemoryBufferForStream(0, "<stdin>", result);
}
<|endoftext|>


<commit_before>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

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

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

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopete.h"

#include <dcopclient.h>
#include "kopeteiface.h"

#define KOPETE_VERSION "0.7.93"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection." ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2003, Duncan Mac-Vicar Prett\n(c) 2002-2003, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer, Oscar Maintainer"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("WinPopup plugin maintainer"), "gjw102@york.ac.uk" );
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Developer, original Gadu plugin author"), "zack@kde.org" );
	aboutData.addAuthor ( "Chris TenHarmsel", I18N_NOOP("Developer, Oscar"), "tenharmsel@users.sourceforge.net", "http://bemis.kicks-ass.net");
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@pandora.be" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, icons, plugins"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin maintainer"), "mattrogers@sbcglobal.net" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Vladimir Shutoff", I18N_NOOP("SIM icq library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Herwin Jan Steehouwer", I18N_NOOP("KxEngine icq code") );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Psi Jabber code") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	Kopete kopete;
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
/*
 * Local variables:
 * c-indentation-style: k&r
 * c-basic-offset: 8
 * indent-tabs-mode: t
 * End:
 */
// vim: set noet ts=4 sts=4 sw=4:

<commit_msg>preparing beta2<commit_after>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

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

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

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopete.h"

#include <dcopclient.h>
#include "kopeteiface.h"

#define KOPETE_VERSION "0.7.94"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection." ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2003, Duncan Mac-Vicar Prett\n(c) 2002-2003, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Developer, Oscar Maintainer"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("WinPopup plugin maintainer"), "gjw102@york.ac.uk" );
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Developer, original Gadu plugin author"), "zack@kde.org" );
	aboutData.addAuthor ( "Chris TenHarmsel", I18N_NOOP("Developer, Oscar"), "tenharmsel@users.sourceforge.net", "http://bemis.kicks-ass.net");
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@pandora.be" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, icons, plugins"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin maintainer"), "mattrogers@sbcglobal.net" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Vladimir Shutoff", I18N_NOOP("SIM icq library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Herwin Jan Steehouwer", I18N_NOOP("KxEngine icq code") );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Psi Jabber code") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	Kopete kopete;
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
/*
 * Local variables:
 * c-indentation-style: k&r
 * c-basic-offset: 8
 * indent-tabs-mode: t
 * End:
 */
// vim: set noet ts=4 sts=4 sw=4:

<|endoftext|>


<commit_before>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

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

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

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopeteapplication.h"

#include <dcopclient.h>
#include "kopeteiface.h"
#include "kimifaceimpl.h"

#define KOPETE_VERSION "0.9.91"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection" ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
//	{ "url <url>",              I18N_NOOP( "Load the given Kopete URL" ), 0 },
//	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	{ "!+[URL]",                 I18N_NOOP("URLs to pass to kopete / emoticon themes to install"), 0},
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2005, Duncan Mac-Vicar Prett\n(c) 2002-2005, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@kde.org");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@telenet.be" );
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin and Oscar plugin maintainer"), "mattrogers@sbcglobal.net" );
	aboutData.addAuthor ( "Richard Smith", I18N_NOOP("Developer, UI maintainer"), "kde@metafoo.co.uk" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, icons, various plugins"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("WinPopup plugin maintainer"), "gjw102@york.ac.uk" );
   aboutData.addAuthor ( "Stefan Gehn", I18N_NOOP("Former Developer"), "metz@gehn.net", "http://metz.gehn.net" );
   aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Former Developer, original Gadu plugin author"), "zack@kde.org" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Iris Jabber Backend Library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Chris TenHarmsel", I18N_NOOP("Former developer, Oscar plugin"), "tenharmsel@users.sourceforge.net");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");
   aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	KopeteApplication kopete;
	new KIMIfaceImpl();
	kapp->dcopClient()->registerAs( "kopete", false );
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Update developer info<commit_after>/*
    Kopete , The KDE Instant Messenger
    Copyright (c) 2001-2002 by Duncan Mac-Vicar Prett <duncan@kde.org>

    Viva Chile Mierda!
    Started at Wed Dec 26 03:12:10 CLST 2001, Santiago de Chile

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

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

#include <kcmdlineargs.h>
#include <kaboutdata.h>
#include "kopeteapplication.h"

#include <dcopclient.h>
#include "kopeteiface.h"
#include "kimifaceimpl.h"

#define KOPETE_VERSION "0.9.92"

static const char description[] =
	I18N_NOOP( "Kopete, the KDE Instant Messenger" );

static KCmdLineOptions options[] =
{
	{ "noplugins",              I18N_NOOP( "Do not load plugins. This option overrides all other options." ), 0 },
	{ "noconnect",              I18N_NOOP( "Disable auto-connection" ), 0 },
	{ "autoconnect <accounts>", I18N_NOOP( "Auto-connect the specified accounts. Use a comma-separated list\n"
		"to auto-connect multiple accounts." ), 0 },
	{ "disable <plugins>",      I18N_NOOP( "Do not load the specified plugin. Use a comma-separated list\n"
		"to disable multiple plugins." ), 0 },
	{ "load-plugins <plugins>", I18N_NOOP( "Load only the specified plugins. Use a comma-separated list\n"
		"to load multiple plugins. This option has no effect when\n"
		"--noplugins is set and overrides all other plugin related\n"
		"command line options." ), 0 },
//	{ "url <url>",              I18N_NOOP( "Load the given Kopete URL" ), 0 },
//	{ "!+[plugin]",            I18N_NOOP( "Load specified plugins" ), 0 },
	{ "!+[URL]",                 I18N_NOOP("URLs to pass to kopete / emoticon themes to install"), 0},
	KCmdLineLastOption
};

int main( int argc, char *argv[] )
{
	KAboutData aboutData( "kopete", I18N_NOOP("Kopete"),
		KOPETE_VERSION, description, KAboutData::License_GPL,
		I18N_NOOP("(c) 2001-2004, Duncan Mac-Vicar Prett\n(c) 2002-2005, Kopete Development Team"), "kopete-devel@kde.org", "http://kopete.kde.org");

	aboutData.addAuthor ( "Duncan Mac-Vicar Prett", I18N_NOOP("Original author, Developer"), "duncan@kde.org", "http://www.mac-vicar.org/~duncan" );
	aboutData.addAuthor ( "Till Gerken", I18N_NOOP("Developer, Jabber plugin maintainer"), "till@tantalo.net");
	aboutData.addAuthor ( "Olivier Goffart", I18N_NOOP("Developer, MSN plugin maintainer"), "ogoffart@tiscalinet.be");
	aboutData.addAuthor ( "Andy Goossens", I18N_NOOP("Developer"), "andygoossens@telenet.be" );
	aboutData.addAuthor ( "Chris Howells", I18N_NOOP("Developer, Connection status plugin author"), "howells@kde.org", "http://chrishowells.co.uk");
	aboutData.addAuthor ( "Grzegorz Jaskiewicz", I18N_NOOP("Developer, Gadu plugin maintainer"), "gj@pointblue.com.pl" );
	aboutData.addAuthor ( "Jason Keirstead", I18N_NOOP("Developer, IRC maintainer"), "jason@keirstead.org", "http://www.keirstead.org");
	aboutData.addAuthor ( "Martijn Klingens", I18N_NOOP("Developer"), "klingens@kde.org" );
	aboutData.addAuthor ( "Matt Rogers", I18N_NOOP("Developer, Yahoo plugin and Oscar plugin maintainer"), "mattrogers@sbcglobal.net" );
	aboutData.addAuthor ( "Zack Rusin", I18N_NOOP("Developer, original Gadu plugin author"), "zack@kde.org" );
	aboutData.addAuthor ( "Richard Smith", I18N_NOOP("Developer, UI maintainer"), "kde@metafoo.co.uk" );
	aboutData.addAuthor ( "Will Stephenson", I18N_NOOP("Developer, GroupWise maintainer"), "lists@stevello.free-online.co.uk" );
	aboutData.addAuthor ( "Gav Wood", I18N_NOOP("Developer, WinPopup plugin maintainer"), "gjw102@york.ac.uk" );

	aboutData.addCredit ( "Luciash d' Being", I18N_NOOP("Kopete's icon author") );
	aboutData.addCredit ( "Steve Cable", I18N_NOOP("Sounds") );
	aboutData.addCredit ( "Justin Karneges", I18N_NOOP("Iris Jabber Backend Library") );
	aboutData.addCredit ( "Tom Linsky", I18N_NOOP("OscarSocket author"), "twl6@po.cwru.edu" );
	aboutData.addCredit ( "Olaf Lueg", I18N_NOOP("Kmerlin MSN code") );

	aboutData.addCredit ( "Nick Betcher", I18N_NOOP("Former developer, project co-founder"), "nbetcher@kde.org");
	aboutData.addCredit ( "Ryan Cumming", I18N_NOOP("Former developer"), "ryan@kde.org" );
	aboutData.addCredit ( "Stefan Gehn", I18N_NOOP("Former developer"), "metz@gehn.net", "http://metz.gehn.net" );
	aboutData.addCredit ( "Andres Krapf", I18N_NOOP("Former developer"), "dae@chez.com" );
	aboutData.addCredit ( "Carsten Pfeiffer", I18N_NOOP("Misc bugfixes and enhancements"), "pfeiffer@kde.org" );
	aboutData.addCredit ( "Richard Stellingwerff", I18N_NOOP("Former developer"), "remenic@linuxfromscratch.org");
	aboutData.addCredit ( "Daniel Stone", I18N_NOOP("Former developer, Jabber plugin author"), "daniel@fooishbar.org", "http://fooishbar.org");
	aboutData.addCredit ( "Chris TenHarmsel", I18N_NOOP("Former developer, Oscar plugin"), "tenharmsel@users.sourceforge.net");
	aboutData.addCredit ( "Hendrik vom Lehn", I18N_NOOP("Former developer"), "hennevl@hennevl.de", "http://www.hennevl.de");

	aboutData.setTranslator( I18N_NOOP("_: NAME OF TRANSLATORS\nYour names"),
		I18N_NOOP("_: EMAIL OF TRANSLATORS\nYour emails") );

	KCmdLineArgs::init( argc, argv, &aboutData );
	KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
	KUniqueApplication::addCmdLineOptions();

	KopeteApplication kopete;
	new KIMIfaceImpl();
	kapp->dcopClient()->registerAs( "kopete", false );
	kapp->dcopClient()->setDefaultObject( (new KopeteIface())->objId() ); // Has to be called before exec

	kopete.exec();
}
// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


<commit_before>/*
 * This istream filter catches fatal errors and attempts to ignore
 * them.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_catch.hxx"
#include "ForwardIstream.hxx"
#include "util/Cast.hxx"

#include <daemon/log.h>

#include <assert.h>

class CatchIstream final : public ForwardIstream {
    off_t available = 0;

    GError *(*const callback)(GError *error, void *ctx);
    void *const callback_ctx;

public:
    CatchIstream(struct pool &pool, struct istream &_input,
                 GError *(*_callback)(GError *error, void *ctx), void *ctx)
        :ForwardIstream(pool, _input,
                        MakeIstreamHandler<CatchIstream>::handler, this),
         callback(_callback), callback_ctx(ctx) {}

    void SendSpace();

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override;

    off_t Skip(off_t length) override {
        off_t nbytes = ForwardIstream::Skip(length);
        if (nbytes > 0) {
            if (nbytes < available)
                available -= nbytes;
            else
                available = 0;
        }

        return nbytes;
    }

    void Read() override;
    void Close() override;

    /* handler */

    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);
    void OnError(GError *error);
};

static constexpr char space[] =
    "                                "
    "                                "
    "                                "
    "                                ";

void
CatchIstream::SendSpace()
{
    assert(!HasInput());
    assert(available > 0);

    do {
        size_t length;
        if (available >= (off_t)sizeof(space) - 1)
            length = sizeof(space) - 1;
        else
            length = (size_t)available;

        size_t nbytes = ForwardIstream::OnData(space, length);
        if (nbytes == 0)
            return;

        available -= nbytes;
        if (nbytes < length)
            return;
    } while (available > 0);

    DestroyEof();
}

/*
 * istream handler
 *
 */

size_t
CatchIstream::OnData(const void *data, size_t length)
{
    size_t nbytes = ForwardIstream::OnData(data, length);
    if (nbytes > 0) {
        if ((off_t)nbytes < available)
            available -= (off_t)nbytes;
        else
            available = 0;
    }

    return nbytes;
}

ssize_t
CatchIstream::OnDirect(FdType type, int fd, size_t max_length)
{
    ssize_t nbytes = ForwardIstream::OnDirect(type, fd, max_length);
    if (nbytes > 0) {
        if ((off_t)nbytes < available)
            available -= (off_t)nbytes;
        else
            available = 0;
    }

    return nbytes;
}

void
CatchIstream::OnError(GError *error)
{
    error = callback(error, callback_ctx);
    if (error != nullptr) {
        /* forward error to our handler */
        ForwardIstream::OnError(error);
        return;
    }

    /* the error has been handled by the callback, and he has disposed
       it */

    ClearInput();

    if (available > 0)
        /* according to a previous call to method "available", there
           is more data which we must provide - fill that with space
           characters */
        SendSpace();
    else
        DestroyEof();
}

/*
 * istream implementation
 *
 */

off_t
CatchIstream::GetAvailable(bool partial)
{
    if (HasInput()) {
        off_t result = ForwardIstream::GetAvailable(partial);
        if (result > available)
            available = result;

        return result;
    } else
        return available;
}

void
CatchIstream::Read()
{
    if (HasInput())
        ForwardIstream::Read();
    else
        SendSpace();
}

void
CatchIstream::Close()
{
    if (HasInput())
        input.CloseHandler();

    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_catch_new(struct pool *pool, struct istream *input,
                  GError *(*callback)(GError *error, void *ctx), void *ctx)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(callback != nullptr);

    return NewIstream<CatchIstream>(*pool, *input, callback, ctx);
}
<commit_msg>istream_catch: include cleanup<commit_after>/*
 * This istream filter catches fatal errors and attempts to ignore
 * them.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_catch.hxx"
#include "ForwardIstream.hxx"

#include <assert.h>

class CatchIstream final : public ForwardIstream {
    off_t available = 0;

    GError *(*const callback)(GError *error, void *ctx);
    void *const callback_ctx;

public:
    CatchIstream(struct pool &pool, struct istream &_input,
                 GError *(*_callback)(GError *error, void *ctx), void *ctx)
        :ForwardIstream(pool, _input,
                        MakeIstreamHandler<CatchIstream>::handler, this),
         callback(_callback), callback_ctx(ctx) {}

    void SendSpace();

    /* virtual methods from class Istream */

    off_t GetAvailable(bool partial) override;

    off_t Skip(off_t length) override {
        off_t nbytes = ForwardIstream::Skip(length);
        if (nbytes > 0) {
            if (nbytes < available)
                available -= nbytes;
            else
                available = 0;
        }

        return nbytes;
    }

    void Read() override;
    void Close() override;

    /* handler */

    size_t OnData(const void *data, size_t length);
    ssize_t OnDirect(FdType type, int fd, size_t max_length);
    void OnError(GError *error);
};

static constexpr char space[] =
    "                                "
    "                                "
    "                                "
    "                                ";

void
CatchIstream::SendSpace()
{
    assert(!HasInput());
    assert(available > 0);

    do {
        size_t length;
        if (available >= (off_t)sizeof(space) - 1)
            length = sizeof(space) - 1;
        else
            length = (size_t)available;

        size_t nbytes = ForwardIstream::OnData(space, length);
        if (nbytes == 0)
            return;

        available -= nbytes;
        if (nbytes < length)
            return;
    } while (available > 0);

    DestroyEof();
}

/*
 * istream handler
 *
 */

size_t
CatchIstream::OnData(const void *data, size_t length)
{
    size_t nbytes = ForwardIstream::OnData(data, length);
    if (nbytes > 0) {
        if ((off_t)nbytes < available)
            available -= (off_t)nbytes;
        else
            available = 0;
    }

    return nbytes;
}

ssize_t
CatchIstream::OnDirect(FdType type, int fd, size_t max_length)
{
    ssize_t nbytes = ForwardIstream::OnDirect(type, fd, max_length);
    if (nbytes > 0) {
        if ((off_t)nbytes < available)
            available -= (off_t)nbytes;
        else
            available = 0;
    }

    return nbytes;
}

void
CatchIstream::OnError(GError *error)
{
    error = callback(error, callback_ctx);
    if (error != nullptr) {
        /* forward error to our handler */
        ForwardIstream::OnError(error);
        return;
    }

    /* the error has been handled by the callback, and he has disposed
       it */

    ClearInput();

    if (available > 0)
        /* according to a previous call to method "available", there
           is more data which we must provide - fill that with space
           characters */
        SendSpace();
    else
        DestroyEof();
}

/*
 * istream implementation
 *
 */

off_t
CatchIstream::GetAvailable(bool partial)
{
    if (HasInput()) {
        off_t result = ForwardIstream::GetAvailable(partial);
        if (result > available)
            available = result;

        return result;
    } else
        return available;
}

void
CatchIstream::Read()
{
    if (HasInput())
        ForwardIstream::Read();
    else
        SendSpace();
}

void
CatchIstream::Close()
{
    if (HasInput())
        input.CloseHandler();

    Destroy();
}

/*
 * constructor
 *
 */

struct istream *
istream_catch_new(struct pool *pool, struct istream *input,
                  GError *(*callback)(GError *error, void *ctx), void *ctx)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));
    assert(callback != nullptr);

    return NewIstream<CatchIstream>(*pool, *input, callback, ctx);
}
<|endoftext|>


<commit_before>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_trace.hxx"
#include "istream_internal.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>
#include <stdio.h>

struct istream_trace {
    struct istream output;
    struct istream *input;
};

static void
trace_data(const void *data0, size_t length)
{
    const char *data = (const char *)data0;
    size_t i;

    fputc('"', stderr);
    for (i = 0; i < length; ++i) {
        if (data[i] == '\n')
            fputs("\\n", stderr);
        else if (data[i] == '\r')
            fputs("\\r", stderr);
        else if (data[i] == 0)
            fputs("\\0", stderr);
        else if (data[i] == '"')
            fputs("\\\"", stderr);
        else
            fputc(data[i], stderr);
    }
    fputs("\"\n", stderr);
}

/*
 * istream handler
 *
 */

static size_t
trace_input_data(const void *data, size_t length, void *ctx)
{
    auto *trace = (struct istream_trace *)ctx;
    size_t nbytes;

    fprintf(stderr, "%p data(%zu)\n", (const void*)trace, length);
    trace_data(data, length);
    nbytes = istream_invoke_data(&trace->output, data, length);
    fprintf(stderr, "%p data(%zu)=%zu\n", (const void*)trace, length, nbytes);

    return nbytes;
}

static ssize_t
trace_input_direct(FdType type, int fd, size_t max_length, void *ctx)
{
    auto *trace = (struct istream_trace *)ctx;

    fprintf(stderr, "%p direct(0x%x, %zd)\n", (const void*)trace,
            trace->output.handler_direct, max_length);
    auto nbytes = istream_invoke_direct(&trace->output, type, fd, max_length);
    fprintf(stderr, "%p direct(0x%x, %zd)=%zd\n", (const void*)trace,
            trace->output.handler_direct, max_length, nbytes);

    return nbytes;
}

static void
trace_input_eof(void *ctx)
{
    auto *trace = (struct istream_trace *)ctx;

    fprintf(stderr, "%p eof()\n", (const void*)trace);

    trace->input = nullptr;
    istream_deinit_eof(&trace->output);
}

static void
trace_input_abort(GError *error, void *ctx)
{
    auto *trace = (struct istream_trace *)ctx;

    fprintf(stderr, "%p abort('%s')\n", (const void*)trace, error->message);

    trace->input = nullptr;
    istream_deinit_abort(&trace->output, error);
}

static constexpr struct istream_handler trace_input_handler = {
    .data = trace_input_data,
    .direct = trace_input_direct,
    .eof = trace_input_eof,
    .abort = trace_input_abort,
};

/*
 * istream implementation
 *
 */

static inline constexpr struct istream_trace *
istream_to_trace(struct istream *istream)
{
    return &ContainerCast2(*istream, &istream_trace::output);
}

static off_t
istream_trace_available(struct istream *istream, bool partial)
{
    struct istream_trace *trace = istream_to_trace(istream);
    off_t available;

    fprintf(stderr, "%p available(%d)\n", (const void*)trace, partial);
    available = istream_available(trace->input, partial);
    fprintf(stderr, "%p available(%d)=%ld\n", (const void*)trace,
            partial, (long)available);

    return available;
}

static void
istream_trace_read(struct istream *istream)
{
    struct istream_trace *trace = istream_to_trace(istream);

    fprintf(stderr, "%p read(0x%x)\n", (const void*)trace,
            trace->output.handler_direct);

    istream_handler_set_direct(trace->input, trace->output.handler_direct);
    istream_read(trace->input);
}

static void
istream_trace_close(struct istream *istream)
{
    struct istream_trace *trace = istream_to_trace(istream);

    fprintf(stderr, "%p close()\n", (const void*)trace);

    istream_close_handler(trace->input);
    istream_deinit(&trace->output);
}

static constexpr struct istream_class istream_trace = {
    .available = istream_trace_available,
    .read = istream_trace_read,
    .close = istream_trace_close,
};

/*
 * constructor
 *
 */

struct istream *
istream_trace_new(struct pool *pool, struct istream *input)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto trace = NewFromPool<struct istream_trace>(*pool);
    istream_init(&trace->output, &istream_trace, pool);

    fprintf(stderr, "%p new()\n", (const void*)trace);

    istream_assign_handler(&trace->input, input,
                           &trace_input_handler, trace,
                           0);

    return &trace->output;
}
<commit_msg>istream_trace: rename the struct with CamelCase<commit_after>/*
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "istream_trace.hxx"
#include "istream_internal.hxx"
#include "pool.hxx"
#include "util/Cast.hxx"

#include <assert.h>
#include <stdio.h>

struct TraceIstream {
    struct istream output;
    struct istream *input;
};

static void
trace_data(const void *data0, size_t length)
{
    const char *data = (const char *)data0;
    size_t i;

    fputc('"', stderr);
    for (i = 0; i < length; ++i) {
        if (data[i] == '\n')
            fputs("\\n", stderr);
        else if (data[i] == '\r')
            fputs("\\r", stderr);
        else if (data[i] == 0)
            fputs("\\0", stderr);
        else if (data[i] == '"')
            fputs("\\\"", stderr);
        else
            fputc(data[i], stderr);
    }
    fputs("\"\n", stderr);
}

/*
 * istream handler
 *
 */

static size_t
trace_input_data(const void *data, size_t length, void *ctx)
{
    auto *trace = (TraceIstream *)ctx;
    size_t nbytes;

    fprintf(stderr, "%p data(%zu)\n", (const void*)trace, length);
    trace_data(data, length);
    nbytes = istream_invoke_data(&trace->output, data, length);
    fprintf(stderr, "%p data(%zu)=%zu\n", (const void*)trace, length, nbytes);

    return nbytes;
}

static ssize_t
trace_input_direct(FdType type, int fd, size_t max_length, void *ctx)
{
    auto *trace = (TraceIstream *)ctx;

    fprintf(stderr, "%p direct(0x%x, %zd)\n", (const void*)trace,
            trace->output.handler_direct, max_length);
    auto nbytes = istream_invoke_direct(&trace->output, type, fd, max_length);
    fprintf(stderr, "%p direct(0x%x, %zd)=%zd\n", (const void*)trace,
            trace->output.handler_direct, max_length, nbytes);

    return nbytes;
}

static void
trace_input_eof(void *ctx)
{
    auto *trace = (TraceIstream *)ctx;

    fprintf(stderr, "%p eof()\n", (const void*)trace);

    trace->input = nullptr;
    istream_deinit_eof(&trace->output);
}

static void
trace_input_abort(GError *error, void *ctx)
{
    auto *trace = (TraceIstream *)ctx;

    fprintf(stderr, "%p abort('%s')\n", (const void*)trace, error->message);

    trace->input = nullptr;
    istream_deinit_abort(&trace->output, error);
}

static constexpr struct istream_handler trace_input_handler = {
    .data = trace_input_data,
    .direct = trace_input_direct,
    .eof = trace_input_eof,
    .abort = trace_input_abort,
};

/*
 * istream implementation
 *
 */

static inline constexpr TraceIstream *
istream_to_trace(struct istream *istream)
{
    return &ContainerCast2(*istream, &TraceIstream::output);
}

static off_t
istream_trace_available(struct istream *istream, bool partial)
{
    TraceIstream *trace = istream_to_trace(istream);
    off_t available;

    fprintf(stderr, "%p available(%d)\n", (const void*)trace, partial);
    available = istream_available(trace->input, partial);
    fprintf(stderr, "%p available(%d)=%ld\n", (const void*)trace,
            partial, (long)available);

    return available;
}

static void
istream_trace_read(struct istream *istream)
{
    TraceIstream *trace = istream_to_trace(istream);

    fprintf(stderr, "%p read(0x%x)\n", (const void*)trace,
            trace->output.handler_direct);

    istream_handler_set_direct(trace->input, trace->output.handler_direct);
    istream_read(trace->input);
}

static void
istream_trace_close(struct istream *istream)
{
    TraceIstream *trace = istream_to_trace(istream);

    fprintf(stderr, "%p close()\n", (const void*)trace);

    istream_close_handler(trace->input);
    istream_deinit(&trace->output);
}

static constexpr struct istream_class istream_trace = {
    .available = istream_trace_available,
    .read = istream_trace_read,
    .close = istream_trace_close,
};

/*
 * constructor
 *
 */

struct istream *
istream_trace_new(struct pool *pool, struct istream *input)
{
    assert(input != nullptr);
    assert(!istream_has_handler(input));

    auto trace = NewFromPool<TraceIstream>(*pool);
    istream_init(&trace->output, &istream_trace, pool);

    fprintf(stderr, "%p new()\n", (const void*)trace);

    istream_assign_handler(&trace->input, input,
                           &trace_input_handler, trace,
                           0);

    return &trace->output;
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "test_roudi_service_discovery.hpp"

class RoudiFindService_test : public RouDiServiceDiscoveryTest
{
  public:
    void SetUp()
    {
    }

    void TearDown()
    {
    }

    iox::runtime::PoshRuntime* senderRuntime{&iox::runtime::PoshRuntime::getInstance("/sender")};
    iox::runtime::PoshRuntime* receiverRuntime{&iox::runtime::PoshRuntime::getInstance("/receiver")};
};

TEST_F(RoudiFindService_test, OfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

///@todo offere service should return bool signalling success/failure
TEST_F(RoudiFindService_test, DISABLED_OfferServiceWithDefaultServiceDescriptionFails)
{
    iox::runtime::InstanceContainer instanceContainer;
    bool isServiceOffered;

    // isServiceOffered = senderRuntime->offerService(iox::capro::ServiceDescription());
    this->InterOpWait();

    ASSERT_EQ(false, isServiceOffered);
}

TEST_F(RoudiFindService_test, ReofferedServiceWithValidServiceDescriptionCanBeFound)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindSameServiceMultipleTimesSuccessfully)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(2u));
    ASSERT_THAT(instanceContainer.at(0), Eq(IdString("instance1")));
    ASSERT_THAT(instanceContainer.at(1), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, DISABLED_OfferMultiMethodServiceSingleInstance_PERFORMANCETEST42)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});

    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, SubscribeAnyInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});

    this->InterOpWait();
    InstanceContainer instanceContainer;
    InstanceContainer instanceContainerExp;
    InitContainer(instanceContainerExp, {"instance1", "instance2", "instance3"});

    receiverRuntime->findService({"service1", "65535"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(3u));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
}

TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service2", "instance2"});
    senderRuntime->offerService({"service2", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, StopOfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    senderRuntime->stopOfferService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopNonExistingService)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service2", "instance2"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindNonExistingServices)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}
TEST_F(RoudiFindService_test, InterfacePort)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto interfacePortData = receiverRuntime->getMiddlewareInterface(iox::capro::Interfaces::SOMEIP);
    iox::popo::InterfacePort interfacePort(interfacePortData);

    this->InterOpWait();

    bool serviceFound = false;

    while (auto maybeCaProMessage = interfacePort.tryGetCaProMessage())
    {
        auto caproMessage = maybeCaProMessage.value();
        if ((caproMessage.m_serviceDescription.getServiceIDString() == IdString("service1"))
            && (caproMessage.m_serviceDescription.getInstanceIDString() == IdString("instance1"))
            && ((caproMessage.m_serviceDescription.getEventIDString() == IdString(iox::capro::AnyEventString))))
        {
            serviceFound = true;
            break;
        }
    }

    EXPECT_THAT(serviceFound, Eq(true));
}

TEST_F(RoudiFindService_test, findServiceMaxInstances)
{
    size_t noOfInstances = iox::MAX_NUMBER_OF_INSTANCES;
    InstanceContainer instanceContainerExp;

    for (size_t i = 0; i < noOfInstances; i++)
    {
        // Service & Instance string is kept short , to reduce the response size in find service request ,
        // (message queue has a limit of 512)
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(false));
}

TEST_F(RoudiFindService_test, findServiceInstanceContainerOverflowError)
{
    size_t noOfInstances = (iox::MAX_NUMBER_OF_INSTANCES + 1);
    InstanceContainer instanceContainerExp;
    for (size_t i = 0; i < noOfInstances; i++)
    {
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(true));
}
<commit_msg>iox-#240 linked iox issue against broken test<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "test_roudi_service_discovery.hpp"

class RoudiFindService_test : public RouDiServiceDiscoveryTest
{
  public:
    void SetUp()
    {
    }

    void TearDown()
    {
    }

    iox::runtime::PoshRuntime* senderRuntime{&iox::runtime::PoshRuntime::getInstance("/sender")};
    iox::runtime::PoshRuntime* receiverRuntime{&iox::runtime::PoshRuntime::getInstance("/receiver")};
};

TEST_F(RoudiFindService_test, OfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

///@todo #359 offereService should return bool signalling success/failure
TEST_F(RoudiFindService_test, DISABLED_OfferServiceWithDefaultServiceDescriptionFails)
{
    iox::runtime::InstanceContainer instanceContainer;
    bool isServiceOffered;

    ///@todo #359 offerService should not allow invalid ServiceDescriptions
    // isServiceOffered = senderRuntime->offerService(iox::capro::ServiceDescription());
    this->InterOpWait();

    ASSERT_EQ(false, isServiceOffered);
}

TEST_F(RoudiFindService_test, ReofferedServiceWithValidServiceDescriptionCanBeFound)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindSameServiceMultipleTimesSuccessfully)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(2u));
    ASSERT_THAT(instanceContainer.at(0), Eq(IdString("instance1")));
    ASSERT_THAT(instanceContainer.at(1), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, DISABLED_OfferMultiMethodServiceSingleInstance_PERFORMANCETEST42)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});

    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, SubscribeAnyInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});

    this->InterOpWait();
    InstanceContainer instanceContainer;
    InstanceContainer instanceContainerExp;
    InitContainer(instanceContainerExp, {"instance1", "instance2", "instance3"});

    receiverRuntime->findService({"service1", "65535"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(3u));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
}

TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service2", "instance2"});
    senderRuntime->offerService({"service2", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, StopOfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    senderRuntime->stopOfferService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopNonExistingService)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service2", "instance2"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindNonExistingServices)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}
TEST_F(RoudiFindService_test, InterfacePort)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto interfacePortData = receiverRuntime->getMiddlewareInterface(iox::capro::Interfaces::SOMEIP);
    iox::popo::InterfacePort interfacePort(interfacePortData);

    this->InterOpWait();

    bool serviceFound = false;

    while (auto maybeCaProMessage = interfacePort.tryGetCaProMessage())
    {
        auto caproMessage = maybeCaProMessage.value();
        if ((caproMessage.m_serviceDescription.getServiceIDString() == IdString("service1"))
            && (caproMessage.m_serviceDescription.getInstanceIDString() == IdString("instance1"))
            && ((caproMessage.m_serviceDescription.getEventIDString() == IdString(iox::capro::AnyEventString))))
        {
            serviceFound = true;
            break;
        }
    }

    EXPECT_THAT(serviceFound, Eq(true));
}

TEST_F(RoudiFindService_test, findServiceMaxInstances)
{
    size_t noOfInstances = iox::MAX_NUMBER_OF_INSTANCES;
    InstanceContainer instanceContainerExp;

    for (size_t i = 0; i < noOfInstances; i++)
    {
        // Service & Instance string is kept short , to reduce the response size in find service request ,
        // (message queue has a limit of 512)
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(false));
}

TEST_F(RoudiFindService_test, findServiceInstanceContainerOverflowError)
{
    size_t noOfInstances = (iox::MAX_NUMBER_OF_INSTANCES + 1);
    InstanceContainer instanceContainerExp;
    for (size_t i = 0; i < noOfInstances; i++)
    {
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(true));
}
<|endoftext|>