<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2010 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    context.cpp
  \author  Tom Fogal
           SCI Institute
           University of Utah
  \brief   Establishes an OpenGL context.
*/
#include "StdTuvokDefines.h"
#ifdef DETECTED_OS_WINDOWS
# include <GL/wgl.h>
# include <windows.h>
#else
# include <GL/glx.h>
# include <X11/Xlib.h>
#endif
#include "Controller/Controller.h"

#include "context.h"

TvkContext::~TvkContext() { }

#ifndef DETECTED_OS_WINDOWS
struct xinfo {
  Display *display;
  XVisualInfo *visual;
  Window win;
  GLXContext ctx;
  Colormap cmap;
};

class TvkGLXContext: public TvkContext {
  public:
    TvkGLXContext(uint32_t w, uint32_t h, uint8_t color_bits,
                  uint8_t depth_bits, uint8_t stencil_bits,
                  bool double_buffer);
    virtual ~TvkGLXContext();

    bool isValid() const;
    bool makeCurrent();
    bool swapBuffers();

  private:
    struct xinfo xi;
};
#endif

class TvkWGLContext: public TvkContext {
  public:
    TvkWGLContext(uint32_t w, uint32_t h, uint8_t color_bits,
                  uint8_t depth_bits, uint8_t stencil_bits,
                  bool double_buffer);
    virtual ~TvkWGLContext() {}

    bool isValid() const;
    bool makeCurrent();
    bool swapBuffers();

  private:
#ifdef DETECTED_OS_WINDOWS
    HDC deviceContext;
    HGLRC renderingContext;
    HWND window;
#endif
};

TvkContext* TvkContext::Create(uint32_t width, uint32_t height,
                               uint8_t color_bits, uint8_t depth_bits,
                               uint8_t stencil_bits, bool double_buffer)
{
#ifdef DETECTED_OS_WINDOWS
  return new TvkWGLContext(width, height, color_bits, depth_bits, stencil_bits,
                           double_buffer);
#else
  return new TvkGLXContext(width, height, color_bits, depth_bits, stencil_bits,
                           double_buffer);
#endif
}

#ifndef DETECTED_OS_WINDOWS
static struct xinfo x_connect(uint32_t, uint32_t, bool);
static XVisualInfo* find_visual(Display*, bool);
static void glx_init(Display*, XVisualInfo*, GLXContext&);

TvkGLXContext::TvkGLXContext(uint32_t w, uint32_t h, uint8_t,
                             uint8_t, uint8_t,
                             bool double_buffer)
{
  // if you *really* require a specific value... just hack this class
  // to your liking.  You probably want to add those parameters to x_connect
  // and use them there.
  WARNING("Ignoring color, depth, stencil bits.  For many applications, it "
          "is better to let the GLX library choose the \"best\" visual.");
  this->xi = x_connect(w, h, double_buffer);
  glx_init(xi.display, xi.visual, xi.ctx);
  this->makeCurrent();
  MESSAGE("Current context: %p", glXGetCurrentContext());
}

TvkGLXContext::~TvkGLXContext()
{
  glXDestroyContext(xi.display, xi.ctx);
  XDestroyWindow(xi.display, xi.win);
  XFree(xi.visual);
  XCloseDisplay(xi.display);
}

bool TvkGLXContext::isValid() const
{
  return this->xi.display != NULL && this->xi.ctx != NULL;
}

bool TvkGLXContext::makeCurrent()
{
  if(glXMakeCurrent(this->xi.display, this->xi.win, this->xi.ctx) != True) {
    T_ERROR("Could not make context current!");
    return false;
  }
  return true;
}

bool TvkGLXContext::swapBuffers()
{
  glXSwapBuffers(this->xi.display, this->xi.win);
  // SwapBuffers generates an X error if it fails.
  return true;
}

static struct xinfo
x_connect(uint32_t width, uint32_t height, bool dbl_buffer)
{
  struct xinfo rv;

  rv.display = XOpenDisplay(NULL);
  if(rv.display == NULL) {
    T_ERROR("Could not connect to display: '%s'!", XDisplayName(NULL));
    throw NoAvailableContext();
  }
  XSynchronize(rv.display, True);

  rv.visual = find_visual(rv.display, dbl_buffer);

  Window parent = RootWindow(rv.display, rv.visual->screen);

  XSetWindowAttributes xw_attr;
  xw_attr.override_redirect = False;
  xw_attr.background_pixel = 0;
  xw_attr.colormap = XCreateColormap(rv.display, parent, rv.visual->visual,
                                     AllocNone);
  xw_attr.event_mask = StructureNotifyMask | ExposureMask;

  rv.win = XCreateWindow(rv.display, parent, 0,0, width,height, 0,
                         rv.visual->depth,
                         InputOutput, rv.visual->visual,
                         CWBackPixel | CWBorderPixel | CWColormap |
                         CWOverrideRedirect | CWEventMask,
                         &xw_attr);
  XStoreName(rv.display, rv.win, "Tuvok testing");
  XSync(rv.display, False);

  return rv;
}

static void
glx_init(Display *disp, XVisualInfo *visual, GLXContext& ctx)
{
  if(!glXQueryExtension(disp, NULL, NULL)) {
    T_ERROR("Display does not support glX.");
    return;
  }

  ctx = glXCreateContext(disp, visual, 0, GL_TRUE);
  if(!ctx) {
    T_ERROR("glX Context creation failed.");
  }
}

static XVisualInfo *
find_visual(Display *d, bool double_buffered)
{
    XVisualInfo *ret_v;
    // GLX_USE_GL is basically a no-op, so this provides a convenient
    // way of specifying double buffering or not.
    int att_buf = double_buffered ? GLX_DOUBLEBUFFER : GLX_USE_GL;
    int attr[] = {
      GLX_RGBA,
      att_buf,
      GLX_RED_SIZE,         5,
      GLX_GREEN_SIZE,       6,
      GLX_BLUE_SIZE,        5,
      GLX_ALPHA_SIZE,       8,
      GLX_DEPTH_SIZE,       8,
      GLX_ACCUM_RED_SIZE,   0,
      GLX_ACCUM_GREEN_SIZE, 0,
      GLX_ACCUM_BLUE_SIZE,  0,
      None
    };

    ret_v = glXChooseVisual(d, DefaultScreen(d), attr);
    MESSAGE("ChooseVisual got us %p", (const void*)ret_v);
    return ret_v;
}
#endif

#ifdef DETECTED_OS_WINDOWS

static void outputLastError() {
  DWORD lastError = GetLastError();
  LPVOID msgBuffer;
  FormatMessageW(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    lastError,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR)&msgBuffer,
    0, NULL
  );
  T_ERROR("Win32 error: %s", std::string((LPSTR)msgBuffer));
  LocalFree(msgBuffer);
}

