<commit_before>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012-2013 Brennan Vincent <brennanv@email.arizona.edu>
 * Copyright (C) 2011 Fridrich Strba <fridrich.strba@bluewin.ch>
 * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <unicode/ucnv.h>
#include <unicode/utypes.h>

#include <string.h> // for memcpy
#include <math.h>
#include <zlib.h>
#include <cstring>

#include "libmspub_utils.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define ZLIB_CHUNK 16384

using std::strcmp;
const char *libmspub::windowsCharsetNameByOriginalCharset(const char *name)
{
  if (strcmp(name, "Shift_JIS") == 0)
  {
    return "windows-932";
  }
  if (strcmp(name, "GB18030") == 0)
  {
    return "windows-936";
  }
  if (strcmp(name, "Big5") == 0)
  {
    return "windows-950";
  }
  if (strcmp(name, "ISO-8859-1") == 0)
  {
    return "windows-1252";
  }
  if (strcmp(name, "ISO-8859-2") == 0)
  {
    return "windows-1250";
  }
  if (strcmp(name, "windows-1251") == 0)
  {
    return "windows-1251";
  }
  if (strcmp(name, "windows-1256") == 0)
  {
    return "windows-1256";
  }
  return NULL;
}

const char *libmspub::mimeByImgType(ImgType type)
{
  switch (type)
  {
  case PNG:
    return "image/png";
  case JPEG:
    return "image/jpeg";
  case DIB:
    return "image/bmp";
  case PICT:
    return "image/pict";
  case WMF:
    return "image/wmf";
  case EMF:
    return "image/emf";
  case TIFF:
    return "image/tiff";
  default:
    MSPUB_DEBUG_MSG(("Unknown image type %d passed to mimeByImgType!\n", type));
    return 0;
  }
}

void libmspub::rotateCounter(double &x, double &y, double centerX, double centerY, short rotation)
{
  double vecX = x - centerX;
  double vecY = centerY - y;
  double sinTheta = sin(rotation * M_PI / 180.);
  double cosTheta = cos(rotation * M_PI / 180.);
  double newVecX = cosTheta * vecX - sinTheta * vecY;
  double newVecY = sinTheta * vecX + cosTheta * vecY;
  x = centerX + newVecX;
  y = centerY - newVecY;
}

double libmspub::doubleModulo(double x, double y)
{
  if (y <= 0) // y <= 0 doesn't make sense
  {
    return x;
  }
  while (x < 0)
  {
    x += y;
  }
  while (x >= y)
  {
    x -= y;
  }
  return x;
}

double libmspub::toFixedPoint(int fp)
{
  unsigned short fractionalPart = ((unsigned short) fp) & 0xFFFF;
  short integralPart = fp >> 16;
  return integralPart + fractionalPart / 65536.;
}

double libmspub::readFixedPoint(WPXInputStream *input)
{
  return toFixedPoint(readS32(input));
}

void libmspub::flipIfNecessary(double &x, double &y, double centerX, double centerY, bool flipVertical, bool flipHorizontal)
{
  double vecX = x - centerX;
  double vecY = centerY - y;
  if (flipVertical)
  {
    y = centerY + vecY;
  }
  if (flipHorizontal)
  {
    x = centerX - vecX;
  }
}

unsigned libmspub::correctModulo(int x, unsigned n) // returns the canonical representation of x in Z/nZ
//difference with C++ % operator is that this never returns negative values.
{
  if (x < 0)
  {
    int result = x % (int)n;
    //sign of result is implementation defined
    if (result < 0)
    {
      return n + result;
    }
    return result;
  }
  return x % n;
}

WPXBinaryData libmspub::inflateData(WPXBinaryData deflated)
{
  WPXBinaryData inflated;
  unsigned char out[ZLIB_CHUNK];
  const unsigned char *data = deflated.getDataBuffer();
  z_stream strm;
  int ret;
  strm.zalloc = Z_NULL;
  strm.zfree = Z_NULL;
  strm.opaque = Z_NULL;
  strm.avail_in = 0;
  strm.next_in = Z_NULL;
  if (inflateInit2(&strm,-MAX_WBITS) != Z_OK)
  {
    return WPXBinaryData();
  }
  int have;
  unsigned left = deflated.size();
  do
  {
    strm.avail_in = ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
    strm.next_in = (unsigned char *)data;
    do
    {
      strm.avail_out = ZLIB_CHUNK;
      strm.next_out = out;
      ret = inflate(&strm, Z_NO_FLUSH);
      if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
      {
        inflateEnd(&strm);
        return WPXBinaryData();
      }
      have = ZLIB_CHUNK - strm.avail_out;
      inflated.append(out, have);
    }
    while (strm.avail_out == 0);
    data += ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
    left -= ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
  }
  while (ret != Z_STREAM_END);
  inflateEnd(&strm);
  return inflated;
}

namespace
{

static void _appendUCS4(WPXString &text, unsigned ucs4Character)
{
  unsigned char first;
  int len;
  if (ucs4Character < 0x80)
  {
    first = 0;
    len = 1;
  }
  else if (ucs4Character < 0x800)
  {
    first = 0xc0;
    len = 2;
  }
  else if (ucs4Character < 0x10000)
  {
    first = 0xe0;
    len = 3;
  }
  else if (ucs4Character < 0x200000)
  {
    first = 0xf0;
    len = 4;
  }
  else if (ucs4Character < 0x4000000)
  {
    first = 0xf8;
    len = 5;
  }
  else
  {
    first = 0xfc;
    len = 6;
  }

  unsigned char outbuf[6] = { 0, 0, 0, 0, 0, 0 };
  int i;
  for (i = len - 1; i > 0; --i)
  {
    outbuf[i] = (ucs4Character & 0x3f) | 0x80;
    ucs4Character >>= 6;
  }
  outbuf[0] = (ucs4Character & 0xff) | first;

  for (i = 0; i < len; i++)
    text.append(outbuf[i]);
}

} // anonymous namespace

#define MSPUB_NUM_ELEMENTS(array) sizeof(array)/sizeof(array[0])

uint8_t libmspub::readU8(WPXInputStream *input)
{
  if (!input || input->atEOS())
  {
    MSPUB_DEBUG_MSG(("Something bad happened here!Tell: %ld\n", input->tell()));
    throw EndOfStreamException();
  }
  unsigned long numBytesRead;
  uint8_t const *p = input->read(sizeof(uint8_t), numBytesRead);

  if (p && numBytesRead == sizeof(uint8_t))
    return *(uint8_t const *)(p);
  throw EndOfStreamException();
}

uint16_t libmspub::readU16(WPXInputStream *input)
{
  uint16_t p0 = (uint16_t)readU8(input);
  uint16_t p1 = (uint16_t)readU8(input);
  return (uint16_t)(p0|(p1<<8));
}

uint32_t libmspub::readU32(WPXInputStream *input)
{
  uint32_t p0 = (uint32_t)readU8(input);
  uint32_t p1 = (uint32_t)readU8(input);
  uint32_t p2 = (uint32_t)readU8(input);
  uint32_t p3 = (uint32_t)readU8(input);
  return (uint32_t)(p0|(p1<<8)|(p2<<16)|(p3<<24));
}

int8_t libmspub::readS8(WPXInputStream *input)
{
  return (int8_t)readU8(input);
}

int16_t libmspub::readS16(WPXInputStream *input)
{
  return (int16_t)readU16(input);
}

int32_t libmspub::readS32(WPXInputStream *input)
{
  return (int32_t)readU32(input);
}

uint64_t libmspub::readU64(WPXInputStream *input)
{
  uint64_t p0 = (uint64_t)readU8(input);
  uint64_t p1 = (uint64_t)readU8(input);
  uint64_t p2 = (uint64_t)readU8(input);
  uint64_t p3 = (uint64_t)readU8(input);
  uint64_t p4 = (uint64_t)readU8(input);
  uint64_t p5 = (uint64_t)readU8(input);
  uint64_t p6 = (uint64_t)readU8(input);
  uint64_t p7 = (uint64_t)readU8(input);
  return (uint64_t)(p0|(p1<<8)|(p2<<16)|(p3<<24)|(p4<<32)|(p5<<40)|(p6<<48)|(p7<<56));
}

void libmspub::readNBytes(WPXInputStream *input, unsigned long length, std::vector<unsigned char> &out)
{
  unsigned long numBytesRead = 0;
  const unsigned char *tmpBuffer = input->read(length, numBytesRead);
  if (numBytesRead != length)
  {
    out.clear();
    return;
  }
  out = std::vector<unsigned char>(numBytesRead);
  memcpy(&out[0], tmpBuffer, numBytesRead);
  return;
}

#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)

void libmspub::appendCharacters(WPXString &text, const std::vector<unsigned char> characters,
                                const char *encoding)
{
  UErrorCode status = U_ZERO_ERROR;
  UConverter *conv = NULL;
  conv = ucnv_open(encoding, &status);
  if (U_SUCCESS(status))
  {
    // ICU documentation claims that character-by-character processing is faster "for small amounts of data" and "'normal' charsets"
    // (in any case, it is more convenient :) )
    const char *src = (const char *)&characters[0];
    const char *srcLimit = (const char *)src + characters.size();
    while (src < srcLimit)
    {
      uint32_t ucs4Character = (uint32_t)ucnv_getNextUChar(conv, &src, srcLimit, &status);
      if (U_SUCCESS(status))
      {
        _appendUCS4(text, ucs4Character);
      }
    }
  }
  if (conv)
  {
    ucnv_close(conv);
  }
}

