<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAndroidCodec.h"
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkRawAdapterCodec.h"
#include "SkSampledCodec.h"
#include "SkWebpAdapterCodec.h"

static bool is_valid_sample_size(int sampleSize) {
    // FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
    return sampleSize > 0;
}

#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
/**
 *  Loads the gamut as a set of three points (triangle).
 */
static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) {
    // rx = rX / (rX + rY + rZ)
    // ry = rY / (rX + rY + rZ)
    // gx, gy, bx, and gy are calulcated similarly.
    float rSum = xyz.get(0, 0) + xyz.get(1, 0) + xyz.get(2, 0);
    float gSum = xyz.get(0, 1) + xyz.get(1, 1) + xyz.get(2, 1);
    float bSum = xyz.get(0, 2) + xyz.get(1, 2) + xyz.get(2, 2);
    rgb[0].fX = xyz.get(0, 0) / rSum;
    rgb[0].fY = xyz.get(1, 0) / rSum;
    rgb[1].fX = xyz.get(0, 1) / gSum;
    rgb[1].fY = xyz.get(1, 1) / gSum;
    rgb[2].fX = xyz.get(0, 2) / bSum;
    rgb[2].fY = xyz.get(1, 2) / bSum;
}

/**
 *  Calculates the area of the triangular gamut.
 */
static float calculate_area(SkPoint abc[]) {
    SkPoint a = abc[0];
    SkPoint b = abc[1];
    SkPoint c = abc[2];
    return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY);
}

static const float kSRGB_D50_GamutArea = 0.084f;

static bool is_wide_gamut(const SkColorSpace* colorSpace) {
    // Determine if the source image has a gamut that is wider than sRGB.  If so, we
    // will use P3 as the output color space to avoid clipping the gamut.
    const SkMatrix44* toXYZD50 = as_CSB(colorSpace)->toXYZD50();
    if (toXYZD50) {
        SkPoint rgb[3];
        load_gamut(rgb, *toXYZD50);
        return calculate_area(rgb) > kSRGB_D50_GamutArea;
    }

    return false;
}
#endif

SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
    : fInfo(codec->getInfo())
    , fCodec(codec)
{}

SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream, chunkReader));
    if (nullptr == codec) {
        return nullptr;
    }

    switch ((SkEncodedImageFormat)codec->getEncodedFormat()) {
#ifdef SK_HAS_PNG_LIBRARY
        case SkEncodedImageFormat::kPNG:
        case SkEncodedImageFormat::kICO:
#endif
#ifdef SK_HAS_JPEG_LIBRARY
        case SkEncodedImageFormat::kJPEG:
#endif
        case SkEncodedImageFormat::kGIF:
        case SkEncodedImageFormat::kBMP:
        case SkEncodedImageFormat::kWBMP:
            return new SkSampledCodec(codec.release());
#ifdef SK_HAS_WEBP_LIBRARY
        case SkEncodedImageFormat::kWEBP:
            return new SkWebpAdapterCodec((SkWebpCodec*) codec.release());
#endif
#ifdef SK_CODEC_DECODES_RAW
        case SkEncodedImageFormat::kDNG:
            return new SkRawAdapterCodec((SkRawCodec*)codec.release());
#endif
        default:
            return nullptr;
    }
}

SkAndroidCodec* SkAndroidCodec::NewFromData(sk_sp<SkData> data, SkPngChunkReader* chunkReader) {
    if (!data) {
        return nullptr;
    }

    return NewFromStream(new SkMemoryStream(data), chunkReader);
}

SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
    bool highPrecision = fCodec->getEncodedInfo().bitsPerComponent() > 8;
    switch (requestedColorType) {
        case kARGB_4444_SkColorType:
            return kN32_SkColorType;
        case kN32_SkColorType:
#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
        case kIndex_8_SkColorType:
#endif
            break;
        case kAlpha_8_SkColorType:
            // Fall through to kGray_8.  Before kGray_8_SkColorType existed,
            // we allowed clients to request kAlpha_8 when they wanted a
            // grayscale decode.
        case kGray_8_SkColorType:
            if (kGray_8_SkColorType == this->getInfo().colorType()) {
                return kGray_8_SkColorType;
            }
            break;
        case kRGB_565_SkColorType:
            if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
                return kRGB_565_SkColorType;
            }
            break;
        case kRGBA_F16_SkColorType:
            return kRGBA_F16_SkColorType;
        default:
            break;
    }

    // F16 is the Android default for high precision images.
    return highPrecision ? kRGBA_F16_SkColorType : kN32_SkColorType;
}

SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
    if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
        return kOpaque_SkAlphaType;
    }
    return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
}

sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputColorType,
                                                            sk_sp<SkColorSpace> prefColorSpace) {
    switch (outputColorType) {
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType:
#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
        case kIndex_8_SkColorType: {
            // If |prefColorSpace| is supported, choose it.
            SkColorSpaceTransferFn fn;
            if (prefColorSpace && prefColorSpace->isNumericalTransferFn(&fn)) {
                return prefColorSpace;
            }

            SkColorSpace* encodedSpace = fCodec->getInfo().colorSpace();
            if (encodedSpace->isNumericalTransferFn(&fn)) {
                // Leave the pixels in the encoded color space.  Color space conversion
                // will be handled after decode time.
                return sk_ref_sp(encodedSpace);
            }

            if (is_wide_gamut(encodedSpace)) {
                return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
                                             SkColorSpace::kDCIP3_D65_Gamut);
            }

            return SkColorSpace::MakeSRGB();
        }
#endif
        case kRGBA_F16_SkColorType:
            // Note that |prefColorSpace| is ignored, F16 is always linear sRGB.
            return SkColorSpace::MakeSRGBLinear();
        case kRGB_565_SkColorType:
            // Note that |prefColorSpace| is ignored, 565 is always sRGB.
            return SkColorSpace::MakeSRGB();
        default:
            // Color correction not supported for kGray.
            return nullptr;
    }
}

SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
    if (!is_valid_sample_size(sampleSize)) {
        return {0, 0};
    }

    // Fast path for when we are not scaling.
    if (1 == sampleSize) {
        return fInfo.dimensions();
    }

    return this->onGetSampledDimensions(sampleSize);
}

bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
    if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
        return false;
    }

    return this->onGetSupportedSubset(desiredSubset);
}

SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
    if (!is_valid_sample_size(sampleSize)) {
        return {0, 0};
    }

    // We require that the input subset is a subset that is supported by SkAndroidCodec.
    // We test this by calling getSupportedSubset() and verifying that no modifications
    // are made to the subset.
    SkIRect copySubset = subset;
    if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
        return {0, 0};
    }

    // If the subset is the entire image, for consistency, use getSampledDimensions().
    if (fInfo.dimensions() == subset.size()) {
        return this->getSampledDimensions(sampleSize);
    }

    // This should perhaps call a virtual function, but currently both of our subclasses
    // want the same implementation.
    return {get_scaled_dimension(subset.width(), sampleSize),
            get_scaled_dimension(subset.height(), sampleSize)};
}

SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
        size_t rowBytes, const AndroidOptions* options) {
    if (!pixels) {
        return SkCodec::kInvalidParameters;
    }
    if (rowBytes < info.minRowBytes()) {
        return SkCodec::kInvalidParameters;
    }

    AndroidOptions defaultOptions;
    if (!options) {
        options = &defaultOptions;
    } else if (options->fSubset) {
        if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
            return SkCodec::kInvalidParameters;
        }

        if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
            // The caller wants the whole thing, rather than a subset. Modify
            // the AndroidOptions passed to onGetAndroidPixels to not specify
            // a subset.
            defaultOptions = *options;
            defaultOptions.fSubset = nullptr;
            options = &defaultOptions;
        }
    }

    return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
}

SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
        size_t rowBytes) {
    return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
}
<commit_msg>Fix computeOutputColorSpace<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkAndroidCodec.h"
#include "SkCodec.h"
#include "SkCodecPriv.h"
#include "SkRawAdapterCodec.h"
#include "SkSampledCodec.h"
#include "SkWebpAdapterCodec.h"

static bool is_valid_sample_size(int sampleSize) {
    // FIXME: As Leon has mentioned elsewhere, surely there is also a maximum sampleSize?
    return sampleSize > 0;
}

/**
 *  Loads the gamut as a set of three points (triangle).
 */
static void load_gamut(SkPoint rgb[], const SkMatrix44& xyz) {
    // rx = rX / (rX + rY + rZ)
    // ry = rY / (rX + rY + rZ)
    // gx, gy, bx, and gy are calulcated similarly.
    float rSum = xyz.get(0, 0) + xyz.get(1, 0) + xyz.get(2, 0);
    float gSum = xyz.get(0, 1) + xyz.get(1, 1) + xyz.get(2, 1);
    float bSum = xyz.get(0, 2) + xyz.get(1, 2) + xyz.get(2, 2);
    rgb[0].fX = xyz.get(0, 0) / rSum;
    rgb[0].fY = xyz.get(1, 0) / rSum;
    rgb[1].fX = xyz.get(0, 1) / gSum;
    rgb[1].fY = xyz.get(1, 1) / gSum;
    rgb[2].fX = xyz.get(0, 2) / bSum;
    rgb[2].fY = xyz.get(1, 2) / bSum;
}

/**
 *  Calculates the area of the triangular gamut.
 */
static float calculate_area(SkPoint abc[]) {
    SkPoint a = abc[0];
    SkPoint b = abc[1];
    SkPoint c = abc[2];
    return 0.5f * SkTAbs(a.fX*b.fY + b.fX*c.fY - a.fX*c.fY - c.fX*b.fY - b.fX*a.fY);
}

static const float kSRGB_D50_GamutArea = 0.084f;

static bool is_wide_gamut(const SkColorSpace* colorSpace) {
    // Determine if the source image has a gamut that is wider than sRGB.  If so, we
    // will use P3 as the output color space to avoid clipping the gamut.
    const SkMatrix44* toXYZD50 = as_CSB(colorSpace)->toXYZD50();
    if (toXYZD50) {
        SkPoint rgb[3];
        load_gamut(rgb, *toXYZD50);
        return calculate_area(rgb) > kSRGB_D50_GamutArea;
    }

    return false;
}