TvkWGLContext::TvkWGLContext(uint32_t w, uint32_t h, uint8_t color_bits,
                             uint8_t depth_bits, uint8_t stencil_bits,
                             bool double_buffer) :
  deviceContext(NULL),
  renderingContext(NULL),
  window(NULL)
{
  if(w == 0 || h == 0 ||
     !(color_bits==8 || color_bits==16 || color_bits==24 || color_bits==32) ||
     !(depth_bits==8 || depth_bits==16 || depth_bits==24 || depth_bits==32 ||
       depth_bits==0) ||
     !(stencil_bits == 0 || stencil_bits == 8)) {
    T_ERROR("Invalid parameters passed to constructor.");
    throw NoAvailableContext();
  }

  window = CreateWindowExW(WS_EX_TOOLWINDOW, L"Static", L"GLContextWindow",
                WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ,
                0, 0, width, height, 0, 0, GetModuleHandle(NULL), 0);
  if (!window)
  {
    outputLastError();
    return;
  }
  ShowWindow(window, SW_HIDE);

  deviceContext = GetDC(window);
  if(!deviceContext) {
    // GetDC doesn't SetLastError, but this still works anyway...
    outputLastError();
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  PIXELFORMATDESCRIPTOR pfd;
  pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA;
  if (useDoubleBuffer) pfd.dwFlags |= PFD_DOUBLEBUFFER;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = colorBits;
  pfd.cRedBits = 0;
  pfd.cRedShift = 0;
  pfd.cGreenBits = 0;
  pfd.cGreenShift = 0;
  pfd.cBlueBits = 0;
  pfd.cBlueShift = 0;
  pfd.cAlphaBits = 0;
  pfd.cAlphaShift = 0;
  pfd.cAccumBits = 0;
  pfd.cAccumRedBits = 0;
  pfd.cAccumGreenBits = 0;
  pfd.cAccumBlueBits = 0;
  pfd.cAccumAlphaBits = 0;
  pfd.cDepthBits = depthBits;
  pfd.cStencilBits = stencilBits;
  pfd.cAuxBuffers = 0;
  pfd.iLayerType = PFD_MAIN_PLANE;
  pfd.bReserved = 0;
  pfd.dwLayerMask = 0;
  pfd.dwVisibleMask = 0;
  pfd.dwDamageMask = 0;

  int pixelFormat = ChoosePixelFormat(deviceContext, &pfd);

  if (!pixelFormat)
  {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  PIXELFORMATDESCRIPTOR pfdResult;
  DescribePixelFormat(deviceContext, pixelFormat,
                      sizeof(PIXELFORMATDESCRIPTOR), &pfdResult);

  if (!(pfdResult.dwFlags & PFD_SUPPORT_OPENGL))
  {
    T_ERROR("No OpenGL support.");
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  if (useDoubleBuffer && !(pfdResult.dwFlags & PFD_DOUBLEBUFFER)) {
    WARNING("No double buffer support!");
  }

  std::ostringstream ss;
  if (pfdResult.cColorBits != colorBits) {
    ss << "Color bits requested: " << colorBits << ", actual color bits: "
       << pfdResult.cColorBits << "\n";
  }
  if (pfdResult.cDepthBits != depthBits) {
    ss << "Depth bits requested " << depthBits << ", actual depth bits: "
       << pfdResult.cDepthBits << "\n";
  }
  if (pfdResult.cStencilBits != stencilBits) {
    ss << "Stencil bits requested " << stencilBits << ", actual stencil bits:"
       << pfdResult.cStencilBits << "\n";
  }
  MESSAGE("%s", ss.str().c_str());

  if (!SetPixelFormat(deviceContext, pixelFormat, &pfd)) {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  renderingContext = wglCreateContext(deviceContext);

  if (!renderingContext) {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }
}

TvkWGLContext::~TvkWGLContext()
{
  wglDeleteContext(renderingContext);
  ReleaseDC(window, deviceContext);
  DestroyWindow(window);
}

bool TvkWGLContext::isValid() const
{
  // Object would not be created otherwise (throw in constructor)
  return true;
}

bool TvkWGLContext::makeCurrent()
{
  if(!wglMakeCurrent(deviceContext, renderingContext)) {
    outputLastError();
    return false;
  }
  return true;
}

bool TvkWGLContext::swapBuffers()
{
  if(!isValid()) { return false; }

  if(!wglSwapBuffers(deviceContext, WGL_SWAP_MAIN_PLANE)) {
    outputLastError();
    return false;
  }
  return true;
}
#endif
<commit_msg>Use GLEW instead of GL headers.<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2010 Scientific Computing and Imaging Institute,
   University of Utah.

   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.
*/

/**
  \file    context.cpp
  \author  Tom Fogal
           SCI Institute
           University of Utah
  \brief   Establishes an OpenGL context.
*/
#include "StdTuvokDefines.h"
#ifdef DETECTED_OS_WINDOWS
# include <GL/wglew.h>
# include <windows.h>
#else
# include <GL/glxew.h>
#endif
#include "Controller/Controller.h"

#include "context.h"

TvkContext::~TvkContext() { }

#ifndef DETECTED_OS_WINDOWS
struct xinfo {
  Display *display;
  XVisualInfo *visual;
  Window win;
  GLXContext ctx;
  Colormap cmap;
};

class TvkGLXContext: public TvkContext {
  public:
    TvkGLXContext(uint32_t w, uint32_t h, uint8_t color_bits,
                  uint8_t depth_bits, uint8_t stencil_bits,
                  bool double_buffer);
    virtual ~TvkGLXContext();

    bool isValid() const;
    bool makeCurrent();
    bool swapBuffers();

  private:
    struct xinfo xi;
};
#endif

class TvkWGLContext: public TvkContext {
  public:
    TvkWGLContext(uint32_t w, uint32_t h, uint8_t color_bits,
                  uint8_t depth_bits, uint8_t stencil_bits,
                  bool double_buffer);
    virtual ~TvkWGLContext() {}

    bool isValid() const;
    bool makeCurrent();
    bool swapBuffers();

  private:
#ifdef DETECTED_OS_WINDOWS
    HDC deviceContext;
    HGLRC renderingContext;
    HWND window;
#endif
};

TvkContext* TvkContext::Create(uint32_t width, uint32_t height,
                               uint8_t color_bits, uint8_t depth_bits,
                               uint8_t stencil_bits, bool double_buffer)
{
#ifdef DETECTED_OS_WINDOWS
  return new TvkWGLContext(width, height, color_bits, depth_bits, stencil_bits,
                           double_buffer);
#else
  return new TvkGLXContext(width, height, color_bits, depth_bits, stencil_bits,
                           double_buffer);
#endif
}

#ifndef DETECTED_OS_WINDOWS
static struct xinfo x_connect(uint32_t, uint32_t, bool);
static XVisualInfo* find_visual(Display*, bool);
static void glx_init(Display*, XVisualInfo*, GLXContext&);

TvkGLXContext::TvkGLXContext(uint32_t w, uint32_t h, uint8_t,
                             uint8_t, uint8_t,
                             bool double_buffer)
{
  // if you *really* require a specific value... just hack this class
  // to your liking.  You probably want to add those parameters to x_connect
  // and use them there.
  WARNING("Ignoring color, depth, stencil bits.  For many applications, it "
          "is better to let the GLX library choose the \"best\" visual.");
  this->xi = x_connect(w, h, double_buffer);
  glx_init(xi.display, xi.visual, xi.ctx);
  this->makeCurrent();
  MESSAGE("Current context: %p", glXGetCurrentContext());
}

TvkGLXContext::~TvkGLXContext()
{
  glXDestroyContext(xi.display, xi.ctx);
  XDestroyWindow(xi.display, xi.win);
  XFree(xi.visual);
  XCloseDisplay(xi.display);
}

bool TvkGLXContext::isValid() const
{
  return this->xi.display != NULL && this->xi.ctx != NULL;
}

bool TvkGLXContext::makeCurrent()
{
  if(glXMakeCurrent(this->xi.display, this->xi.win, this->xi.ctx) != True) {
    T_ERROR("Could not make context current!");
    return false;
  }
  return true;
}

bool TvkGLXContext::swapBuffers()
{
  glXSwapBuffers(this->xi.display, this->xi.win);
  // SwapBuffers generates an X error if it fails.
  return true;
}

static struct xinfo
x_connect(uint32_t width, uint32_t height, bool dbl_buffer)
{
  struct xinfo rv;

  rv.display = XOpenDisplay(NULL);
  if(rv.display == NULL) {
    T_ERROR("Could not connect to display: '%s'!", XDisplayName(NULL));
    throw NoAvailableContext();
  }
  XSynchronize(rv.display, True);

  rv.visual = find_visual(rv.display, dbl_buffer);

  Window parent = RootWindow(rv.display, rv.visual->screen);

  XSetWindowAttributes xw_attr;
  xw_attr.override_redirect = False;
  xw_attr.background_pixel = 0;
  xw_attr.colormap = XCreateColormap(rv.display, parent, rv.visual->visual,
                                     AllocNone);
  xw_attr.event_mask = StructureNotifyMask | ExposureMask;

  rv.win = XCreateWindow(rv.display, parent, 0,0, width,height, 0,
                         rv.visual->depth,
                         InputOutput, rv.visual->visual,
                         CWBackPixel | CWBorderPixel | CWColormap |
                         CWOverrideRedirect | CWEventMask,
                         &xw_attr);
  XStoreName(rv.display, rv.win, "Tuvok testing");
  XSync(rv.display, False);

  return rv;
}

static void
glx_init(Display *disp, XVisualInfo *visual, GLXContext& ctx)
{
  if(!glXQueryExtension(disp, NULL, NULL)) {
    T_ERROR("Display does not support glX.");
    return;
  }

  ctx = glXCreateContext(disp, visual, 0, GL_TRUE);
  if(!ctx) {
    T_ERROR("glX Context creation failed.");
  }
}

static XVisualInfo *
find_visual(Display *d, bool double_buffered)
{
    XVisualInfo *ret_v;
    // GLX_USE_GL is basically a no-op, so this provides a convenient
    // way of specifying double buffering or not.
    int att_buf = double_buffered ? GLX_DOUBLEBUFFER : GLX_USE_GL;
    int attr[] = {
      GLX_RGBA,
      att_buf,
      GLX_RED_SIZE,         5,
      GLX_GREEN_SIZE,       6,
      GLX_BLUE_SIZE,        5,
      GLX_ALPHA_SIZE,       8,
      GLX_DEPTH_SIZE,       8,
      GLX_ACCUM_RED_SIZE,   0,
      GLX_ACCUM_GREEN_SIZE, 0,
      GLX_ACCUM_BLUE_SIZE,  0,
      None
    };

    ret_v = glXChooseVisual(d, DefaultScreen(d), attr);
    MESSAGE("ChooseVisual got us %p", (const void*)ret_v);
    return ret_v;
}
#endif

#ifdef DETECTED_OS_WINDOWS

static void outputLastError() {
  DWORD lastError = GetLastError();
  LPVOID msgBuffer;
  FormatMessageW(
    FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
    FORMAT_MESSAGE_IGNORE_INSERTS,
    NULL,
    lastError,
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR)&msgBuffer,
    0, NULL
  );
  T_ERROR("Win32 error: %s", std::string((LPSTR)msgBuffer));
  LocalFree(msgBuffer);
}

TvkWGLContext::TvkWGLContext(uint32_t w, uint32_t h, uint8_t color_bits,
                             uint8_t depth_bits, uint8_t stencil_bits,
                             bool double_buffer) :
  deviceContext(NULL),
  renderingContext(NULL),
  window(NULL)
{
  if(w == 0 || h == 0 ||
     !(color_bits==8 || color_bits==16 || color_bits==24 || color_bits==32) ||
     !(depth_bits==8 || depth_bits==16 || depth_bits==24 || depth_bits==32 ||
       depth_bits==0) ||
     !(stencil_bits == 0 || stencil_bits == 8)) {
    T_ERROR("Invalid parameters passed to constructor.");
    throw NoAvailableContext();
  }

  window = CreateWindowExW(WS_EX_TOOLWINDOW, L"Static", L"GLContextWindow",
                WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN ,
                0, 0, width, height, 0, 0, GetModuleHandle(NULL), 0);
  if (!window)
  {
    outputLastError();
    return;
  }
  ShowWindow(window, SW_HIDE);

  deviceContext = GetDC(window);
  if(!deviceContext) {
    // GetDC doesn't SetLastError, but this still works anyway...
    outputLastError();
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  PIXELFORMATDESCRIPTOR pfd;
  pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
  pfd.nVersion = 1;
  pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_TYPE_RGBA;
  if (useDoubleBuffer) pfd.dwFlags |= PFD_DOUBLEBUFFER;
  pfd.iPixelType = PFD_TYPE_RGBA;
  pfd.cColorBits = colorBits;
  pfd.cRedBits = 0;
  pfd.cRedShift = 0;
  pfd.cGreenBits = 0;
  pfd.cGreenShift = 0;
  pfd.cBlueBits = 0;
  pfd.cBlueShift = 0;
  pfd.cAlphaBits = 0;
  pfd.cAlphaShift = 0;
  pfd.cAccumBits = 0;
  pfd.cAccumRedBits = 0;
  pfd.cAccumGreenBits = 0;
  pfd.cAccumBlueBits = 0;
  pfd.cAccumAlphaBits = 0;
  pfd.cDepthBits = depthBits;
  pfd.cStencilBits = stencilBits;
  pfd.cAuxBuffers = 0;
  pfd.iLayerType = PFD_MAIN_PLANE;
  pfd.bReserved = 0;
  pfd.dwLayerMask = 0;
  pfd.dwVisibleMask = 0;
  pfd.dwDamageMask = 0;

  int pixelFormat = ChoosePixelFormat(deviceContext, &pfd);

  if (!pixelFormat)
  {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  PIXELFORMATDESCRIPTOR pfdResult;
  DescribePixelFormat(deviceContext, pixelFormat,
                      sizeof(PIXELFORMATDESCRIPTOR), &pfdResult);

  if (!(pfdResult.dwFlags & PFD_SUPPORT_OPENGL))
  {
    T_ERROR("No OpenGL support.");
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  if (useDoubleBuffer && !(pfdResult.dwFlags & PFD_DOUBLEBUFFER)) {
    WARNING("No double buffer support!");
  }

  std::ostringstream ss;
  if (pfdResult.cColorBits != colorBits) {
    ss << "Color bits requested: " << colorBits << ", actual color bits: "
       << pfdResult.cColorBits << "\n";
  }
  if (pfdResult.cDepthBits != depthBits) {
    ss << "Depth bits requested " << depthBits << ", actual depth bits: "
       << pfdResult.cDepthBits << "\n";
  }
  if (pfdResult.cStencilBits != stencilBits) {
    ss << "Stencil bits requested " << stencilBits << ", actual stencil bits:"
       << pfdResult.cStencilBits << "\n";
  }
  MESSAGE("%s", ss.str().c_str());

  if (!SetPixelFormat(deviceContext, pixelFormat, &pfd)) {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }

  renderingContext = wglCreateContext(deviceContext);

  if (!renderingContext) {
    outputLastError();
    ReleaseDC(window, deviceContext);
    DestroyWindow(window);
    throw NoAvailableContext();
  }
}

TvkWGLContext::~TvkWGLContext()
{
  wglDeleteContext(renderingContext);
  ReleaseDC(window, deviceContext);
  DestroyWindow(window);
}

bool TvkWGLContext::isValid() const
{
  // Object would not be created otherwise (throw in constructor)
  return true;
}

bool TvkWGLContext::makeCurrent()
{
  if(!wglMakeCurrent(deviceContext, renderingContext)) {
    outputLastError();
    return false;
  }
  return true;
}

bool TvkWGLContext::swapBuffers()
{
  if(!isValid()) { return false; }

  if(!wglSwapBuffers(deviceContext, WGL_SWAP_MAIN_PLANE)) {
    outputLastError();
    return false;
  }
  return true;
}
#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <deque>

#include "catch.hpp"

#include "dll/dbn.hpp"
#include "dll/stochastic_gradient_descent.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE( "dbn/sgd/1", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>, dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(500);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

TEST_CASE( "dbn/sgd/2", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::momentum>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(1000);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.05;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

TEST_CASE( "dbn/sgd/3", "[dbn][mnist][sgd][gaussian]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 200, dll::momentum, dll::batch_size<25>, dll::visible<dll::unit_type::GAUSSIAN>>::rbm_t,
        dll::rbm_desc<200, 500, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<500, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::deque, double>(1000);

    REQUIRE(!dataset.training_images.empty());

    mnist::normalize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 20);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

//This test should not perform well, but should not fail
TEST_CASE( "dbn/sgd/4", "[dbn][mnist][sgd][relu]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::RELU>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::deque, double>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(std::isfinite(error));
}

TEST_CASE( "dbn/sgd/5", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::weight_decay<dll::decay_type::L2>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>();

    REQUIRE(!dataset.training_images.empty());
    dataset.training_images.resize(200);
    dataset.training_labels.resize(200);

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 5);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 200, 10);

    REQUIRE(error < 1e-1);
}

TEST_CASE( "dbn/sgd/6", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::momentum, dll::weight_decay<dll::decay_type::L2>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>();

    REQUIRE(!dataset.training_images.empty());
    dataset.training_images.resize(200);
    dataset.training_labels.resize(200);

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 10);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 200, 100);

    REQUIRE(error < 5e-2);
}

TEST_CASE( "dbn/sgd/7", "[dbn][mnist][sgd][memory]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
            dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
            dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>,
        dll::memory
        >::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(500);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}
<commit_msg>Cleanup<commit_after>//=======================================================================
// Copyright (c) 2014-2015 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#include <deque>

#include "catch.hpp"

#include "dll/dbn.hpp"
#include "dll/stochastic_gradient_descent.hpp"

#include "mnist/mnist_reader.hpp"
#include "mnist/mnist_utils.hpp"

TEST_CASE( "dbn/sgd/1", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>, dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(500);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

TEST_CASE( "dbn/sgd/2", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::momentum>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(1000);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.05;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

TEST_CASE( "dbn/sgd/3", "[dbn][mnist][sgd][gaussian]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 200, dll::momentum, dll::batch_size<25>, dll::visible<dll::unit_type::GAUSSIAN>>::rbm_t,
        dll::rbm_desc<200, 500, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<500, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::deque, double>(1000);

    REQUIRE(!dataset.training_images.empty());

    mnist::normalize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 20);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}

//This test should not perform well, but should not fail
TEST_CASE( "dbn/sgd/4", "[dbn][mnist][sgd][relu]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::RELU>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::deque, double>(200);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(std::isfinite(error));
}

TEST_CASE( "dbn/sgd/5", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::weight_decay<dll::decay_type::L2>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>();

    REQUIRE(!dataset.training_images.empty());
    dataset.training_images.resize(200);
    dataset.training_labels.resize(200);

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 5);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 200, 10);

    REQUIRE(error < 1e-1);
}

TEST_CASE( "dbn/sgd/6", "[dbn][mnist][sgd]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
        dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
        dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
        dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>,
        dll::trainer<dll::sgd_trainer>, dll::momentum, dll::weight_decay<dll::decay_type::L2>>::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>();

    REQUIRE(!dataset.training_images.empty());
    dataset.training_images.resize(200);
    dataset.training_labels.resize(200);

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 10);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 200, 100);

    REQUIRE(error < 5e-2);
}