bool libmspub::stillReading(WPXInputStream *input, unsigned long until)
{
  if (input->atEOS())
    return false;
  if (input->tell() < 0)
    return false;
  if ((unsigned long)input->tell() >= until)
    return false;
  return true;
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<commit_msg>return immediately if there's nothing to read<commit_after>/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* libmspub
 * Version: MPL 1.1 / GPLv2+ / LGPLv2+
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License or as specified alternatively below. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * Major Contributor(s):
 * Copyright (C) 2012-2013 Brennan Vincent <brennanv@email.arizona.edu>
 * Copyright (C) 2011 Fridrich Strba <fridrich.strba@bluewin.ch>
 * Copyright (C) 2011 Eilidh McAdam <tibbylickle@gmail.com>
 *
 *
 * All Rights Reserved.
 *
 * For minor contributions see the git repository.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPLv2+"), or
 * the GNU Lesser General Public License Version 2 or later (the "LGPLv2+"),
 * in which case the provisions of the GPLv2+ or the LGPLv2+ are applicable
 * instead of those above.
 */

#include <unicode/ucnv.h>
#include <unicode/utypes.h>

#include <string.h> // for memcpy
#include <math.h>
#include <zlib.h>
#include <cstring>

#include "libmspub_utils.h"

#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

#define ZLIB_CHUNK 16384

using std::strcmp;
const char *libmspub::windowsCharsetNameByOriginalCharset(const char *name)
{
  if (strcmp(name, "Shift_JIS") == 0)
  {
    return "windows-932";
  }
  if (strcmp(name, "GB18030") == 0)
  {
    return "windows-936";
  }
  if (strcmp(name, "Big5") == 0)
  {
    return "windows-950";
  }
  if (strcmp(name, "ISO-8859-1") == 0)
  {
    return "windows-1252";
  }
  if (strcmp(name, "ISO-8859-2") == 0)
  {
    return "windows-1250";
  }
  if (strcmp(name, "windows-1251") == 0)
  {
    return "windows-1251";
  }
  if (strcmp(name, "windows-1256") == 0)
  {
    return "windows-1256";
  }
  return NULL;
}

const char *libmspub::mimeByImgType(ImgType type)
{
  switch (type)
  {
  case PNG:
    return "image/png";
  case JPEG:
    return "image/jpeg";
  case DIB:
    return "image/bmp";
  case PICT:
    return "image/pict";
  case WMF:
    return "image/wmf";
  case EMF:
    return "image/emf";
  case TIFF:
    return "image/tiff";
  default:
    MSPUB_DEBUG_MSG(("Unknown image type %d passed to mimeByImgType!\n", type));
    return 0;
  }
}

void libmspub::rotateCounter(double &x, double &y, double centerX, double centerY, short rotation)
{
  double vecX = x - centerX;
  double vecY = centerY - y;
  double sinTheta = sin(rotation * M_PI / 180.);
  double cosTheta = cos(rotation * M_PI / 180.);
  double newVecX = cosTheta * vecX - sinTheta * vecY;
  double newVecY = sinTheta * vecX + cosTheta * vecY;
  x = centerX + newVecX;
  y = centerY - newVecY;
}

double libmspub::doubleModulo(double x, double y)
{
  if (y <= 0) // y <= 0 doesn't make sense
  {
    return x;
  }
  while (x < 0)
  {
    x += y;
  }
  while (x >= y)
  {
    x -= y;
  }
  return x;
}

double libmspub::toFixedPoint(int fp)
{
  unsigned short fractionalPart = ((unsigned short) fp) & 0xFFFF;
  short integralPart = fp >> 16;
  return integralPart + fractionalPart / 65536.;
}

double libmspub::readFixedPoint(WPXInputStream *input)
{
  return toFixedPoint(readS32(input));
}

void libmspub::flipIfNecessary(double &x, double &y, double centerX, double centerY, bool flipVertical, bool flipHorizontal)
{
  double vecX = x - centerX;
  double vecY = centerY - y;
  if (flipVertical)
  {
    y = centerY + vecY;
  }
  if (flipHorizontal)
  {
    x = centerX - vecX;
  }
}

unsigned libmspub::correctModulo(int x, unsigned n) // returns the canonical representation of x in Z/nZ
//difference with C++ % operator is that this never returns negative values.
{
  if (x < 0)
  {
    int result = x % (int)n;
    //sign of result is implementation defined
    if (result < 0)
    {
      return n + result;
    }
    return result;
  }
  return x % n;
}

WPXBinaryData libmspub::inflateData(WPXBinaryData deflated)
{
  WPXBinaryData inflated;
  unsigned char out[ZLIB_CHUNK];
  const unsigned char *data = deflated.getDataBuffer();
  z_stream strm;
  int ret;
  strm.zalloc = Z_NULL;
  strm.zfree = Z_NULL;
  strm.opaque = Z_NULL;
  strm.avail_in = 0;
  strm.next_in = Z_NULL;
  if (inflateInit2(&strm,-MAX_WBITS) != Z_OK)
  {
    return WPXBinaryData();
  }
  int have;
  unsigned left = deflated.size();
  do
  {
    strm.avail_in = ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
    strm.next_in = (unsigned char *)data;
    do
    {
      strm.avail_out = ZLIB_CHUNK;
      strm.next_out = out;
      ret = inflate(&strm, Z_NO_FLUSH);
      if (ret == Z_STREAM_ERROR || ret == Z_NEED_DICT || ret == Z_DATA_ERROR || ret == Z_MEM_ERROR)
      {
        inflateEnd(&strm);
        return WPXBinaryData();
      }
      have = ZLIB_CHUNK - strm.avail_out;
      inflated.append(out, have);
    }
    while (strm.avail_out == 0);
    data += ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
    left -= ZLIB_CHUNK > left ? left : ZLIB_CHUNK;
  }
  while (ret != Z_STREAM_END);
  inflateEnd(&strm);
  return inflated;
}

namespace
{

static void _appendUCS4(WPXString &text, unsigned ucs4Character)
{
  unsigned char first;
  int len;
  if (ucs4Character < 0x80)
  {
    first = 0;
    len = 1;
  }
  else if (ucs4Character < 0x800)
  {
    first = 0xc0;
    len = 2;
  }
  else if (ucs4Character < 0x10000)
  {
    first = 0xe0;
    len = 3;
  }
  else if (ucs4Character < 0x200000)
  {
    first = 0xf0;
    len = 4;
  }
  else if (ucs4Character < 0x4000000)
  {
    first = 0xf8;
    len = 5;
  }
  else
  {
    first = 0xfc;
    len = 6;
  }

  unsigned char outbuf[6] = { 0, 0, 0, 0, 0, 0 };
  int i;
  for (i = len - 1; i > 0; --i)
  {
    outbuf[i] = (ucs4Character & 0x3f) | 0x80;
    ucs4Character >>= 6;
  }
  outbuf[0] = (ucs4Character & 0xff) | first;

  for (i = 0; i < len; i++)
    text.append(outbuf[i]);
}

} // anonymous namespace

#define MSPUB_NUM_ELEMENTS(array) sizeof(array)/sizeof(array[0])

uint8_t libmspub::readU8(WPXInputStream *input)
{
  if (!input || input->atEOS())
  {
    MSPUB_DEBUG_MSG(("Something bad happened here!Tell: %ld\n", input->tell()));
    throw EndOfStreamException();
  }
  unsigned long numBytesRead;
  uint8_t const *p = input->read(sizeof(uint8_t), numBytesRead);

  if (p && numBytesRead == sizeof(uint8_t))
    return *(uint8_t const *)(p);
  throw EndOfStreamException();
}

uint16_t libmspub::readU16(WPXInputStream *input)
{
  uint16_t p0 = (uint16_t)readU8(input);
  uint16_t p1 = (uint16_t)readU8(input);
  return (uint16_t)(p0|(p1<<8));
}

uint32_t libmspub::readU32(WPXInputStream *input)
{
  uint32_t p0 = (uint32_t)readU8(input);
  uint32_t p1 = (uint32_t)readU8(input);
  uint32_t p2 = (uint32_t)readU8(input);
  uint32_t p3 = (uint32_t)readU8(input);
  return (uint32_t)(p0|(p1<<8)|(p2<<16)|(p3<<24));
}

int8_t libmspub::readS8(WPXInputStream *input)
{
  return (int8_t)readU8(input);
}

int16_t libmspub::readS16(WPXInputStream *input)
{
  return (int16_t)readU16(input);
}

int32_t libmspub::readS32(WPXInputStream *input)
{
  return (int32_t)readU32(input);
}

uint64_t libmspub::readU64(WPXInputStream *input)
{
  uint64_t p0 = (uint64_t)readU8(input);
  uint64_t p1 = (uint64_t)readU8(input);
  uint64_t p2 = (uint64_t)readU8(input);
  uint64_t p3 = (uint64_t)readU8(input);
  uint64_t p4 = (uint64_t)readU8(input);
  uint64_t p5 = (uint64_t)readU8(input);
  uint64_t p6 = (uint64_t)readU8(input);
  uint64_t p7 = (uint64_t)readU8(input);
  return (uint64_t)(p0|(p1<<8)|(p2<<16)|(p3<<24)|(p4<<32)|(p5<<40)|(p6<<48)|(p7<<56));
}

void libmspub::readNBytes(WPXInputStream *input, unsigned long length, std::vector<unsigned char> &out)
{
  if (length == 0)
  {
    MSPUB_DEBUG_MSG(("Attempt to read 0 bytes!"));
    return;
  }

  unsigned long numBytesRead = 0;
  const unsigned char *tmpBuffer = input->read(length, numBytesRead);
  if (numBytesRead != length)
  {
    out.clear();
    return;
  }
  out = std::vector<unsigned char>(numBytesRead);
  memcpy(&out[0], tmpBuffer, numBytesRead);
  return;
}

#define SURROGATE_VALUE(h,l) (((h) - 0xd800) * 0x400 + (l) - 0xdc00 + 0x10000)

void libmspub::appendCharacters(WPXString &text, const std::vector<unsigned char> characters,
                                const char *encoding)
{
  UErrorCode status = U_ZERO_ERROR;
  UConverter *conv = NULL;
  conv = ucnv_open(encoding, &status);
  if (U_SUCCESS(status))
  {
    // ICU documentation claims that character-by-character processing is faster "for small amounts of data" and "'normal' charsets"
    // (in any case, it is more convenient :) )
    const char *src = (const char *)&characters[0];
    const char *srcLimit = (const char *)src + characters.size();
    while (src < srcLimit)
    {
      uint32_t ucs4Character = (uint32_t)ucnv_getNextUChar(conv, &src, srcLimit, &status);
      if (U_SUCCESS(status))
      {
        _appendUCS4(text, ucs4Character);
      }
    }
  }
  if (conv)
  {
    ucnv_close(conv);
  }
}

bool libmspub::stillReading(WPXInputStream *input, unsigned long until)
{
  if (input->atEOS())
    return false;
  if (input->tell() < 0)
    return false;
  if ((unsigned long)input->tell() >= until)
    return false;
  return true;
}

/* vim:set shiftwidth=2 softtabstop=2 expandtab: */
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "frtconfigagent.h"
#include "frtconfigrequestv3.h"
#include <vespa/config/common/trace.h>

#include <vespa/log/log.h>
LOG_SETUP(".config.frt.frtconfigagent");

namespace config {

FRTConfigAgent::FRTConfigAgent(const IConfigHolder::SP & holder, const TimingValues & timingValues)
    : _holder(holder),
      _timingValues(timingValues),
      _configState(),
      _latest(),
      _waitTime(0),
      _numConfigured(0),
      _failedRequests(0),
      _nextTimeout(_timingValues.initialTimeout)
{
}

FRTConfigAgent::~FRTConfigAgent() {}

void
FRTConfigAgent::handleResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    if (LOG_WOULD_LOG(spam)) {
        const ConfigKey & key(request.getKey());
        LOG(spam, "current state for %s: generation %ld md5 %s", key.toString().c_str(), _configState.generation, _configState.md5.c_str());
    }
    if (response->validateResponse() && !response->isError()) {
        handleOKResponse(request, std::move(response));
    } else {
        handleErrorResponse(request, std::move(response));
    }
}

void
FRTConfigAgent::handleOKResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    _failedRequests = 0;
    response->fill();
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "trace(%s)", response->getTrace().toString().c_str());
    }

    ConfigState newState = response->getConfigState();
    if ( ! request.verifyState(newState)) {
        handleUpdatedGeneration(response->getKey(), newState, response->getValue());
    }
    setWaitTime(_timingValues.successDelay, 1);
    _nextTimeout = _timingValues.successTimeout;
}