SkAndroidCodec::SkAndroidCodec(SkCodec* codec)
    : fInfo(codec->getInfo())
    , fCodec(codec)
{}

SkAndroidCodec* SkAndroidCodec::NewFromStream(SkStream* stream, SkPngChunkReader* chunkReader) {
    std::unique_ptr<SkCodec> codec(SkCodec::NewFromStream(stream, chunkReader));
    if (nullptr == codec) {
        return nullptr;
    }

    switch ((SkEncodedImageFormat)codec->getEncodedFormat()) {
#ifdef SK_HAS_PNG_LIBRARY
        case SkEncodedImageFormat::kPNG:
        case SkEncodedImageFormat::kICO:
#endif
#ifdef SK_HAS_JPEG_LIBRARY
        case SkEncodedImageFormat::kJPEG:
#endif
        case SkEncodedImageFormat::kGIF:
        case SkEncodedImageFormat::kBMP:
        case SkEncodedImageFormat::kWBMP:
            return new SkSampledCodec(codec.release());
#ifdef SK_HAS_WEBP_LIBRARY
        case SkEncodedImageFormat::kWEBP:
            return new SkWebpAdapterCodec((SkWebpCodec*) codec.release());
#endif
#ifdef SK_CODEC_DECODES_RAW
        case SkEncodedImageFormat::kDNG:
            return new SkRawAdapterCodec((SkRawCodec*)codec.release());
#endif
        default:
            return nullptr;
    }
}

SkAndroidCodec* SkAndroidCodec::NewFromData(sk_sp<SkData> data, SkPngChunkReader* chunkReader) {
    if (!data) {
        return nullptr;
    }

    return NewFromStream(new SkMemoryStream(data), chunkReader);
}

SkColorType SkAndroidCodec::computeOutputColorType(SkColorType requestedColorType) {
    bool highPrecision = fCodec->getEncodedInfo().bitsPerComponent() > 8;
    switch (requestedColorType) {
        case kARGB_4444_SkColorType:
            return kN32_SkColorType;
        case kN32_SkColorType:
#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
        case kIndex_8_SkColorType:
#endif
            break;
        case kAlpha_8_SkColorType:
            // Fall through to kGray_8.  Before kGray_8_SkColorType existed,
            // we allowed clients to request kAlpha_8 when they wanted a
            // grayscale decode.
        case kGray_8_SkColorType:
            if (kGray_8_SkColorType == this->getInfo().colorType()) {
                return kGray_8_SkColorType;
            }
            break;
        case kRGB_565_SkColorType:
            if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
                return kRGB_565_SkColorType;
            }
            break;
        case kRGBA_F16_SkColorType:
            return kRGBA_F16_SkColorType;
        default:
            break;
    }

    // F16 is the Android default for high precision images.
    return highPrecision ? kRGBA_F16_SkColorType : kN32_SkColorType;
}

SkAlphaType SkAndroidCodec::computeOutputAlphaType(bool requestedUnpremul) {
    if (kOpaque_SkAlphaType == this->getInfo().alphaType()) {
        return kOpaque_SkAlphaType;
    }
    return requestedUnpremul ? kUnpremul_SkAlphaType : kPremul_SkAlphaType;
}

sk_sp<SkColorSpace> SkAndroidCodec::computeOutputColorSpace(SkColorType outputColorType,
                                                            sk_sp<SkColorSpace> prefColorSpace) {
    switch (outputColorType) {
#ifdef SK_SUPPORT_LEGACY_INDEX_8_COLORTYPE
        case kIndex_8_SkColorType:
#endif
        case kRGBA_8888_SkColorType:
        case kBGRA_8888_SkColorType: {
            // If |prefColorSpace| is supported, choose it.
            SkColorSpaceTransferFn fn;
            if (prefColorSpace && prefColorSpace->isNumericalTransferFn(&fn)) {
                return prefColorSpace;
            }

            SkColorSpace* encodedSpace = fCodec->getInfo().colorSpace();
            if (encodedSpace->isNumericalTransferFn(&fn)) {
                // Leave the pixels in the encoded color space.  Color space conversion
                // will be handled after decode time.
                return sk_ref_sp(encodedSpace);
            }

            if (is_wide_gamut(encodedSpace)) {
                return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma,
                                             SkColorSpace::kDCIP3_D65_Gamut);
            }

            return SkColorSpace::MakeSRGB();
        }
        case kRGBA_F16_SkColorType:
            // Note that |prefColorSpace| is ignored, F16 is always linear sRGB.
            return SkColorSpace::MakeSRGBLinear();
        case kRGB_565_SkColorType:
            // Note that |prefColorSpace| is ignored, 565 is always sRGB.
            return SkColorSpace::MakeSRGB();
        default:
            // Color correction not supported for kGray.
            return nullptr;
    }
}

SkISize SkAndroidCodec::getSampledDimensions(int sampleSize) const {
    if (!is_valid_sample_size(sampleSize)) {
        return {0, 0};
    }

    // Fast path for when we are not scaling.
    if (1 == sampleSize) {
        return fInfo.dimensions();
    }

    return this->onGetSampledDimensions(sampleSize);
}

bool SkAndroidCodec::getSupportedSubset(SkIRect* desiredSubset) const {
    if (!desiredSubset || !is_valid_subset(*desiredSubset, fInfo.dimensions())) {
        return false;
    }

    return this->onGetSupportedSubset(desiredSubset);
}

SkISize SkAndroidCodec::getSampledSubsetDimensions(int sampleSize, const SkIRect& subset) const {
    if (!is_valid_sample_size(sampleSize)) {
        return {0, 0};
    }

    // We require that the input subset is a subset that is supported by SkAndroidCodec.
    // We test this by calling getSupportedSubset() and verifying that no modifications
    // are made to the subset.
    SkIRect copySubset = subset;
    if (!this->getSupportedSubset(&copySubset) || copySubset != subset) {
        return {0, 0};
    }

    // If the subset is the entire image, for consistency, use getSampledDimensions().
    if (fInfo.dimensions() == subset.size()) {
        return this->getSampledDimensions(sampleSize);
    }

    // This should perhaps call a virtual function, but currently both of our subclasses
    // want the same implementation.
    return {get_scaled_dimension(subset.width(), sampleSize),
            get_scaled_dimension(subset.height(), sampleSize)};
}

SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
        size_t rowBytes, const AndroidOptions* options) {
    if (!pixels) {
        return SkCodec::kInvalidParameters;
    }
    if (rowBytes < info.minRowBytes()) {
        return SkCodec::kInvalidParameters;
    }

    AndroidOptions defaultOptions;
    if (!options) {
        options = &defaultOptions;
    } else if (options->fSubset) {
        if (!is_valid_subset(*options->fSubset, fInfo.dimensions())) {
            return SkCodec::kInvalidParameters;
        }

        if (SkIRect::MakeSize(fInfo.dimensions()) == *options->fSubset) {
            // The caller wants the whole thing, rather than a subset. Modify
            // the AndroidOptions passed to onGetAndroidPixels to not specify
            // a subset.
            defaultOptions = *options;
            defaultOptions.fSubset = nullptr;
            options = &defaultOptions;
        }
    }

    return this->onGetAndroidPixels(info, pixels, rowBytes, *options);
}

SkCodec::Result SkAndroidCodec::getAndroidPixels(const SkImageInfo& info, void* pixels,
        size_t rowBytes) {
    return this->getAndroidPixels(info, pixels, rowBytes, nullptr);
}
<|endoftext|>


<commit_before>//===- FindUnsafePointerTypes.cpp - Check pointer usage safety ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a pass that can be used to determine, interprocedurally,
// which pointer types are accessed unsafely in a program.  If there is an
// "unsafe" access to a specific pointer type, transformations that depend on
// type safety cannot be permitted.
//
// The result of running this analysis over a program is a set of unsafe pointer
// types that cannot be transformed.  Safe pointer types are not tracked.
//
// Additionally, this analysis exports a hidden command line argument that (when
// enabled) prints out the reasons a type was determined to be unsafe.
//
// Currently, the only allowed operations on pointer types are:
//   alloca, malloc, free, getelementptr, load, and store
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/FindUnsafePointerTypes.h"
#include "llvm/Assembly/CachedWriter.h"
#include "llvm/Type.h"
#include "llvm/Module.h"
#include "llvm/Support/InstIterator.h"
#include "Support/CommandLine.h"

namespace llvm {

static RegisterAnalysis<FindUnsafePointerTypes>
X("unsafepointertypes", "Find Unsafe Pointer Types");

// Provide a command line option to turn on printing of which instructions cause
// a type to become invalid
//
static cl::opt<bool>
PrintFailures("printunsafeptrinst", cl::Hidden,
              cl::desc("Print Unsafe Pointer Access Instructions"));

static inline bool isSafeInstruction(const Instruction &I) {
  switch (I.getOpcode()) {
  case Instruction::Alloca:
  case Instruction::Malloc:
  case Instruction::Free:
  case Instruction::Load:
  case Instruction::Store:
  case Instruction::GetElementPtr:
  case Instruction::Call:
  case Instruction::Invoke:
  case Instruction::PHI:
    return true;
  }
  return false;
}

bool FindUnsafePointerTypes::run(Module &Mod) {
  for (Module::iterator FI = Mod.begin(), E = Mod.end();
       FI != E; ++FI) {
    const Function *F = FI;  // We don't need/want write access
    for (const_inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
      const Type *ITy = I->getType();
      if (isa<PointerType>(ITy) && !UnsafeTypes.count((PointerType*)ITy))
        if (!isSafeInstruction(*I)) {
          UnsafeTypes.insert((PointerType*)ITy);

          if (PrintFailures) {
            CachedWriter CW(F->getParent(), std::cerr);
            CW << "FindUnsafePointerTypes: Type '" << ITy
               << "' marked unsafe in '" << F->getName() << "' by:\n" << *I;
          }
        }
    }
  }

  return false;
}

// printResults - Loop over the results of the analysis, printing out unsafe
// types.
//
void FindUnsafePointerTypes::print(std::ostream &o, const Module *M) const {
  if (UnsafeTypes.empty()) {
    o << "SafePointerAccess Analysis: No unsafe types found!\n";
    return;
  }

  CachedWriter CW(M, o);

  CW << "SafePointerAccess Analysis: Found these unsafe types:\n";
  unsigned Counter = 1;
  for (std::set<PointerType*>::const_iterator I = getUnsafeTypes().begin(),
         E = getUnsafeTypes().end(); I != E; ++I, ++Counter) {

    CW << " #" << Counter << ". " << (Value*)*I << "\n";
  }
}

} // End llvm namespace
<commit_msg>Send text and numbers directly to CachedWriter's contained ostream.<commit_after>//===- FindUnsafePointerTypes.cpp - Check pointer usage safety ------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines a pass that can be used to determine, interprocedurally,
// which pointer types are accessed unsafely in a program.  If there is an
// "unsafe" access to a specific pointer type, transformations that depend on
// type safety cannot be permitted.
//
// The result of running this analysis over a program is a set of unsafe pointer
// types that cannot be transformed.  Safe pointer types are not tracked.
//
// Additionally, this analysis exports a hidden command line argument that (when
// enabled) prints out the reasons a type was determined to be unsafe.
//
// Currently, the only allowed operations on pointer types are:
//   alloca, malloc, free, getelementptr, load, and store
//
//===----------------------------------------------------------------------===//

