<commit_before>/******************************************************************************
 *  Copyright (c) 2008 - 2010 IBM Corporation and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  Contributors:
 *    David Ungar, IBM Research - Initial Implementation
 *    Sam Adams, IBM Research - Initial Implementation
 *    Stefan Marr, Vrije Universiteit Brussel - Port to x86 Multi-Core Systems
 ******************************************************************************/

#include "headers.h"

void Abstract_Object_Heap::initialize() {
  int size_in_oops = heap_byte_size() / sizeof(Oop);
  int size_in_bytes = size_in_oops * sizeof(Oop);
  initialize(allocate_my_space(size_in_bytes), size_in_bytes);
 }

void Abstract_Object_Heap::initialize(void* mem, int size) {
  _start = _next = (Oop*)mem;
  _end = _next + size/sizeof(Oop);
  zap_unused_portion();
  lowSpaceThreshold = 1000;
}

// ObjectMemory object enumeration

Object* Abstract_Object_Heap::firstAccessibleObject() {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    if (!obj->isFreeObject())  return obj;
  return NULL;
}

Oop Abstract_Object_Heap::initialInstanceOf(Oop classPointer) {
  // "Support for instance enumeration. Return the first instance of the given class, or nilObj if it has no instances."
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    if (!obj->isFreeObject()  &&  obj->fetchClass() == classPointer )
      return obj->as_oop();
  return The_Squeak_Interpreter()->roots.nilObj;
}

Object* Abstract_Object_Heap::first_object_or_null() {
  if (_start == _next)
    return NULL;
  return object_from_chunk((Chunk*)startOfMemory());
}

Object* Abstract_Object_Heap::first_object_without_preheader() {
  if (_start == _next)
    return NULL;
  return object_from_chunk_without_preheader((Chunk*)startOfMemory());
}

bool Abstract_Object_Heap::verify() {
  if (!is_initialized()) return true;

  bool ok = true;
  Object *prev_obj = NULL;
  __attribute__((unused)) Object *prev_prev_obj = NULL; // debugging
  FOR_EACH_OBJECT_IN_HEAP(this, obj) {
    if (obj->is_marked()) {
      lprintf("object 0x%x should not be marked but is; header is 0x%x, in heaps[%d][%d]\n",
      obj, obj->baseHeader, obj->rank(), obj->mutability());
      fatal("");
    }
    if (!obj->isFreeObject() &&  obj->is_current_copy())
      ok = obj->verify() && ok;
    prev_prev_obj = prev_obj;
    prev_obj = obj;
  }
  dittoing_stdout_printer->printf("Object_Heap %sverified\n", ok ? "" : "NOT ");
  return ok;
}

void Abstract_Object_Heap::check_multiple_stores_for_generations_only( Oop dsts[], oop_int_t n) {
  return; // unused
  for (oop_int_t i = 0;  i < n;  ++i)
    check_store( &dsts[i] );
}

void Abstract_Object_Heap::multistore( Oop* dst, Oop* end, Oop src) {
  multistore(dst, src, end - dst);
}
void Abstract_Object_Heap::multistore( Oop* dst, Oop src, oop_int_t n) {
  assert(The_Memory_System()->contains(dst));
  oopset_no_store_check(dst, src, n /* never read-mostly */);
  check_multiple_stores_for_generations_only(dst, n);
}
void Abstract_Object_Heap::multistore( Oop* dst, Oop* src, oop_int_t n) {
  assert(The_Memory_System()->contains(dst));

  The_Memory_System()->enforce_coherence_before_store(dst, n << ShiftForWord /* never read-mostly */);
  DEBUG_MULTIMOVE_CHECK(dst, src, n);
  memmove(dst, src, n * bytes_per_oop);
  The_Memory_System()->enforce_coherence_after_store(dst, n << ShiftForWord);
  check_multiple_stores_for_generations_only(dst, n);
}

// verify does it anyway
void Abstract_Object_Heap::ensure_all_unmarked() {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    assert_always(!obj->is_marked());
}

void Abstract_Object_Heap::do_all_oops(Oop_Closure* oc) {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    obj->do_all_oops_of_object(oc);
}

void Abstract_Object_Heap::scan_compact_or_make_free_objects(bool compacting, Abstract_Mark_Sweep_Collector* gc_or_null) {
  bool for_gc = gc_or_null != NULL;
  // enforce mutability at higher level
  if (for_gc || compacting)
    The_Memory_System()->object_table->pre_store_whole_enchillada();

  if (compacting) ++compactionsSinceLastQuery;

  Chunk* dst_chunk = (Chunk*)startOfMemory();
  for (__attribute__((unused))
       Chunk *src_chunk = dst_chunk,
        *next_src_chunk = NULL,
        *prev_src_chunk = NULL; // prev is only for debugging
       src_chunk  <  (Chunk*)end_objects();
       prev_src_chunk = src_chunk,  src_chunk = next_src_chunk) {

    Object* obj = src_chunk->object_from_chunk();
    next_src_chunk = obj->nextChunk();

    if (obj->isFreeObject())
      continue;

    Oop oop = obj->as_oop();

    if (for_gc) {
      if (!obj->is_marked()) {
        The_Memory_System()->object_table->free_oop(oop  COMMA_FALSE_OR_NOTHING);
        if (!compacting)
          src_chunk->make_free_object((char*)next_src_chunk - (char*)src_chunk, 0);
        continue;
      }
      obj->unmark_without_store_barrier();
    }
    if (!compacting)
      continue;

    Object_p new_obj_addr = (Object_p)(Object*)((char*)dst_chunk + ((char*)obj - (char*)src_chunk));

    if (src_chunk == dst_chunk)
      dst_chunk = next_src_chunk;

    else {
      The_Memory_System()->object_table->set_object_for(oop, new_obj_addr  COMMA_FALSE_OR_NOTHING); // noop unless indirect oops
      int n_oops = (Oop*)next_src_chunk - (Oop*)src_chunk;
      // no mutability barrier wanted here, may need generational store barrier in the future

      DEBUG_MULTIMOVE_CHECK(dst_chunk, src_chunk, n_oops);
      memmove(dst_chunk, src_chunk, n_oops * sizeof(Oop));
      src_chunk = next_src_chunk;
      dst_chunk = (Chunk*)&((Oop*)dst_chunk)[n_oops];
    }
  }
  if (compacting)
    set_end_objects((Oop*)dst_chunk);

  if (for_gc || compacting)
    The_Memory_System()->object_table->post_store_whole_enchillada();

  // enforce coherence at higher level
}

void Abstract_Object_Heap::zap_unused_portion() {
  assert_always(end_of_space() != NULL);
  if (check_many_assertions) {
    enforce_coherence_before_store(end_objects(), (char*)end_of_space() - (char*)end_objects());

    for (Oop* p = (Oop*)end_objects();
         p < (Oop*)end_of_space();
         *p++ = Oop::from_bits(Oop::Illegals::zapped)) {}

    enforce_coherence_after_store(end_objects(), (char*)end_of_space() - (char*)end_objects());
  }
}

void Abstract_Object_Heap::print(FILE*) {
  lprintf("start 0x%x, next 0x%x, end 0x%x\n", _start, _next, _end);
}

<commit_msg>Added a debugging printout for objects that failed to verify<commit_after>/******************************************************************************
 *  Copyright (c) 2008 - 2010 IBM Corporation and others.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the Eclipse Public License v1.0
 *  which accompanies this distribution, and is available at
 *  http://www.eclipse.org/legal/epl-v10.html
 *
 *  Contributors:
 *    David Ungar, IBM Research - Initial Implementation
 *    Sam Adams, IBM Research - Initial Implementation
 *    Stefan Marr, Vrije Universiteit Brussel - Port to x86 Multi-Core Systems
 ******************************************************************************/

#include "headers.h"

void Abstract_Object_Heap::initialize() {
  int size_in_oops = heap_byte_size() / sizeof(Oop);
  int size_in_bytes = size_in_oops * sizeof(Oop);
  initialize(allocate_my_space(size_in_bytes), size_in_bytes);
 }

void Abstract_Object_Heap::initialize(void* mem, int size) {
  _start = _next = (Oop*)mem;
  _end = _next + size/sizeof(Oop);
  zap_unused_portion();
  lowSpaceThreshold = 1000;
}

// ObjectMemory object enumeration

Object* Abstract_Object_Heap::firstAccessibleObject() {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    if (!obj->isFreeObject())  return obj;
  return NULL;
}

Oop Abstract_Object_Heap::initialInstanceOf(Oop classPointer) {
  // "Support for instance enumeration. Return the first instance of the given class, or nilObj if it has no instances."
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    if (!obj->isFreeObject()  &&  obj->fetchClass() == classPointer )
      return obj->as_oop();
  return The_Squeak_Interpreter()->roots.nilObj;
}

Object* Abstract_Object_Heap::first_object_or_null() {
  if (_start == _next)
    return NULL;
  return object_from_chunk((Chunk*)startOfMemory());
}

Object* Abstract_Object_Heap::first_object_without_preheader() {
  if (_start == _next)
    return NULL;
  return object_from_chunk_without_preheader((Chunk*)startOfMemory());
}

bool Abstract_Object_Heap::verify() {
  if (!is_initialized()) return true;

  bool ok = true;
  Object *prev_obj = NULL;
  __attribute__((unused)) Object *prev_prev_obj = NULL; // debugging
  FOR_EACH_OBJECT_IN_HEAP(this, obj) {
    if (obj->is_marked()) {
      lprintf("object 0x%x should not be marked but is; header is 0x%x, in heaps[%d][%d]\n",
      obj, obj->baseHeader, obj->rank(), obj->mutability());
      fatal("");
    }
    if (!obj->isFreeObject() &&  obj->is_current_copy())
      ok = obj->verify() && ok;

    if (not ok) dittoing_stdout_printer->printf("Failed to verify obj at %p\n", obj);

    prev_prev_obj = prev_obj;
    prev_obj = obj;
  }
  dittoing_stdout_printer->printf("Object_Heap %sverified\n", ok ? "" : "NOT ");
  return ok;
}

void Abstract_Object_Heap::check_multiple_stores_for_generations_only( Oop dsts[], oop_int_t n) {
  return; // unused
  for (oop_int_t i = 0;  i < n;  ++i)
    check_store( &dsts[i] );
}

void Abstract_Object_Heap::multistore( Oop* dst, Oop* end, Oop src) {
  multistore(dst, src, end - dst);
}
void Abstract_Object_Heap::multistore( Oop* dst, Oop src, oop_int_t n) {
  assert(The_Memory_System()->contains(dst));
  oopset_no_store_check(dst, src, n /* never read-mostly */);
  check_multiple_stores_for_generations_only(dst, n);
}
void Abstract_Object_Heap::multistore( Oop* dst, Oop* src, oop_int_t n) {
  assert(The_Memory_System()->contains(dst));

  The_Memory_System()->enforce_coherence_before_store(dst, n << ShiftForWord /* never read-mostly */);
  DEBUG_MULTIMOVE_CHECK(dst, src, n);
  memmove(dst, src, n * bytes_per_oop);
  The_Memory_System()->enforce_coherence_after_store(dst, n << ShiftForWord);
  check_multiple_stores_for_generations_only(dst, n);
}