TEST_CASE( "dbn/sgd/7", "[dbn][mnist][sgd][memory]" ) {
    typedef dll::dbn_desc<
        dll::dbn_layers<
            dll::rbm_desc<28 * 28, 100, dll::momentum, dll::batch_size<25>, dll::init_weights>::rbm_t,
            dll::rbm_desc<100, 200, dll::momentum, dll::batch_size<25>>::rbm_t,
            dll::rbm_desc<200, 10, dll::momentum, dll::batch_size<25>, dll::hidden<dll::unit_type::SOFTMAX>>::rbm_t>
        , dll::trainer<dll::sgd_trainer>
        , dll::memory
        >::dbn_t dbn_t;

    auto dataset = mnist::read_dataset<std::vector, std::vector, double>(500);

    REQUIRE(!dataset.training_images.empty());

    mnist::binarize_dataset(dataset);

    auto dbn = std::make_unique<dbn_t>();

    dbn->learning_rate = 0.1;

    dbn->pretrain(dataset.training_images, 20);
    auto error = dbn->fine_tune(dataset.training_images, dataset.training_labels, 100, 10);

    REQUIRE(error < 5e-2);

    auto test_error = dll::test_set(dbn, dataset.test_images, dataset.test_labels, dll::predictor());

    std::cout << "test_error:" << test_error << std::endl;

    REQUIRE(test_error < 0.2);
}
<|endoftext|>


<commit_before>// Module:  Log4CPLUS
// File:    appender.cxx
// Created: 6/2001
// Author:  Tad E. Smith
//
//
// Copyright (C) Tad E. Smith  All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//
// $Log: not supported by cvs2svn $
// Revision 1.12  2003/06/06 17:04:27  tcsmith
// Changed the ctor to take a 'const' Properties object.
//
// Revision 1.11  2003/06/04 00:19:15  tcsmith
// Modified the Appender(Properties) ctor to build the filtering chain
// specified in the properties file.
//
// Revision 1.10  2003/06/03 20:20:51  tcsmith
// Changed the logging in the destructorImpl() method.
//
// Revision 1.9  2003/05/28 17:39:54  tcsmith
// Added filtering support.
//
// Revision 1.8  2003/05/14 23:07:16  tcsmith
// Fixed some TABs.
//
// Revision 1.7  2003/04/18 21:00:34  tcsmith
// Converted from std::string to log4cplus::tstring.
//
// Revision 1.6  2003/04/07 16:35:21  tcsmith
// Fixed gcc 3.2 compilation error.
//
// Revision 1.5  2003/04/03 01:37:16  tcsmith
// Removed tabs from this file.
//
// Revision 1.4  2003/04/03 00:35:22  tcsmith
// Standardized the formatting.
//

#include <log4cplus/appender.h>
#include <log4cplus/layout.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/spi/loggingevent.h>

using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::spi;

///////////////////////////////////////////////////////////////////////////////
// file LOCAL methods
///////////////////////////////////////////////////////////////////////////////