#include "llvm/Analysis/FindUnsafePointerTypes.h"
#include "llvm/Assembly/CachedWriter.h"
#include "llvm/Type.h"
#include "llvm/Module.h"
#include "llvm/Support/InstIterator.h"
#include "Support/CommandLine.h"

namespace llvm {

static RegisterAnalysis<FindUnsafePointerTypes>
X("unsafepointertypes", "Find Unsafe Pointer Types");

// Provide a command line option to turn on printing of which instructions cause
// a type to become invalid
//
static cl::opt<bool>
PrintFailures("printunsafeptrinst", cl::Hidden,
              cl::desc("Print Unsafe Pointer Access Instructions"));

static inline bool isSafeInstruction(const Instruction &I) {
  switch (I.getOpcode()) {
  case Instruction::Alloca:
  case Instruction::Malloc:
  case Instruction::Free:
  case Instruction::Load:
  case Instruction::Store:
  case Instruction::GetElementPtr:
  case Instruction::Call:
  case Instruction::Invoke:
  case Instruction::PHI:
    return true;
  }
  return false;
}

bool FindUnsafePointerTypes::run(Module &Mod) {
  for (Module::iterator FI = Mod.begin(), E = Mod.end();
       FI != E; ++FI) {
    const Function *F = FI;  // We don't need/want write access
    for (const_inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
      const Type *ITy = I->getType();
      if (isa<PointerType>(ITy) && !UnsafeTypes.count((PointerType*)ITy))
        if (!isSafeInstruction(*I)) {
          UnsafeTypes.insert((PointerType*)ITy);

          if (PrintFailures) {
            CachedWriter CW(F->getParent(), std::cerr);
            CW << "FindUnsafePointerTypes: Type '" << ITy
               << "' marked unsafe in '" << F->getName() << "' by:\n" << *I;
          }
        }
    }
  }

  return false;
}

// printResults - Loop over the results of the analysis, printing out unsafe
// types.
//
void FindUnsafePointerTypes::print(std::ostream &o, const Module *M) const {
  if (UnsafeTypes.empty()) {
    o << "SafePointerAccess Analysis: No unsafe types found!\n";
    return;
  }

  CachedWriter CW(M, o);

  CW << "SafePointerAccess Analysis: Found these unsafe types:\n";
  unsigned Counter = 1;
  for (std::set<PointerType*>::const_iterator I = getUnsafeTypes().begin(),
         E = getUnsafeTypes().end(); I != E; ++I, ++Counter) {

    o << " #" << Counter << ". ";
    CW << (Value*)*I << "\n";
  }
}

} // End llvm namespace
<|endoftext|>


<commit_before>#include "logging.hh"
#include "nixexpr.hh"
#include "util.hh"

#include <iostream>
#include <optional>

using namespace nix;

MakeError(DemoError, Error);

int main()
{
    verbosity = lvlVomit;

    // In each program where errors occur, this has to be set.
    ErrorInfo::programName = std::optional("error-demo");

    // 'DemoError' appears as error name.
    try {
        throw DemoError("demo error was thrown");
    } catch (Error &e) {
        logger->logEI(e.info());
    }

    // appending to the hint from the previous error
    try {
        auto e = Error("initial error");
        throw DemoError(e.info());
    } catch (Error &e) {
        ErrorInfo ei = e.info();
        // using normaltxt to avoid the default yellow highlighting.
        ei.hint = hintfmt("%s; subsequent error message.",
            normaltxt(e.info().hint ? e.info().hint->str() : ""));
        logger->logEI(ei);
    }

    // SysError; picks up errno
    try {
        auto x = readFile(-1);
    }
    catch (SysError &e) {
        std::cout << "errno was: " << e.errNo << std::endl;
        logError(e.info());
    }

    // current exception
    try {
        throw DemoError("DemoError handled as a %1%", "std::exception");
    }
    catch (...) {
        const std::exception_ptr &eptr = std::current_exception();
        try
        {
            std::rethrow_exception(eptr);
        }
        catch (std::exception& e)
        {
            std::cerr << e.what() << std::endl;
        }
    }

    // For completeness sake, show 'info' through 'vomit' levels.
    // But this is maybe a heavy format for those.
    logger->logEI(
        ErrorInfo { .level = lvlInfo,
                    .name = "Info name",
                    .description = "Info description",
        });

    logger->logEI(
        ErrorInfo { .level = lvlTalkative,
                    .name = "Talkative name",
                    .description = "Talkative description",
        });

    logger->logEI(
        ErrorInfo { .level = lvlChatty,
                    .name = "Chatty name",
                    .description = "Chatty description",
        });

    logger->logEI(
        ErrorInfo { .level = lvlDebug,
                    .name = "Debug name",
                    .description = "Debug description",
        });

    logger->logEI(
        ErrorInfo { .level = lvlVomit,
                    .name = "Vomit name",
                    .description = "Vomit description",
        });

    // Error in a program; no hint and no nix code.
    logError(
        ErrorInfo { .name = "name",
                    .description = "error description",
        });

    // Warning with name, description, and hint.
    // The hintfmt function makes all the substituted text yellow.
    logWarning(
        ErrorInfo { .name = "name",
                    .description = "error description",
                    .hint = hintfmt("there was a %1%", "warning"),
        });

    // Warning with nix file, line number, column, and the lines of
    // code where a warning occurred.
    SymbolTable testTable;
    auto problem_file = testTable.create("myfile.nix");

    logWarning(
        ErrorInfo { .name = "warning name",
                    .description = "warning description",
                    .hint = hintfmt("this hint has %1% templated %2%!!",
                        "yellow",
                        "values"),
                    .nixCode = NixCode {
                        .errPos = Pos(foFile, problem_file, 40, 13),
                        .prevLineOfCode = std::nullopt,
                        .errLineOfCode = "this is the problem line of code",
                        .nextLineOfCode = std::nullopt
                    }});

    // Error with previous and next lines of code.
    logError(
        ErrorInfo { .name = "error name",
                    .description = "error with code lines",
                    .hint = hintfmt("this hint has %1% templated %2%!!",
                        "yellow",
                        "values"),
                    .nixCode = NixCode {
                        .errPos = Pos(foFile, problem_file, 40, 13),
                        .prevLineOfCode = "previous line of code",
                        .errLineOfCode = "this is the problem line of code",
                        .nextLineOfCode = "next line of code",
                    }});

    // Error without lines of code.
    logError(
        ErrorInfo { .name = "error name",
                    .description = "error without any code lines.",
                    .hint = hintfmt("this hint has %1% templated %2%!!",
                        "yellow",
                        "values"),
                    .nixCode = NixCode {
                        .errPos = Pos(foFile, problem_file, 40, 13)
                    }});

    // Error with only hint and name..
    logError(
        ErrorInfo { .name = "error name",
                    .hint = hintfmt("hint %1%", "only"),
                    .nixCode = NixCode {
                        .errPos = Pos(foFile, problem_file, 40, 13)
                    }});

    return 0;
}
<commit_msg>re-remove<commit_after><|endoftext|>


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

//++
// File:        MIUtilStreamStdin.cpp
//
// Overview:    CMICmnStreamStdinLinux implementation.
//
// Environment: Compilers:  Visual C++ 12.
//                          gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
//              Libraries:  See MIReadmetxt.
//
// Copyright:   None.
//--

// Third Party Headers:
#if !defined(_MSC_VER)
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#endif              // !defined( _MSC_VER )
#include <string.h> // For std::strerror()

// In-house headers:
#include "MICmnStreamStdinLinux.h"
#include "MICmnLog.h"
#include "MICmnResources.h"
#include "MIUtilSingletonHelper.h"

//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdinLinux constructor.
// Type:    Method.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnStreamStdinLinux::CMICmnStreamStdinLinux(void)
    : m_constBufferSize(1024)
    , m_pStdin(nullptr)
    , m_pCmdBuffer(nullptr)
{
}

//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdinLinux destructor.
// Type:    Overridable.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnStreamStdinLinux::~CMICmnStreamStdinLinux(void)
{
    Shutdown();
}