// verify does it anyway
void Abstract_Object_Heap::ensure_all_unmarked() {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    assert_always(!obj->is_marked());
}

void Abstract_Object_Heap::do_all_oops(Oop_Closure* oc) {
  FOR_EACH_OBJECT_IN_HEAP(this, obj)
    obj->do_all_oops_of_object(oc);
}

void Abstract_Object_Heap::scan_compact_or_make_free_objects(bool compacting, Abstract_Mark_Sweep_Collector* gc_or_null) {
  bool for_gc = gc_or_null != NULL;
  // enforce mutability at higher level
  if (for_gc || compacting)
    The_Memory_System()->object_table->pre_store_whole_enchillada();

  if (compacting) ++compactionsSinceLastQuery;

  Chunk* dst_chunk = (Chunk*)startOfMemory();
  for (__attribute__((unused))
       Chunk *src_chunk = dst_chunk,
        *next_src_chunk = NULL,
        *prev_src_chunk = NULL; // prev is only for debugging
       src_chunk  <  (Chunk*)end_objects();
       prev_src_chunk = src_chunk,  src_chunk = next_src_chunk) {

    Object* obj = src_chunk->object_from_chunk();
    next_src_chunk = obj->nextChunk();

    if (obj->isFreeObject())
      continue;

    Oop oop = obj->as_oop();

    if (for_gc) {
      if (!obj->is_marked()) {
        The_Memory_System()->object_table->free_oop(oop  COMMA_FALSE_OR_NOTHING);
        if (!compacting)
          src_chunk->make_free_object((char*)next_src_chunk - (char*)src_chunk, 0);
        continue;
      }
      obj->unmark_without_store_barrier();
    }
    if (!compacting)
      continue;

    Object_p new_obj_addr = (Object_p)(Object*)((char*)dst_chunk + ((char*)obj - (char*)src_chunk));

    if (src_chunk == dst_chunk)
      dst_chunk = next_src_chunk;

    else {
      The_Memory_System()->object_table->set_object_for(oop, new_obj_addr  COMMA_FALSE_OR_NOTHING); // noop unless indirect oops
      int n_oops = (Oop*)next_src_chunk - (Oop*)src_chunk;
      // no mutability barrier wanted here, may need generational store barrier in the future

      DEBUG_MULTIMOVE_CHECK(dst_chunk, src_chunk, n_oops);
      memmove(dst_chunk, src_chunk, n_oops * sizeof(Oop));
      src_chunk = next_src_chunk;
      dst_chunk = (Chunk*)&((Oop*)dst_chunk)[n_oops];
    }
  }
  if (compacting)
    set_end_objects((Oop*)dst_chunk);

  if (for_gc || compacting)
    The_Memory_System()->object_table->post_store_whole_enchillada();

  // enforce coherence at higher level
}

void Abstract_Object_Heap::zap_unused_portion() {
  assert_always(end_of_space() != NULL);
  if (check_many_assertions) {
    enforce_coherence_before_store(end_objects(), (char*)end_of_space() - (char*)end_objects());

    for (Oop* p = (Oop*)end_objects();
         p < (Oop*)end_of_space();
         *p++ = Oop::from_bits(Oop::Illegals::zapped)) {}

    enforce_coherence_after_store(end_objects(), (char*)end_of_space() - (char*)end_objects());
  }
}

void Abstract_Object_Heap::print(FILE*) {
  lprintf("start 0x%x, next 0x%x, end 0x%x\n", _start, _next, _end);
}

<|endoftext|>


<commit_before>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

// Based on minputmethodstate.cpp from libmeegotouch

#include "inputmethod.h"
#include "inputmethod_p.h"

#if QT_VERSION >= 0x050000
#include <QGuiApplication>
#include <QInputMethod>
#else
#include <QApplication>
#include <QInputContext>
#endif

namespace Maliit {

InputMethodPrivate::InputMethodPrivate() :
    area(),
    widget(0),
    orientationAngle(),
    rotationInProgress(false)
{
}

InputMethodPrivate::~InputMethodPrivate()
{
}

InputMethod::InputMethod() :
    QObject(),
    d_ptr(new InputMethodPrivate)
{
}

InputMethod::~InputMethod()
{
}

InputMethod *InputMethod::instance()
{
    static InputMethod singleton;

    return &singleton;
}

void InputMethod::setWidget(QWidget *widget)
{
    Q_D(InputMethod);
    d->widget = widget;
}

QWidget *InputMethod::widget() const
{
    Q_D(const InputMethod);
    return d->widget;
}

QRect InputMethod::area() const
{
    Q_D(const InputMethod);

    return d->area;
}

void InputMethod::setArea(const QRect &newArea)
{
    Q_D(InputMethod);

    if (d->area != newArea) {
        d->area = newArea;
        Q_EMIT areaChanged(d->area);
    }
}

void InputMethod::startOrientationAngleChange(OrientationAngle newOrientationAngle)
{
    Q_D(InputMethod);

    if (d->orientationAngle != newOrientationAngle) {
        d->orientationAngle = newOrientationAngle;
        d->rotationInProgress = true;
        Q_EMIT orientationAngleAboutToChange(d->orientationAngle);
    }
}

void InputMethod::setOrientationAngle(OrientationAngle newOrientationAngle)
{
    Q_D(InputMethod);

    if (d->orientationAngle != newOrientationAngle) {
        d->orientationAngle = newOrientationAngle;
        d->rotationInProgress = true;
    }

    if (d->rotationInProgress) {
        d->rotationInProgress = false;
        Q_EMIT orientationAngleChanged(d->orientationAngle);
    }
}

OrientationAngle InputMethod::orientationAngle() const
{
    Q_D(const InputMethod);

    return d->orientationAngle;
}

void InputMethod::emitKeyPress(const QKeyEvent &event)
{
    Q_EMIT keyPress(event);
}

void InputMethod::emitKeyRelease(const QKeyEvent &event)
{
    Q_EMIT keyRelease(event);
}

void InputMethod::setLanguage(const QString &language)
{
    Q_D(InputMethod);
    if (d->language != language) {
        d->language = language;
        Q_EMIT languageChanged(language);
    }
}

const QString &InputMethod::language() const
{
    Q_D(const InputMethod);
    return d->language;
}

void requestInputMethodPanel()
{
#if QT_VERSION >= 0x050000
    qApp->inputMethod()->show();
#else
    QInputContext *inputContext = qApp->inputContext();

    if (!inputContext) {
        return;
    }

    QEvent request(QEvent::RequestSoftwareInputPanel);
    inputContext->filterEvent(&request);
#endif
}

void closeInputMethodPanel()
{
#if QT_VERSION >= 0x050000
    qApp->inputMethod()->hide();
#else
    QInputContext *inputContext = qApp->inputContext();

    if (!inputContext) {
        return;
    }

    QEvent close(QEvent::CloseSoftwareInputPanel);
    inputContext->filterEvent(&close);
    inputContext->reset();
#endif
}

} // namespace Maliit
<commit_msg>Use QT_VERSION_CHECK instead of hex version number.<commit_after>/* * This file is part of Maliit framework *
 *
 * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies).
 * All rights reserved.
 *
 * Contact: maliit-discuss@lists.maliit.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation
 * and appearing in the file LICENSE.LGPL included in the packaging
 * of this file.
 */

// Based on minputmethodstate.cpp from libmeegotouch

#include "inputmethod.h"
#include "inputmethod_p.h"

#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QGuiApplication>
#include <QInputMethod>
#else
#include <QApplication>
#include <QInputContext>
#endif

namespace Maliit {

InputMethodPrivate::InputMethodPrivate() :
    area(),
    widget(0),
    orientationAngle(),
    rotationInProgress(false)
{
}

InputMethodPrivate::~InputMethodPrivate()
{
}

InputMethod::InputMethod() :
    QObject(),
    d_ptr(new InputMethodPrivate)
{
}

InputMethod::~InputMethod()
{
}

InputMethod *InputMethod::instance()
{
    static InputMethod singleton;

    return &singleton;
}

void InputMethod::setWidget(QWidget *widget)
{
    Q_D(InputMethod);
    d->widget = widget;
}

QWidget *InputMethod::widget() const
{
    Q_D(const InputMethod);
    return d->widget;
}

QRect InputMethod::area() const
{
    Q_D(const InputMethod);

    return d->area;
}

void InputMethod::setArea(const QRect &newArea)
{
    Q_D(InputMethod);

    if (d->area != newArea) {
        d->area = newArea;
        Q_EMIT areaChanged(d->area);
    }
}

void InputMethod::startOrientationAngleChange(OrientationAngle newOrientationAngle)
{
    Q_D(InputMethod);

    if (d->orientationAngle != newOrientationAngle) {
        d->orientationAngle = newOrientationAngle;
        d->rotationInProgress = true;
        Q_EMIT orientationAngleAboutToChange(d->orientationAngle);
    }
}

void InputMethod::setOrientationAngle(OrientationAngle newOrientationAngle)
{
    Q_D(InputMethod);

    if (d->orientationAngle != newOrientationAngle) {
        d->orientationAngle = newOrientationAngle;
        d->rotationInProgress = true;
    }

    if (d->rotationInProgress) {
        d->rotationInProgress = false;
        Q_EMIT orientationAngleChanged(d->orientationAngle);
    }
}

OrientationAngle InputMethod::orientationAngle() const
{
    Q_D(const InputMethod);

    return d->orientationAngle;
}

void InputMethod::emitKeyPress(const QKeyEvent &event)
{
    Q_EMIT keyPress(event);
}

void InputMethod::emitKeyRelease(const QKeyEvent &event)
{
    Q_EMIT keyRelease(event);
}

void InputMethod::setLanguage(const QString &language)
{
    Q_D(InputMethod);
    if (d->language != language) {
        d->language = language;
        Q_EMIT languageChanged(language);
    }
}

const QString &InputMethod::language() const
{
    Q_D(const InputMethod);
    return d->language;
}

void requestInputMethodPanel()
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
    qApp->inputMethod()->show();
#else
    QInputContext *inputContext = qApp->inputContext();

    if (!inputContext) {
        return;
    }

    QEvent request(QEvent::RequestSoftwareInputPanel);
    inputContext->filterEvent(&request);
#endif
}

void closeInputMethodPanel()
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
    qApp->inputMethod()->hide();
#else
    QInputContext *inputContext = qApp->inputContext();

    if (!inputContext) {
        return;
    }

    QEvent close(QEvent::CloseSoftwareInputPanel);
    inputContext->filterEvent(&close);
    inputContext->reset();
#endif
}

} // namespace Maliit
<|endoftext|>


<commit_before>/*! \file uclient.cc
****************************************************************************
 *
 * Implementation of the URBI interface class
 *
 * Copyright (C) 2004, 2006, 2007, 2008, 2009 Gostai S.A.S.  All rights reserved.
 *
 * 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.
**********************************************************************/