namespace {
    log4cplus::tstring asString(int i) {
        log4cplus::tostringstream tmp;
        tmp << i;
        return tmp.str();
    }
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::ErrorHandler dtor
///////////////////////////////////////////////////////////////////////////////

ErrorHandler::~ErrorHandler()
{
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::OnlyOnceErrorHandler public methods
///////////////////////////////////////////////////////////////////////////////

void
OnlyOnceErrorHandler::error(const log4cplus::tstring& err)
{
    if(firstTime) {
        getLogLog().error(err);
        firstTime = false;
    }
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::Appender ctors
///////////////////////////////////////////////////////////////////////////////

Appender::Appender()
 : layout(new SimpleLayout()),
   name( LOG4CPLUS_TEXT("") ),
   threshold(NOT_SET_LOG_LEVEL),
   errorHandler(new OnlyOnceErrorHandler()),
   closed(false)
{
}

Appender::Appender(const log4cplus::helpers::Properties properties)
 : layout(new SimpleLayout()),
   name( LOG4CPLUS_TEXT("") ),
   threshold(NOT_SET_LOG_LEVEL),
   errorHandler(new OnlyOnceErrorHandler()),
   closed(false)
{
    if(properties.exists( LOG4CPLUS_TEXT("layout") )) {
       log4cplus::tstring factoryName = properties.getProperty( LOG4CPLUS_TEXT("layout") );
        LayoutFactory* factory = getLayoutFactoryRegistry().get(factoryName);
        if(factory == 0) {
            getLogLog().error(  LOG4CPLUS_TEXT("Cannot find LayoutFactory: \"")
                              + factoryName
                              + LOG4CPLUS_TEXT("\"") );
            return;
        }

        Properties layoutProperties =
                properties.getPropertySubset( LOG4CPLUS_TEXT("layout.") );
        try {
            std::auto_ptr<Layout> newLayout = factory->createObject(layoutProperties);
            if(newLayout.get() == 0) {
                getLogLog().error(  LOG4CPLUS_TEXT("Failed to create appender: ")
                                  + factoryName);
            }
            else {
                layout = newLayout;
            }
        }
        catch(std::exception& e) {
            getLogLog().error(  LOG4CPLUS_TEXT("Error while creating Layout: ")
                              + LOG4CPLUS_C_STR_TO_TSTRING(e.what()));
            return;
        }

    }

    // Configure the filters
    Properties filterProps = properties.getPropertySubset( LOG4CPLUS_TEXT("filters.") );
    int filterCount = 0;
    FilterPtr filterChain;
    while( filterProps.exists(asString(++filterCount)) ) {
        tstring filterName = asString(filterCount);
        tstring factoryName = filterProps.getProperty(filterName);
        FilterFactory* factory = getFilterFactoryRegistry().get(factoryName);

        if(factory == 0) {
            tstring err = LOG4CPLUS_TEXT("Appender::ctor()- Cannot find FilterFactory: ");
            getLogLog().error(err + factoryName);
            continue;
        }
        FilterPtr filter = factory->createObject
                      (filterProps.getPropertySubset(filterName + LOG4CPLUS_TEXT(".")));
        if(filter.get() == 0) {
            tstring err = LOG4CPLUS_TEXT("Appender::ctor()- Failed to create filter: ");
            getLogLog().error(err + filterName);
        }
        if(filterChain.get() == 0) {
            filterChain = filter;
        }
        else {
            filterChain->appendFilter(filter);
        }
    }
    setFilter(filterChain);
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::Appender public methods
///////////////////////////////////////////////////////////////////////////////

void
Appender::destructorImpl()
{
    getLogLog().debug(  LOG4CPLUS_TEXT("Destroying appender named [")
                      + name
                      + LOG4CPLUS_TEXT("]."));

    // An appender might be closed then destroyed. There is no
    // point in closing twice.
    if(closed) {
        return;
    }

    close();
    closed = true;
}

void
Appender::doAppend(const log4cplus::spi::InternalLoggingEvent& event)
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        if(closed) {
            getLogLog().error(  LOG4CPLUS_TEXT("Attempted to append to closed appender named [")
                              + name
                              + LOG4CPLUS_TEXT("]."));
            return;
        }

        if(!isAsSevereAsThreshold(event.getLogLevel())) {
            return;
        }

        if(checkFilter(filter.get(), event) == DENY) {
            return;
        }

        append(event);
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

log4cplus::tstring
Appender::getName()
{
    return name;
}

void
Appender::setName(const log4cplus::tstring& name)
{
    this->name = name;
}

ErrorHandler*
Appender::getErrorHandler()
{
    return errorHandler.get();
}

void
Appender::setErrorHandler(std::auto_ptr<ErrorHandler> eh)
{
    if(eh.get() == NULL) {
        // We do not throw exception here since the cause is probably a
        // bad config file.
        getLogLog().warn(LOG4CPLUS_TEXT("You have tried to set a null error-handler."));
        return;
    }
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        this->errorHandler = eh;
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

void
Appender::setLayout(std::auto_ptr<Layout> lo)
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        this->layout = lo;
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

Layout*
Appender::getLayout()
{
    return layout.get();
}

<commit_msg>Added support for the "Threshold" property.<commit_after>// Module:  Log4CPLUS
// File:    appender.cxx
// Created: 6/2001
// Author:  Tad E. Smith
//
//
// Copyright (C) Tad E. Smith  All rights reserved.
//
// This software is published under the terms of the Apache Software
// License version 1.1, a copy of which has been included with this
// distribution in the LICENSE.APL file.
//
// $Log: not supported by cvs2svn $
// Revision 1.13  2003/06/23 20:56:43  tcsmith
// Modified to support the changes in the spi::InternalLoggingEvent class.
//
// Revision 1.12  2003/06/06 17:04:27  tcsmith
// Changed the ctor to take a 'const' Properties object.
//
// Revision 1.11  2003/06/04 00:19:15  tcsmith
// Modified the Appender(Properties) ctor to build the filtering chain
// specified in the properties file.
//
// Revision 1.10  2003/06/03 20:20:51  tcsmith
// Changed the logging in the destructorImpl() method.
//
// Revision 1.9  2003/05/28 17:39:54  tcsmith
// Added filtering support.
//
// Revision 1.8  2003/05/14 23:07:16  tcsmith
// Fixed some TABs.
//
// Revision 1.7  2003/04/18 21:00:34  tcsmith
// Converted from std::string to log4cplus::tstring.
//
// Revision 1.6  2003/04/07 16:35:21  tcsmith
// Fixed gcc 3.2 compilation error.
//
// Revision 1.5  2003/04/03 01:37:16  tcsmith
// Removed tabs from this file.
//
// Revision 1.4  2003/04/03 00:35:22  tcsmith
// Standardized the formatting.
//

#include <log4cplus/appender.h>
#include <log4cplus/layout.h>
#include <log4cplus/helpers/loglog.h>
#include <log4cplus/helpers/pointer.h>
#include <log4cplus/helpers/stringhelper.h>
#include <log4cplus/spi/factory.h>
#include <log4cplus/spi/loggingevent.h>

using namespace log4cplus;
using namespace log4cplus::helpers;
using namespace log4cplus::spi;

///////////////////////////////////////////////////////////////////////////////
// file LOCAL methods
///////////////////////////////////////////////////////////////////////////////

namespace {
    log4cplus::tstring asString(int i) {
        log4cplus::tostringstream tmp;
        tmp << i;
        return tmp.str();
    }
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::ErrorHandler dtor
///////////////////////////////////////////////////////////////////////////////

ErrorHandler::~ErrorHandler()
{
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::OnlyOnceErrorHandler public methods
///////////////////////////////////////////////////////////////////////////////

void
OnlyOnceErrorHandler::error(const log4cplus::tstring& err)
{
    if(firstTime) {
        getLogLog().error(err);
        firstTime = false;
    }
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::Appender ctors
///////////////////////////////////////////////////////////////////////////////

Appender::Appender()
 : layout(new SimpleLayout()),
   name( LOG4CPLUS_TEXT("") ),
   threshold(NOT_SET_LOG_LEVEL),
   errorHandler(new OnlyOnceErrorHandler()),
   closed(false)
{
}

Appender::Appender(const log4cplus::helpers::Properties properties)
 : layout(new SimpleLayout()),
   name( LOG4CPLUS_TEXT("") ),
   threshold(NOT_SET_LOG_LEVEL),
   errorHandler(new OnlyOnceErrorHandler()),
   closed(false)
{
    if(properties.exists( LOG4CPLUS_TEXT("layout") )) {
       log4cplus::tstring factoryName = properties.getProperty( LOG4CPLUS_TEXT("layout") );
        LayoutFactory* factory = getLayoutFactoryRegistry().get(factoryName);
        if(factory == 0) {
            getLogLog().error(  LOG4CPLUS_TEXT("Cannot find LayoutFactory: \"")
                              + factoryName
                              + LOG4CPLUS_TEXT("\"") );
            return;
        }

        Properties layoutProperties =
                properties.getPropertySubset( LOG4CPLUS_TEXT("layout.") );
        try {
            std::auto_ptr<Layout> newLayout = factory->createObject(layoutProperties);
            if(newLayout.get() == 0) {
                getLogLog().error(  LOG4CPLUS_TEXT("Failed to create appender: ")
                                  + factoryName);
            }
            else {
                layout = newLayout;
            }
        }
        catch(std::exception& e) {
            getLogLog().error(  LOG4CPLUS_TEXT("Error while creating Layout: ")
                              + LOG4CPLUS_C_STR_TO_TSTRING(e.what()));
            return;
        }

    }

    // Support for appender.Threshold in properties configuration file
    if(properties.exists(LOG4CPLUS_TEXT("Threshold"))) {
        tstring tmp = properties.getProperty(LOG4CPLUS_TEXT("Threshold"));
        tmp = log4cplus::helpers::toUpper(tmp);
        threshold = log4cplus::getLogLevelManager().fromString(tmp);
    }

    // Configure the filters
    Properties filterProps = properties.getPropertySubset( LOG4CPLUS_TEXT("filters.") );
    int filterCount = 0;
    FilterPtr filterChain;
    while( filterProps.exists(asString(++filterCount)) ) {
        tstring filterName = asString(filterCount);
        tstring factoryName = filterProps.getProperty(filterName);
        FilterFactory* factory = getFilterFactoryRegistry().get(factoryName);

        if(factory == 0) {
            tstring err = LOG4CPLUS_TEXT("Appender::ctor()- Cannot find FilterFactory: ");
            getLogLog().error(err + factoryName);
            continue;
        }
        FilterPtr filter = factory->createObject
                      (filterProps.getPropertySubset(filterName + LOG4CPLUS_TEXT(".")));
        if(filter.get() == 0) {
            tstring err = LOG4CPLUS_TEXT("Appender::ctor()- Failed to create filter: ");
            getLogLog().error(err + filterName);
        }
        if(filterChain.get() == 0) {
            filterChain = filter;
        }
        else {
            filterChain->appendFilter(filter);
        }
    }
    setFilter(filterChain);
}

///////////////////////////////////////////////////////////////////////////////
// log4cplus::Appender public methods
///////////////////////////////////////////////////////////////////////////////

void
Appender::destructorImpl()
{
    getLogLog().debug(  LOG4CPLUS_TEXT("Destroying appender named [")
                      + name
                      + LOG4CPLUS_TEXT("]."));

    // An appender might be closed then destroyed. There is no
    // point in closing twice.
    if(closed) {
        return;
    }

    close();
    closed = true;
}

void
Appender::doAppend(const log4cplus::spi::InternalLoggingEvent& event)
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        if(closed) {
            getLogLog().error(  LOG4CPLUS_TEXT("Attempted to append to closed appender named [")
                              + name
                              + LOG4CPLUS_TEXT("]."));
            return;
        }

        if(!isAsSevereAsThreshold(event.getLogLevel())) {
            return;
        }

        if(checkFilter(filter.get(), event) == DENY) {
            return;
        }

        append(event);
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

log4cplus::tstring
Appender::getName()
{
    return name;
}

void
Appender::setName(const log4cplus::tstring& name)
{
    this->name = name;
}

ErrorHandler*
Appender::getErrorHandler()
{
    return errorHandler.get();
}

void
Appender::setErrorHandler(std::auto_ptr<ErrorHandler> eh)
{
    if(eh.get() == NULL) {
        // We do not throw exception here since the cause is probably a
        // bad config file.
        getLogLog().warn(LOG4CPLUS_TEXT("You have tried to set a null error-handler."));
        return;
    }
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        this->errorHandler = eh;
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

void
Appender::setLayout(std::auto_ptr<Layout> lo)
{
    LOG4CPLUS_BEGIN_SYNCHRONIZE_ON_MUTEX( access_mutex )
        this->layout = lo;
    LOG4CPLUS_END_SYNCHRONIZE_ON_MUTEX
}

Layout*
Appender::getLayout()
{
    return layout.get();
}

<|endoftext|>


<commit_before>/*  -*- mode: C++; c-file-style: "gnu" -*-

    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qlabel.h>
#include <qlayout.h>

#include <dcopref.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kparts/part.h>

#include "core.h"
#include "summary.h"
#include "summarywidget.h"

SummaryWidget::SummaryWidget( Kontact::Plugin *plugin, QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ),
    DCOPObject( QCString("MailSummary") ),
    mPlugin( plugin )
{
  QVBoxLayout *mainLayout = new QVBoxLayout( this, 3, 3 );

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kmail", KIcon::Desktop, KIcon::SizeMedium);
  QWidget *header = createHeader(this, icon, i18n("New Messages"));
  mLayout = new QGridLayout( 1, 3, 3 );

  mainLayout->addWidget(header);
  mainLayout->addLayout(mLayout);
  mainLayout->addStretch();

  slotUnreadCountChanged();
  connectDCOPSignal( 0, 0, "unreadCountChanged()", "slotUnreadCountChanged()",
                     false );
}

void SummaryWidget::selectFolder( const QString& folder )
{
  if ( mPlugin->isRunningStandalone() )
    mPlugin->bringToForeground();
  else
    mPlugin->core()->selectPlugin( mPlugin );
  DCOPRef kmail( "kmail", "KMailIface" );
  DCOPRef folderRef = kmail.call( "getFolder(QString)", folder );
  folderRef.call( "select()" );
}

void SummaryWidget::slotUnreadCountChanged()
{
  DCOPRef kmail( "kmail", "KMailIface" );
  DCOPReply reply = kmail.call( "folderList" );
  if ( reply.isValid() ) {
    QStringList folderList = reply;
    updateFolderList( folderList );
  }
  else {
    kdDebug(5602) << "Calling kmail->KMailIface->folderList() via DCOP failed."
                  << endl;
  }
}

void SummaryWidget::updateFolderList( const QStringList& folders )
{
  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  KConfig config( "kcmkmailsummaryrc" );
  config.setGroup( "General" );

  QStringList activeFolders;
  if ( !config.hasKey( "ActiveFolders" ) )
    activeFolders << "/inbox";
  else
    activeFolders = config.readListEntry( "ActiveFolders" );

  bool showFullPath = config.readBoolEntry( "ShowFullPath", false );

  int counter = 0;
  QStringList::ConstIterator it;
  DCOPRef kmail( "kmail", "KMailIface" );
  for ( it = folders.begin(); it != folders.end() && counter < 9; ++it ) {
    DCOPRef folderRef = kmail.call( "getFolder(QString)", *it );
    int numMsg = folderRef.call( "messages()" );
    int numUnreadMsg = folderRef.call( "unreadMessages()" );

    if ( activeFolders.contains( *it ) ) {
      QString folderPath = *it;
      if ( !showFullPath )
        folderPath = folderPath.mid( folderPath.findRev( '/' ) + 1 );

      KURLLabel *urlLabel = new KURLLabel( *it, folderPath,
                                           this );
      urlLabel->setAlignment( AlignLeft );
      urlLabel->show();
      // ### FIXME emit dcop signal to jumo to actual folder
      connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
               SLOT( selectFolder( const QString& ) ) );
      mLayout->addWidget( urlLabel, counter, 0 );
      mLabels.append( urlLabel );

      QLabel *label = new QLabel( QString( "%1 / %2" )
                                  .arg( numUnreadMsg ).arg( numMsg ), this );
      label->setAlignment( AlignLeft );
      label->show();
      mLayout->addWidget( label, counter, 2 );
      mLabels.append( label );

      counter++;
    }
  }

  if ( counter == 0 ) {
    QLabel *label = new QLabel( i18n( "No unread messages" ), this );
    label->show();
    mLayout->addMultiCellWidget( label, 1, 1, 1, 2 );
    mLabels.append( label );
  }
}

QStringList SummaryWidget::configModules() const
{
  return QStringList( "kcmkmailsummary.desktop" );
}

#include "summarywidget.moc"
<commit_msg>CVS_SILENT implemented<commit_after>/*  -*- mode: C++; c-file-style: "gnu" -*-

    This file is part of Kontact.
    Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>

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

    This program 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 General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include <qlabel.h>
#include <qlayout.h>

#include <dcopref.h>
#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <kdialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kparts/part.h>

#include "core.h"
#include "summary.h"
#include "summarywidget.h"

SummaryWidget::SummaryWidget( Kontact::Plugin *plugin, QWidget *parent, const char *name )
  : Kontact::Summary( parent, name ),
    DCOPObject( QCString("MailSummary") ),
    mPlugin( plugin )
{
  QVBoxLayout *mainLayout = new QVBoxLayout( this, 3, 3 );

  QPixmap icon = KGlobal::iconLoader()->loadIcon( "kmail", KIcon::Desktop, KIcon::SizeMedium);
  QWidget *header = createHeader(this, icon, i18n("New Messages"));
  mLayout = new QGridLayout( 1, 3, 3 );

  mainLayout->addWidget(header);
  mainLayout->addLayout(mLayout);
  mainLayout->addStretch();

  slotUnreadCountChanged();
  connectDCOPSignal( 0, 0, "unreadCountChanged()", "slotUnreadCountChanged()",
                     false );
}

void SummaryWidget::selectFolder( const QString& folder )
{
  if ( mPlugin->isRunningStandalone() )
    mPlugin->bringToForeground();
  else
    mPlugin->core()->selectPlugin( mPlugin );
  DCOPRef kmail( "kmail", "KMailIface" );
  DCOPRef folderRef = kmail.call( "getFolder(QString)", folder );
  folderRef.call( "select()" );
}

void SummaryWidget::slotUnreadCountChanged()
{
  DCOPRef kmail( "kmail", "KMailIface" );
  DCOPReply reply = kmail.call( "folderList" );
  if ( reply.isValid() ) {
    QStringList folderList = reply;
    updateFolderList( folderList );
  }
  else {
    kdDebug(5602) << "Calling kmail->KMailIface->folderList() via DCOP failed."
                  << endl;
  }
}

void SummaryWidget::updateFolderList( const QStringList& folders )
{
  mLabels.setAutoDelete( true );
  mLabels.clear();
  mLabels.setAutoDelete( false );

  KConfig config( "kcmkmailsummaryrc" );
  config.setGroup( "General" );

  QStringList activeFolders;
  if ( !config.hasKey( "ActiveFolders" ) )
    activeFolders << "/inbox";
  else
    activeFolders = config.readListEntry( "ActiveFolders" );

  bool showFullPath = config.readBoolEntry( "ShowFullPath", false );

  int counter = 0;
  QStringList::ConstIterator it;
  DCOPRef kmail( "kmail", "KMailIface" );
  for ( it = folders.begin(); it != folders.end() && counter < 9; ++it ) {
    DCOPRef folderRef = kmail.call( "getFolder(QString)", *it );
    int numMsg = folderRef.call( "messages()" );
    int numUnreadMsg = folderRef.call( "unreadMessages()" );

    if ( activeFolders.contains( *it ) ) {
      QString folderPath = *it;
      if ( !showFullPath )
        folderPath = folderPath.mid( folderPath.findRev( '/' ) + 1 );

      KURLLabel *urlLabel = new KURLLabel( *it, folderPath,
                                           this );
      urlLabel->setAlignment( AlignLeft );
      urlLabel->show();
      connect( urlLabel, SIGNAL( leftClickedURL( const QString& ) ),
               SLOT( selectFolder( const QString& ) ) );
      mLayout->addWidget( urlLabel, counter, 0 );
      mLabels.append( urlLabel );

      QLabel *label = new QLabel( QString( "%1 / %2" )
                                  .arg( numUnreadMsg ).arg( numMsg ), this );
      label->setAlignment( AlignLeft );
      label->show();
      mLayout->addWidget( label, counter, 2 );
      mLabels.append( label );

      counter++;
    }
  }

  if ( counter == 0 ) {
    QLabel *label = new QLabel( i18n( "No unread messages" ), this );
    label->show();
    mLayout->addMultiCellWidget( label, 1, 1, 1, 2 );
    mLabels.append( label );
  }
}

QStringList SummaryWidget::configModules() const
{
  return QStringList( "kcmkmailsummary.desktop" );
}

#include "summarywidget.moc"
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2013, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <pcl/io/pcd_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <pcl/common/centroid.h>

using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;

void
printHelp (int, char **argv)
{
  print_error ("Syntax is: %s input.pcd output.pcd\n", argv[0]);
}

bool
loadCloud (const std::string &filename, pcl::PCLPointCloud2 &cloud)
{
  TicToc tt;
  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (loadPCDFile (filename, cloud) < 0)
    return (false);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
saveCloud (const std::string &filename, const pcl::PCLPointCloud2 &cloud)
{
  TicToc tt;
  tt.tic ();

  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::PCDWriter writer;
  writer.writeBinaryCompressed (filename, cloud);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
  print_info ("Convert a PCD file to PLY format. For more information, use: %s -h\n", argv[0]);

  if (argc < 3)
  {
    printHelp (argc, argv);
    return (-1);
  }

  // Parse the command line arguments for .pcd files
  std::vector<int> pcd_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
  if (pcd_file_indices.size () != 2)
  {
    print_error ("Need one input and one output PCD file.\n");
    return (-1);
  }

  // Load the first file
  pcl::PCLPointCloud2 cloud;
  if (!loadCloud (argv[pcd_file_indices[0]], cloud))
    return (-1);

  PointCloud<PointXYZ> cloud_xyz, cloud_xyz_demeaned;
  fromPCLPointCloud2 (cloud, cloud_xyz);
  Eigen::Vector4f centroid;
  compute3DCentroid (cloud_xyz, centroid);
  demeanPointCloud (cloud_xyz, centroid, cloud_xyz_demeaned);

  pcl::PCLPointCloud2 cloud2_xyz_demeaned;
  toPCLPointCloud2 (cloud_xyz_demeaned, cloud2_xyz_demeaned);
  pcl::PCLPointCloud2 cloud_out;
  concatenateFields (cloud, cloud2_xyz_demeaned, cloud_out);

  // Save cloud
  saveCloud (argv[pcd_file_indices[1]], cloud_out);

  return (0);
}

<commit_msg>fix:fix error info<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2013, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <pcl/io/pcd_io.h>
#include <pcl/console/print.h>
#include <pcl/console/parse.h>
#include <pcl/console/time.h>
#include <pcl/common/centroid.h>

using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;

void
printHelp (int, char **argv)
{
  print_error ("Syntax is: %s input.pcd output.pcd\n", argv[0]);
}

bool
loadCloud (const std::string &filename, pcl::PCLPointCloud2 &cloud)
{
  TicToc tt;
  print_highlight ("Loading "); print_value ("%s ", filename.c_str ());

  tt.tic ();
  if (loadPCDFile (filename, cloud) < 0)
    return (false);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
  print_info ("Available dimensions: "); print_value ("%s\n", pcl::getFieldsList (cloud).c_str ());

  return (true);
}

void
saveCloud (const std::string &filename, const pcl::PCLPointCloud2 &cloud)
{
  TicToc tt;
  tt.tic ();

  print_highlight ("Saving "); print_value ("%s ", filename.c_str ());

  pcl::PCDWriter writer;
  writer.writeBinaryCompressed (filename, cloud);
  print_info ("[done, "); print_value ("%g", tt.toc ()); print_info (" ms : "); print_value ("%d", cloud.width * cloud.height); print_info (" points]\n");
}

/* ---[ */
int
main (int argc, char** argv)
{
  print_info ("Convert a PCD file to a de-meaned PCD file. For more information, use: %s -h\n", argv[0]);

  if (argc < 3)
  {
    printHelp (argc, argv);
    return (-1);
  }

  // Parse the command line arguments for .pcd files
  std::vector<int> pcd_file_indices = parse_file_extension_argument (argc, argv, ".pcd");
  if (pcd_file_indices.size () != 2)
  {
    print_error ("Need one input and one output PCD file.\n");
    return (-1);
  }

  // Load the first file
  pcl::PCLPointCloud2 cloud;
  if (!loadCloud (argv[pcd_file_indices[0]], cloud))
    return (-1);

  PointCloud<PointXYZ> cloud_xyz, cloud_xyz_demeaned;
  fromPCLPointCloud2 (cloud, cloud_xyz);
  Eigen::Vector4f centroid;
  compute3DCentroid (cloud_xyz, centroid);
  demeanPointCloud (cloud_xyz, centroid, cloud_xyz_demeaned);

  pcl::PCLPointCloud2 cloud2_xyz_demeaned;
  toPCLPointCloud2 (cloud_xyz_demeaned, cloud2_xyz_demeaned);
  pcl::PCLPointCloud2 cloud_out;
  concatenateFields (cloud, cloud2_xyz_demeaned, cloud_out);

  // Save cloud
  saveCloud (argv[pcd_file_indices[1]], cloud_out);

  return (0);
}

<|endoftext|>


<commit_before>/******************************************************************************
 Copyright (c) 2016-20 Leandro T. C. Melo (ltcmelo@gmail.com)

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

 This library is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 for more details.

 You should have received a copy of the GNU Lesser General Public License along
 with this library; if not, write to the Free Software Foundation, Inc., 51
 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *****************************************************************************/

#include "Driver.h"

#include "AST.h"
#include "ASTDotWriter.h"
#include "ASTNormalizer.h"
#include "BaseTester.h"
#include "Binder.h"
#include "CompilerFacade.h"
#include "ConstraintGenerator.h"
#include "ConstraintWriter.h"
#include "DeclarationInterceptor.h"
#include "Debug.h"
#include "DiagnosticCollector.h"
#include "DomainLattice.h"
#include "FileInfo.h"
#include "GenericsInstantiatior.h"
#include "IO.h"
#include "Literals.h"
#include "Plugin.h"
#include "ProgramValidator.h"
#include "SourceInspector.h"
#include "Symbols.h"
#include "cxxopts.hpp"
#include <iostream>
#include <sstream>
#include <cstring>

using namespace psyche;
using namespace psyche;
using namespace std::placeholders;

namespace psyche {
    extern bool debugEnabled;
}

constexpr int Driver::Exit_OK;
constexpr int Driver::Exit_Error;
constexpr int Driver::Exit_ParsingError_Internal;
constexpr int Driver::Exit_SyntaxError;
constexpr int Driver::Exit_ASTError_Internal;
constexpr int Driver::Exit_UnresolvedSyntaxAmbiguityError;
constexpr int Driver::Exit_UnspecifiedInputFileError;
constexpr int Driver::Exit_UnknownCommandLineOptionError;
constexpr int Driver::Exit_PluginLoadingError;
constexpr int Driver::Exit_PreprocessingError;

namespace {

void honorFlag(bool flag, std::function<void ()> f)
{
    if (flag)
        f();
}

} // anonymous

Driver::Driver(const Factory& factory)
    : factory_(factory)
    , global_(nullptr)
    , withGenerics_(true)
{}

TranslationUnit *Driver::unit() const
{
    return unit_.get();
}

TranslationUnitAST* Driver::ast() const
{
    return unit()->ast()->asTranslationUnit();
}

Dialect Driver::adjustedDialect(const ExecutionOptions&)
{
    Dialect dialect;
    dialect.c99 = 1; // TODO: Requires further work for actual customization.
    dialect.ext_KeywordsGNU = 1;
    dialect.ext_EnumeratorAttributes = 1;
    dialect.ext_AvailabilityAttribute = 1;
    dialect.nullptrOnNULL = 1;
    dialect.generics = 1;

    return dialect;
}

void Driver::configure(const ExecutionOptions& flags)
{
    control_.reset();
    global_ = control_.newNamespace(0, nullptr);
    opts_ = flags;
}

std::string Driver::augmentSource(const std::string& source, const std::vector<std::string>& headers)
{
    if (headers.empty())
        return source;

    for (const auto& h : headers)
        includes_ += "#include <" + h + ">\n";
    includes_ += "\n";

    std::string augmented = "\n/* psychec: automatic inclusion */\n";
    augmented += includes_;
    augmented += "/* psychec end: automatic inclusion */\n\n";
    augmented += source;

    return augmented;
}

int Driver::process(int argc, char *argv[])
{
    ExecutionOptions exeOpts;
    std::string in;
    cxxopts::Options cmdOpts(argv[0], "PsycheC constraint generator");

    try {
        cmdOpts.positional_help("file");

        cmdOpts.add_options()
            ("h,help", "Print help")
            ("o,output", "Specify output file",
                cxxopts::value<std::string>()->default_value("a.cstr"))
            ("d,debug", "Enable debugging messages",
                cxxopts::value<bool>(debugEnabled))
            ("c,constraints", "Display generated constraints")
            ("a,ast", "Dump AST in .dot format")
            ("s,stats", "Display AST disambiguation and constraint-generation stats")
            ("t,test", "Run tests (except for inference)")
            ("p,plugin", "Load named plugin",
                cxxopts::value<std::string>())
            ("no-heuristic", "Disable heuristics on unresolved syntax ambiguities")
            ("no-typedef", "Forbid typedef and struct/union declarations")
            ("cc", "Specify host C compiler",
                cxxopts::value<std::string>()->default_value("gcc"))
            ("cc-std", "Specify C dialect",
                cxxopts::value<std::string>()->default_value("c99"))
            ("cc-D", "Predefine a macro",
                cxxopts::value<std::vector<std::string>>())
            ("cc-U", "Undefine a macro",
                cxxopts::value<std::vector<std::string>>())
            ("positional", "Positional arguments",
                cxxopts::value<std::vector<std::string>>());

        cmdOpts.parse_positional(std::vector<std::string>{"file", "positional"});
        cmdOpts.parse(argc, argv);
    } catch (const cxxopts::OptionException& e) {
        std::cerr << kPsychePrefix << e.what() << std::endl;
        return Exit_UnknownCommandLineOptionError;
    }

    if (cmdOpts.count("help")) {
        std::cout << cmdOpts.help({"", "Group"}) << std::endl;
        return Exit_OK;
    }

    if (cmdOpts.count("test")) {
        try {
            BaseTester::runSuite();
        } catch (...) {
            std::cout << "\nTests failed." << std::endl;
            return Exit_Error;
        }
        return Exit_OK;
    }

    if (!cmdOpts.count("positional")) {
        std::cerr << kPsychePrefix << "unspecified input file" << std::endl;
        return Exit_UnspecifiedInputFileError;
    }

    // The input file name is the single positional argument.
    if (cmdOpts.count("positional")) {
        auto& v = cmdOpts["positional"].as<std::vector<std::string>>();
        in = v[0];
    }

    exeOpts.flag_.dumpAst = cmdOpts.count("ast");
    exeOpts.flag_.displayConstraints = cmdOpts.count("constraints");
    exeOpts.flag_.displayStats = cmdOpts.count("stats");
    exeOpts.flag_.noHeuristics = cmdOpts.count("no-heuristic");
    exeOpts.flag_.noTypedef = cmdOpts.count("no-typedef");
    exeOpts.flag_.handleGNUerrorFunc_ = true; // TODO: POSIX stuff?
    exeOpts.nativeCC_ = cmdOpts["cc"].as<std::string>();
    exeOpts.dialect_ = cmdOpts["cc-std"].as<std::string>();
    exeOpts.defs_ = cmdOpts["cc-D"].as<std::vector<std::string>>();
    exeOpts.undefs_ = cmdOpts["cc-U"].as<std::vector<std::string>>();

    if (cmdOpts.count("plugin")) {
        Plugin::load(cmdOpts["plugin"].as<std::string>());
        if (!Plugin::isLoaded()) {
            std::cerr << kPsychePrefix << "cannot load plugin" << std::endl;
            return Exit_PluginLoadingError;
        }
    }

    const std::string& source = readFile(in);
    int code = 0;
    try {
        code = process(in, source, exeOpts);
    } catch (...) {
        Plugin::unload();
    }

    switch (code) {
    case Exit_OK:
        if (!constraints_.empty()) {
            writeFile(cmdOpts["output"].as<std::string>(), constraints_);
            if (!includes_.empty()) {
                FileInfo fi(cmdOpts["output"].as<std::string>());
                writeFile(fi.fullFileBaseName() + ".inc", includes_);
            }
        }
        break;

    case Exit_ParsingError_Internal:
        std::cerr << kPsychePrefix << "parsing (internal) error" << std::endl;
        break;

    case Exit_ASTError_Internal:
        std::cerr << kPsychePrefix << "unavailable AST (internal) error" << in << std::endl;
        break;

    default:
        break;
    }

    return code;
}

int Driver::process(const std::string& unitName,
                    const std::string& source,
                    const ExecutionOptions& flags)
{
    configure(flags);

    StringLiteral name(unitName.c_str(), unitName.length());
    unit_.reset(new TranslationUnit(&control_, &name));
    unit_->setDialect(adjustedDialect(flags));

    static DiagnosticCollector collector;
    control_.setDiagnosticCollector(&collector);

    collectIncludes(source);

    if (Plugin::isLoaded()) {
        SourceInspector* inspector = Plugin::createInspector();
        auto includes = inspector->identifyIncludes(source);
        return preprocess(augmentSource(source, includes));
    }

    return parse(source);
}

void Driver::collectIncludes(const std::string& source)
{
    std::istringstream iss(source);
    for (std::string line; std::getline(iss, line);) {
        if (line.find("#include ") == 0)
            includes_ += line + "\n";
    }
}

int Driver::preprocess(const std::string& source)
{
    CompilerFacade cc(opts_.nativeCC_, opts_.defs_, opts_.undefs_);
    auto r = cc.preprocessSource(source);
    if (!r.first) {
        writeFile(FileInfo(unit()->fileName()).fullFileBaseName() + ".i", r.second);
        return parse(r.second);
    }

    return Exit_PreprocessingError;
}

int Driver::parse(const std::string& source)
{
    control_.diagnosticCollector()->reset();

    unit_->setSource(source.c_str(), source.length());

    if (!unit_->parse())
        return Exit_ParsingError_Internal;

    if (!unit_->ast() || !ast())
        return Exit_ASTError_Internal;

    honorFlag(opts_.flag_.dumpAst,
              [this] () { ASTDotWriter(unit()).write(ast(), ".ast.dot"); });

    ProgramValidator validator(unit(), opts_.flag_.noTypedef);
    validator.validate(ast());

    if (control_.diagnosticCollector()->seenBlockingIssue())
        return Exit_SyntaxError;

    return annotateAST();
}

int Driver::annotateAST()
{
    // Create symbols.
    Binder bind(unit());
    bind(ast(), global_);

    // Try to disambiguate syntax ambiguities and normalize the AST according to the resolutions.
    ASTNormalizer fixer(unit(), !opts_.flag_.noHeuristics);
    if (!fixer.normalize(ast()))
        return Exit_UnresolvedSyntaxAmbiguityError;

    honorFlag(opts_.flag_.displayStats,
              [this, &fixer] () {
                 std::cout << "Ambiguities stats" << std::endl << fixer.stats() << std::endl;
              });

    honorFlag(opts_.flag_.dumpAst,
              [this] () { ASTDotWriter(unit()).write(ast(), ".ast.fixed.dot"); });

    if (opts_.flag_.disambOnly)
        return Exit_OK;

    return withGenerics_
                ? instantiateGenerics()
                : generateConstraints();
}

int Driver::instantiateGenerics()
{
    std::cout << "\n\ninstantiate generics \n\n";
    GenericsInstantiatior instantiator(unit());
    bool r = instantiator.quantify(ast(), global_);
    if (!r)
        return generateConstraints();

    auto origSource = readFile(unit()->fileName());
    auto newSource = instantiator.instantiate(origSource);

    writeFile(FileInfo(unit()->fileName()).fullFileBaseName() + ".poly", newSource);

    // Ignore generics in next pass.
    withGenerics_ = false;
    opts_.defs_.push_back("_Template=");
    opts_.defs_.push_back("'_Forall(v)=v'");
    opts_.defs_.push_back("'_Exists(v)=v'");

    return preprocess(newSource);
}

int Driver::generateConstraints()
{
    // Build domain lattice.
    DomainLattice lattice(unit());
    lattice.categorize(ast(), global_);

    std::ostringstream oss;
    auto writer = factory_.makeConstraintWriter(oss);

    ConstraintGenerator generator(unit(), writer.get());
    generator.employDomainLattice(&lattice);

    if (Plugin::isLoaded()) {
        generator.installInterceptor(Plugin::createInterceptor());
        generator.installObserver(Plugin::createObserver());
    }

    if (opts_.flag_.handleGNUerrorFunc_)
        generator.addPrintfLike("error", 2);
    generator.generate(ast(), global_);

    constraints_ = oss.str();

    honorFlag(opts_.flag_.displayConstraints,
              [this] () { std::cout << constraints_ << std::endl; });

    return Exit_OK;
}
<commit_msg>remove std::cout<commit_after>/******************************************************************************
 Copyright (c) 2016-20 Leandro T. C. Melo (ltcmelo@gmail.com)

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

 This library is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 for more details.

 You should have received a copy of the GNU Lesser General Public License along
 with this library; if not, write to the Free Software Foundation, Inc., 51
 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
 *****************************************************************************/

#include "Driver.h"

#include "AST.h"
#include "ASTDotWriter.h"
#include "ASTNormalizer.h"
#include "BaseTester.h"
#include "Binder.h"
#include "CompilerFacade.h"
#include "ConstraintGenerator.h"
#include "ConstraintWriter.h"
#include "DeclarationInterceptor.h"
#include "Debug.h"
#include "DiagnosticCollector.h"
#include "DomainLattice.h"
#include "FileInfo.h"
#include "GenericsInstantiatior.h"
#include "IO.h"
#include "Literals.h"
#include "Plugin.h"
#include "ProgramValidator.h"
#include "SourceInspector.h"
#include "Symbols.h"
#include "cxxopts.hpp"
#include <iostream>
#include <sstream>
#include <cstring>

using namespace psyche;
using namespace psyche;
using namespace std::placeholders;

namespace psyche {
    extern bool debugEnabled;
}

constexpr int Driver::Exit_OK;
constexpr int Driver::Exit_Error;
constexpr int Driver::Exit_ParsingError_Internal;
constexpr int Driver::Exit_SyntaxError;
constexpr int Driver::Exit_ASTError_Internal;
constexpr int Driver::Exit_UnresolvedSyntaxAmbiguityError;
constexpr int Driver::Exit_UnspecifiedInputFileError;
constexpr int Driver::Exit_UnknownCommandLineOptionError;
constexpr int Driver::Exit_PluginLoadingError;
constexpr int Driver::Exit_PreprocessingError;

namespace {

void honorFlag(bool flag, std::function<void ()> f)
{
    if (flag)
        f();
}

} // anonymous

Driver::Driver(const Factory& factory)
    : factory_(factory)
    , global_(nullptr)
    , withGenerics_(true)
{}

TranslationUnit *Driver::unit() const
{
    return unit_.get();
}

TranslationUnitAST* Driver::ast() const
{
    return unit()->ast()->asTranslationUnit();
}

Dialect Driver::adjustedDialect(const ExecutionOptions&)
{
    Dialect dialect;
    dialect.c99 = 1; // TODO: Requires further work for actual customization.
    dialect.ext_KeywordsGNU = 1;
    dialect.ext_EnumeratorAttributes = 1;
    dialect.ext_AvailabilityAttribute = 1;
    dialect.nullptrOnNULL = 1;
    dialect.generics = 1;

    return dialect;
}

void Driver::configure(const ExecutionOptions& flags)
{
    control_.reset();
    global_ = control_.newNamespace(0, nullptr);
    opts_ = flags;
}

std::string Driver::augmentSource(const std::string& source, const std::vector<std::string>& headers)
{
    if (headers.empty())
        return source;

    for (const auto& h : headers)
        includes_ += "#include <" + h + ">\n";
    includes_ += "\n";

    std::string augmented = "\n/* psychec: automatic inclusion */\n";
    augmented += includes_;
    augmented += "/* psychec end: automatic inclusion */\n\n";
    augmented += source;

    return augmented;
}

int Driver::process(int argc, char *argv[])
{
    ExecutionOptions exeOpts;
    std::string in;
    cxxopts::Options cmdOpts(argv[0], "PsycheC constraint generator");

    try {
        cmdOpts.positional_help("file");

        cmdOpts.add_options()
            ("h,help", "Print help")
            ("o,output", "Specify output file",
                cxxopts::value<std::string>()->default_value("a.cstr"))
            ("d,debug", "Enable debugging messages",
                cxxopts::value<bool>(debugEnabled))
            ("c,constraints", "Display generated constraints")
            ("a,ast", "Dump AST in .dot format")
            ("s,stats", "Display AST disambiguation and constraint-generation stats")
            ("t,test", "Run tests (except for inference)")
            ("p,plugin", "Load named plugin",
                cxxopts::value<std::string>())
            ("no-heuristic", "Disable heuristics on unresolved syntax ambiguities")
            ("no-typedef", "Forbid typedef and struct/union declarations")
            ("cc", "Specify host C compiler",
                cxxopts::value<std::string>()->default_value("gcc"))
            ("cc-std", "Specify C dialect",
                cxxopts::value<std::string>()->default_value("c99"))
            ("cc-D", "Predefine a macro",
                cxxopts::value<std::vector<std::string>>())
            ("cc-U", "Undefine a macro",
                cxxopts::value<std::vector<std::string>>())
            ("positional", "Positional arguments",
                cxxopts::value<std::vector<std::string>>());

        cmdOpts.parse_positional(std::vector<std::string>{"file", "positional"});
        cmdOpts.parse(argc, argv);
    } catch (const cxxopts::OptionException& e) {
        std::cerr << kPsychePrefix << e.what() << std::endl;
        return Exit_UnknownCommandLineOptionError;
    }

    if (cmdOpts.count("help")) {
        std::cout << cmdOpts.help({"", "Group"}) << std::endl;
        return Exit_OK;
    }

    if (cmdOpts.count("test")) {
        try {
            BaseTester::runSuite();
        } catch (...) {
            std::cout << "\nTests failed." << std::endl;
            return Exit_Error;
        }
        return Exit_OK;
    }

    if (!cmdOpts.count("positional")) {
        std::cerr << kPsychePrefix << "unspecified input file" << std::endl;
        return Exit_UnspecifiedInputFileError;
    }

    // The input file name is the single positional argument.
    if (cmdOpts.count("positional")) {
        auto& v = cmdOpts["positional"].as<std::vector<std::string>>();
        in = v[0];
    }

    exeOpts.flag_.dumpAst = cmdOpts.count("ast");
    exeOpts.flag_.displayConstraints = cmdOpts.count("constraints");
    exeOpts.flag_.displayStats = cmdOpts.count("stats");
    exeOpts.flag_.noHeuristics = cmdOpts.count("no-heuristic");
    exeOpts.flag_.noTypedef = cmdOpts.count("no-typedef");
    exeOpts.flag_.handleGNUerrorFunc_ = true; // TODO: POSIX stuff?
    exeOpts.nativeCC_ = cmdOpts["cc"].as<std::string>();
    exeOpts.dialect_ = cmdOpts["cc-std"].as<std::string>();
    exeOpts.defs_ = cmdOpts["cc-D"].as<std::vector<std::string>>();
    exeOpts.undefs_ = cmdOpts["cc-U"].as<std::vector<std::string>>();

    if (cmdOpts.count("plugin")) {
        Plugin::load(cmdOpts["plugin"].as<std::string>());
        if (!Plugin::isLoaded()) {
            std::cerr << kPsychePrefix << "cannot load plugin" << std::endl;
            return Exit_PluginLoadingError;
        }
    }

    const std::string& source = readFile(in);
    int code = 0;
    try {
        code = process(in, source, exeOpts);
    } catch (...) {
        Plugin::unload();
    }

    switch (code) {
    case Exit_OK:
        if (!constraints_.empty()) {
            writeFile(cmdOpts["output"].as<std::string>(), constraints_);
            if (!includes_.empty()) {
                FileInfo fi(cmdOpts["output"].as<std::string>());
                writeFile(fi.fullFileBaseName() + ".inc", includes_);
            }
        }
        break;

    case Exit_ParsingError_Internal:
        std::cerr << kPsychePrefix << "parsing (internal) error" << std::endl;
        break;

    case Exit_ASTError_Internal:
        std::cerr << kPsychePrefix << "unavailable AST (internal) error" << in << std::endl;
        break;

    default:
        break;
    }

    return code;
}

int Driver::process(const std::string& unitName,
                    const std::string& source,
                    const ExecutionOptions& flags)
{
    configure(flags);

    StringLiteral name(unitName.c_str(), unitName.length());
    unit_.reset(new TranslationUnit(&control_, &name));
    unit_->setDialect(adjustedDialect(flags));

    static DiagnosticCollector collector;
    control_.setDiagnosticCollector(&collector);

    collectIncludes(source);

    if (Plugin::isLoaded()) {
        SourceInspector* inspector = Plugin::createInspector();
        auto includes = inspector->identifyIncludes(source);
        return preprocess(augmentSource(source, includes));
    }

    return parse(source);
}

void Driver::collectIncludes(const std::string& source)
{
    std::istringstream iss(source);
    for (std::string line; std::getline(iss, line);) {
        if (line.find("#include ") == 0)
            includes_ += line + "\n";
    }
}

int Driver::preprocess(const std::string& source)
{
    CompilerFacade cc(opts_.nativeCC_, opts_.defs_, opts_.undefs_);
    auto r = cc.preprocessSource(source);
    if (!r.first) {
        writeFile(FileInfo(unit()->fileName()).fullFileBaseName() + ".i", r.second);
        return parse(r.second);
    }

    return Exit_PreprocessingError;
}

int Driver::parse(const std::string& source)
{
    control_.diagnosticCollector()->reset();

    unit_->setSource(source.c_str(), source.length());

    if (!unit_->parse())
        return Exit_ParsingError_Internal;

    if (!unit_->ast() || !ast())
        return Exit_ASTError_Internal;

    honorFlag(opts_.flag_.dumpAst,
              [this] () { ASTDotWriter(unit()).write(ast(), ".ast.dot"); });

    ProgramValidator validator(unit(), opts_.flag_.noTypedef);
    validator.validate(ast());

    if (control_.diagnosticCollector()->seenBlockingIssue())
        return Exit_SyntaxError;

    return annotateAST();
}

int Driver::annotateAST()
{
    // Create symbols.
    Binder bind(unit());
    bind(ast(), global_);

    // Try to disambiguate syntax ambiguities and normalize the AST according to the resolutions.
    ASTNormalizer fixer(unit(), !opts_.flag_.noHeuristics);
    if (!fixer.normalize(ast()))
        return Exit_UnresolvedSyntaxAmbiguityError;

    honorFlag(opts_.flag_.displayStats,
              [this, &fixer] () {
                 std::cout << "Ambiguities stats" << std::endl << fixer.stats() << std::endl;
              });

    honorFlag(opts_.flag_.dumpAst,
              [this] () { ASTDotWriter(unit()).write(ast(), ".ast.fixed.dot"); });

    if (opts_.flag_.disambOnly)
        return Exit_OK;

    return withGenerics_
                ? instantiateGenerics()
                : generateConstraints();
}

int Driver::instantiateGenerics()
{
    GenericsInstantiatior instantiator(unit());
    bool r = instantiator.quantify(ast(), global_);
    if (!r)
        return generateConstraints();

    auto origSource = readFile(unit()->fileName());
    auto newSource = instantiator.instantiate(origSource);

    writeFile(FileInfo(unit()->fileName()).fullFileBaseName() + ".poly", newSource);

    // Ignore generics in next pass.
    withGenerics_ = false;
    opts_.defs_.push_back("_Template=");
    opts_.defs_.push_back("'_Forall(v)=v'");
    opts_.defs_.push_back("'_Exists(v)=v'");

    return preprocess(newSource);
}

int Driver::generateConstraints()
{
    // Build domain lattice.
    DomainLattice lattice(unit());
    lattice.categorize(ast(), global_);

    std::ostringstream oss;
    auto writer = factory_.makeConstraintWriter(oss);

    ConstraintGenerator generator(unit(), writer.get());
    generator.employDomainLattice(&lattice);

    if (Plugin::isLoaded()) {
        generator.installInterceptor(Plugin::createInterceptor());
        generator.installObserver(Plugin::createObserver());
    }

    if (opts_.flag_.handleGNUerrorFunc_)
        generator.addPrintfLike("error", 2);
    generator.generate(ast(), global_);

    constraints_ = oss.str();

    honorFlag(opts_.flag_.displayConstraints,
              [this] () { std::cout << constraints_ << std::endl; });

    return Exit_OK;
}
<|endoftext|>