//++ ------------------------------------------------------------------------------------
// Details: Initialize resources for *this Stdin stream.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::Initialize(void)
{
    if (m_bInitialized)
        return MIstatus::success;

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;

    // Note initialisation order is important here as some resources depend on previous
    MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
    MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);

    // Other resources required
    if (bOk)
    {
        m_pCmdBuffer = new MIchar[m_constBufferSize];
        m_pStdin = stdin;
    }

    // Clear error indicators for std input
    ::clearerr(stdin);

    m_bInitialized = bOk;

    if (!bOk)
    {
        CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_OS_STDIN_HANDLER), errMsg.c_str()));
        SetErrorDescription(strInitError);
        return MIstatus::failure;
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Release resources for *this Stdin stream.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::Shutdown(void)
{
    if (!m_bInitialized)
        return MIstatus::success;

    m_bInitialized = false;

    ClrErrorDescription();

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;

    // Tidy up
    if (m_pCmdBuffer != nullptr)
    {
        delete[] m_pCmdBuffer;
        m_pCmdBuffer = nullptr;
    }
    m_pStdin = nullptr;

    // Note shutdown order is important here
    MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
    MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);

    if (!bOk)
    {
        SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER), errMsg.c_str());
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Determine if stdin has any characters present in its buffer.
// Type:    Method.
// Args:    vwbAvail    - (W) True = There is chars available, false = nothing there.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::InputAvailable(bool &vwbAvail)
{
#if !defined(_WIN32)
    // The code below is needed on OSX where lldb-mi hangs when doing -exec-run.
    // The hang seems to come from calling fgets and fileno from different thread.
    // Although this problem was not observed on Linux.
    // A solution based on 'select' was also proposed but it seems to slow things down
    // a lot.
    static bool bInitialized = false;

    if (!bInitialized)
    {
        // Use termios to turn off line buffering
        ::termios term;
        ::tcgetattr(STDIN_FILENO, &term);
        term.c_lflag &= ~ICANON;
        ::tcsetattr(STDIN_FILENO, TCSANOW, &term);
        ::setbuf(stdin, NULL);
        bInitialized = true;
    }

    int nBytesWaiting;
    ::ioctl(STDIN_FILENO, FIONREAD, &nBytesWaiting);
    vwbAvail = (nBytesWaiting > 0);
#endif
    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
// Type:    Method.
// Args:    vwErrMsg    - (W) Empty string ok or error description.
// Return:  MIchar * - text buffer pointer or NULL on failure.
// Throws:  None.
//--
const MIchar *
CMICmnStreamStdinLinux::ReadLine(CMIUtilString &vwErrMsg)
{
    vwErrMsg.clear();

    // Read user input
    const MIchar *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
    if (pText == nullptr)
    {
        if (::ferror(m_pStdin) != 0)
            vwErrMsg = ::strerror(errno);
        return nullptr;
    }

    // Strip off new line characters
    for (MIchar *pI = m_pCmdBuffer; *pI != '\0'; pI++)
    {
        if ((*pI == '\n') || (*pI == '\r'))
        {
            *pI = '\0';
            break;
        }
    }

    return pText;
}

<commit_msg>Cleanup of the fix done recently for a lldb-mi hang on OSX. It was observed that we dont need to set stdin to unbuffered and setting console to non-canonical mode.<commit_after>//===-- MICmnStreamStdinLinux.cpp --------------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

//++
// File:        MIUtilStreamStdin.cpp
//
// Overview:    CMICmnStreamStdinLinux implementation.
//
// Environment: Compilers:  Visual C++ 12.
//                          gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
//              Libraries:  See MIReadmetxt.
//
// Copyright:   None.
//--

// Third Party Headers:
#if !defined(_MSC_VER)
#include <sys/select.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>
#endif              // !defined( _MSC_VER )
#include <string.h> // For std::strerror()

// In-house headers:
#include "MICmnStreamStdinLinux.h"
#include "MICmnLog.h"
#include "MICmnResources.h"
#include "MIUtilSingletonHelper.h"

//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdinLinux constructor.
// Type:    Method.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnStreamStdinLinux::CMICmnStreamStdinLinux(void)
    : m_constBufferSize(1024)
    , m_pStdin(nullptr)
    , m_pCmdBuffer(nullptr)
{
}

//++ ------------------------------------------------------------------------------------
// Details: CMICmnStreamStdinLinux destructor.
// Type:    Overridable.
// Args:    None.
// Return:  None.
// Throws:  None.
//--
CMICmnStreamStdinLinux::~CMICmnStreamStdinLinux(void)
{
    Shutdown();
}

//++ ------------------------------------------------------------------------------------
// Details: Initialize resources for *this Stdin stream.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::Initialize(void)
{
    if (m_bInitialized)
        return MIstatus::success;

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;

    // Note initialisation order is important here as some resources depend on previous
    MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
    MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);

    // Other resources required
    if (bOk)
    {
        m_pCmdBuffer = new MIchar[m_constBufferSize];
        m_pStdin = stdin;
    }

    // Clear error indicators for std input
    ::clearerr(stdin);

    m_bInitialized = bOk;

    if (!bOk)
    {
        CMIUtilString strInitError(CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_OS_STDIN_HANDLER), errMsg.c_str()));
        SetErrorDescription(strInitError);
        return MIstatus::failure;
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Release resources for *this Stdin stream.
// Type:    Method.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::Shutdown(void)
{
    if (!m_bInitialized)
        return MIstatus::success;

    m_bInitialized = false;

    ClrErrorDescription();

    bool bOk = MIstatus::success;
    CMIUtilString errMsg;

    // Tidy up
    if (m_pCmdBuffer != nullptr)
    {
        delete[] m_pCmdBuffer;
        m_pCmdBuffer = nullptr;
    }
    m_pStdin = nullptr;

    // Note shutdown order is important here
    MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
    MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);

    if (!bOk)
    {
        SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_OS_STDIN_HANDLER), errMsg.c_str());
    }

    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Determine if stdin has any characters present in its buffer.
// Type:    Method.
// Args:    vwbAvail    - (W) True = There is chars available, false = nothing there.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool
CMICmnStreamStdinLinux::InputAvailable(bool &vwbAvail)
{
#if !defined(_WIN32)
    // The code below is needed on OSX where lldb-mi hangs when doing -exec-run.
    // The hang seems to come from calling fgets and fileno from different thread.
    // Although this problem was not observed on Linux.
    // A solution based on 'select' was also proposed but it seems to slow things down
    // a lot.
    int nBytesWaiting;
    if (::ioctl(STDIN_FILENO, FIONREAD, &nBytesWaiting) == -1)
    {
        vwbAvail = false;
        return MIstatus::failure;;
    }
    vwbAvail = (nBytesWaiting > 0);
#endif // !defined( _WIN32 )
    return MIstatus::success;
}

//++ ------------------------------------------------------------------------------------
// Details: Wait on new line of data from stdin stream (completed by '\n' or '\r').
// Type:    Method.
// Args:    vwErrMsg    - (W) Empty string ok or error description.
// Return:  MIchar * - text buffer pointer or NULL on failure.
// Throws:  None.
//--
const MIchar *
CMICmnStreamStdinLinux::ReadLine(CMIUtilString &vwErrMsg)
{
    vwErrMsg.clear();

    // Read user input
    const MIchar *pText = ::fgets(&m_pCmdBuffer[0], m_constBufferSize, stdin);
    if (pText == nullptr)
    {
        if (::ferror(m_pStdin) != 0)
            vwErrMsg = ::strerror(errno);
        return nullptr;
    }

    // Strip off new line characters
    for (MIchar *pI = m_pCmdBuffer; *pI != '\0'; pI++)
    {
        if ((*pI == '\n') || (*pI == '\r'))
        {
            *pI = '\0';
            break;
        }
    }

    return pText;
}

<|endoftext|>


<commit_before>#include <tr1/cstdint>
#include <cstddef>
#include <cstdio>
#include <string>
#include <time.h>
#include "barrier.h"
#include "socket.h"
#include "stream.h"

Client::Client(Barrier& barrier, const char* host, uint16_t port) :
	Stream(),
	barr(barrier),
	hostname(host),
	rem_port(port),
	loc_port(0),
	buflen(BUFFER_SIZE),
	ival(0)
{
}

Client::Client(Barrier& barrier, const char* host, uint16_t r_port, uint16_t l_port) :
	Stream(),
	barr(barrier),
	hostname(host),
	rem_port(r_port),
	loc_port(l_port),
	buflen(BUFFER_SIZE),
	ival(0)
{
}

void Client::run()
{
	// Create connection to remote host
	Sock* sock;

	if (loc_port > 0) {
		sock = Sock::create(hostname, rem_port, loc_port);
	} else {
		sock = Sock::create(hostname, rem_port);
	}

	// Couldn't create connection
	if (sock == NULL) {
		fprintf(stderr, "Couldn't connect to %s:%u\n", hostname, rem_port);
		barr.wait();
		return;
	}

	established = true;
	std::string host = sock->host();
	uint16_t port = sock->port();
	fprintf(stdout, "%s:%u Connected\n", host.c_str(), port);
	fflush(stdout);

	// Synchronize all threads
	barr.wait();

	// Send loop
	timespec timeout = {0, 1000000L};
	while (active && sock->alive()) {

		// Sleep for an interval
		uint64_t i = ival;
		while (active && i--) {
			nanosleep(&timeout, NULL);
		}

		ssize_t total, sent;
		total = buflen > 0 ? buflen : BUFFER_SIZE;
		sent = 0;

		// Send a chunk
		while (active && sock->alive() && total > 0) {
			sent = sock->write(buffer, total);
			if (sent < 0) {
				// Something went wrong
				break;
			}

			total -= sent;
		}
	}

	// Free socket
	established = false;
	fprintf(stdout, "%s:%u Closing connection\n", host.c_str(), port);
	fflush(stdout);
	delete sock;
}

void Client::set_chunk_size(size_t len)
{
	if (len <= BUFFER_SIZE) {
		buflen = len;
	}
}

void Client::set_interval(unsigned i)
{
	ival = i;
}
<commit_msg>message when send buffer is full<commit_after>#include <tr1/cstdint>
#include <cstddef>
#include <cstdio>
#include <string>
#include <time.h>
#include "barrier.h"
#include "socket.h"
#include "stream.h"

Client::Client(Barrier& barrier, const char* host, uint16_t port) :
	Stream(),
	barr(barrier),
	hostname(host),
	rem_port(port),
	loc_port(0),
	buflen(BUFFER_SIZE),
	ival(0)
{
}

Client::Client(Barrier& barrier, const char* host, uint16_t r_port, uint16_t l_port) :
	Stream(),
	barr(barrier),
	hostname(host),
	rem_port(r_port),
	loc_port(l_port),
	buflen(BUFFER_SIZE),
	ival(0)
{
}