#include <cstdlib>
#include <cerrno>

#include <locale.h>

#include <libport/windows.hh>
#include <libport/unistd.h>

#include <libport/sys/time.h>
#if !defined WIN32
# include <time.h>
# include <signal.h>
#endif

#include <libport/cstdio>
#include <libport/sys/select.h>
#include <libport/arpa/inet.h>
#include <libport/netdb.h>
#include <libport/errors.hh>
#include <libport/lockable.hh>
#include <libport/thread.hh>
#include <libport/utime.hh>

#include <urbi/uclient.hh>
#include <urbi/utag.hh>

namespace urbi
{
  /*! Establish the connection with the server.
   Spawn a new thread that will listen to the socket, parse the incoming URBI
   messages, and notify the appropriate callbacks.
   */
  UClient::UClient(const std::string& host, unsigned port,
                   size_t buflen, bool server,
                   int semListenInc)
    : UAbstractClient(host, port, buflen, server)
    , thread(0)
    , pingInterval(0)
    , semListenInc_ (semListenInc)
  {
    sd = -1;
    int pos = 0;

    setlocale(LC_NUMERIC, "C");
    control_fd[0] = control_fd[1] = -1;

#ifndef WIN32
    if (::pipe(control_fd) == -1)
    {
      rc = -1;
      libport::perror("UClient::UClient failed to create pipe");
      return;
    }
    //block sigpipe
    signal(SIGPIPE, SIG_IGN);
#endif

    // Address resolution stage.
    struct sockaddr_in sa;	// Internet address struct
    memset(&sa, 0, sizeof sa);
#ifdef WIN32
    WSADATA wsaData;
    WORD wVersionRequested;
    wVersionRequested = MAKEWORD(1, 1);
    WSAStartup(wVersionRequested, &wsaData);
#endif
    sa.sin_family = AF_INET;
    sa.sin_port = htons(port);

    // host-to-IP translation
    struct hostent* hen = gethostbyname(host_.c_str());
    if (!hen)
    {
      // maybe it is an IP address
      sa.sin_addr.s_addr = inet_addr(host_.c_str());
      if (sa.sin_addr.s_addr == INADDR_NONE)
      {
        std::cerr << "UClient::UClient cannot resolve host name." << std::endl;
        rc = -1;
        return;
      }
    }
    else
      memcpy(&sa.sin_addr.s_addr, hen->h_addr_list[0], hen->h_length);

    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0)
    {
      rc = -1;
      libport::perror("UClient::UClient socket");
      return;
    }

    if (!server_)
    {
      // Connect on given host and port
      rc = connect(sd, (struct sockaddr *) &sa, sizeof sa);
      // If we attempt to connect too fast to aperios ipstack it will fail.
      if (rc)
      {
	usleep(20000);
	rc = connect(sd, (struct sockaddr *) &sa, sizeof sa);
      }

      // Check there was no error.
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient connect");
	return;
      }

      // Check that it really worked.
      while (!pos)
	pos = ::recv(sd, recvBuffer, buflen, 0);
      if (pos < 0)
      {
	rc = -1;
	libport::perror("UClient::UClient recv");
	return;
      }

    }
    else
    {
      // Allow to rebind on the same port shortly after having used it.
      {
	int one = 1;
	rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
	if (rc)
	{
	  rc = -1;
	  libport::perror("UClient::UClient cannot use setsockopt");
	  return;
	}
      }
      // Bind socket
      rc = bind (sd, (struct sockaddr *) &sa, sizeof sa);
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient cannot bind");
	return;
      }
      // Activate listen/passive mode, do not allow queued connections
      rc = listen (sd, 0);
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient cannot listen");
	return;
      }

      // Create a thread waiting for incoming connection.
      // This must not be blocking in case of a remote server.
      // FIXME: block if normal remote ?
      init_ = false;
      thread = libport::startThread(this, &UClient::acceptThread);
    }

    recvBufferPosition = pos;
    recvBuffer[recvBufferPosition] = 0;

    // Do not create thread if one is already waiting for incoming connection
    if (!thread)
    {
      thread = libport::startThread(this, &UClient::listenThread);
      // Notify the base class that connection is established.
      onConnection();
    }

    if (!defaultClient)
      defaultClient = this;

    listenSem_++;
    acceptSem_++;

  }

  UClient::~UClient()
  {
    if (sd >= 0)
      closeUClient ();
  }

  int
  UClient::closeUClient ()
  {
    if (sd >= 0 && libport::closeSocket(sd) == -1)
      libport::perror ("cannot close sd");

    sd = -1;
    if (control_fd[1] != -1
        && ::write(control_fd[1], "a", 1) == -1)
      libport::perror ("cannot write to control_fd[1]");

    // If the connection has failed while building the client, the
    // thread is not created.
    if (thread)
      // Must wait for listen thread to terminate.
      libport::joinThread(thread);

    if (control_fd[1] != -1
        && close(control_fd[1]) == -1)
      libport::perror ("cannot close controlfd[1]");
    if (control_fd[0] != -1
        && close(control_fd[0]) == -1)
      libport::perror ("cannot close controlfd[0]");

    return 0;
  }

  bool
  UClient::canSend(size_t)
  {
    return true;
  }

  int
  UClient::effectiveSend(const void* buffer, size_t size)
  {
#if DEBUG
    char output[size+1];
    memcpy (static_cast<void*> (output), buffer, size);
    output[size]=0;
    std::cerr << ">>>> SENT : [" << output << "]" << std::endl;
#endif
    if (rc)
      return -1;
    size_t pos = 0;
    while (pos != size)
    {
      int retval = ::send(sd, (char *) buffer + pos, size-pos, 0);
      if (retval< 0)
      {
        rc = retval;
        clientError("send error", rc);
        return rc;
      }
      pos += retval;
    }
    return 0;
  }

  void
  UClient::acceptThread()
  {
    // Wait for it...
    acceptSem_--;

    // Accept one connection
    struct sockaddr_in saClient;
    socklen_t addrlenClient;
    int acceptFD = 0;

    acceptFD = accept (sd, (struct sockaddr *) &saClient, &addrlenClient);
    if (acceptFD < 0)
    {
      libport::perror("UClient::UClient cannot accept");
      rc = -1;
      return;
    }

    // Store client connection info
    host_ = inet_ntoa(saClient.sin_addr);
    port_ = saClient.sin_port;

    // Do not listen anymore.
    close(sd);
    // Redirect send/receive on accepted connection.
    sd = acceptFD;

    // FIXME: leaking ?
    thread = libport::startThread(this, &UClient::listenThread);

    init_ = true;
    onConnection();

    // Stop this thread, the listen one is the real thing.
    return;
  }

  void
  UClient::listenThread()
  {
    // Wait for it...
    for (int i = semListenInc_; i > 0; --i)
      listenSem_--;

    int maxfd = 1 + std::max(sd, control_fd[0]);
    waitingPong = false;
    // Declare ping channel for kernel that requires it.
    send("if (isdef(Channel)) var lobby.%s = Channel.new(\"%s\");",
	internalPongTag.c_str(), internalPongTag.c_str());
    while (true)
    {
      if (sd == -1)
        return;

      fd_set rfds;
      FD_ZERO(&rfds);
      LIBPORT_FD_SET(sd, &rfds);

      fd_set efds;
      FD_ZERO(&efds);
      LIBPORT_FD_SET(sd, &efds);

#ifndef WIN32
      LIBPORT_FD_SET(control_fd[0], &rfds);
#endif

      int selectReturn;
      if (pingInterval)
      {
        const unsigned delay = waitingPong ? pongTimeout : pingInterval;
        struct timeval timeout = { delay / 1000, (delay % 1000) * 1000};
        selectReturn = ::select(maxfd + 1, &rfds, NULL, &efds, &timeout);
      }
      else
      {
        selectReturn = ::select(maxfd + 1, &rfds, NULL, &efds, NULL);
      }

      if (sd < 0)
	return;

      // Treat error
      if (selectReturn < 0 && errno != EINTR)
      {
        rc = -1;
        clientError("Connection error : ", errno);
        notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                 "!!! Connection error", std::list<BinaryData>() ));
        return;
      }

      if (selectReturn < 0)  // ::select catch a signal (errno == EINTR)
        continue;
      // timeout
      else if (selectReturn == 0)
      {
        if (waitingPong) // Timeout while waiting PONG
        {
          rc = -1;
          // FIXME: Choose between two differents way to alert user program
          clientError("Lost connection with server");
          notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                   "!!! Lost connection with server",
                                   std::list<BinaryData>() ));
          return;
        }
        else // Timeout : Ping_interval
        {
          send("%s << 1,", internalPongTag.c_str());
          waitingPong = true;
        }
      }
      else
      {
        // We receive data, at least the "1" value sent through the pong tag
        // channel so we are no longer waiting for a pong.
        waitingPong = false;
        int count = ::recv(sd, &recvBuffer[recvBufferPosition],
                           buflen - recvBufferPosition - 1, 0);

        if (count <= 0)
        {
          std::string errorMsg;
          int         errorCode = 0;

          if (count < 0)
          {
#ifdef WIN32
            errorCode = WSAGetLastError();
#else
            errorCode = errno;
#endif
            errorMsg = "!!! Connection error";
          }
          else // count == 0  => Connection close
          {
            errorMsg = "!!! Connection closed";
          }

          rc = -1;
          clientError(errorMsg.c_str(), errorCode);
          notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                   errorMsg.c_str(), std::list<BinaryData>() ));
          return;
        }

        recvBufferPosition += count;
        recvBuffer[recvBufferPosition] = 0;
        processRecvBuffer();
      }
    }
  }

  void
  UClient::printf(const char * format, ...)
  {
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr, format, arg);
    va_end(arg);
  }

  unsigned int UClient::getCurrentTime() const
  {
  // FIXME: Put this into libport.
#ifdef WIN32
    return GetTickCount();
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec*1000+tv.tv_usec/1000;
#endif
  }

  void execute()
  {
    while (true)
      sleep(100);
  }

  void exit(int code)
  {
    ::exit(code);
  }

  UClient& connect(const std::string& host)
  {
    return *new UClient(host);
  }

  void disconnect(UClient &client)
  {
    delete &client;
  }

  void
  UClient::setKeepAliveCheck(const unsigned pingInterval,
                             const unsigned pongTimeout)
  {
    this->pingInterval = pingInterval;
    this->pongTimeout  = pongTimeout;
  }

} // namespace urbi
<commit_msg>Get rid of spurious parse error.<commit_after>/*! \file uclient.cc
****************************************************************************
 *
 * Implementation of the URBI interface class
 *
 * Copyright (C) 2004, 2006, 2007, 2008, 2009 Gostai S.A.S.  All rights reserved.
 *
 * 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.
**********************************************************************/

#include <cstdlib>
#include <cerrno>

#include <locale.h>

#include <libport/windows.hh>
#include <libport/unistd.h>

#include <libport/sys/time.h>
#if !defined WIN32
# include <time.h>
# include <signal.h>
#endif