void
FRTConfigAgent::handleUpdatedGeneration(const ConfigKey & key, const ConfigState & newState, const ConfigValue & configValue)
{
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "new generation %ld for key %s", newState.generation, key.toString().c_str());
    }
    _latest = configValue;

    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "updating holder for key %s,", key.toString().c_str());
    }
    _holder->handle(ConfigUpdate::UP(new ConfigUpdate(_latest, true, newState.generation)));
    _numConfigured++;
    _configState = newState;
}

void
FRTConfigAgent::handleErrorResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    _failedRequests++;
    int multiplier = std::min(_failedRequests, _timingValues.maxDelayMultiplier);
    setWaitTime(_numConfigured > 0 ? _timingValues.configuredErrorDelay : _timingValues.unconfiguredDelay, multiplier);
    _nextTimeout = _timingValues.errorTimeout;
    const ConfigKey & key(request.getKey());
    LOG(info, "Error response or no response from config server (key: %s) (errcode=%d, validresponse:%d), trying again in %ld milliseconds", key.toString().c_str(), response->errorCode(), response->hasValidResponse() ? 1 : 0, _waitTime);
}

void
FRTConfigAgent::setWaitTime(uint64_t delay, int multiplier)
{
    uint64_t prevWait = _waitTime;
    _waitTime = _timingValues.fixedDelay + (multiplier * delay);
    LOG(spam, "Adjusting waittime from %ld to %ld", prevWait, _waitTime);
}

uint64_t FRTConfigAgent::getTimeout() const { return _nextTimeout; }
uint64_t FRTConfigAgent::getWaitTime() const { return _waitTime; }
const ConfigState & FRTConfigAgent::getConfigState() const { return _configState; }

}
<commit_msg>Set _configState before calling out to holder.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "frtconfigagent.h"
#include "frtconfigrequestv3.h"
#include <vespa/config/common/trace.h>

#include <vespa/log/log.h>
LOG_SETUP(".config.frt.frtconfigagent");

namespace config {

FRTConfigAgent::FRTConfigAgent(const IConfigHolder::SP & holder, const TimingValues & timingValues)
    : _holder(holder),
      _timingValues(timingValues),
      _configState(),
      _latest(),
      _waitTime(0),
      _numConfigured(0),
      _failedRequests(0),
      _nextTimeout(_timingValues.initialTimeout)
{
}

FRTConfigAgent::~FRTConfigAgent() {}

void
FRTConfigAgent::handleResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    if (LOG_WOULD_LOG(spam)) {
        const ConfigKey & key(request.getKey());
        LOG(spam, "current state for %s: generation %ld md5 %s", key.toString().c_str(), _configState.generation, _configState.md5.c_str());
    }
    if (response->validateResponse() && !response->isError()) {
        handleOKResponse(request, std::move(response));
    } else {
        handleErrorResponse(request, std::move(response));
    }
}

void
FRTConfigAgent::handleOKResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    _failedRequests = 0;
    response->fill();
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "trace(%s)", response->getTrace().toString().c_str());
    }

    ConfigState newState = response->getConfigState();
    if ( ! request.verifyState(newState)) {
        handleUpdatedGeneration(response->getKey(), newState, response->getValue());
    }
    setWaitTime(_timingValues.successDelay, 1);
    _nextTimeout = _timingValues.successTimeout;
}

void
FRTConfigAgent::handleUpdatedGeneration(const ConfigKey & key, const ConfigState & newState, const ConfigValue & configValue)
{
    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "new generation %ld for key %s", newState.generation, key.toString().c_str());
    }
    _latest = configValue;
    _configState = newState;

    if (LOG_WOULD_LOG(spam)) {
        LOG(spam, "updating holder for key %s,", key.toString().c_str());
    }
    _holder->handle(ConfigUpdate::UP(new ConfigUpdate(_latest, true, newState.generation)));
    _numConfigured++;
}

void
FRTConfigAgent::handleErrorResponse(const ConfigRequest & request, ConfigResponse::UP response)
{
    _failedRequests++;
    int multiplier = std::min(_failedRequests, _timingValues.maxDelayMultiplier);
    setWaitTime(_numConfigured > 0 ? _timingValues.configuredErrorDelay : _timingValues.unconfiguredDelay, multiplier);
    _nextTimeout = _timingValues.errorTimeout;
    const ConfigKey & key(request.getKey());
    LOG(info, "Error response or no response from config server (key: %s) (errcode=%d, validresponse:%d), trying again in %ld milliseconds", key.toString().c_str(), response->errorCode(), response->hasValidResponse() ? 1 : 0, _waitTime);
}

void
FRTConfigAgent::setWaitTime(uint64_t delay, int multiplier)
{
    uint64_t prevWait = _waitTime;
    _waitTime = _timingValues.fixedDelay + (multiplier * delay);
    LOG(spam, "Adjusting waittime from %ld to %ld", prevWait, _waitTime);
}

uint64_t FRTConfigAgent::getTimeout() const { return _nextTimeout; }
uint64_t FRTConfigAgent::getWaitTime() const { return _waitTime; }
const ConfigState & FRTConfigAgent::getConfigState() const { return _configState; }

}
<|endoftext|>


<commit_before>/*
 *  qiesmap.cpp
 *
 *  Copyright (c) 2016 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>

#include "QI/Util.h"
#include "Filters/ApplyAlgorithmFilter.h"

using namespace std;
using namespace Eigen;

class ESAlgo : public Algorithm<complex<double>> {
protected:
    size_t m_size = 0;
public:
    size_t numInputs() const override { return 1; }
    size_t numConsts() const override { return 0; }
    size_t numOutputs() const override { return 6; }
    const vector<string> & names() const {
        static vector<string> _names = {"M", "T1", "T2", "th", "a", "b"};
        return _names;
    }
    size_t dataSize() const override { return m_size; }
    void setSize(const size_t s) { m_size = s; }
    virtual TArray defaultConsts() override {
        // B1
        TArray def = TArray::Ones(0);
        return def;
    }
    void apply(const TInput &data, const TArray &inputs, TArray &outputs, TArray &resids, TIterations &its) const override
    {
        typedef Matrix<double, 6, 6> Matrix6d;
        typedef Matrix<double, 6, 1> Vector6d;
        double scale = data.abs().maxCoeff();
        ArrayXd x = data.real() / scale;
        ArrayXd y = data.imag() / scale;

        Matrix<double, Dynamic, 6> D(data.rows(), 6);
        D.col(0) = x*x;
        D.col(1) = x*y;
        D.col(2) = y*y;
        D.col(3) = x;
        D.col(4) = y;
        D.col(5).setConstant(1);
        Matrix6d S = D.transpose() * D;
        Matrix6d C = Matrix6d::Zero();
        C(0,2) = -2; C(1,1) = 1; C(2,0) = -2;

        typedef GeneralizedEigenSolver<Matrix6d> ESolver;
        ESolver es(S, C);
        ArrayXd eVals = es.eigenvalues().real();
        ArrayXd Z;
        for (int i = 0; i < 6; i++) {
            if (isfinite(eVals(i)) && (eVals(i) < 0)) {
                Z = es.eigenvectors().col(i);
                break;
            }
        }

        const double za = Z[0];
        const double zb = Z[1]/2;
        const double zc = Z[2];
        const double zd = Z[3]/2;
        const double zf = Z[4]/2;
        const double zg = Z[5];
        const double dsc=(zb*zb-za*zc);
        const double xc = (zc*zd-zb*zf)/dsc;
        const double yc = (za*zf-zb*zd)/dsc;
        const double th = atan2(yc,xc);
        double A = sqrt((2*(za*(zf*zf)+zc*(zd*zd)+zg*(zb*zb)-2*zb*zd*zf-za*zc*zg))/(dsc*(sqrt((za-zc)*(za-zc) + 4*zb*zb)-(za+zc))));
        double B = sqrt((2*(za*(zf*zf)+zc*(zd*zd)+zg*(zb*zb)-2*zb*zd*zf-za*zc*zg))/(dsc*(-sqrt((za-zc)*(za-zc) + 4*zb*zb)-(za+zc))));
        if (A > B) {
            std::swap(A, B);
        }
        cout << "Z " << Z.transpose() << endl;
        cout << "dsc " << dsc << " xc " << xc << " yc " << yc << " A " << A << " B " << B << endl;
        const double c = sqrt(xc*xc+yc*xc);
        const double b = (-2*c*A + sqrt(pow(2*c*A,2)-4*(c*c+B*B)*(A*A-B*B)))/(2*(c*c+B*B));
        const double a = B / (b*B + c*sqrt(1-b*b));
        const double M = scale*c*(1-b*b)/(1-a*b);
        const double TR = 0.0065;
        const double FA = (25*M_PI/180.);
        const double T1 = -TR / log((a*(1+cos(FA)-a*b*cos(FA))-b)/(a*(1+cos(FA)-a*b)-b*cos(FA)));
        const double T2 = -TR / log(a);

        outputs[0] = M;
        outputs[1] = T1;
        outputs[2] = T2;
        outputs[3] = th;
        outputs[4] = a;
        outputs[5] = b;
    }
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: qiesmap [options] input \n\
\n\
A utility for calculating T1,T2,PD and f0 maps from SSFP data.\n\
Input must be a single complex image with at least 6 phase increments.\n\
\n\
Options:\n\
    --help, -h       : Print this message.\n\
    --verbose, -v    : Print more information.\n\
    --out, -o path   : Specify an output prefix.\n\
    --mask, -m file  : Mask input with specified file.\n\
    --threads, -T N  : Use N threads (default=hardware limit).\n"
};

bool verbose = false;
static size_t num_threads = 4;
static string outPrefix;
const struct option long_opts[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"out", required_argument, 0, 'o'},
    {"mask", required_argument, 0, 'm'},
    {"threads", required_argument, 0, 'T'},
    {0, 0, 0, 0}
};
const char *short_opts = "hvo:m:T:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();
    QI::VolumeF::Pointer mask = ITK_NULLPTR;
    QI::VolumeF::Pointer B1   = ITK_NULLPTR;

    shared_ptr<ESAlgo> algo = make_shared<ESAlgo>();
    int indexptr = 0, c;
    while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
        switch (c) {
            case 'v': verbose = true; break;
            case 'm':
                if (verbose) cout << "Opening mask file " << optarg << endl;
                mask = QI::ReadImage(optarg);
                break;
            case 'o':
                outPrefix = optarg;
                if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
                break;
            case 'b':
                if (verbose) cout << "Opening B1 file: " << optarg << endl;
                B1 = QI::ReadImage(optarg);
                break;
            case 'T':
                num_threads = stoi(optarg);
                if (num_threads == 0)
                    num_threads = std::thread::hardware_concurrency();
                break;
            case 'h':
                cout << QI::GetVersion() << endl << usage << endl;
                return EXIT_SUCCESS;
            case '?': // getopt will print an error message
                return EXIT_FAILURE;
            default:
                cout << "Unhandled option " << string(1, c) << endl;
                return EXIT_FAILURE;
        }
    }
    if ((argc - optind) != 1) {
        cout << "Incorrect number of arguments." << endl << usage << endl;
        return EXIT_FAILURE;
    }

    string inputFilename = argv[optind++];
    if (verbose) cout << "Opening file: " << inputFilename << endl;
    auto data = QI::ReadVectorImage<complex<float>>(inputFilename);
    auto apply = itk::ApplyAlgorithmFilter<ESAlgo, complex<float>>::New();
    algo->setSize(data->GetNumberOfComponentsPerPixel());
    apply->SetAlgorithm(algo);
    apply->SetPoolsize(num_threads);
    apply->SetInput(0, data);
    if (mask)
        apply->SetMask(mask);
    /*if (B1)
        apply->SetConst(0, B1);*/
    if (verbose) {
        cout << "Processing" << endl;
        auto monitor = QI::GenericMonitor::New();
        apply->AddObserver(itk::ProgressEvent(), monitor);
    }
    apply->Update();
    if (verbose) {
        cout << "Elapsed time was " << apply->GetTotalTime() << "s" << endl;
        cout << "Mean time per voxel was " << apply->GetMeanTime() << "s" << endl;
        cout << "Writing results files." << endl;
    }
    outPrefix = outPrefix + "ES_";
    for (int i = 0; i < algo->numOutputs(); i++) {
        QI::WriteImage(apply->GetOutput(i), outPrefix + algo->names().at(i) + QI::OutExt());
    }

    if (verbose) cout << "Finished." << endl;
    return EXIT_SUCCESS;
}
<commit_msg>ENH: Added own code to find generalized eigenvectors.<commit_after>/*
 *  qiesmap.cpp
 *
 *  Copyright (c) 2016 Tobias Wood.
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 */