void Client::run()
{
	// Create connection to remote host
	Sock* sock;

	if (loc_port > 0) {
		sock = Sock::create(hostname, rem_port, loc_port);
	} else {
		sock = Sock::create(hostname, rem_port);
	}

	// Couldn't create connection
	if (sock == NULL) {
		fprintf(stderr, "Couldn't connect to %s:%u\n", hostname, rem_port);
		barr.wait();
		return;
	}

	established = true;
	std::string host = sock->host();
	uint16_t port = sock->port();
	fprintf(stdout, "%s:%u Connected\n", host.c_str(), port);
	fflush(stdout);

	// Synchronize all threads
	barr.wait();

	// Send loop
	timespec timeout = {0, 1000000L};
	while (active && sock->alive()) {

		// Sleep for an interval
		uint64_t i = ival;
		while (active && i--) {
			nanosleep(&timeout, NULL);
		}

		ssize_t total, sent;
		total = buflen > 0 ? buflen : BUFFER_SIZE;
		sent = 0;
		bool full = false;

		// Send a chunk
		while (active && sock->alive() && total > 0) {

			sent = sock->write(buffer, total);
			if (sent < 0) {
				// Something went wrong
				break;
			}

			// Check if send buffer is full
			if (ival > 0 && !full && sent == 0) {
				full = true;
				fprintf(stdout, "%s:%u Send buffer full\n", host.c_str(), port);
				fflush(stdout);
			} else if (full && sent > 0) {
				full = false;
				fprintf(stdout, "%s:%u Send buffer cleared\n", host.c_str(), port);
				fflush(stdout);
			}

			total -= sent;
		}
	}

	// Free socket
	established = false;
	fprintf(stdout, "%s:%u Closing connection\n", host.c_str(), port);
	fflush(stdout);
	delete sock;
}

void Client::set_chunk_size(size_t len)
{
	if (len <= BUFFER_SIZE) {
		buflen = len;
	}
}