#include <libport/cstdio>
#include <libport/sys/select.h>
#include <libport/arpa/inet.h>
#include <libport/netdb.h>
#include <libport/errors.hh>
#include <libport/lockable.hh>
#include <libport/thread.hh>
#include <libport/utime.hh>

#include <urbi/uclient.hh>
#include <urbi/utag.hh>

namespace urbi
{
  /*! Establish the connection with the server.
   Spawn a new thread that will listen to the socket, parse the incoming URBI
   messages, and notify the appropriate callbacks.
   */
  UClient::UClient(const std::string& host, unsigned port,
                   size_t buflen, bool server,
                   int semListenInc)
    : UAbstractClient(host, port, buflen, server)
    , thread(0)
    , pingInterval(0)
    , semListenInc_ (semListenInc)
  {
    sd = -1;
    int pos = 0;

    setlocale(LC_NUMERIC, "C");
    control_fd[0] = control_fd[1] = -1;

#ifndef WIN32
    if (::pipe(control_fd) == -1)
    {
      rc = -1;
      libport::perror("UClient::UClient failed to create pipe");
      return;
    }
    //block sigpipe
    signal(SIGPIPE, SIG_IGN);
#endif

    // Address resolution stage.
    struct sockaddr_in sa;	// Internet address struct
    memset(&sa, 0, sizeof sa);
#ifdef WIN32
    WSADATA wsaData;
    WORD wVersionRequested;
    wVersionRequested = MAKEWORD(1, 1);
    WSAStartup(wVersionRequested, &wsaData);
#endif
    sa.sin_family = AF_INET;
    sa.sin_port = htons(port);

    // host-to-IP translation
    struct hostent* hen = gethostbyname(host_.c_str());
    if (!hen)
    {
      // maybe it is an IP address
      sa.sin_addr.s_addr = inet_addr(host_.c_str());
      if (sa.sin_addr.s_addr == INADDR_NONE)
      {
        std::cerr << "UClient::UClient cannot resolve host name." << std::endl;
        rc = -1;
        return;
      }
    }
    else
      memcpy(&sa.sin_addr.s_addr, hen->h_addr_list[0], hen->h_length);

    sd = socket(AF_INET, SOCK_STREAM, 0);
    if (sd < 0)
    {
      rc = -1;
      libport::perror("UClient::UClient socket");
      return;
    }

    if (!server_)
    {
      // Connect on given host and port
      rc = connect(sd, (struct sockaddr *) &sa, sizeof sa);
      // If we attempt to connect too fast to aperios ipstack it will fail.
      if (rc)
      {
	usleep(20000);
	rc = connect(sd, (struct sockaddr *) &sa, sizeof sa);
      }

      // Check there was no error.
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient connect");
	return;
      }

      // Check that it really worked.
      while (!pos)
	pos = ::recv(sd, recvBuffer, buflen, 0);
      if (pos < 0)
      {
	rc = -1;
	libport::perror("UClient::UClient recv");
	return;
      }

    }
    else
    {
      // Allow to rebind on the same port shortly after having used it.
      {
	int one = 1;
	rc = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one);
	if (rc)
	{
	  rc = -1;
	  libport::perror("UClient::UClient cannot use setsockopt");
	  return;
	}
      }
      // Bind socket
      rc = bind (sd, (struct sockaddr *) &sa, sizeof sa);
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient cannot bind");
	return;
      }
      // Activate listen/passive mode, do not allow queued connections
      rc = listen (sd, 0);
      if (rc)
      {
	rc = -1;
	libport::perror("UClient::UClient cannot listen");
	return;
      }

      // Create a thread waiting for incoming connection.
      // This must not be blocking in case of a remote server.
      // FIXME: block if normal remote ?
      init_ = false;
      thread = libport::startThread(this, &UClient::acceptThread);
    }

    recvBufferPosition = pos;
    recvBuffer[recvBufferPosition] = 0;

    // Do not create thread if one is already waiting for incoming connection
    if (!thread)
    {
      thread = libport::startThread(this, &UClient::listenThread);
      // Notify the base class that connection is established.
      onConnection();
    }

    if (!defaultClient)
      defaultClient = this;

    listenSem_++;
    acceptSem_++;

  }

  UClient::~UClient()
  {
    if (sd >= 0)
      closeUClient ();
  }

  int
  UClient::closeUClient ()
  {
    if (sd >= 0 && libport::closeSocket(sd) == -1)
      libport::perror ("cannot close sd");

    sd = -1;
    if (control_fd[1] != -1
        && ::write(control_fd[1], "a", 1) == -1)
      libport::perror ("cannot write to control_fd[1]");

    // If the connection has failed while building the client, the
    // thread is not created.
    if (thread)
      // Must wait for listen thread to terminate.
      libport::joinThread(thread);

    if (control_fd[1] != -1
        && close(control_fd[1]) == -1)
      libport::perror ("cannot close controlfd[1]");
    if (control_fd[0] != -1
        && close(control_fd[0]) == -1)
      libport::perror ("cannot close controlfd[0]");

    return 0;
  }

  bool
  UClient::canSend(size_t)
  {
    return true;
  }

  int
  UClient::effectiveSend(const void* buffer, size_t size)
  {
#if DEBUG
    char output[size+1];
    memcpy (static_cast<void*> (output), buffer, size);
    output[size]=0;
    std::cerr << ">>>> SENT : [" << output << "]" << std::endl;
#endif
    if (rc)
      return -1;
    size_t pos = 0;
    while (pos != size)
    {
      int retval = ::send(sd, (char *) buffer + pos, size-pos, 0);
      if (retval< 0)
      {
        rc = retval;
        clientError("send error", rc);
        return rc;
      }
      pos += retval;
    }
    return 0;
  }

  void
  UClient::acceptThread()
  {
    // Wait for it...
    acceptSem_--;

    // Accept one connection
    struct sockaddr_in saClient;
    socklen_t addrlenClient;
    int acceptFD = 0;

    acceptFD = accept (sd, (struct sockaddr *) &saClient, &addrlenClient);
    if (acceptFD < 0)
    {
      libport::perror("UClient::UClient cannot accept");
      rc = -1;
      return;
    }

    // Store client connection info
    host_ = inet_ntoa(saClient.sin_addr);
    port_ = saClient.sin_port;

    // Do not listen anymore.
    close(sd);
    // Redirect send/receive on accepted connection.
    sd = acceptFD;

    // FIXME: leaking ?
    thread = libport::startThread(this, &UClient::listenThread);

    init_ = true;
    onConnection();

    // Stop this thread, the listen one is the real thing.
    return;
  }

  void
  UClient::listenThread()
  {
    // Wait for it...
    for (int i = semListenInc_; i > 0; --i)
      listenSem_--;

    int maxfd = 1 + std::max(sd, control_fd[0]);
    waitingPong = false;
    // Declare ping channel for kernel that requires it.
    send("if (isdef(Channel)) var lobby.%s = Channel.new(\"%s\") | {};",
	internalPongTag.c_str(), internalPongTag.c_str());
    while (true)
    {
      if (sd == -1)
        return;

      fd_set rfds;
      FD_ZERO(&rfds);
      LIBPORT_FD_SET(sd, &rfds);

      fd_set efds;
      FD_ZERO(&efds);
      LIBPORT_FD_SET(sd, &efds);

#ifndef WIN32
      LIBPORT_FD_SET(control_fd[0], &rfds);
#endif

      int selectReturn;
      if (pingInterval)
      {
        const unsigned delay = waitingPong ? pongTimeout : pingInterval;
        struct timeval timeout = { delay / 1000, (delay % 1000) * 1000};
        selectReturn = ::select(maxfd + 1, &rfds, NULL, &efds, &timeout);
      }
      else
      {
        selectReturn = ::select(maxfd + 1, &rfds, NULL, &efds, NULL);
      }

      if (sd < 0)
	return;

      // Treat error
      if (selectReturn < 0 && errno != EINTR)
      {
        rc = -1;
        clientError("Connection error : ", errno);
        notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                 "!!! Connection error", std::list<BinaryData>() ));
        return;
      }

      if (selectReturn < 0)  // ::select catch a signal (errno == EINTR)
        continue;
      // timeout
      else if (selectReturn == 0)
      {
        if (waitingPong) // Timeout while waiting PONG
        {
          rc = -1;
          // FIXME: Choose between two differents way to alert user program
          clientError("Lost connection with server");
          notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                   "!!! Lost connection with server",
                                   std::list<BinaryData>() ));
          return;
        }
        else // Timeout : Ping_interval
        {
          send("%s << 1,", internalPongTag.c_str());
          waitingPong = true;
        }
      }
      else
      {
        // We receive data, at least the "1" value sent through the pong tag
        // channel so we are no longer waiting for a pong.
        waitingPong = false;
        int count = ::recv(sd, &recvBuffer[recvBufferPosition],
                           buflen - recvBufferPosition - 1, 0);

        if (count <= 0)
        {
          std::string errorMsg;
          int         errorCode = 0;

          if (count < 0)
          {
#ifdef WIN32
            errorCode = WSAGetLastError();
#else
            errorCode = errno;
#endif
            errorMsg = "!!! Connection error";
          }
          else // count == 0  => Connection close
          {
            errorMsg = "!!! Connection closed";
          }

          rc = -1;
          clientError(errorMsg.c_str(), errorCode);
          notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag.c_str(),
                                   errorMsg.c_str(), std::list<BinaryData>() ));
          return;
        }

        recvBufferPosition += count;
        recvBuffer[recvBufferPosition] = 0;
        processRecvBuffer();
      }
    }
  }

  void
  UClient::printf(const char * format, ...)
  {
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr, format, arg);
    va_end(arg);
  }

  unsigned int UClient::getCurrentTime() const
  {
  // FIXME: Put this into libport.
#ifdef WIN32
    return GetTickCount();
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec*1000+tv.tv_usec/1000;
#endif
  }

  void execute()
  {
    while (true)
      sleep(100);
  }

  void exit(int code)
  {
    ::exit(code);
  }

  UClient& connect(const std::string& host)
  {
    return *new UClient(host);
  }

  void disconnect(UClient &client)
  {
    delete &client;
  }

  void
  UClient::setKeepAliveCheck(const unsigned pingInterval,
                             const unsigned pongTimeout)
  {
    this->pingInterval = pingInterval;
    this->pongTimeout  = pongTimeout;
  }

} // namespace urbi
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file liburbi/uclient.cc

#if !defined WIN32
# include <libport/ctime>
# include <libport/csignal>
#endif

#include <boost/lambda/bind.hpp>

#include <libport/boost-error.hh>
#include <libport/format.hh>

#include <urbi/uclient.hh>
#include <urbi/utag.hh>

#include <liburbi/compatibility.hh>

GD_CATEGORY(Urbi.Client);

namespace urbi
{

  /*-------------------.
  | UClient::options.  |
  `-------------------*/

  UClient::options::options(bool server)
    : server_(server)
      // Unless stated otherwise, auto start.
    , start_(true)
    , asynchronous_(false)
  {
  }