#include <getopt.h>
#include <iostream>
#include <Eigen/Dense>
#include <Eigen/Eigenvalues>

#include "QI/Util.h"
#include "Filters/ApplyAlgorithmFilter.h"

using namespace std;
using namespace Eigen;

class ESAlgo : public Algorithm<complex<double>> {
protected:
    size_t m_size = 0;
public:
    size_t numInputs() const override { return 1; }
    size_t numConsts() const override { return 1; }
    size_t numOutputs() const override { return 6; }
    const vector<string> & names() const {
        static vector<string> _names = {"M", "T1", "T2", "th", "a", "b"};
        return _names;
    }
    size_t dataSize() const override { return m_size; }
    void setSize(const size_t s) { m_size = s; }
    virtual TArray defaultConsts() override {
        // B1
        TArray def = TArray::Ones(1);
        return def;
    }

    ArrayXd solveEig(const MatrixXd &A, const MatrixXd &B) const {
        RealQZ<MatrixXd> qz(A, B);
        VectorXd v = ArrayXd::Zero(A.cols());
        const MatrixXd &mS = qz.matrixS();
        const MatrixXd &mT = qz.matrixT();
        const MatrixXd &mZT = qz.matrixZ().transpose();
        for (int i = 0; i < 6; i++) {
            const double a = mS.coeffRef(i,i);
            const double b = mT.coeffRef(i,i);
            const double l = a / b;
            if (isfinite(l) && (l < 0)) {
                v(i) = 1.0;
                const double a = qz.matrixS().coeffRef(i,i);
                const double b = qz.matrixT().coeffRef(i,i);
                for (Index j = i-1; j >= 0; j--) {
                    const Index st = j+1;
                    const Index sz = i-j;
                    v.coeffRef(j) = -v.segment(st,sz).transpose().cwiseProduct(b*mS.block(j,st,1,sz) - a*mT.block(j,st,1,sz)).sum() / (b*mS.coeffRef(j,j) - a*mT.coeffRef(j,j));
                }
                v = (mZT * v).normalized();
                break;
            }
        }
        return v;
    }

    void apply(const TInput &data, const TArray &inputs, TArray &outputs, TArray &resids, TIterations &its) const override
    {
        typedef Matrix<double, 6, 6> Matrix6d;
        typedef Matrix<double, 6, 1> Vector6d;
        const double B1 = inputs[0];
        const double scale = data.abs().maxCoeff();
        ArrayXd x = data.real() / scale;
        ArrayXd y = data.imag() / scale;

        Matrix<double, Dynamic, 6> D(data.rows(), 6);
        D.col(0) = x*x;
        D.col(1) = x*y;
        D.col(2) = y*y;
        D.col(3) = x;
        D.col(4) = y;
        D.col(5).setConstant(1);
        Matrix6d S = D.transpose() * D;
        Matrix6d C = Matrix6d::Zero();
        C(0,2) = -2; C(1,1) = 1; C(2,0) = -2;
        ArrayXd Z = solveEig(S, C);
        const double za = Z[0];
        const double zb = Z[1]/2;
        const double zc = Z[2];
        const double zd = Z[3]/2;
        const double zf = Z[4]/2;
        const double zg = Z[5];
        const double dsc=(zb*zb-za*zc);
        const double xc = (zc*zd-zb*zf)/dsc;
        const double yc = (za*zf-zb*zd)/dsc;
        const double th = atan2(yc,xc);
        double A = sqrt((2*(za*(zf*zf)+zc*(zd*zd)+zg*(zb*zb)-2*zb*zd*zf-za*zc*zg))/(dsc*(sqrt((za-zc)*(za-zc) + 4*zb*zb)-(za+zc))));
        double B = sqrt((2*(za*(zf*zf)+zc*(zd*zd)+zg*(zb*zb)-2*zb*zd*zf-za*zc*zg))/(dsc*(-sqrt((za-zc)*(za-zc) + 4*zb*zb)-(za+zc))));
        if (A > B) {
            std::swap(A, B);
        }
        //cout << "Z " << Z.transpose() << endl;
        //cout << "dsc " << dsc << " xc " << xc << " yc " << yc << " A " << A << " B " << B << endl;
        const double c = sqrt(xc*xc+yc*yc);
        const double b = (-c*A + sqrt(c*c*A*A - (c*c + B*B)*(A*A - B*B)))/(c*c + B*B);
        const double a = B / (b*B + c*sqrt(1-b*b));
        const double M = scale*c*(1-b*b)/(1-a*b);
        const double TR = 0.0065;
        const double FA = B1 * (25*M_PI/180.);
        const double T1 = -TR / log((a*(1+cos(FA)-a*b*cos(FA))-b)/(a*(1+cos(FA)-a*b)-b*cos(FA)));
        const double T2 = -TR / log(a);

        outputs[0] = M;
        outputs[1] = T1;
        outputs[2] = T2;
        outputs[3] = th;
        outputs[4] = a;
        outputs[5] = b;
    }
};

//******************************************************************************
// Arguments / Usage
//******************************************************************************
const string usage {
"Usage is: qiesmap [options] input \n\
\n\
A utility for calculating T1,T2,PD and f0 maps from SSFP data.\n\
Input must be a single complex image with at least 6 phase increments.\n\
\n\
Options:\n\
    --help, -h       : Print this message.\n\
    --verbose, -v    : Print more information.\n\
    --out, -o path   : Specify an output prefix.\n\
    --mask, -m file  : Mask input with specified file.\n\
    --B1, -b file    : B1 Map file (ratio)\n\
    --threads, -T N  : Use N threads (default=hardware limit).\n"
};

bool verbose = false;
static size_t num_threads = 4;
static string outPrefix;
const struct option long_opts[] = {
    {"help", no_argument, 0, 'h'},
    {"verbose", no_argument, 0, 'v'},
    {"out", required_argument, 0, 'o'},
    {"mask", required_argument, 0, 'm'},
    {"B1", required_argument, 0, 'b'},
    {"threads", required_argument, 0, 'T'},
    {0, 0, 0, 0}
};
const char *short_opts = "hvo:m:b:T:";