void Client::set_interval(unsigned i)
{
	ival = i;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 deepstreamHub GmbH
 *
 * 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 <ostream>

#include <deepstream/client.hpp>
#include <deepstream/message.hpp>
#include <deepstream/use.hpp>

#include <cassert>

namespace deepstream {
namespace client
{

std::ostream& operator<<(std::ostream& os, State state)
{
	os << static_cast<int>(state);
	return os;
}

State transition(State state, const Message& message, Sender sender)
{
	assert( state != State::ERROR );
	assert( state != State::DISCONNECTED );

	const Topic topic = message.topic();
	const Action action = message.action();
	const bool is_ack = message.is_ack();

	const auto expected_num_args = Message::num_arguments( message.header() );
	const std::size_t& num_args = message.num_arguments();

	use(expected_num_args);
	use(num_args);
	assert( num_args >= expected_num_args.first );
	assert( num_args <= expected_num_args.second );

	// ping/pong
	// heartbeats are implemented within deepstream and independent of
	// websocket heartbeats (https://tools.ietf.org/html/rfc6455#section-5.5)
	if( topic == Topic::CONNECTION &&
		action == Action::PING &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return state;
	}

	if( topic == Topic::CONNECTION &&
		action == Action::PONG &&
		sender == Sender::CLIENT )
	{
		assert( !is_ack );

		return state;
	}

	// actual state transitions
	if( state == State::AWAIT_CONNECTION &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::CHALLENGING;
	}

	if( state == State::CHALLENGING &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE_RESPONSE &&
		!is_ack &&
		sender == Sender::CLIENT )
	{
		return State::CHALLENGING_WAIT;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE_RESPONSE &&
		is_ack &&
		sender == Sender::SERVER )
	{
		return State::AWAIT_AUTHENTICATION;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::REDIRECT &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::AWAIT_CONNECTION;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::REJECT &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::AWAIT_AUTHENTICATION &&
		topic == Topic::AUTH &&
		action == Action::REQUEST &&
		!is_ack &&
		sender == Sender::CLIENT )
	{
		return State::AUTHENTICATING;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::REQUEST &&
		is_ack &&
		sender == Sender::SERVER )
	{
		return State::CONNECTED;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_TOO_MANY_AUTH_ATTEMPTS &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_INVALID_AUTH_DATA &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::AWAIT_AUTHENTICATION;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_INVALID_AUTH_MSG &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::CONNECTED &&
		topic == Topic::EVENT )
	{
		if( action == Action::LISTEN ||
			action == Action::SUBSCRIBE ||
			action == Action::UNLISTEN ||
			action == Action::UNSUBSCRIBE )
		{
			if( (sender == Sender::CLIENT && !is_ack) ||
				(sender == Sender::SERVER && is_ack) )
				return state;
		}
		else if( action == Action::EVENT )
		{
			return state;
		}
		else if( action == Action::SUBSCRIPTION_FOR_PATTERN_FOUND ||
				 action == Action::SUBSCRIPTION_FOR_PATTERN_REMOVED )
		{
			assert( !is_ack );

			if( sender == Sender::SERVER )
				return state;
		}
	}

	if( state == State::CONNECTED && topic == Topic::PRESENCE )
	{
		if( action == Action::SUBSCRIBE ||
			action == Action::UNSUBSCRIBE ||
			action == Action::QUERY )
		{
			if( (sender == Sender::CLIENT && !is_ack) ||
				(sender == Sender::SERVER && is_ack) )
				return state;
		}
		if( action == Action::PRESENCE_JOIN ||
			action == Action::PRESENCE_LEAVE )
		{
			if( sender == Sender::SERVER )
				return state;
		}
	}

	return State::ERROR;
}

}
}
<commit_msg>add state transitions for event LISTENER_ACCEPT and LISTENER_REJECT messages<commit_after>/*
 * Copyright 2017 deepstreamHub GmbH
 *
 * 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 <ostream>

#include <deepstream/client.hpp>
#include <deepstream/message.hpp>
#include <deepstream/use.hpp>

#include <cassert>

namespace deepstream {
namespace client
{

std::ostream& operator<<(std::ostream& os, State state)
{
	os << static_cast<int>(state);
	return os;
}

State transition(State state, const Message& message, Sender sender)
{
	assert( state != State::ERROR );
	assert( state != State::DISCONNECTED );

	const Topic topic = message.topic();
	const Action action = message.action();
	const bool is_ack = message.is_ack();

	const auto expected_num_args = Message::num_arguments( message.header() );
	const std::size_t& num_args = message.num_arguments();

	use(expected_num_args);
	use(num_args);
	assert( num_args >= expected_num_args.first );
	assert( num_args <= expected_num_args.second );

	// ping/pong
	// heartbeats are implemented within deepstream and independent of
	// websocket heartbeats (https://tools.ietf.org/html/rfc6455#section-5.5)
	if( topic == Topic::CONNECTION &&
		action == Action::PING &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return state;
	}

	if( topic == Topic::CONNECTION &&
		action == Action::PONG &&
		sender == Sender::CLIENT )
	{
		assert( !is_ack );

		return state;
	}

	// actual state transitions
	if( state == State::AWAIT_CONNECTION &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::CHALLENGING;
	}

	if( state == State::CHALLENGING &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE_RESPONSE &&
		!is_ack &&
		sender == Sender::CLIENT )
	{
		return State::CHALLENGING_WAIT;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::CHALLENGE_RESPONSE &&
		is_ack &&
		sender == Sender::SERVER )
	{
		return State::AWAIT_AUTHENTICATION;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::REDIRECT &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::AWAIT_CONNECTION;
	}

	if( state == State::CHALLENGING_WAIT &&
		topic == Topic::CONNECTION &&
		action == Action::REJECT &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::AWAIT_AUTHENTICATION &&
		topic == Topic::AUTH &&
		action == Action::REQUEST &&
		!is_ack &&
		sender == Sender::CLIENT )
	{
		return State::AUTHENTICATING;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::REQUEST &&
		is_ack &&
		sender == Sender::SERVER )
	{
		return State::CONNECTED;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_TOO_MANY_AUTH_ATTEMPTS &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_INVALID_AUTH_DATA &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::AWAIT_AUTHENTICATION;
	}

	if( state == State::AUTHENTICATING &&
		topic == Topic::AUTH &&
		action == Action::ERROR_INVALID_AUTH_MSG &&
		sender == Sender::SERVER )
	{
		assert( !is_ack );

		return State::DISCONNECTED;
	}

	if( state == State::CONNECTED &&
		topic == Topic::EVENT )
	{
		if( action == Action::LISTEN ||
			action == Action::SUBSCRIBE ||
			action == Action::UNLISTEN ||
			action == Action::UNSUBSCRIBE ||
			action == Action::LISTEN_ACCEPT ||
			action == Action::LISTEN_REJECT )
		{
			if( (sender == Sender::CLIENT && !is_ack) ||
				(sender == Sender::SERVER && is_ack) )
				return state;
		}
		else if( action == Action::EVENT )
		{
			return state;
		}
		else if( action == Action::SUBSCRIPTION_FOR_PATTERN_FOUND ||
				 action == Action::SUBSCRIPTION_FOR_PATTERN_REMOVED )
		{
			assert( !is_ack );

			if( sender == Sender::SERVER )
				return state;
		}
	}

	if( state == State::CONNECTED && topic == Topic::PRESENCE )
	{
		if( action == Action::SUBSCRIBE ||
			action == Action::UNSUBSCRIBE ||
			action == Action::QUERY )
		{
			if( (sender == Sender::CLIENT && !is_ack) ||
				(sender == Sender::SERVER && is_ack) )
				return state;
		}
		if( action == Action::PRESENCE_JOIN ||
			action == Action::PRESENCE_LEAVE )
		{
			if( sender == Sender::SERVER )
				return state;
		}
	}

	return State::ERROR;
}

}
}
<|endoftext|>


<commit_before>#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#include <readline/readline.h>
#include <readline/history.h>

namespace {

enum Request {
  Execute,
  Complete
};

enum Response {
  RowSet,
  NewDatabase,
  CopySuccess,
  Success,
  Error
};

enum RowSetFlag {
  InsertedRow,
  DeletedRow,
  End,
  Item
};

class Buffer {
 public:
  Buffer(int capacity):
    array(static_cast<char*>(malloc(capacity))),
    capacity(capacity),
    position(0),
    limit(0)
  { }

  ~Buffer() {
    if (array) free(array);
  }

  char* array;
  int capacity;
  int position;
  int limit;
};

class Context {
 public:
  Context():
    buffer(8 * 1024),
    databaseName(0),
    socket(-1),
    completionCount(-1),
    trouble(false),
    exit(false),
    copying(false)
  { }

  ~Context() {
    if (databaseName) {
      free(databaseName);
    }
  }

  Buffer buffer;
  char* databaseName;
  int socket;
  int completionCount;
  bool trouble;
  bool exit;
  bool copying;
};

Context* globalContext = 0;

int
min(int a, int b)
{
  return a > b ? b : a;
}

int
connect(const char* host, int port)
{
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;

  addrinfo* result;
  int r = getaddrinfo(host, 0, &hints, &result);
  if (r != 0) {
    fprintf(stderr, "unable to resolve host %s: %s\n", host, gai_strerror(r));
    return -1;
  }

  sockaddr_in address;
  memset(&address, 0, sizeof(sockaddr_in));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  address.sin_addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;

  freeaddrinfo(result);

  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (socket < 0) {
    perror("unable to open socket");
    return -1;
  }

  r = connect(socket, reinterpret_cast<sockaddr*>(&address),
              sizeof(sockaddr_in));
  if (r != 0) {
    perror("unable to connect");
    return -1;
  }

  return socket;
}

bool
flush(Context* context)
{
  int r = write
    (context->socket, context->buffer.array, context->buffer.position);
  if (r != context->buffer.position) {
    perror("\nunable to write");
    context->trouble = true;
    return false;
  }
  context->buffer.position = 0;
  return true;
}

int
writeBytes(Context* context, const char* src, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      if (not flush(context)) {
        return -1;
      }
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(context->buffer.array + context->buffer.position, src + total, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

bool
writeByte(Context* context, int v)
{
  char src[] = { v };
  return writeBytes(context, src, 1) == 1;
}

bool
writeInteger(Context* context, int v)
{
  char src[] = { (v >> 24) & 0xFF,
                 (v >> 16) & 0xFF,
                 (v >>  8) & 0xFF,
                 (v      ) & 0xFF };
  return writeBytes(context, src, 4) == 4;
}

bool
writeString(Context* context, const char* s, int length)
{
  if (writeInteger(context, length)) {
    return writeBytes(context, s, length) == length;
  } else {
    return false;
  }
}

int
readBytes(Context* context, char* dst, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      context->buffer.position = 0;
      int r = read
        (context->socket, context->buffer.array, context->buffer.capacity);
      if (r == 0) {
        fprintf(stderr, "\nunexpected end of stream from server\n");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      } else if (r < 0) {
        perror("\nunable to read");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      }
      context->buffer.limit = r;
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(dst + total, context->buffer.array + context->buffer.position, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

int
readByte(Context* context)
{
  char dst[1];
  int r = readBytes(context, dst, 1);
  return r < 1 ? -1 : dst[0];
}

int
readInteger(Context* context)
{
  char dst[4];
  int r = readBytes(context, dst, 4);
  return r < 4 ? -1 : (((dst[0] & 0xFF) << 24) |
                       ((dst[1] & 0xFF) << 16) |
                       ((dst[2] & 0xFF) <<  8) |
                       ((dst[3] & 0xFF)      ));
}

char*
readString(Context* context)
{
  int length = readInteger(context);
  if (length < 0) {
    return 0;
  }

  char* string = static_cast<char*>(malloc(length + 1));
  if (string == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    context->trouble = true;
    return 0;
  }

  int count = readBytes(context, string, length);
  if (count != length) {
    free(string);
    return 0;
  }

  string[length] = 0;

  return string;
}

int
startCompletion(Context* context, const char* text)
{
  context->buffer.position = 0;
  context->buffer.limit = context->buffer.capacity;

  if (not writeByte(context, Complete)) {
    return -1;
  }

  if (not writeString(context, text, strlen(text))) {
    return -1;
  }

  if (not flush(context)) {
    return -1;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case Success: {
    return readInteger(context);
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return -1;
    }

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }

  return -1;
}

char*
completionGenerator(const char*, int state)
{
  Context* context = globalContext;

  if (context->trouble) {
    return 0;
  }

  if (state == 0) {
    context->completionCount = startCompletion(context, rl_line_buffer);
  }

  if (context->completionCount <= 0) {
    return 0;
  } else {
    -- context->completionCount;

    return readString(context);
  }
}

char*
removeEdgeWhitespace(char* s)
{
  while (isspace(*s)) ++s;

  if (*s == 0) return s;

  char* p = s;
  char* lastNonSpace = p;
  while (*p) {
    if (not isspace(*p)) {
      lastNonSpace = p;
    }
    ++ p;
  }

  lastNonSpace[1] = 0;

  return s;
}

void
execute(Context* context, const char* command)
{
  if (strcmp(command, "exit") == 0
      || strcmp(command, "quit") == 0)
  {
    context->exit = true;
    return;
  }

  if (context->trouble) {
    return;
  }

  if (not context->copying) {
    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;
  }

  if (not writeByte(context, Execute)) {
    return;
  }

  if (not writeString(context, command, strlen(command))) {
    return;
  }

  if (context->copying && strcmp(command, "\\.") == 0) {
    if (not flush(context)) {
      return;
    }
    context->copying = false;
  }

  if (context->copying) {
    return;
  }

  if (not flush(context)) {
    return;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case NewDatabase: {
    if (context->databaseName) {
      free(context->databaseName);
    }

    context->databaseName = readString(context);
    if (context->databaseName == 0) {
      return;
    }

    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case CopySuccess: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);

    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;

    context->copying = true;
  } break;

  case Success: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case RowSet: {
    bool done = false;
    bool sawRow = false;
    while (not done) {
      int flag = readByte(context);
      switch (flag) {
      case -1:
        return;

      case InsertedRow:
        sawRow = true;
        fprintf(stdout, "\n inserted:");
        break;

      case DeletedRow:
        sawRow = true;
        fprintf(stdout, "\n  deleted:");
        break;

      case Item: {
        char* item = readString(context);
        if (item == 0) {
          return;
        }

        fprintf(stdout, " %s", item);

        free(item);
      } break;

      case End:
        if (not sawRow) {
          fprintf(stdout, "\n no matching rows found");
        }
        done = true;
        fprintf(stdout, "\n");
        break;

      default:
        fprintf(stderr, "\nunexpected flag from server: %d\n", flag);
        context->trouble = true;
        return;
      }
    }
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stderr, "error: %s\n", message);

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }
}

void
usage(const char* name)
{
  fprintf(stderr, "usage: %s [--batch] <hostname> <port> [<database>]\n",
          name);
}

} // namespace

int
main(int argumentCount, const char** arguments)
{
  bool interactive = true;
  const char* hostname = 0;
  int port = -1;
  const char* database = 0;
  for (int i = 1; i < argumentCount; ++i) {
    if (strcmp("--batch", arguments[i]) == 0) {
      interactive = false;
    } else if (hostname == 0) {
      hostname = arguments[i];
    } else if (port == -1) {
      port = atoi(arguments[i]);
    } else if (database == 0) {
      database = arguments[i];
    } else {
      usage(arguments[0]);
      return -1;
    }
  }

  if (hostname == 0 or port == -1) {
    usage(arguments[0]);
    return -1;
  }

  Context context;
  globalContext = &context;

  if (context.buffer.array == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    return -1;
  }

  context.socket = connect(hostname, port);
  if (context.socket < 0) {
    return -1;
  }

  if (database) {
    const int BufferSize = 256;
    char buffer[BufferSize];
    snprintf(buffer, BufferSize, "use database %s", database);
    execute(&context, buffer);

    if (context.trouble) {
      return -1;
    }
  }

  if (interactive) {
    fprintf(stdout, "\nWelcome to the DBMS SQL client interface.  "
            "Type \"help\" to get started.\n");

    rl_readline_name = "DBMSClient";

    rl_completion_entry_function = completionGenerator;

    while (not (context.trouble or context.exit)) {
      char* line;
      if (context.databaseName) {
        int length = strlen(context.databaseName) + 4;
        char* prompt = static_cast<char*>(malloc(length));
        if (prompt == 0) {
          fprintf(stderr, "\nunable to allocate memory\n");
          return -1;
        }

        snprintf(prompt, length, "%s > ", context.databaseName);
        line = readline(prompt);
        free(prompt);
      } else {
        line = readline("> ");
      }

      if (line == 0) {
        fprintf(stdout, "\n");
        break;
      }

      if (context.copying) {
        execute(&context, line);
      } else {
        char* s = removeEdgeWhitespace(line);
        if (*s) {
          add_history(s);

          execute(&context, s);
          fprintf(stdout, "\n");
        }
      }

      free(line);
    }
  } else {
    const int BufferSize = 8096;
    char buffer[BufferSize];
    int i = 0;

    while (true) {
      int c = fgetc(stdin);
      switch (c) {
      case EOF:
        return 0;

      case '\n':
        buffer[i] = 0;
        execute(&context, buffer);
        i = 0;
        break;

      default:
        if (i < BufferSize - 1) {
          buffer[i++] = c;
        } else {
          fprintf(stderr, "buffer overflow\n");
          return -1;
        }
        break;
      }
    }
  }

  close(context.socket);

  return context.trouble ? -1 : 0;
}
<commit_msg>fix C++11 warnings<commit_after>#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

#include <readline/readline.h>
#include <readline/history.h>

namespace {

enum Request {
  Execute,
  Complete
};

enum Response {
  RowSet,
  NewDatabase,
  CopySuccess,
  Success,
  Error
};

enum RowSetFlag {
  InsertedRow,
  DeletedRow,
  End,
  Item
};

class Buffer {
 public:
  Buffer(int capacity):
    array(static_cast<char*>(malloc(capacity))),
    capacity(capacity),
    position(0),
    limit(0)
  { }

  ~Buffer() {
    if (array) free(array);
  }

  char* array;
  int capacity;
  int position;
  int limit;
};

class Context {
 public:
  Context():
    buffer(8 * 1024),
    databaseName(0),
    socket(-1),
    completionCount(-1),
    trouble(false),
    exit(false),
    copying(false)
  { }

  ~Context() {
    if (databaseName) {
      free(databaseName);
    }
  }

  Buffer buffer;
  char* databaseName;
  int socket;
  int completionCount;
  bool trouble;
  bool exit;
  bool copying;
};

Context* globalContext = 0;

int
min(int a, int b)
{
  return a > b ? b : a;
}

int
connect(const char* host, int port)
{
  addrinfo hints;
  memset(&hints, 0, sizeof(addrinfo));
  hints.ai_family = AF_INET;
  hints.ai_socktype = SOCK_STREAM;

  addrinfo* result;
  int r = getaddrinfo(host, 0, &hints, &result);
  if (r != 0) {
    fprintf(stderr, "unable to resolve host %s: %s\n", host, gai_strerror(r));
    return -1;
  }

  sockaddr_in address;
  memset(&address, 0, sizeof(sockaddr_in));
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  address.sin_addr = reinterpret_cast<sockaddr_in*>(result->ai_addr)->sin_addr;

  freeaddrinfo(result);

  int socket = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if (socket < 0) {
    perror("unable to open socket");
    return -1;
  }

  r = connect(socket, reinterpret_cast<sockaddr*>(&address),
              sizeof(sockaddr_in));
  if (r != 0) {
    perror("unable to connect");
    return -1;
  }

  return socket;
}

bool
flush(Context* context)
{
  int r = write
    (context->socket, context->buffer.array, context->buffer.position);
  if (r != context->buffer.position) {
    perror("\nunable to write");
    context->trouble = true;
    return false;
  }
  context->buffer.position = 0;
  return true;
}

int
writeBytes(Context* context, const char* src, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      if (not flush(context)) {
        return -1;
      }
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(context->buffer.array + context->buffer.position, src + total, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

bool
writeByte(Context* context, int v)
{
  char src[] = { static_cast<char>(v) };
  return writeBytes(context, src, 1) == 1;
}

bool
writeInteger(Context* context, int v)
{
  char src[] = { static_cast<char>((v >> 24) & 0xFF),
                 static_cast<char>((v >> 16) & 0xFF),
                 static_cast<char>((v >>  8) & 0xFF),
                 static_cast<char>((v      ) & 0xFF) };
  return writeBytes(context, src, 4) == 4;
}

bool
writeString(Context* context, const char* s, int length)
{
  if (writeInteger(context, length)) {
    return writeBytes(context, s, length) == length;
  } else {
    return false;
  }
}

int
readBytes(Context* context, char* dst, int count)
{
  int total = 0;
  while (total < count) {
    if (context->buffer.limit == context->buffer.position) {
      context->buffer.position = 0;
      int r = read
        (context->socket, context->buffer.array, context->buffer.capacity);
      if (r == 0) {
        fprintf(stderr, "\nunexpected end of stream from server\n");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      } else if (r < 0) {
        perror("\nunable to read");
        context->trouble = true;
        context->buffer.limit = 0;
        return -1;
      }
      context->buffer.limit = r;
    }

    int c = min
      (count - total, context->buffer.limit - context->buffer.position);
    memcpy(dst + total, context->buffer.array + context->buffer.position, c);
    context->buffer.position += c;
    total += c;
  }
  return total;
}

int
readByte(Context* context)
{
  char dst[1];
  int r = readBytes(context, dst, 1);
  return r < 1 ? -1 : dst[0];
}

int
readInteger(Context* context)
{
  char dst[4];
  int r = readBytes(context, dst, 4);
  return r < 4 ? -1 : (((dst[0] & 0xFF) << 24) |
                       ((dst[1] & 0xFF) << 16) |
                       ((dst[2] & 0xFF) <<  8) |
                       ((dst[3] & 0xFF)      ));
}

char*
readString(Context* context)
{
  int length = readInteger(context);
  if (length < 0) {
    return 0;
  }

  char* string = static_cast<char*>(malloc(length + 1));
  if (string == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    context->trouble = true;
    return 0;
  }

  int count = readBytes(context, string, length);
  if (count != length) {
    free(string);
    return 0;
  }

  string[length] = 0;

  return string;
}

int
startCompletion(Context* context, const char* text)
{
  context->buffer.position = 0;
  context->buffer.limit = context->buffer.capacity;

  if (not writeByte(context, Complete)) {
    return -1;
  }

  if (not writeString(context, text, strlen(text))) {
    return -1;
  }

  if (not flush(context)) {
    return -1;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case Success: {
    return readInteger(context);
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return -1;
    }

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }

  return -1;
}

char*
completionGenerator(const char*, int state)
{
  Context* context = globalContext;

  if (context->trouble) {
    return 0;
  }

  if (state == 0) {
    context->completionCount = startCompletion(context, rl_line_buffer);
  }

  if (context->completionCount <= 0) {
    return 0;
  } else {
    -- context->completionCount;

    return readString(context);
  }
}

char*
removeEdgeWhitespace(char* s)
{
  while (isspace(*s)) ++s;

  if (*s == 0) return s;

  char* p = s;
  char* lastNonSpace = p;
  while (*p) {
    if (not isspace(*p)) {
      lastNonSpace = p;
    }
    ++ p;
  }

  lastNonSpace[1] = 0;

  return s;
}

void
execute(Context* context, const char* command)
{
  if (strcmp(command, "exit") == 0
      || strcmp(command, "quit") == 0)
  {
    context->exit = true;
    return;
  }

  if (context->trouble) {
    return;
  }

  if (not context->copying) {
    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;
  }

  if (not writeByte(context, Execute)) {
    return;
  }

  if (not writeString(context, command, strlen(command))) {
    return;
  }

  if (context->copying && strcmp(command, "\\.") == 0) {
    if (not flush(context)) {
      return;
    }
    context->copying = false;
  }

  if (context->copying) {
    return;
  }

  if (not flush(context)) {
    return;
  }

  context->buffer.limit = 0;

  int result = readByte(context);
  switch (result) {
  case -1:
    break;

  case NewDatabase: {
    if (context->databaseName) {
      free(context->databaseName);
    }

    context->databaseName = readString(context);
    if (context->databaseName == 0) {
      return;
    }

    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case CopySuccess: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);

    context->buffer.position = 0;
    context->buffer.limit = context->buffer.capacity;

    context->copying = true;
  } break;

  case Success: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stdout, "%s\n", message);

    free(message);
  } break;

  case RowSet: {
    bool done = false;
    bool sawRow = false;
    while (not done) {
      int flag = readByte(context);
      switch (flag) {
      case -1:
        return;

      case InsertedRow:
        sawRow = true;
        fprintf(stdout, "\n inserted:");
        break;

      case DeletedRow:
        sawRow = true;
        fprintf(stdout, "\n  deleted:");
        break;

      case Item: {
        char* item = readString(context);
        if (item == 0) {
          return;
        }

        fprintf(stdout, " %s", item);

        free(item);
      } break;

      case End:
        if (not sawRow) {
          fprintf(stdout, "\n no matching rows found");
        }
        done = true;
        fprintf(stdout, "\n");
        break;

      default:
        fprintf(stderr, "\nunexpected flag from server: %d\n", flag);
        context->trouble = true;
        return;
      }
    }
  } break;

  case Error: {
    char* message = readString(context);
    if (message == 0) {
      return;
    }

    fprintf(stderr, "error: %s\n", message);

    free(message);
  } break;

  default:
    fprintf(stderr, "\nunexpected result from server: %d\n", result);
    context->trouble = true;
    break;
  }
}

void
usage(const char* name)
{
  fprintf(stderr, "usage: %s [--batch] <hostname> <port> [<database>]\n",
          name);
}

} // namespace

int
main(int argumentCount, const char** arguments)
{
  bool interactive = true;
  const char* hostname = 0;
  int port = -1;
  const char* database = 0;
  for (int i = 1; i < argumentCount; ++i) {
    if (strcmp("--batch", arguments[i]) == 0) {
      interactive = false;
    } else if (hostname == 0) {
      hostname = arguments[i];
    } else if (port == -1) {
      port = atoi(arguments[i]);
    } else if (database == 0) {
      database = arguments[i];
    } else {
      usage(arguments[0]);
      return -1;
    }
  }

  if (hostname == 0 or port == -1) {
    usage(arguments[0]);
    return -1;
  }

  Context context;
  globalContext = &context;

  if (context.buffer.array == 0) {
    fprintf(stderr, "\nunable to allocate memory\n");
    return -1;
  }

  context.socket = connect(hostname, port);
  if (context.socket < 0) {
    return -1;
  }

  if (database) {
    const int BufferSize = 256;
    char buffer[BufferSize];
    snprintf(buffer, BufferSize, "use database %s", database);
    execute(&context, buffer);

    if (context.trouble) {
      return -1;
    }
  }

  if (interactive) {
    fprintf(stdout, "\nWelcome to the DBMS SQL client interface.  "
            "Type \"help\" to get started.\n");

    rl_readline_name = "DBMSClient";

    rl_completion_entry_function = completionGenerator;

    while (not (context.trouble or context.exit)) {
      char* line;
      if (context.databaseName) {
        int length = strlen(context.databaseName) + 4;
        char* prompt = static_cast<char*>(malloc(length));
        if (prompt == 0) {
          fprintf(stderr, "\nunable to allocate memory\n");
          return -1;
        }

        snprintf(prompt, length, "%s > ", context.databaseName);
        line = readline(prompt);
        free(prompt);
      } else {
        line = readline("> ");
      }

      if (line == 0) {
        fprintf(stdout, "\n");
        break;
      }

      if (context.copying) {
        execute(&context, line);
      } else {
        char* s = removeEdgeWhitespace(line);
        if (*s) {
          add_history(s);

          execute(&context, s);
          fprintf(stdout, "\n");
        }
      }

      free(line);
    }
  } else {
    const int BufferSize = 8096;
    char buffer[BufferSize];
    int i = 0;

    while (true) {
      int c = fgetc(stdin);
      switch (c) {
      case EOF:
        return 0;

      case '\n':
        buffer[i] = 0;
        execute(&context, buffer);
        i = 0;
        break;

      default:
        if (i < BufferSize - 1) {
          buffer[i++] = c;
        } else {
          fprintf(stderr, "buffer overflow\n");
          return -1;
        }
        break;
      }
    }
  }

  close(context.socket);

  return context.trouble ? -1 : 0;
}
<|endoftext|>


<commit_before>#include "reductions.h"
#include "vw.h"

using namespace LEARNER;

struct confidence
{ vw* all;//statistics, loss
};

template <bool is_learn>
void predict_or_learn_with_confidence(confidence& c, base_learner& base, example& ec)
{ if (is_learn)
    base.learn(ec);
  else
    base.predict(ec);
  float threshold = 0.f;

  ec.confidence = fabsf(ec.pred.scalar - threshold) / base.sensitivity(ec);
  cout << "confidence = " << ec.confidence << " pred = " << ec.pred.scalar << " threshold = " << threshold << " sensitivity = " << base.sensitivity(ec) << endl;
}

void confidence_print_result(int f, float res, float confidence, v_array<char> tag)
{ if (f >= 0)
  { std::stringstream ss;
    char temp[30];
    sprintf(temp, "%f %f", res, confidence);
    ss << temp;
    if(!print_tag(ss, tag))
      ss << ' ';
    ss << '\n';
    ssize_t len = ss.str().size();
    ssize_t t = io_buf::write_file_or_socket(f, ss.str().c_str(), (unsigned int)len);
    if (t != len)
      cerr << "write error: " << strerror(errno) << endl;
  }
}

void output_and_account_confidence_example(vw& all, example& ec)
{ label_data& ld = ec.l.simple;

  all.sd->update(ec.test_only, ec.loss, ec.weight, ec.num_features);
  if (ld.label != FLT_MAX && !ec.test_only)
    all.sd->weighted_labels += ld.label * ec.weight;
  all.sd->weighted_unlabeled_examples += ld.label == FLT_MAX ? ec.weight : 0;

  all.print(all.raw_prediction, ec.partial_prediction, -1, ec.tag);
  for (size_t i = 0; i<all.final_prediction_sink.size(); i++)
  { int f = (int)all.final_prediction_sink[i];
    confidence_print_result(f, ec.pred.scalar, ec.confidence, ec.tag);
  }

  print_update(all, ec);
}

void return_confidence_example(vw& all, confidence& c, example& ec)
{ output_and_account_confidence_example(all, ec);
  VW::finish_example(all,&ec);
}

base_learner* confidence_setup(vw& all)
{ //parse and set arguments
  if(missing_option(all, false, "confidence", "Get confidence for binary predictions")) return nullptr;

  confidence& data = calloc_or_throw<confidence>();
  data.all=&all;

  //Create new learner
  learner<confidence>& l = init_learner(&data, setup_base(all), predict_or_learn_with_confidence<true>,
                                        predict_or_learn_with_confidence<false>);
  l.set_finish_example(return_confidence_example);

  return make_base(l);
}
<commit_msg>edit confidence.cc to compute confidence before learning with a flag, confidence_after_training, added to do so after learning<commit_after>#include "reductions.h"
#include "vw.h"

using namespace LEARNER;

struct confidence
{ vw* all;//statistics, loss
};

template <bool is_learn, bool is_confidence_after_training>
void predict_or_learn_with_confidence(confidence& c, base_learner& base, example& ec)
{ float threshold = 0.f;
  float sensitivity;
  if (!is_confidence_after_training){
	  sensitivity = base.sensitivity(ec);
  }

  if (is_learn)
    base.learn(ec);
  else
    base.predict(ec);

  if (is_confidence_after_training){
	  sensitivity = base.sensitivity(ec);
  }

  ec.confidence = fabsf(ec.pred.scalar - threshold) / sensitivity;
}

void confidence_print_result(int f, float res, float confidence, v_array<char> tag)
{ if (f >= 0)
  { std::stringstream ss;
    char temp[30];
    sprintf(temp, "%f %f", res, confidence);
    ss << temp;
    if(!print_tag(ss, tag))
      ss << ' ';
    ss << '\n';
    ssize_t len = ss.str().size();
    ssize_t t = io_buf::write_file_or_socket(f, ss.str().c_str(), (unsigned int)len);
    if (t != len)
      cerr << "write error: " << strerror(errno) << endl;
  }
}

void output_and_account_confidence_example(vw& all, example& ec)
{ label_data& ld = ec.l.simple;

  all.sd->update(ec.test_only, ec.loss, ec.weight, ec.num_features);
  if (ld.label != FLT_MAX && !ec.test_only)
    all.sd->weighted_labels += ld.label * ec.weight;
  all.sd->weighted_unlabeled_examples += ld.label == FLT_MAX ? ec.weight : 0;

  all.print(all.raw_prediction, ec.partial_prediction, -1, ec.tag);
  for (size_t i = 0; i<all.final_prediction_sink.size(); i++)
  { int f = (int)all.final_prediction_sink[i];
    confidence_print_result(f, ec.pred.scalar, ec.confidence, ec.tag);
  }

  print_update(all, ec);
}

void return_confidence_example(vw& all, confidence& c, example& ec)
{ output_and_account_confidence_example(all, ec);
  VW::finish_example(all,&ec);
}

base_learner* confidence_setup(vw& all)
{ //parse and set arguments

  new_options(all, "confidence options") ("confidence_after_training", "Confidence after training");
  add_options(all);
  po::variables_map& vm = all.vm;

  if(missing_option(all, false, "confidence", "Get confidence for binary predictions")) return nullptr;

  confidence& data = calloc_or_throw<confidence>();
  data.all=&all;

  void (*learn_with_confidence_ptr)(confidence&, base_learner&, example&) = nullptr;
  void (*predict_with_confidence_ptr)(confidence&, base_learner&, example&) = nullptr;

  if(vm.count("confidence_after_training")){
	  learn_with_confidence_ptr = predict_or_learn_with_confidence<true, false>;
	  predict_with_confidence_ptr = predict_or_learn_with_confidence<false, false>;
  }else{
	  learn_with_confidence_ptr = predict_or_learn_with_confidence<true, true>;
	  predict_with_confidence_ptr = predict_or_learn_with_confidence<false, true>;
  }

  //Create new learner
  learner<confidence>& l = init_learner(&data, setup_base(all), learn_with_confidence_ptr, predict_with_confidence_ptr);

  l.set_finish_example(return_confidence_example);

  return make_base(l);
}
<|endoftext|>


<commit_before>#include "texas_code/client/client.h"

#include <chrono>

#include <spdlog/spdlog.h>

namespace texas_code {

namespace client {

Client::Client(const std::string& rpc_endpoint, const std::string& sub_endpoint)
    : Messenger(rpc_endpoint, sub_endpoint) {
}

void Client::init() {
    Messenger::init();
    Heartbeat request;
    request.set_sequence_num(time(nullptr));
    send_message(static_cast<std::int32_t>(MessageType::HEARTBEAT), request.SerializeAsString());

    get_service().post([this]{
        while (true) {
            Heartbeat request;
            request.set_sequence_num(time(nullptr));
            spdlog::get("console")->info(request.sequence_num());
            send_message(static_cast<std::int32_t>(MessageType::HEARTBEAT), request.SerializeAsString());
            std::this_thread::sleep_for(std::chrono::seconds(30));
        }
    });
}

void Client::run() {
    Messenger::run();
}

void Client::dispatch_message(std::unique_ptr<InquireActionMessage>) {

}

void Client::dispatch_message(std::unique_ptr<SeatInfoMessage>) {

}

void Client::dispatch_message(std::unique_ptr<BlindMessage>) {

}

void Client::dispatch_message(std::unique_ptr<FlopMessage>) {

}

void Client::dispatch_message(std::unique_ptr<HoldCardsMessage>) {

}

void Client::dispatch_message(std::unique_ptr<TurnMessage>) {

}

void Client::dispatch_message(std::unique_ptr<RiverMessage>) {

}

void Client::dispatch_message(std::unique_ptr<InquireShowDownMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ShowDownMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ShowDownResponse>) {

}

void Client::dispatch_message(std::unique_ptr<PotWinMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ConnectResponse>) {

}

}
}
<commit_msg>fix block<commit_after>#include "texas_code/client/client.h"

#include <chrono>

#include <spdlog/spdlog.h>

namespace texas_code {

namespace client {

Client::Client(const std::string& rpc_endpoint, const std::string& sub_endpoint)
    : Messenger(rpc_endpoint, sub_endpoint) {
}

void Client::init() {
    Messenger::init();
    new std::thread([this]{
        while (true) {
            Heartbeat request;
            request.set_sequence_num(time(nullptr));
            spdlog::get("console")->info(request.sequence_num());
            send_message(static_cast<std::int32_t>(MessageType::HEARTBEAT), request.SerializeAsString());
            std::this_thread::sleep_for(std::chrono::seconds(30));
        }
    });
}

void Client::run() {
    Messenger::run();
}

void Client::dispatch_message(std::unique_ptr<InquireActionMessage>) {

}

void Client::dispatch_message(std::unique_ptr<SeatInfoMessage>) {

}

void Client::dispatch_message(std::unique_ptr<BlindMessage>) {

}

void Client::dispatch_message(std::unique_ptr<FlopMessage>) {

}

void Client::dispatch_message(std::unique_ptr<HoldCardsMessage>) {

}

void Client::dispatch_message(std::unique_ptr<TurnMessage>) {

}

void Client::dispatch_message(std::unique_ptr<RiverMessage>) {

}

void Client::dispatch_message(std::unique_ptr<InquireShowDownMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ShowDownMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ShowDownResponse>) {

}

void Client::dispatch_message(std::unique_ptr<PotWinMessage>) {

}

void Client::dispatch_message(std::unique_ptr<ConnectResponse>) {

}

}
}
<|endoftext|>