  UCLIENT_OPTION_IMPL(UClient, bool, server)
  UCLIENT_OPTION_IMPL(UClient, bool, start)
  UCLIENT_OPTION_IMPL(UClient, bool, asynchronous)

  /*----------.
  | UClient.  |
  `----------*/

  UClient::UClient(const std::string& host, unsigned port,
                   size_t buflen,
                   const options& opt)
    : UAbstractClient(host, port, buflen, opt.server())
    , ping_interval_(0)
    , pong_timeout_(0)
    , link_(new UClient*(this))
    , ping_sent_(libport::utime())
    , ping_sem_(0)
    , asynchronous_(opt.asynchronous())
    , synchronous_send_(false)
  {
    if (opt.start())
      start();
  }

  UClient::error_type
  UClient::start()
  {
    return rc = server_ ? listen_() : connect_();
  }

  UClient::error_type
  UClient::connect_()
  {
    if (boost::system::error_code erc = connect(host_, port_, false, 0,
                                                asynchronous_))
    {
      libport::boost_error(libport::format("UClient::UClient connect(%s, %s)",
                                           host_, port_),
                           erc);
      return -1;
    }
    else
      return 0;
  }

  UClient::error_type
  UClient::listen_()
  {
    if (boost::system::error_code erc =
        listen(boost::bind(&UClient::mySocketFactory, this), host_, port_))
    {
      libport::boost_error(libport::format("UClient::UClient listen(%s, %s)",
                                           host_, port_),
                           erc);
      return -1;
    }
    else
      return 0;
  }

  UClient::~UClient()
  {
    *link_ = 0;
    closeUClient();
  }

  UClient::error_type
  UClient::onClose()
  {
    if (closed_)
      return 1;
    UAbstractClient::onClose();
    return 0;
  }

  UClient::error_type
  UClient::closeUClient()
  {
    close();
    onClose();
    return 0;
  }

  UClient::error_type
  UClient::effectiveSend(const void* buffer, size_t size)
  {
    if (rc)
      return -1;
    if (synchronous_send_)
      libport::Socket::syncWrite(buffer, size);
    else
      libport::Socket::write(buffer, size);
    return 0;
  }

  libport::Socket*
  UClient::mySocketFactory()
  {
    return this;
  }

  void
  UClient::onConnect()
  {
    init_ = true;
    onConnection();

    // Declare ping channel for kernel that requires it.  Do not try
    // to depend on kernelMajor, because it has not been computed yet.
    // And computing kernelMajor requires this code to be run.  So we
    // need to write something that both k1 and k2 will like.
    send(SYNCLINE_WRAP(
           "if (isdef(Channel))\n"
           "  var lobby.%s = Channel.new(\"%s\")|;",
           internalPongTag, internalPongTag));
    // The folowwing calls may fail if we got disconnected.
    try
    {
      host_ = getRemoteHost();
      port_ = getRemotePort();
    }
    catch(const std::exception&)
    { // Ignore the error, next read attempt will trigger onError.
    }
    if (ping_interval_)
      sendPing(link_);
  }

  void
  UClient::onError(boost::system::error_code erc)
  {
    rc = -1;
    resetAsyncCalls_();
    clientError("!!! " + erc.message());
    notifyCallbacks(UMessage(*this, 0, CLIENTERROR_TAG,
                             "!!! " + erc.message()));
    return;
  }

  size_t
  UClient::onRead(const void* data, size_t length)
  {
    size_t capacity = recvBufSize - recvBufferPosition - 1;

    if (ping_interval_ && ping_sem_.uget(1))
    {
      pong_timeout_handler_->cancel();
      send_ping_handler_ =
        libport::asyncCall(boost::bind(&UClient::sendPing,
                                       this, link_),
                           ping_interval_ - (libport::utime() - ping_sent_));
    }
    if (capacity < length)
    {
      size_t nsz = std::max(recvBufSize*2, recvBufferPosition + length+1);
      char* nbuf = new char[nsz];
      memcpy(nbuf, recvBuffer, recvBufferPosition);
      delete[] recvBuffer;
      recvBuffer = nbuf;
      recvBufSize = nsz;
    }
    memcpy(&recvBuffer[recvBufferPosition], data, length);
    recvBufferPosition += length;
    recvBuffer[recvBufferPosition] = 0;
    processRecvBuffer();
    return length;
  }

  void
  UClient::pongTimeout(link_type l)
  {
    if (*l)
    {
      const char* err = "!!! Lost connection with server: ping timeout";
      // FIXME: Choose between two differents way to alert user program.
      clientError(err);
      notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag, err));
      close();
    }
  }

  void
  UClient::sendPing(link_type l)
  {
    if (*l)
    {
      pong_timeout_handler_ =
        libport::asyncCall(boost::bind(&UClient::pongTimeout, this, link_),
                           pong_timeout_);
      send("%s << 1,", internalPongTag);
      ping_sent_ = libport::utime();
      ping_sem_++;
    }
  }

  void
  UClient::printf(const char * format, ...)
  {
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr, format, arg);
    va_end(arg);
  }

  unsigned int UClient::getCurrentTime() const
  {
  // FIXME: Put this into libport.
#ifdef WIN32
    return GetTickCount();
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec*1000+tv.tv_usec/1000;
#endif
  }

  void
  UClient::setKeepAliveCheck(unsigned ping_interval,
                             unsigned pong_timeout)
  {
    // Always interrupt previous ping handler.
    resetAsyncCalls_();
    // From milliseconds to microseconds.
    ping_interval_ = ping_interval * 1000;
    pong_timeout_  = pong_timeout * 1000;
    if (ping_interval_)
      sendPing(link_);
  }

  void
  UClient::resetAsyncCalls_()
  {
    if (pong_timeout_handler_)
    {
      pong_timeout_handler_->cancel();
      pong_timeout_handler_.reset();
    }
    if (send_ping_handler_)
    {
      send_ping_handler_->cancel();
      send_ping_handler_.reset();
    }
  }

  void
  UClient::waitForKernelVersion() const
  {
    // FIXME: use a condition.
    while (kernelMajor_ < 0 && !error())
      sleep(100000);
  }

  void
  UClient::setSynchronousSend(bool enable)
  {
    synchronous_send_ = enable;
  }
/*-----------------------.
| Standalone functions.  |
`-----------------------*/

  void execute()
  {
    while (true)
      sleep(100);
  }

  void exit(int code)
  {
    ::exit(code);
  }

  UClient&
  connect(const std::string& host)
  {
    return *new UClient(host);
  }

  void disconnect(UClient &client)
  {
    // Asynchronous deletion to let our async handlers terminate.
    client.destroy();
  }

} // namespace urbi
<commit_msg>uclient: style changes.<commit_after>/*
 * Copyright (C) 2005-2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

/// \file liburbi/uclient.cc

#if !defined WIN32
# include <libport/ctime>
# include <libport/csignal>
#endif

#include <boost/lambda/bind.hpp>

#include <libport/boost-error.hh>
#include <libport/format.hh>

#include <urbi/uclient.hh>
#include <urbi/utag.hh>

#include <liburbi/compatibility.hh>

GD_CATEGORY(Urbi.Client);

namespace urbi
{

  /*-------------------.
  | UClient::options.  |
  `-------------------*/

  UClient::options::options(bool server)
    : server_(server)
      // Unless stated otherwise, auto start.
    , start_(true)
    , asynchronous_(false)
  {
  }

  UCLIENT_OPTION_IMPL(UClient, bool, server)
  UCLIENT_OPTION_IMPL(UClient, bool, start)
  UCLIENT_OPTION_IMPL(UClient, bool, asynchronous)

  /*----------.
  | UClient.  |
  `----------*/

  UClient::UClient(const std::string& host, unsigned port,
                   size_t buflen,
                   const options& opt)
    : UAbstractClient(host, port, buflen, opt.server())
    , ping_interval_(0)
    , pong_timeout_(0)
    , link_(new UClient*(this))
    , ping_sent_(libport::utime())
    , ping_sem_(0)
    , asynchronous_(opt.asynchronous())
    , synchronous_send_(false)
  {
    if (opt.start())
      start();
  }

  UClient::error_type
  UClient::start()
  {
    return rc = server_ ? listen_() : connect_();
  }

  UClient::error_type
  UClient::connect_()
  {
    if (boost::system::error_code erc = connect(host_, port_, false, 0,
                                                asynchronous_))
    {
      libport::boost_error(libport::format("UClient::UClient connect(%s, %s)",
                                           host_, port_),
                           erc);
      return -1;
    }
    else
      return 0;
  }

  UClient::error_type
  UClient::listen_()
  {
    if (boost::system::error_code erc =
        listen(boost::bind(&UClient::mySocketFactory, this), host_, port_))
    {
      libport::boost_error(libport::format("UClient::UClient listen(%s, %s)",
                                           host_, port_),
                           erc);
      return -1;
    }
    else
      return 0;
  }

  UClient::~UClient()
  {
    *link_ = 0;
    closeUClient();
  }

  UClient::error_type
  UClient::onClose()
  {
    if (!closed_)
      UAbstractClient::onClose();
    return !!closed_;
  }

  UClient::error_type
  UClient::closeUClient()
  {
    close();
    onClose();
    return 0;
  }

  UClient::error_type
  UClient::effectiveSend(const void* buffer, size_t size)
  {
    if (rc)
      return -1;
    if (synchronous_send_)
      libport::Socket::syncWrite(buffer, size);
    else
      libport::Socket::write(buffer, size);
    return 0;
  }

  libport::Socket*
  UClient::mySocketFactory()
  {
    return this;
  }

  void
  UClient::onConnect()
  {
    init_ = true;
    onConnection();

    // Declare ping channel for kernel that requires it.  Do not try
    // to depend on kernelMajor, because it has not been computed yet.
    // And computing kernelMajor requires this code to be run.  So we
    // need to write something that both k1 and k2 will like.
    send(SYNCLINE_WRAP(
           "if (isdef(Channel))\n"
           "  var lobby.%s = Channel.new(\"%s\")|;",
           internalPongTag, internalPongTag));
    // The folowwing calls may fail if we got disconnected.
    try
    {
      host_ = getRemoteHost();
      port_ = getRemotePort();
    }
    catch (const std::exception& e)
    {
      // Ignore the error, next read attempt will trigger onError.
      GD_FINFO_DUMP("ignore std::exception: %s", e.what());
    }
    if (ping_interval_)
      sendPing(link_);
  }

  void
  UClient::onError(boost::system::error_code erc)
  {
    rc = -1;
    resetAsyncCalls_();
    clientError("!!! " + erc.message());
    notifyCallbacks(UMessage(*this, 0, CLIENTERROR_TAG,
                             "!!! " + erc.message()));
    return;
  }

  size_t
  UClient::onRead(const void* data, size_t length)
  {
    size_t capacity = recvBufSize - recvBufferPosition - 1;

    if (ping_interval_ && ping_sem_.uget(1))
    {
      pong_timeout_handler_->cancel();
      send_ping_handler_ =
        libport::asyncCall(boost::bind(&UClient::sendPing,
                                       this, link_),
                           ping_interval_ - (libport::utime() - ping_sent_));
    }
    if (capacity < length)
    {
      size_t nsz = std::max(recvBufSize*2, recvBufferPosition + length+1);
      char* nbuf = new char[nsz];
      memcpy(nbuf, recvBuffer, recvBufferPosition);
      delete[] recvBuffer;
      recvBuffer = nbuf;
      recvBufSize = nsz;
    }
    memcpy(&recvBuffer[recvBufferPosition], data, length);
    recvBufferPosition += length;
    recvBuffer[recvBufferPosition] = 0;
    processRecvBuffer();
    return length;
  }

  void
  UClient::pongTimeout(link_type l)
  {
    if (*l)
    {
      const char* err = "!!! Lost connection with server: ping timeout";
      // FIXME: Choose between two differents way to alert user program.
      clientError(err);
      notifyCallbacks(UMessage(*this, 0, connectionTimeoutTag, err));
      close();
    }
  }

  void
  UClient::sendPing(link_type l)
  {
    if (*l)
    {
      pong_timeout_handler_ =
        libport::asyncCall(boost::bind(&UClient::pongTimeout, this, link_),
                           pong_timeout_);
      send("%s << 1,", internalPongTag);
      ping_sent_ = libport::utime();
      ping_sem_++;
    }
  }

  void
  UClient::printf(const char * format, ...)
  {
    va_list arg;
    va_start(arg, format);
    vfprintf(stderr, format, arg);
    va_end(arg);
  }

  unsigned int UClient::getCurrentTime() const
  {
  // FIXME: Put this into libport.
#ifdef WIN32
    return GetTickCount();
#else
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return tv.tv_sec*1000+tv.tv_usec/1000;
#endif
  }

  void
  UClient::setKeepAliveCheck(unsigned ping_interval,
                             unsigned pong_timeout)
  {
    // Always interrupt previous ping handler.
    resetAsyncCalls_();
    // From milliseconds to microseconds.
    ping_interval_ = ping_interval * 1000;
    pong_timeout_  = pong_timeout * 1000;
    if (ping_interval_)
      sendPing(link_);
  }

  void
  UClient::resetAsyncCalls_()
  {
    if (pong_timeout_handler_)
    {
      pong_timeout_handler_->cancel();
      pong_timeout_handler_.reset();
    }
    if (send_ping_handler_)
    {
      send_ping_handler_->cancel();
      send_ping_handler_.reset();
    }
  }

  void
  UClient::waitForKernelVersion() const
  {
    // FIXME: use a condition.
    while (kernelMajor_ < 0 && !error())
      sleep(100000);
  }

  void
  UClient::setSynchronousSend(bool enable)
  {
    synchronous_send_ = enable;
  }