//******************************************************************************
// Main
//******************************************************************************
int main(int argc, char **argv) {
    Eigen::initParallel();
    QI::VolumeF::Pointer mask = ITK_NULLPTR;
    QI::VolumeF::Pointer B1   = ITK_NULLPTR;

    shared_ptr<ESAlgo> algo = make_shared<ESAlgo>();
    int indexptr = 0, c;
    while ((c = getopt_long(argc, argv, short_opts, long_opts, &indexptr)) != -1) {
        switch (c) {
            case 'v': verbose = true; break;
            case 'm':
                if (verbose) cout << "Opening mask file " << optarg << endl;
                mask = QI::ReadImage(optarg);
                break;
            case 'o':
                outPrefix = optarg;
                if (verbose) cout << "Output prefix will be: " << outPrefix << endl;
                break;
            case 'b':
                if (verbose) cout << "Opening B1 file: " << optarg << endl;
                B1 = QI::ReadImage(optarg);
                break;
            case 'T':
                num_threads = stoi(optarg);
                if (num_threads == 0)
                    num_threads = std::thread::hardware_concurrency();
                break;
            case 'h':
                cout << QI::GetVersion() << endl << usage << endl;
                return EXIT_SUCCESS;
            case '?': // getopt will print an error message
                return EXIT_FAILURE;
            default:
                cout << "Unhandled option " << string(1, c) << endl;
                return EXIT_FAILURE;
        }
    }
    if ((argc - optind) != 1) {
        cout << "Incorrect number of arguments." << endl << usage << endl;
        return EXIT_FAILURE;
    }

    string inputFilename = argv[optind++];
    if (verbose) cout << "Opening file: " << inputFilename << endl;
    auto data = QI::ReadVectorImage<complex<float>>(inputFilename);
    auto apply = itk::ApplyAlgorithmFilter<ESAlgo, complex<float>>::New();
    algo->setSize(data->GetNumberOfComponentsPerPixel());
    apply->SetAlgorithm(algo);
    apply->SetPoolsize(num_threads);
    apply->SetInput(0, data);
    if (mask)
        apply->SetMask(mask);
    if (B1)
        apply->SetConst(0, B1);
    if (verbose) {
        cout << "Processing" << endl;
        auto monitor = QI::GenericMonitor::New();
        apply->AddObserver(itk::ProgressEvent(), monitor);
    }
    apply->Update();
    if (verbose) {
        cout << "Elapsed time was " << apply->GetTotalTime() << "s" << endl;
        cout << "Mean time per voxel was " << apply->GetMeanTime() << "s" << endl;
        cout << "Writing results files." << endl;
    }
    outPrefix = outPrefix + "ES_";
    for (int i = 0; i < algo->numOutputs(); i++) {
        QI::WriteImage(apply->GetOutput(i), outPrefix + algo->names().at(i) + QI::OutExt());
    }

    if (verbose) cout << "Finished." << endl;
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#endif
#include <boost/preprocessor.hpp>

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(BOOST_PP_EXPAND(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x), _ELIM)

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (5, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    ~constructor_arity~,   /* constructor arity */ \
    ~full_name~,           /* full name */ \
    BOOST_PP_NIL           /* methods */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name           0
#define FLUSSPFERD_CD_PARAM__constructor_name   1
#define FLUSSPFERD_CD_PARAM__constructor_arity  2
#define FLUSSPFERD_CD_PARAM__full_name          3
#define FLUSSPFERD_CD_PARAM__methods            4

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods \
) \
  class p_cpp_name { \
    struct class_info : ::flusspferd::class_info_base { \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_SEQ_FOR_EACH( \
          FLUSSPFERD_CD_METHOD, \
          p_cpp_name, \
          p_methods) \
      } \
    }; \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, element) \
  ::flusspferd::create_native_method( \
      proto, \
      BOOST_PP_STRINGIZE(element), \
      & p_cpp_name :: element); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<commit_msg>class_macros: add augment_constructor<commit_after>// vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
/*
Copyright (c) 2009 Aristid Breitkreuz, Ash Berlin, Ruediger Sonderfeld

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

#ifndef FLUSSFPERD_CLASS_DESCRIPTION_HPP
#define FLUSSFPERD_CLASS_DESCRIPTION_HPP

#ifndef PREPROC_DEBUG
#include "class.hpp"
#endif
#include <boost/preprocessor.hpp>

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS(x, y) \
  ((x, y)) \
  FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS_ELIM
#define FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS2_ELIM

#define FLUSSPFERD_PP_GEN_TUPLE2SEQ(x) \
  BOOST_PP_CAT(BOOST_PP_EXPAND(FLUSSPFERD_PP_GEN_TUPLE2SEQ_PROCESS x), _ELIM)

#define FLUSSPFERD_CD_PARAM_FOLD(s, state, elem) \
  BOOST_PP_ARRAY_REPLACE( \
    state, \
    BOOST_PP_EXPAND( \
      BOOST_PP_CAT(FLUSSPFERD_CD_PARAM__, \
        BOOST_PP_TUPLE_ELEM(2, 0, elem))), \
    BOOST_PP_TUPLE_ELEM(2, 1, elem)) \
  /* */

#define FLUSSPFERD_CD_PARAM_INITIAL \
  (6, ( \
    ~cpp_name~,            /* name */ \
    ~constructor_name~,    /* constructor name */ \
    ~constructor_arity~,   /* constructor arity */ \
    ~full_name~,           /* full name */ \
    BOOST_PP_NIL,          /* methods */ \
    0                      /* augment constructor */ \
  )) \
  /* */

#define FLUSSPFERD_CD_PARAM__cpp_name               0
#define FLUSSPFERD_CD_PARAM__constructor_name       1
#define FLUSSPFERD_CD_PARAM__constructor_arity      2
#define FLUSSPFERD_CD_PARAM__full_name              3
#define FLUSSPFERD_CD_PARAM__methods                4
#define FLUSSPFERD_CD_PARAM__augment_constructor    5