/*-----------------------.
| Standalone functions.  |
`-----------------------*/

  void execute()
  {
    while (true)
      sleep(100);
  }

  void exit(int code)
  {
    ::exit(code);
  }

  UClient&
  connect(const std::string& host)
  {
    return *new UClient(host);
  }

  void disconnect(UClient &client)
  {
    // Asynchronous deletion to let our async handlers terminate.
    client.destroy();
  }

} // namespace urbi
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "quicktest.h"
#include "quicktestresult_p.h"
#include <QtTest/qtestsystem.h>
#include "qtestoptions_p.h"
#include <QtQml/qqml.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qjsvalue.h>
#include <QtQml/qjsengine.h>
#include <QtGui/qopengl.h>
#include <QtCore/qurl.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
#include <QtCore/qeventloop.h>
#include <QtCore/qtextstream.h>
#include <QtGui/qtextdocument.h>
#include <stdio.h>
#include <QtGui/QGuiApplication>
#include <QtCore/QTranslator>
#include <QtTest/QSignalSpy>

QT_BEGIN_NAMESPACE

class QTestRootObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
    Q_PROPERTY(bool hasTestCase READ hasTestCase WRITE setHasTestCase NOTIFY hasTestCaseChanged)
public:
    QTestRootObject(QObject *parent = 0)
        : QObject(parent), hasQuit(false), m_windowShown(false), m_hasTestCase(false)  {}

    bool hasQuit:1;
    bool hasTestCase() const { return m_hasTestCase; }
    void setHasTestCase(bool value) { m_hasTestCase = value; emit hasTestCaseChanged(); }

    bool windowShown() const { return m_windowShown; }
    void setWindowShown(bool value) { m_windowShown = value; emit windowShownChanged(); }

Q_SIGNALS:
    void windowShownChanged();
    void hasTestCaseChanged();

private Q_SLOTS:
    void quit() { hasQuit = true; }

private:
    bool m_windowShown : 1;
    bool m_hasTestCase :1;
};

static inline QString stripQuotes(const QString &s)
{
    if (s.length() >= 2 && s.startsWith(QLatin1Char('"')) && s.endsWith(QLatin1Char('"')))
        return s.mid(1, s.length() - 2);
    else
        return s;
}

void handleCompileErrors(const QFileInfo &fi, QQuickView *view)
{
    // Error compiling the test - flag failure in the log and continue.
    const QList<QQmlError> errors = view->errors();
    QuickTestResult results;
    results.setTestCaseName(fi.baseName());
    results.startLogging();
    results.setFunctionName(QLatin1String("compile"));
    // Verbose warning output of all messages and relevant parameters
    QString message;
    QTextStream str(&message);
    str << "\n  " << QDir::toNativeSeparators(fi.absoluteFilePath()) << " produced "
        << errors.size() << " error(s):\n";
    foreach (const QQmlError &e, errors) {
        str << "    ";
        if (e.url().isLocalFile()) {
            str << e.url().toLocalFile();
        } else {
            str << e.url().toString();
        }
        if (e.line() > 0)
            str << ':' << e.line() << ',' << e.column();
        str << ": " << e.description() << '\n';
    }
    str << "  Working directory: " << QDir::toNativeSeparators(QDir::current().absolutePath()) << '\n';
    if (QQmlEngine *engine = view->engine()) {
        str << "  View: " << view->metaObject()->className() << ", import paths:\n";
        foreach (const QString &i, engine->importPathList())
            str << "    '" << QDir::toNativeSeparators(i) << "'\n";
        const QStringList pluginPaths = engine->pluginPathList();
        str << "  Plugin paths:\n";
        foreach (const QString &p, pluginPaths)
            str << "    '" << QDir::toNativeSeparators(p) << "'\n";
    }
    qWarning("%s", qPrintable(message));
    // Fail with error 0.
    results.fail(errors.at(0).description(),
                 errors.at(0).url(), errors.at(0).line());
    results.finishTestData();
    results.finishTestDataCleanup();
    results.finishTestFunction();
    results.setFunctionName(QString());
    results.stopLogging();
}

bool qWaitForSignal(QObject *obj, const char* signal, int timeout = 5000)
{
    QSignalSpy spy(obj, signal);
    QElapsedTimer timer;
    timer.start();

    while (!spy.size()) {
        int remaining = timeout - int(timer.elapsed());
        if (remaining <= 0)
            break;
        QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
        QTest::qSleep(10);
    }

    return spy.size();
}

int quick_test_main(int argc, char **argv, const char *name, const char *sourceDir)
{
    QGuiApplication* app = 0;
    if (!QCoreApplication::instance()) {
        app = new QGuiApplication(argc, argv);
    }

    // Look for QML-specific command-line options.
    //      -import dir         Specify an import directory.
    //      -input dir          Specify the input directory for test cases.
    //      -translation file   Specify the translation file.
    QStringList imports;
    QString testPath;
    QString translationFile;
    int outargc = 1;
    int index = 1;
    while (index < argc) {
        if (strcmp(argv[index], "-import") == 0 && (index + 1) < argc) {
            imports += stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (strcmp(argv[index], "-input") == 0 && (index + 1) < argc) {
            testPath = stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (strcmp(argv[index], "-opengl") == 0) {
            ++index;
        } else if (strcmp(argv[index], "-translation") == 0 && (index + 1) < argc) {
            translationFile = stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (outargc != index) {
            argv[outargc++] = argv[index++];
        } else {
            ++outargc;
            ++index;
        }
    }
    argv[outargc] = 0;
    argc = outargc;

    // Parse the command-line arguments.

    // Setting currentAppname and currentTestObjectName (via setProgramName) are needed
    // for the code coverage analysis. Must be done before parseArgs is called.
    QuickTestResult::setCurrentAppname(argv[0]);
    QuickTestResult::setProgramName(name);

    QuickTestResult::parseArgs(argc, argv);

    QTranslator translator;
    if (!translationFile.isEmpty()) {
        if (translator.load(translationFile)) {
            app->installTranslator(&translator);
        } else {
            qWarning("Could not load the translation file '%s'.", qPrintable(translationFile));
        }
    }

    // Determine where to look for the test data.
    if (testPath.isEmpty() && sourceDir) {
        const QString s = QString::fromLocal8Bit(sourceDir);
        if (QFile::exists(s))
            testPath = s;
    }
    if (testPath.isEmpty()) {
        QDir current = QDir::current();
#ifdef Q_OS_WIN
        // Skip release/debug subfolders
        if (!current.dirName().compare(QLatin1String("Release"), Qt::CaseInsensitive)
            || !current.dirName().compare(QLatin1String("Debug"), Qt::CaseInsensitive))
            current.cdUp();
#endif // Q_OS_WIN
        testPath = current.absolutePath();
    }
    QStringList files;

    const QFileInfo testPathInfo(testPath);
    if (testPathInfo.isFile()) {
        if (!testPath.endsWith(QStringLiteral(".qml"))) {
            qWarning("'%s' does not have the suffix '.qml'.", qPrintable(testPath));
            return 1;
        }
        files << testPath;
    } else if (testPathInfo.isDir()) {
        // Scan the test data directory recursively, looking for "tst_*.qml" files.
        const QStringList filters(QStringLiteral("tst_*.qml"));
        QDirIterator iter(testPathInfo.absoluteFilePath(), filters, QDir::Files,
                          QDirIterator::Subdirectories |
                          QDirIterator::FollowSymlinks);
        while (iter.hasNext())
            files += iter.next();
        files.sort();
        if (files.isEmpty()) {
            qWarning("The directory '%s' does not contain any test files matching '%s'",
                     qPrintable(testPath), qPrintable(filters.front()));
            return 1;
        }
    } else {
        qWarning("'%s' does not exist under '%s'.",
                 qPrintable(testPath), qPrintable(QDir::currentPath()));
        return 1;
    }

    // Scan through all of the "tst_*.qml" files and run each of them
    // in turn with a QQuickView.
    QQuickView *view = new QQuickView;
    QTestRootObject rootobj;
    QEventLoop eventLoop;
    QObject::connect(view->engine(), SIGNAL(quit()),
                     &rootobj, SLOT(quit()));
    QObject::connect(view->engine(), SIGNAL(quit()),
                     &eventLoop, SLOT(quit()));
    view->rootContext()->setContextProperty
        (QLatin1String("qtest"), &rootobj);
    foreach (const QString &path, imports)
        view->engine()->addImportPath(path);

    foreach (QString file, files) {
        QFileInfo fi(file);
        if (!fi.exists())
            continue;

        rootobj.setHasTestCase(false);
        rootobj.setWindowShown(false);
        rootobj.hasQuit = false;
        QString path = fi.absoluteFilePath();
        if (path.startsWith(QLatin1String(":/")))
            view->setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
        else
            view->setSource(QUrl::fromLocalFile(path));

        if (QTest::printAvailableFunctions)
            continue;
        if (view->status() == QQuickView::Error) {
            handleCompileErrors(fi, view);
            continue;
        }
        if (!rootobj.hasQuit) {
            // If the test already quit, then it was performed
            // synchronously during setSource().  Otherwise it is
            // an asynchronous test and we need to show the window
            // and wait for the first frame to be rendered
            // and then wait for quit indication.
            view->show();
            if (qWaitForSignal(view, SIGNAL(frameSwapped())))
                rootobj.setWindowShown(true);
            if (!rootobj.hasQuit && rootobj.hasTestCase())
                eventLoop.exec();
        }
    }

    // Flush the current logging stream.
    QuickTestResult::setProgramName(0);
    delete view;
    delete app;

    // Return the number of failures as the exit code.
    return QuickTestResult::exitCode();
}

QT_END_NAMESPACE

#include "quicktest.moc"
<commit_msg>Fix qmltest library.<commit_after>/****************************************************************************
**
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "quicktest.h"
#include "quicktestresult_p.h"
#include <QtTest/qtestsystem.h>
#include "qtestoptions_p.h"
#include <QtQml/qqml.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQuick/qquickview.h>
#include <QtQml/qjsvalue.h>
#include <QtQml/qjsengine.h>
#include <QtGui/qopengl.h>
#include <QtCore/qurl.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qdir.h>
#include <QtCore/qdiriterator.h>
#include <QtCore/qfile.h>
#include <QtCore/qdebug.h>
#include <QtCore/qeventloop.h>
#include <QtCore/qtextstream.h>
#include <QtGui/qtextdocument.h>
#include <stdio.h>
#include <QtGui/QGuiApplication>
#include <QtCore/QTranslator>
#include <QtTest/QSignalSpy>

QT_BEGIN_NAMESPACE

class QTestRootObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool windowShown READ windowShown NOTIFY windowShownChanged)
    Q_PROPERTY(bool hasTestCase READ hasTestCase WRITE setHasTestCase NOTIFY hasTestCaseChanged)
public:
    QTestRootObject(QObject *parent = 0)
        : QObject(parent), hasQuit(false), m_windowShown(false), m_hasTestCase(false)  {}

    bool hasQuit:1;
    bool hasTestCase() const { return m_hasTestCase; }
    void setHasTestCase(bool value) { m_hasTestCase = value; emit hasTestCaseChanged(); }

    bool windowShown() const { return m_windowShown; }
    void setWindowShown(bool value) { m_windowShown = value; emit windowShownChanged(); }

Q_SIGNALS:
    void windowShownChanged();
    void hasTestCaseChanged();

private Q_SLOTS:
    void quit() { hasQuit = true; }

private:
    bool m_windowShown : 1;
    bool m_hasTestCase :1;
};

static inline QString stripQuotes(const QString &s)
{
    if (s.length() >= 2 && s.startsWith(QLatin1Char('"')) && s.endsWith(QLatin1Char('"')))
        return s.mid(1, s.length() - 2);
    else
        return s;
}

void handleCompileErrors(const QFileInfo &fi, QQuickView *view)
{
    // Error compiling the test - flag failure in the log and continue.
    const QList<QQmlError> errors = view->errors();
    QuickTestResult results;
    results.setTestCaseName(fi.baseName());
    results.startLogging();
    results.setFunctionName(QLatin1String("compile"));
    // Verbose warning output of all messages and relevant parameters
    QString message;
    QTextStream str(&message);
    str << "\n  " << QDir::toNativeSeparators(fi.absoluteFilePath()) << " produced "
        << errors.size() << " error(s):\n";
    foreach (const QQmlError &e, errors) {
        str << "    ";
        if (e.url().isLocalFile()) {
            str << QDir::toNativeSeparators(e.url().toLocalFile());
        } else {
            str << e.url().toString();
        }
        if (e.line() > 0)
            str << ':' << e.line() << ',' << e.column();
        str << ": " << e.description() << '\n';
    }
    str << "  Working directory: " << QDir::toNativeSeparators(QDir::current().absolutePath()) << '\n';
    if (QQmlEngine *engine = view->engine()) {
        str << "  View: " << view->metaObject()->className() << ", import paths:\n";
        foreach (const QString &i, engine->importPathList())
            str << "    '" << QDir::toNativeSeparators(i) << "'\n";
        const QStringList pluginPaths = engine->pluginPathList();
        str << "  Plugin paths:\n";
        foreach (const QString &p, pluginPaths)
            str << "    '" << QDir::toNativeSeparators(p) << "'\n";
    }
    qWarning("%s", qPrintable(message));
    // Fail with error 0.
    results.fail(errors.at(0).description(),
                 errors.at(0).url(), errors.at(0).line());
    results.finishTestData();
    results.finishTestDataCleanup();
    results.finishTestFunction();
    results.setFunctionName(QString());
    results.stopLogging();
}

bool qWaitForSignal(QObject *obj, const char* signal, int timeout = 5000)
{
    QSignalSpy spy(obj, signal);
    QElapsedTimer timer;
    timer.start();

    while (!spy.size()) {
        int remaining = timeout - int(timer.elapsed());
        if (remaining <= 0)
            break;
        QCoreApplication::processEvents(QEventLoop::AllEvents, remaining);
        QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
        QTest::qSleep(10);
    }

    return spy.size();
}

int quick_test_main(int argc, char **argv, const char *name, const char *sourceDir)
{
    QGuiApplication* app = 0;
    if (!QCoreApplication::instance()) {
        app = new QGuiApplication(argc, argv);
    }

    // Look for QML-specific command-line options.
    //      -import dir         Specify an import directory.
    //      -input dir          Specify the input directory for test cases.
    //      -translation file   Specify the translation file.
    QStringList imports;
    QString testPath;
    QString translationFile;
    int outargc = 1;
    int index = 1;
    while (index < argc) {
        if (strcmp(argv[index], "-import") == 0 && (index + 1) < argc) {
            imports += stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (strcmp(argv[index], "-input") == 0 && (index + 1) < argc) {
            testPath = stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (strcmp(argv[index], "-opengl") == 0) {
            ++index;
        } else if (strcmp(argv[index], "-translation") == 0 && (index + 1) < argc) {
            translationFile = stripQuotes(QString::fromLocal8Bit(argv[index + 1]));
            index += 2;
        } else if (outargc != index) {
            argv[outargc++] = argv[index++];
        } else {
            ++outargc;
            ++index;
        }
    }
    argv[outargc] = 0;
    argc = outargc;

    // Parse the command-line arguments.

    // Setting currentAppname and currentTestObjectName (via setProgramName) are needed
    // for the code coverage analysis. Must be done before parseArgs is called.
    QuickTestResult::setCurrentAppname(argv[0]);
    QuickTestResult::setProgramName(name);

    QuickTestResult::parseArgs(argc, argv);

    QTranslator translator;
    if (!translationFile.isEmpty()) {
        if (translator.load(translationFile)) {
            app->installTranslator(&translator);
        } else {
            qWarning("Could not load the translation file '%s'.", qPrintable(translationFile));
        }
    }

    // Determine where to look for the test data.
    if (testPath.isEmpty() && sourceDir) {
        const QString s = QString::fromLocal8Bit(sourceDir);
        if (QFile::exists(s))
            testPath = s;
    }
    if (testPath.isEmpty()) {
        QDir current = QDir::current();
#ifdef Q_OS_WIN
        // Skip release/debug subfolders
        if (!current.dirName().compare(QLatin1String("Release"), Qt::CaseInsensitive)
            || !current.dirName().compare(QLatin1String("Debug"), Qt::CaseInsensitive))
            current.cdUp();
#endif // Q_OS_WIN
        testPath = current.absolutePath();
    }
    QStringList files;

    const QFileInfo testPathInfo(testPath);
    if (testPathInfo.isFile()) {
        if (!testPath.endsWith(QStringLiteral(".qml"))) {
            qWarning("'%s' does not have the suffix '.qml'.", qPrintable(testPath));
            return 1;
        }
        files << testPath;
    } else if (testPathInfo.isDir()) {
        // Scan the test data directory recursively, looking for "tst_*.qml" files.
        const QStringList filters(QStringLiteral("tst_*.qml"));
        QDirIterator iter(testPathInfo.absoluteFilePath(), filters, QDir::Files,
                          QDirIterator::Subdirectories |
                          QDirIterator::FollowSymlinks);
        while (iter.hasNext())
            files += iter.next();
        files.sort();
        if (files.isEmpty()) {
            qWarning("The directory '%s' does not contain any test files matching '%s'",
                     qPrintable(testPath), qPrintable(filters.front()));
            return 1;
        }
    } else {
        qWarning("'%s' does not exist under '%s'.",
                 qPrintable(testPath), qPrintable(QDir::currentPath()));
        return 1;
    }

    // Scan through all of the "tst_*.qml" files and run each of them
    // in turn with a QQuickView.
    QQuickView *view = new QQuickView;
    view->setWindowFlags(Qt::Window | Qt::WindowSystemMenuHint
                         | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint
                         | Qt::WindowCloseButtonHint);
    QTestRootObject rootobj;
    QEventLoop eventLoop;
    QObject::connect(view->engine(), SIGNAL(quit()),
                     &rootobj, SLOT(quit()));
    QObject::connect(view->engine(), SIGNAL(quit()),
                     &eventLoop, SLOT(quit()));
    view->rootContext()->setContextProperty
        (QLatin1String("qtest"), &rootobj);
    foreach (const QString &path, imports)
        view->engine()->addImportPath(path);
    foreach (const QString &file, files) {
        const QFileInfo fi(file);
        if (!fi.exists())
            continue;

        view->setObjectName(fi.baseName());
        view->setWindowTitle(view->objectName());
        rootobj.setHasTestCase(false);
        rootobj.setWindowShown(false);
        rootobj.hasQuit = false;
        QString path = fi.absoluteFilePath();
        if (path.startsWith(QLatin1String(":/")))
            view->setSource(QUrl(QLatin1String("qrc:") + path.mid(2)));
        else
            view->setSource(QUrl::fromLocalFile(path));

        if (QTest::printAvailableFunctions)
            continue;
        if (view->status() == QQuickView::Error) {
            handleCompileErrors(fi, view);
            continue;
        }
        if (!rootobj.hasQuit) {
            // If the test already quit, then it was performed
            // synchronously during setSource().  Otherwise it is
            // an asynchronous test and we need to show the window
            // and wait for the first frame to be rendered
            // and then wait for quit indication.
            view->setFramePos(QPoint(50, 50));
            if (view->size().isEmpty()) { // Avoid hangs with empty windows.
                qWarning().nospace()
                    << "Test '" << QDir::toNativeSeparators(path) << "' has invalid size "
                    << view->size() << ", resizing.";
                view->resize(200, 200);
            }
            view->show();
            if (qWaitForSignal(view, SIGNAL(frameSwapped())))
                rootobj.setWindowShown(true);
            if (!rootobj.hasQuit && rootobj.hasTestCase())
                eventLoop.exec();
            view->hide();
        }
    }

    // Flush the current logging stream.
    QuickTestResult::setProgramName(0);
    delete view;
    delete app;

    // Return the number of failures as the exit code.
    return QuickTestResult::exitCode();
}

QT_END_NAMESPACE

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


<commit_before>#include "MainPanel.h"

#include <QMessageBox>
#include <QGridLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QSettings>

QString g_getStylesheet(QString location)
{
    QFile stylesheet(location);
    if (stylesheet.open(QFile::ReadOnly))
    {
        QString styleSheet = stylesheet.readAll();
        return styleSheet;
    }
    return "";
}

MainPanel::MainPanel(QWidget* parent)
    : QWidget(parent)
{
    setObjectName("mainPanel");

    init();
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    show();
}

void MainPanel::init()
{
    if (!db.init())
    {
        QMessageBox error;
        error.critical(0, "Error!", "An error occured while trying to load the database.");
        exit(EXIT_FAILURE);
        return;
    }

    QString style = g_getStylesheet(":/Styles/Content.css");
    QSettings p("palette.ini", QSettings::IniFormat);

    setObjectName("mainPanel");
    setStyleSheet("background-color: " + p.value("Primary/DarkestBase").toString() + ";");

    // Main panel layout
    QGridLayout *mainGridLayout = new QGridLayout(this);
    mainGridLayout->setSpacing(0);
    mainGridLayout->setMargin(0);
    setLayout(mainGridLayout);

    // Main panel scroll area
    QScrollArea *scrollArea = new QScrollArea(this);
    scrollArea->setWidgetResizable(true);
    scrollArea->setObjectName("mainPanelScrollArea");
    scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    mainGridLayout->addWidget(scrollArea);

    // Core widget
    QWidget *coreWidget = new QWidget(this);
    coreWidget->setObjectName("centralWidget");
    coreWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scrollArea->setWidget(coreWidget);

    // Vertical layout #1
    QVBoxLayout *verticalLayout1 = new QVBoxLayout(this);
    verticalLayout1->setSpacing(0);
    verticalLayout1->setMargin(0);
    verticalLayout1->setAlignment(Qt::AlignHCenter);
    coreWidget->setLayout(verticalLayout1);

    // Accent border
    QLabel *accentBorder = new QLabel(this);
    accentBorder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    accentBorder->setMaximumHeight(3);
    accentBorder->setStyleSheet("background-color: " + p.value("Primary/DarkestBase").toString() +
                                ";border-top: 2px solid " + p.value("Accent/MediumAccent").toString() +
                                ";border-bottom: 1px solid" + p.value("Accent/DarkAccent").toString() + ";");
    accentBorder->adjustSize();
    verticalLayout1->addWidget(accentBorder);

    // Horizontal layout #1
    QHBoxLayout *horizontalLayout1 = new QHBoxLayout(this);
    horizontalLayout1->setSpacing(0);
    horizontalLayout1->setMargin(0);
    horizontalLayout1->setAlignment(Qt::AlignVCenter);
    verticalLayout1->addLayout(horizontalLayout1);

    // Sidebar widget - locked width
    QWidget *sidebar = new QWidget(this);
    sidebar->setMinimumWidth(224);
    sidebar->setMaximumWidth(224);
    sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
    sidebar->setStyleSheet("background-image: url(:/Elements/Sidebar.png);");
    horizontalLayout1->addWidget(sidebar);

    // Vertical layout #3
    QVBoxLayout *verticalLayout3 = new QVBoxLayout(this);
    verticalLayout3->setSpacing(0);
    verticalLayout3->setMargin(0);
    verticalLayout3->setAlignment(Qt::AlignHCenter);
    horizontalLayout1->addLayout(verticalLayout3);

    // Horizontal layout #2 - window controls
    QHBoxLayout *horizontalLayout2 = new QHBoxLayout(this);
    horizontalLayout2->setSpacing(0);
    horizontalLayout2->setMargin(8);
    verticalLayout3->addLayout(horizontalLayout2);

    // Window title
    QLabel *windowTitle = new QLabel(this);
    windowTitle->setText("Project Ascension");
    windowTitle->setStyleSheet("font-size: 16px; color: #444444;");
    windowTitle->setAttribute(Qt::WA_TransparentForMouseEvents);
    horizontalLayout2->addWidget(windowTitle);
    horizontalLayout2->addStretch();

    // Window controls
    // Minimize
    QPushButton *pushButtonMinimize = new QPushButton("", this);
    pushButtonMinimize->setObjectName("pushButtonMinimize");
    horizontalLayout2->addWidget(pushButtonMinimize);
    QObject::connect(pushButtonMinimize, SIGNAL(clicked()), this, SLOT(pushButtonMinimize()));

    // Maximize
    QPushButton *pushButtonMaximize = new QPushButton("", this);
    pushButtonMaximize->setObjectName("pushButtonMaximize");
    horizontalLayout2->addWidget(pushButtonMaximize);
    QObject::connect(pushButtonMaximize, SIGNAL(clicked()), this, SLOT(pushButtonMaximize()));

    // Close
    QPushButton *pushButtonClose = new QPushButton("", this);
    pushButtonClose->setObjectName("pushButtonClose");
    horizontalLayout2->addWidget(pushButtonClose);
    QObject::connect(pushButtonClose, SIGNAL(clicked()), this, SLOT(pushButtonClose()));

    // Stacked content panel
    QStackedWidget *stack = new QStackedWidget(this);
    stack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    verticalLayout3->addWidget(stack);

    // Show
    show();
}
<commit_msg>Remove erroneous window label<commit_after>#include "MainPanel.h"

#include <QMessageBox>
#include <QGridLayout>
#include <QPushButton>
#include <QScrollArea>
#include <QSettings>

QString g_getStylesheet(QString location)
{
    QFile stylesheet(location);
    if (stylesheet.open(QFile::ReadOnly))
    {
        QString styleSheet = stylesheet.readAll();
        return styleSheet;
    }
    return "";
}

MainPanel::MainPanel(QWidget* parent)
    : QWidget(parent)
{
    setObjectName("mainPanel");

    init();
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    show();
}

void MainPanel::init()
{
    if (!db.init())
    {
        QMessageBox error;
        error.critical(0, "Error!", "An error occured while trying to load the database.");
        exit(EXIT_FAILURE);
        return;
    }

    QString style = g_getStylesheet(":/Styles/Content.css");
    QSettings p("palette.ini", QSettings::IniFormat);

    setObjectName("mainPanel");
    setStyleSheet("background-color: " + p.value("Primary/DarkestBase").toString() + ";");

    // Main panel layout
    QGridLayout *mainGridLayout = new QGridLayout(this);
    mainGridLayout->setSpacing(0);
    mainGridLayout->setMargin(0);
    setLayout(mainGridLayout);

    // Main panel scroll area
    QScrollArea *scrollArea = new QScrollArea(this);
    scrollArea->setWidgetResizable(true);
    scrollArea->setObjectName("mainPanelScrollArea");
    scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    mainGridLayout->addWidget(scrollArea);

    // Core widget
    QWidget *coreWidget = new QWidget(this);
    coreWidget->setObjectName("centralWidget");
    coreWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scrollArea->setWidget(coreWidget);

    // Vertical layout #1
    QVBoxLayout *verticalLayout1 = new QVBoxLayout(this);
    verticalLayout1->setSpacing(0);
    verticalLayout1->setMargin(0);
    verticalLayout1->setAlignment(Qt::AlignHCenter);
    coreWidget->setLayout(verticalLayout1);

    // Accent border
    QLabel *accentBorder = new QLabel(this);
    accentBorder->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    accentBorder->setMaximumHeight(3);
    accentBorder->setStyleSheet("background-color: " + p.value("Primary/DarkestBase").toString() +
                                ";border-top: 2px solid " + p.value("Accent/MediumAccent").toString() +
                                ";border-bottom: 1px solid" + p.value("Accent/DarkAccent").toString() + ";");
    accentBorder->adjustSize();
    verticalLayout1->addWidget(accentBorder);

    // Horizontal layout #1
    QHBoxLayout *horizontalLayout1 = new QHBoxLayout(this);
    horizontalLayout1->setSpacing(0);
    horizontalLayout1->setMargin(0);
    horizontalLayout1->setAlignment(Qt::AlignVCenter);
    verticalLayout1->addLayout(horizontalLayout1);

    // Sidebar widget - locked width
    QWidget *sidebar = new QWidget(this);
    sidebar->setMinimumWidth(224);
    sidebar->setMaximumWidth(224);
    sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
    sidebar->setStyleSheet("background-image: url(:/Elements/Sidebar.png);");
    horizontalLayout1->addWidget(sidebar);

    // Vertical layout #3
    QVBoxLayout *verticalLayout3 = new QVBoxLayout(this);
    verticalLayout3->setSpacing(0);
    verticalLayout3->setMargin(0);
    verticalLayout3->setAlignment(Qt::AlignHCenter);
    horizontalLayout1->addLayout(verticalLayout3);

    // Horizontal layout #2 - window controls
    QHBoxLayout *horizontalLayout2 = new QHBoxLayout(this);
    horizontalLayout2->setSpacing(0);
    horizontalLayout2->setMargin(8);
    verticalLayout3->addLayout(horizontalLayout2);

    horizontalLayout2->addStretch();

    // Window controls
    // Minimize
    QPushButton *pushButtonMinimize = new QPushButton("", this);
    pushButtonMinimize->setObjectName("pushButtonMinimize");
    horizontalLayout2->addWidget(pushButtonMinimize);
    QObject::connect(pushButtonMinimize, SIGNAL(clicked()), this, SLOT(pushButtonMinimize()));

    // Maximize
    QPushButton *pushButtonMaximize = new QPushButton("", this);
    pushButtonMaximize->setObjectName("pushButtonMaximize");
    horizontalLayout2->addWidget(pushButtonMaximize);
    QObject::connect(pushButtonMaximize, SIGNAL(clicked()), this, SLOT(pushButtonMaximize()));

    // Close
    QPushButton *pushButtonClose = new QPushButton("", this);
    pushButtonClose->setObjectName("pushButtonClose");
    horizontalLayout2->addWidget(pushButtonClose);
    QObject::connect(pushButtonClose, SIGNAL(clicked()), this, SLOT(pushButtonClose()));

    // Stacked content panel
    QStackedWidget *stack = new QStackedWidget(this);
    stack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    verticalLayout3->addWidget(stack);

    // Show
    show();
}
<|endoftext|>