#define FLUSSPFERD_CD_PARAM(tuple_seq) \
  BOOST_PP_SEQ_FOLD_LEFT( \
    FLUSSPFERD_CD_PARAM_FOLD, \
    FLUSSPFERD_CD_PARAM_INITIAL, \
    FLUSSPFERD_PP_GEN_TUPLE2SEQ(tuple_seq) \
  ) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_A(array) \
  BOOST_PP_EXPAND(FLUSSPFERD_CLASS_DESCRIPTION_P BOOST_PP_ARRAY_DATA(array)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_P( \
  p_cpp_name, \
  p_constructor_name, \
  p_constructor_arity, \
  p_full_name, \
  p_methods, \
  p_augment_constructor \
) \
  class p_cpp_name { \
    struct class_info : ::flusspferd::class_info_base { \
      static char const *constructor_name() { \
        return (p_constructor_name); \
      } \
      typedef ::boost::mpl::size_t< (p_constructor_arity) > constructor_arity; \
      static char const *full_name() { \
        return (p_full_name); \
      } \
      static ::flusspferd::object create_prototype() { \
        ::flusspferd::object proto = ::flusspferd::create_object(); \
        BOOST_PP_SEQ_FOR_EACH( \
          FLUSSPFERD_CD_METHOD, \
          p_cpp_name, \
          p_methods) \
      } \
      BOOST_PP_EXPR_IF( \
        p_augment_constructor, \
        static void augment_constructor(::flusspferd::object &); \
      ) \
    }; \
  /* */

#define FLUSSPFERD_CD_METHOD(r, p_cpp_name, element) \
  ::flusspferd::create_native_method( \
      proto, \
      BOOST_PP_STRINGIZE(element), \
      & p_cpp_name :: element); \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION(tuple_seq) \
  FLUSSPFERD_CLASS_DESCRIPTION_A(FLUSSPFERD_CD_PARAM(tuple_seq)) \
  /* */

#define FLUSSPFERD_CLASS_DESCRIPTION_END() \
  }; \
  /* */

#endif
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dbmetadata.cxx,v $
 * $Revision: 1.10.22.1 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"

#include "connectivity/dbmetadata.hxx"
#include "connectivity/dbexception.hxx"
#include "connectivity/DriversConfig.hxx"
#include "resource/common_res.hrc"
#include "resource/sharedresources.hxx"

/** === begin UNO includes === **/
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
#include <com/sun/star/sdbc/XDriverAccess.hpp>
/** === end UNO includes === **/

#include <tools/diagnose_ex.h>
#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/componentcontext.hxx>
#include <comphelper/processfactory.hxx>

#include <boost/optional.hpp>

//........................................................................
namespace dbtools
{
//........................................................................

    /** === begin UNO using === **/
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::sdbc::XConnection;
    using ::com::sun::star::sdbc::XConnection;
    using ::com::sun::star::sdbc::XDatabaseMetaData;
    using ::com::sun::star::sdbc::XDatabaseMetaData2;
    using ::com::sun::star::lang::IllegalArgumentException;
    using ::com::sun::star::uno::Exception;
    using ::com::sun::star::uno::Any;
    using ::com::sun::star::container::XChild;
    using ::com::sun::star::uno::UNO_QUERY_THROW;
    using ::com::sun::star::beans::XPropertySet;
    using ::com::sun::star::uno::Sequence;
    using ::com::sun::star::beans::PropertyValue;
    using ::com::sun::star::beans::XPropertySetInfo;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::sdbcx::XUsersSupplier;
    using ::com::sun::star::sdbcx::XDataDefinitionSupplier;
    using ::com::sun::star::sdbc::XDriverAccess;
    using ::com::sun::star::uno::UNO_SET_THROW;
    /** === end UNO using === **/
    namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;

    //====================================================================
    //= DatabaseMetaData_Impl
    //====================================================================
    struct DatabaseMetaData_Impl
    {
        Reference< XConnection >        xConnection;
        Reference< XDatabaseMetaData >  xConnectionMetaData;
        ::connectivity::DriversConfig   aDriverConfig;

        ::boost::optional< ::rtl::OUString >    sCachedIdentifierQuoteString;
        ::boost::optional< ::rtl::OUString >    sCachedCatalogSeparator;

        DatabaseMetaData_Impl()
            :xConnection()
            ,xConnectionMetaData()
            ,aDriverConfig( ::comphelper::getProcessServiceFactory() )
            ,sCachedIdentifierQuoteString()
            ,sCachedCatalogSeparator()
        {
        }
    };

    //--------------------------------------------------------------------
    namespace
    {
        //................................................................
        static void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection )
        {
            _metaDataImpl.xConnection = _connection;
            if ( !_metaDataImpl.xConnection.is() )
                return;

            _metaDataImpl.xConnectionMetaData = _connection->getMetaData();
            if ( !_metaDataImpl.xConnectionMetaData.is() )
                throw IllegalArgumentException();
        }

        //................................................................
        static void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl )
        {
            if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() )
            {
                ::connectivity::SharedResources aResources;
                const ::rtl::OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN));
                throwSQLException( sError, SQL_CONNECTION_DOES_NOT_EXIST, NULL );
            }
        }

        //................................................................
        static bool lcl_getDriverSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
        {
            lcl_checkConnected( _metaData );
            const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() );
            if ( !rDriverMetaData.has( _asciiName ) )
                return false;
            _out_setting = rDriverMetaData.get( _asciiName );
            return true;
        }

        //................................................................
        static bool lcl_getConnectionSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
        {
            try
            {
                Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY );
                if ( xConnectionAsChild.is() )
                {
                    Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW );
                    Reference< XPropertySet > xDataSourceSettings(
                        xDataSource->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings" ) ) ),
                        UNO_QUERY_THROW );

                    _out_setting = xDataSourceSettings->getPropertyValue( ::rtl::OUString::createFromAscii( _asciiName ) );
                }
                else
                {
                    Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW );
                    ::comphelper::NamedValueCollection aSettings( xExtendedMetaData->getConnectionInfo() );
                    _out_setting = aSettings.get( _asciiName );
                    return _out_setting.hasValue();
                }
                return true;
            }
            catch( const Exception& )
            {
                DBG_UNHANDLED_EXCEPTION();
            }
            return false;
        }

        //................................................................
        static const ::rtl::OUString& lcl_getConnectionStringSetting(
            const DatabaseMetaData_Impl& _metaData, ::boost::optional< ::rtl::OUString >& _cachedSetting,
            ::rtl::OUString (SAL_CALL XDatabaseMetaData::*_getter)() )
        {
            if ( !_cachedSetting )
            {
                lcl_checkConnected( _metaData );
                try
                {
                    _cachedSetting.reset( (_metaData.xConnectionMetaData.get()->*_getter)() );
                }
                catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
            }
            return *_cachedSetting;
        }
    }

    //====================================================================
    //= DatabaseMetaData
    //====================================================================
    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData()
        :m_pImpl( new DatabaseMetaData_Impl )
    {
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection )
        :m_pImpl( new DatabaseMetaData_Impl )
    {
        lcl_construct( *m_pImpl, _connection );
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom )
        :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) )
    {
    }

    //--------------------------------------------------------------------
    DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom )
    {
        if ( this == &_copyFrom )
            return *this;

        m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) );
        return *this;
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::~DatabaseMetaData()
    {
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::isConnected() const
    {
        return m_pImpl->xConnection.is();
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsSubqueriesInFrom() const
    {
        lcl_checkConnected( *m_pImpl );

        bool supportsSubQueries = false;
        try
        {
            sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect();
            supportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 );
            // TODO: is there a better way to determine this? The above is not really true. More precise,
            // it's a *very* generous heuristics ...
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return supportsSubQueries;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsPrimaryKeys() const
    {
        lcl_checkConnected( *m_pImpl );

        bool supportsPrimaryKeys = false;
        try
        {
            Any setting;
            if  (   !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) )
                ||  !( setting >>= supportsPrimaryKeys )
                )
                supportsPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar();
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return supportsPrimaryKeys;
    }

    //--------------------------------------------------------------------
    const ::rtl::OUString&  DatabaseMetaData::getIdentifierQuoteString() const
    {
        return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString );
    }

    //--------------------------------------------------------------------
    const ::rtl::OUString&  DatabaseMetaData::getCatalogSeparator() const
    {
        return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator );
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::restrictIdentifiersToSQL92() const
    {
        lcl_checkConnected( *m_pImpl );

        bool restrict( false );
        Any setting;
        if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= restrict );
        return restrict;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::generateASBeforeCorrelationName() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::shouldEscapeDateTime() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::isAutoIncrementPrimaryKey() const
    {
        bool is( true );
        Any setting;
        if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= is );
        return is;
    }
    //--------------------------------------------------------------------
    sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const
    {
        sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER );
        Any setting;
        if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= mode );
        return mode;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsRelations() const
    {
        lcl_checkConnected( *m_pImpl );
        bool bSupport = false;
        try
        {
            bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility();
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        try
        {
            if ( !bSupport )
            {
                const ::rtl::OUString url = m_pImpl->xConnectionMetaData->getURL();
                char pMySQL[] = "sdbc:mysql";
                bSupport = url.matchAsciiL(pMySQL,(sizeof(pMySQL)/sizeof(pMySQL[0]))-1);
            }
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return bSupport;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsColumnAliasInOrderBy() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsUserAdministration( const ::comphelper::ComponentContext& _rContext ) const
    {
        lcl_checkConnected( *m_pImpl  );

        bool isSupported( false );
        try
        {
            // find the XUsersSupplier interface
            // - either directly at the connection
            Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY );
            if ( !xUsersSupp.is() )
            {
                // - or at the driver manager
                Reference< XDriverAccess > xDriverManager(
                    _rContext.createComponent( "com.sun.star.sdbc.DriverManager" ), UNO_QUERY_THROW );
                Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY );
                if ( xDriver.is() )
                    xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY );
            }

            isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return isSupported;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::displayEmptyTableFolders() const
    {
        bool doDisplay( true );
#ifdef IMPLEMENTED_LATER
        Any setting;
        if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doDisplay );
#else
        try
        {
            Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
            ::rtl::OUString sConnectionURL( xMeta->getURL() );
            doDisplay = sConnectionURL.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:mysqlc" ) ) == 0;
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
#endif
        return doDisplay;
    }

//........................................................................
} // namespace dbtools
//........................................................................

<commit_msg>#i10000#<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dbmetadata.cxx,v $
 * $Revision: 1.10.22.1 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_connectivity.hxx"

#include "connectivity/dbmetadata.hxx"
#include "connectivity/dbexception.hxx"
#include "connectivity/DriversConfig.hxx"
#include "resource/common_res.hrc"
#include "resource/sharedresources.hxx"

/** === begin UNO includes === **/
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
#include <com/sun/star/sdbc/XDatabaseMetaData2.hpp>
#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
#include <com/sun/star/sdbc/XDriverAccess.hpp>
/** === end UNO includes === **/

#include <tools/diagnose_ex.h>
#include <comphelper/namedvaluecollection.hxx>
#include <comphelper/componentcontext.hxx>
#include <comphelper/processfactory.hxx>

#include <boost/optional.hpp>

//........................................................................
namespace dbtools
{
//........................................................................

    /** === begin UNO using === **/
    using ::com::sun::star::uno::Reference;
    using ::com::sun::star::sdbc::XConnection;
    using ::com::sun::star::sdbc::XConnection;
    using ::com::sun::star::sdbc::XDatabaseMetaData;
    using ::com::sun::star::sdbc::XDatabaseMetaData2;
    using ::com::sun::star::lang::IllegalArgumentException;
    using ::com::sun::star::uno::Exception;
    using ::com::sun::star::uno::Any;
    using ::com::sun::star::container::XChild;
    using ::com::sun::star::uno::UNO_QUERY_THROW;
    using ::com::sun::star::beans::XPropertySet;
    using ::com::sun::star::uno::Sequence;
    using ::com::sun::star::beans::PropertyValue;
    using ::com::sun::star::beans::XPropertySetInfo;
    using ::com::sun::star::uno::UNO_QUERY;
    using ::com::sun::star::sdbcx::XUsersSupplier;
    using ::com::sun::star::sdbcx::XDataDefinitionSupplier;
    using ::com::sun::star::sdbc::XDriverAccess;
    using ::com::sun::star::uno::UNO_SET_THROW;
    /** === end UNO using === **/
    namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;

    //====================================================================
    //= DatabaseMetaData_Impl
    //====================================================================
    struct DatabaseMetaData_Impl
    {
        Reference< XConnection >        xConnection;
        Reference< XDatabaseMetaData >  xConnectionMetaData;
        ::connectivity::DriversConfig   aDriverConfig;

        ::boost::optional< ::rtl::OUString >    sCachedIdentifierQuoteString;
        ::boost::optional< ::rtl::OUString >    sCachedCatalogSeparator;

        DatabaseMetaData_Impl()
            :xConnection()
            ,xConnectionMetaData()
            ,aDriverConfig( ::comphelper::getProcessServiceFactory() )
            ,sCachedIdentifierQuoteString()
            ,sCachedCatalogSeparator()
        {
        }
    };

    //--------------------------------------------------------------------
    namespace
    {
        //................................................................
        static void lcl_construct( DatabaseMetaData_Impl& _metaDataImpl, const Reference< XConnection >& _connection )
        {
            _metaDataImpl.xConnection = _connection;
            if ( !_metaDataImpl.xConnection.is() )
                return;

            _metaDataImpl.xConnectionMetaData = _connection->getMetaData();
            if ( !_metaDataImpl.xConnectionMetaData.is() )
                throw IllegalArgumentException();
        }

        //................................................................
        static void lcl_checkConnected( const DatabaseMetaData_Impl& _metaDataImpl )
        {
            if ( !_metaDataImpl.xConnection.is() || !_metaDataImpl.xConnectionMetaData.is() )
            {
                ::connectivity::SharedResources aResources;
                const ::rtl::OUString sError( aResources.getResourceString(STR_NO_CONNECTION_GIVEN));
                throwSQLException( sError, SQL_CONNECTION_DOES_NOT_EXIST, NULL );
            }
        }

        //................................................................
        static bool lcl_getDriverSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
        {
            lcl_checkConnected( _metaData );
            const ::comphelper::NamedValueCollection& rDriverMetaData = _metaData.aDriverConfig.getMetaData( _metaData.xConnectionMetaData->getURL() );
            if ( !rDriverMetaData.has( _asciiName ) )
                return false;
            _out_setting = rDriverMetaData.get( _asciiName );
            return true;
        }

        //................................................................
        static bool lcl_getConnectionSetting( const sal_Char* _asciiName, const DatabaseMetaData_Impl& _metaData, Any& _out_setting )
        {
            try
            {
                Reference< XChild > xConnectionAsChild( _metaData.xConnection, UNO_QUERY );
                if ( xConnectionAsChild.is() )
                {
                    Reference< XPropertySet > xDataSource( xConnectionAsChild->getParent(), UNO_QUERY_THROW );
                    Reference< XPropertySet > xDataSourceSettings(
                        xDataSource->getPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Settings" ) ) ),
                        UNO_QUERY_THROW );

                    _out_setting = xDataSourceSettings->getPropertyValue( ::rtl::OUString::createFromAscii( _asciiName ) );
                }
                else
                {
                    Reference< XDatabaseMetaData2 > xExtendedMetaData( _metaData.xConnectionMetaData, UNO_QUERY_THROW );
                    ::comphelper::NamedValueCollection aSettings( xExtendedMetaData->getConnectionInfo() );
                    _out_setting = aSettings.get( _asciiName );
                    return _out_setting.hasValue();
                }
                return true;
            }
            catch( const Exception& )
            {
                DBG_UNHANDLED_EXCEPTION();
            }
            return false;
        }

        //................................................................
        static const ::rtl::OUString& lcl_getConnectionStringSetting(
            const DatabaseMetaData_Impl& _metaData, ::boost::optional< ::rtl::OUString >& _cachedSetting,
            ::rtl::OUString (SAL_CALL XDatabaseMetaData::*_getter)() )
        {
            if ( !_cachedSetting )
            {
                lcl_checkConnected( _metaData );
                try
                {
                    _cachedSetting.reset( (_metaData.xConnectionMetaData.get()->*_getter)() );
                }
                catch( const Exception& ) { DBG_UNHANDLED_EXCEPTION(); }
            }
            return *_cachedSetting;
        }
    }

    //====================================================================
    //= DatabaseMetaData
    //====================================================================
    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData()
        :m_pImpl( new DatabaseMetaData_Impl )
    {
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData( const Reference< XConnection >& _connection )
        :m_pImpl( new DatabaseMetaData_Impl )
    {
        lcl_construct( *m_pImpl, _connection );
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::DatabaseMetaData( const DatabaseMetaData& _copyFrom )
        :m_pImpl( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) )
    {
    }

    //--------------------------------------------------------------------
    DatabaseMetaData& DatabaseMetaData::operator=( const DatabaseMetaData& _copyFrom )
    {
        if ( this == &_copyFrom )
            return *this;

        m_pImpl.reset( new DatabaseMetaData_Impl( *_copyFrom.m_pImpl ) );
        return *this;
    }

    //--------------------------------------------------------------------
    DatabaseMetaData::~DatabaseMetaData()
    {
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::isConnected() const
    {
        return m_pImpl->xConnection.is();
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsSubqueriesInFrom() const
    {
        lcl_checkConnected( *m_pImpl );

        bool supportsSubQueries = false;
        try
        {
            sal_Int32 maxTablesInselect = m_pImpl->xConnectionMetaData->getMaxTablesInSelect();
            supportsSubQueries = ( maxTablesInselect > 1 ) || ( maxTablesInselect == 0 );
            // TODO: is there a better way to determine this? The above is not really true. More precise,
            // it's a *very* generous heuristics ...
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return supportsSubQueries;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsPrimaryKeys() const
    {
        lcl_checkConnected( *m_pImpl );

        bool doesSupportPrimaryKeys = false;
        try
        {
            Any setting;
            if  (   !( lcl_getConnectionSetting( "PrimaryKeySupport", *m_pImpl, setting ) )
                ||  !( setting >>= doesSupportPrimaryKeys )
                )
                doesSupportPrimaryKeys = m_pImpl->xConnectionMetaData->supportsCoreSQLGrammar();
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return doesSupportPrimaryKeys;
    }

    //--------------------------------------------------------------------
    const ::rtl::OUString&  DatabaseMetaData::getIdentifierQuoteString() const
    {
        return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedIdentifierQuoteString, &XDatabaseMetaData::getIdentifierQuoteString );
    }

    //--------------------------------------------------------------------
    const ::rtl::OUString&  DatabaseMetaData::getCatalogSeparator() const
    {
        return lcl_getConnectionStringSetting( *m_pImpl, m_pImpl->sCachedCatalogSeparator, &XDatabaseMetaData::getCatalogSeparator );
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::restrictIdentifiersToSQL92() const
    {
        lcl_checkConnected( *m_pImpl );

        bool restrict( false );
        Any setting;
        if ( lcl_getConnectionSetting( "EnableSQL92Check", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= restrict );
        return restrict;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::generateASBeforeCorrelationName() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "GenerateASBeforeCorrelationName", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::shouldEscapeDateTime() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "EscapeDateTime", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::isAutoIncrementPrimaryKey() const
    {
        bool is( true );
        Any setting;
        if ( lcl_getDriverSetting( "AutoIncrementIsPrimaryKey", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= is );
        return is;
    }
    //--------------------------------------------------------------------
    sal_Int32 DatabaseMetaData::getBooleanComparisonMode() const
    {
        sal_Int32 mode( BooleanComparisonMode::EQUAL_INTEGER );
        Any setting;
        if ( lcl_getConnectionSetting( "BooleanComparisonMode", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= mode );
        return mode;
    }
    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsRelations() const
    {
        lcl_checkConnected( *m_pImpl );
        bool bSupport = false;
        try
        {
            bSupport = m_pImpl->xConnectionMetaData->supportsIntegrityEnhancementFacility();
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        try
        {
            if ( !bSupport )
            {
                const ::rtl::OUString url = m_pImpl->xConnectionMetaData->getURL();
                char pMySQL[] = "sdbc:mysql";
                bSupport = url.matchAsciiL(pMySQL,(sizeof(pMySQL)/sizeof(pMySQL[0]))-1);
            }
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return bSupport;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsColumnAliasInOrderBy() const
    {
        bool doGenerate( true );
        Any setting;
        if ( lcl_getConnectionSetting( "ColumnAliasInOrderBy", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doGenerate );
        return doGenerate;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::supportsUserAdministration( const ::comphelper::ComponentContext& _rContext ) const
    {
        lcl_checkConnected( *m_pImpl  );

        bool isSupported( false );
        try
        {
            // find the XUsersSupplier interface
            // - either directly at the connection
            Reference< XUsersSupplier > xUsersSupp( m_pImpl->xConnection, UNO_QUERY );
            if ( !xUsersSupp.is() )
            {
                // - or at the driver manager
                Reference< XDriverAccess > xDriverManager(
                    _rContext.createComponent( "com.sun.star.sdbc.DriverManager" ), UNO_QUERY_THROW );
                Reference< XDataDefinitionSupplier > xDriver( xDriverManager->getDriverByURL( m_pImpl->xConnectionMetaData->getURL() ), UNO_QUERY );
                if ( xDriver.is() )
                    xUsersSupp.set( xDriver->getDataDefinitionByConnection( m_pImpl->xConnection ), UNO_QUERY );
            }

            isSupported = ( xUsersSupp.is() && xUsersSupp->getUsers().is() );
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
        return isSupported;
    }

    //--------------------------------------------------------------------
    bool DatabaseMetaData::displayEmptyTableFolders() const
    {
        bool doDisplay( true );
#ifdef IMPLEMENTED_LATER
        Any setting;
        if ( lcl_getConnectionSetting( "DisplayEmptyTableFolders", *m_pImpl, setting ) )
            OSL_VERIFY( setting >>= doDisplay );
#else
        try
        {
            Reference< XDatabaseMetaData > xMeta( m_pImpl->xConnectionMetaData, UNO_SET_THROW );
            ::rtl::OUString sConnectionURL( xMeta->getURL() );
            doDisplay = sConnectionURL.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "sdbc:mysql:mysqlc" ) ) == 0;
        }
        catch( const Exception& )
        {
            DBG_UNHANDLED_EXCEPTION();
        }
#endif
        return doDisplay;
    }

//........................................................................
} // namespace dbtools
//........................................................................

<|endoftext|>


<commit_before>
#include "common_headers.h"

#include "parser/token.h"
#include "parser/token_stream.h"
#include "bootstrapping.h"
#include "branch.h"
#include "builtin_functions.h"
#include "errors.h"
#include "function.h"
#include "operations.h"
#include "structs.h"
#include "subroutine.h"
#include "term.h"
#include "type.h"

Branch* KERNEL = NULL;
Term* BUILTIN_INT_TYPE = NULL;
Term* BUILTIN_FLOAT_TYPE = NULL;
Term* BUILTIN_BOOL_TYPE = NULL;
Term* BUILTIN_STRING_TYPE = NULL;
Term* BUILTIN_TYPE_TYPE = NULL;
Term* BUILTIN_FUNCTION_TYPE = NULL;
Term* BUILTIN_CODEUNIT_TYPE = NULL;
Term* BUILTIN_SUBROUTINE_TYPE = NULL;
Term* BUILTIN_STRUCT_DEFINITION_TYPE = NULL;
Term* BUILTIN_BRANCH_TYPE = NULL;
Term* BUILTIN_ANY_TYPE = NULL;
Term* BUILTIN_VOID_TYPE = NULL;
Term* BUILTIN_REFERENCE_TYPE = NULL;
Term* BUILTIN_LIST_TYPE = NULL;

void empty_execute_function(Term*) { }
void empty_alloc_function(Term*) { }

void const_generator(Term* caller)
{
    Function *output = as_function(caller);
    Type* type = as_type(caller->inputs[0]);
    output->name = "const-" + type->name;
    output->outputType = caller->inputs[0];
    output->execute = empty_execute_function;
}

Term* get_global(string name)
{
    if (KERNEL->containsName(name))
        return KERNEL->getNamed(name);

    throw errors::KeyError(name);
}

void bootstrap_kernel()
{
    KERNEL = new Branch();

    // Create const-generator function
    Term* constGenerator = new Term();
    Function_alloc(constGenerator);
    Function_setName(constGenerator, "const-generator");
    Function_setPureFunction(constGenerator, true);
    Function_setExecute(constGenerator, const_generator);
    KERNEL->bindName(constGenerator, "const-generator");

    // Create const-Type function
    Term* constTypeFunc = new Term();
    constTypeFunc->function = constGenerator;
    Function_alloc(constTypeFunc);
    Function_setName(constTypeFunc, "const-Type");
    Function_setPureFunction(constTypeFunc, true);

    // Create Type type
    Term* typeType = new Term;
    BUILTIN_TYPE_TYPE = typeType;
    typeType->function = constTypeFunc;
    typeType->type = typeType;
    Type_alloc(typeType);
    as_type(typeType)->name = "Type";
    as_type(typeType)->alloc = Type_alloc;
    KERNEL->bindName(typeType, "Type");

    // Implant the Type type
    set_input(constTypeFunc, 0, typeType);
    Function_setInputType(constGenerator, 0, typeType);
    Function_setOutputType(constTypeFunc, typeType);

    // Create const-Function function
    Term* constFuncFunc = new Term;
    constFuncFunc->function = constGenerator;
    Function_alloc(constFuncFunc);
    Function_setName        (constFuncFunc, "const-Function");
    Function_setPureFunction(constFuncFunc, true);
    KERNEL->bindName(constFuncFunc, "const-Function");

    // Implant const-Function
    constGenerator->function = constFuncFunc;

    // Create Function type
    Term* functionType = new Term;
    BUILTIN_FUNCTION_TYPE = functionType;
    functionType->function = constTypeFunc;
    functionType->type = typeType;
    Type_alloc(functionType);
    as_type(functionType)->name = "Function";
    as_type(functionType)->alloc = Function_alloc;
    KERNEL->bindName(functionType, "Function");

    // Implant Function type
    set_input(constGenerator, 0, typeType);
    set_input(constFuncFunc, 0, functionType);
    constGenerator->type = functionType;
    constFuncFunc->type = functionType;
    constTypeFunc->type = functionType;
    Function_setOutputType(constGenerator, functionType);
    Function_setOutputType(constFuncFunc, functionType);

    // Don't let these terms get updated
    constGenerator->needsUpdate = false;
    constFuncFunc->needsUpdate = false;
    constTypeFunc->needsUpdate = false;
    functionType->needsUpdate = false;
    typeType->needsUpdate = false;
}

void int_alloc(Term* caller)
{
    caller->value = new int;
}
void int_copy(Term* source, Term* dest)
{
    as_int(dest) = as_int(source);
}

void float_alloc(Term* caller)
{
    caller->value = new float;
}
void float_copy(Term* source, Term* dest)
{
    as_float(dest) = as_float(source);
}

void string_alloc(Term* caller)
{
    caller->value = new string;
}

void bool_alloc(Term* caller)
{
    caller->value = new bool;
}

void int_tostring(Term* caller)
{
    std::stringstream strm;
    strm << as_int(caller->inputs[0]);
    as_string(caller) = strm.str();
}
void float_tostring(Term* caller)
{
    std::stringstream strm;
    strm << as_float(caller->inputs[0]);
    as_string(caller) = strm.str();
}
void string_tostring(Term* caller)
{
    as_string(caller) = as_string(caller->inputs[0]);
}

void bool_tostring(Term* caller)
{
    if (as_bool(caller))
        as_string(caller) = "true";
    else
        as_string(caller) = "false";
}

void create_builtin_types()
{
    BUILTIN_STRING_TYPE = quick_create_type(KERNEL, "string", string_alloc, string_tostring);
    BUILTIN_INT_TYPE = quick_create_type(KERNEL, "int",
            int_alloc, int_tostring, int_copy);
    BUILTIN_FLOAT_TYPE = quick_create_type(KERNEL, "float",
            float_alloc, float_tostring, float_copy);
    BUILTIN_BOOL_TYPE = quick_create_type(KERNEL, "bool", bool_alloc, bool_tostring);
    BUILTIN_ANY_TYPE = quick_create_type(KERNEL, "any", empty_alloc_function, NULL);
    BUILTIN_VOID_TYPE = quick_create_type(KERNEL, "void", empty_alloc_function, NULL);
    BUILTIN_REFERENCE_TYPE = quick_create_type(KERNEL, "Reference", empty_alloc_function, NULL);
}

void initialize()
{
    try {
        bootstrap_kernel();
        create_builtin_types();

        // Do initialize_term first
        initialize_term(KERNEL);

        initialize_branch(KERNEL);
        initialize_builtin_functions(KERNEL);
        initialize_structs(KERNEL);
        initialize_subroutine(KERNEL);

    } catch (errors::CircaError& e)
    {
        std::cout << "An error occured while initializing." << std::endl;
        std::cout << e.message() << std::endl;
        exit(1);
    }
}
<commit_msg>Added string_copy<commit_after>
#include "common_headers.h"

#include "parser/token.h"
#include "parser/token_stream.h"
#include "bootstrapping.h"
#include "branch.h"
#include "builtin_functions.h"
#include "errors.h"
#include "function.h"
#include "operations.h"
#include "structs.h"
#include "subroutine.h"
#include "term.h"
#include "type.h"

Branch* KERNEL = NULL;
Term* BUILTIN_INT_TYPE = NULL;
Term* BUILTIN_FLOAT_TYPE = NULL;
Term* BUILTIN_BOOL_TYPE = NULL;
Term* BUILTIN_STRING_TYPE = NULL;
Term* BUILTIN_TYPE_TYPE = NULL;
Term* BUILTIN_FUNCTION_TYPE = NULL;
Term* BUILTIN_CODEUNIT_TYPE = NULL;
Term* BUILTIN_SUBROUTINE_TYPE = NULL;
Term* BUILTIN_STRUCT_DEFINITION_TYPE = NULL;
Term* BUILTIN_BRANCH_TYPE = NULL;
Term* BUILTIN_ANY_TYPE = NULL;
Term* BUILTIN_VOID_TYPE = NULL;
Term* BUILTIN_REFERENCE_TYPE = NULL;
Term* BUILTIN_LIST_TYPE = NULL;

void empty_execute_function(Term*) { }
void empty_alloc_function(Term*) { }

void const_generator(Term* caller)
{
    Function *output = as_function(caller);
    Type* type = as_type(caller->inputs[0]);
    output->name = "const-" + type->name;
    output->outputType = caller->inputs[0];
    output->execute = empty_execute_function;
}

Term* get_global(string name)
{
    if (KERNEL->containsName(name))
        return KERNEL->getNamed(name);

    throw errors::KeyError(name);
}

void bootstrap_kernel()
{
    KERNEL = new Branch();

    // Create const-generator function
    Term* constGenerator = new Term();
    Function_alloc(constGenerator);
    Function_setName(constGenerator, "const-generator");
    Function_setPureFunction(constGenerator, true);
    Function_setExecute(constGenerator, const_generator);
    KERNEL->bindName(constGenerator, "const-generator");

    // Create const-Type function
    Term* constTypeFunc = new Term();
    constTypeFunc->function = constGenerator;
    Function_alloc(constTypeFunc);
    Function_setName(constTypeFunc, "const-Type");
    Function_setPureFunction(constTypeFunc, true);

    // Create Type type
    Term* typeType = new Term;
    BUILTIN_TYPE_TYPE = typeType;
    typeType->function = constTypeFunc;
    typeType->type = typeType;
    Type_alloc(typeType);
    as_type(typeType)->name = "Type";
    as_type(typeType)->alloc = Type_alloc;
    KERNEL->bindName(typeType, "Type");

    // Implant the Type type
    set_input(constTypeFunc, 0, typeType);
    Function_setInputType(constGenerator, 0, typeType);
    Function_setOutputType(constTypeFunc, typeType);

    // Create const-Function function
    Term* constFuncFunc = new Term;
    constFuncFunc->function = constGenerator;
    Function_alloc(constFuncFunc);
    Function_setName        (constFuncFunc, "const-Function");
    Function_setPureFunction(constFuncFunc, true);
    KERNEL->bindName(constFuncFunc, "const-Function");

    // Implant const-Function
    constGenerator->function = constFuncFunc;

    // Create Function type
    Term* functionType = new Term;
    BUILTIN_FUNCTION_TYPE = functionType;
    functionType->function = constTypeFunc;
    functionType->type = typeType;
    Type_alloc(functionType);
    as_type(functionType)->name = "Function";
    as_type(functionType)->alloc = Function_alloc;
    KERNEL->bindName(functionType, "Function");

    // Implant Function type
    set_input(constGenerator, 0, typeType);
    set_input(constFuncFunc, 0, functionType);
    constGenerator->type = functionType;
    constFuncFunc->type = functionType;
    constTypeFunc->type = functionType;
    Function_setOutputType(constGenerator, functionType);
    Function_setOutputType(constFuncFunc, functionType);

    // Don't let these terms get updated
    constGenerator->needsUpdate = false;
    constFuncFunc->needsUpdate = false;
    constTypeFunc->needsUpdate = false;
    functionType->needsUpdate = false;
    typeType->needsUpdate = false;
}

void int_alloc(Term* caller)
{
    caller->value = new int;
}
void int_copy(Term* source, Term* dest)
{
    as_int(dest) = as_int(source);
}

void float_alloc(Term* caller)
{
    caller->value = new float;
}
void float_copy(Term* source, Term* dest)
{
    as_float(dest) = as_float(source);
}

void string_alloc(Term* caller)
{
    caller->value = new string;
}

void bool_alloc(Term* caller)
{
    caller->value = new bool;
}

void int_tostring(Term* caller)
{
    std::stringstream strm;
    strm << as_int(caller->inputs[0]);
    as_string(caller) = strm.str();
}
void float_tostring(Term* caller)
{
    std::stringstream strm;
    strm << as_float(caller->inputs[0]);
    as_string(caller) = strm.str();
}
void string_tostring(Term* caller)
{
    as_string(caller) = as_string(caller->inputs[0]);
}
void string_copy(Term* source, Term* dest)
{
    as_string(dest) = as_string(source);
}

void bool_tostring(Term* caller)
{
    if (as_bool(caller))
        as_string(caller) = "true";
    else
        as_string(caller) = "false";
}

void create_builtin_types()
{
    BUILTIN_STRING_TYPE = quick_create_type(KERNEL, "string",
            string_alloc, string_tostring, string_copy);
    BUILTIN_INT_TYPE = quick_create_type(KERNEL, "int",
            int_alloc, int_tostring, int_copy);
    BUILTIN_FLOAT_TYPE = quick_create_type(KERNEL, "float",
            float_alloc, float_tostring, float_copy);
    BUILTIN_BOOL_TYPE = quick_create_type(KERNEL, "bool", bool_alloc, bool_tostring);
    BUILTIN_ANY_TYPE = quick_create_type(KERNEL, "any", empty_alloc_function, NULL);
    BUILTIN_VOID_TYPE = quick_create_type(KERNEL, "void", empty_alloc_function, NULL);
    BUILTIN_REFERENCE_TYPE = quick_create_type(KERNEL, "Reference", empty_alloc_function, NULL);
}

void initialize()
{
    try {
        bootstrap_kernel();
        create_builtin_types();

        // Do initialize_term first
        initialize_term(KERNEL);

        initialize_branch(KERNEL);
        initialize_builtin_functions(KERNEL);
        initialize_structs(KERNEL);
        initialize_subroutine(KERNEL);

    } catch (errors::CircaError& e)
    {
        std::cout << "An error occured while initializing." << std::endl;
        std::cout << e.message() << std::endl;
        exit(1);
    }
}
<|endoftext|>