<commit_before>#include <cubez/cubez.h>
#include <cubez/utils.h>
#include "defs.h"
#include "private_universe.h"
#include "byte_vector.h"
#include "component.h"
#include "system_impl.h"
#include "utils_internal.h"
#include "coro_scheduler.h"

#define AS_PRIVATE(expr) ((PrivateUniverse*)(universe_->self))->expr

const qbVar qbNone = { QB_TAG_VOID, 0 };
const qbVar qbUnset = { QB_TAG_UNSET, 0 };

static qbUniverse* universe_ = nullptr;
Coro main;
CoroScheduler* coro_scheduler;

qbResult qb_init(qbUniverse* u) {
  utils_initialize();

  universe_ = u;
  universe_->self = new PrivateUniverse();

  main = coro_initialize();
  coro_scheduler = new CoroScheduler(4);

  return AS_PRIVATE(init());
}

qbResult qb_start() {
  return AS_PRIVATE(start());
}

qbResult qb_stop() {
  qbResult ret = AS_PRIVATE(stop());
  universe_ = nullptr;
  return ret;
}

qbResult qb_loop() {
  qbResult result = AS_PRIVATE(loop());
  coro_scheduler->run_sync();

  return result;
}

qbId qb_create_program(const char* name) {
  return AS_PRIVATE(create_program(name));
}

qbResult qb_run_program(qbId program) {
  return AS_PRIVATE(run_program(program));
}

qbResult qb_detach_program(qbId program) {
  return AS_PRIVATE(detach_program(program));
}

qbResult qb_join_program(qbId program) {
  return AS_PRIVATE(join_program(program));
}

qbResult qb_system_enable(qbSystem system) {
  return AS_PRIVATE(enable_system(system));
}

qbResult qb_system_disable(qbSystem system) {
  return AS_PRIVATE(disable_system(system));
}

qbResult qb_componentattr_create(qbComponentAttr* attr) {
  *attr = (qbComponentAttr)calloc(1, sizeof(qbComponentAttr_));
  new (*attr) qbComponentAttr_;
  (*attr)->is_shared = false;
  (*attr)->type = qbComponentType::QB_COMPONENT_TYPE_RAW;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_destroy(qbComponentAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_setdatasize(qbComponentAttr attr, size_t size) {
  attr->data_size = size;
  return qbResult::QB_OK;
}

qbResult qb_componentattr_settype(qbComponentAttr attr, qbComponentType type) {
  attr->type = type;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_setshared(qbComponentAttr attr) {
  attr->is_shared = true;
  return qbResult::QB_OK;
}

qbResult qb_component_create(
    qbComponent* component, qbComponentAttr attr) {
  return AS_PRIVATE(component_create(component, attr));
}

qbResult qb_component_destroy(qbComponent*) {
	return qbResult::QB_OK;
}

size_t qb_component_getcount(qbComponent component) {
  return AS_PRIVATE(component_getcount(component));
}

qbResult qb_entityattr_create(qbEntityAttr* attr) {
  *attr = (qbEntityAttr)calloc(1, sizeof(qbEntityAttr_));
  new (*attr) qbEntityAttr_;
	return qbResult::QB_OK;
}

qbResult qb_entityattr_destroy(qbEntityAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_entityattr_addcomponent(qbEntityAttr attr, qbComponent component,
                                    void* instance_data) {
  attr->component_list.push_back({component, instance_data});
	return qbResult::QB_OK;
}

qbResult qb_entity_create(qbEntity* entity, qbEntityAttr attr) {
  return AS_PRIVATE(entity_create(entity, *attr));
}

qbResult qb_entity_destroy(qbEntity entity) {
  return AS_PRIVATE(entity_destroy(entity));
}

bool qb_entity_hascomponent(qbEntity entity, qbComponent component) {
  return AS_PRIVATE(entity_hascomponent(entity, component));
}

qbResult qb_entity_addcomponent(qbEntity entity, qbComponent component,
                                void* instance_data) {
  return AS_PRIVATE(entity_addcomponent(entity, component, instance_data));
}

qbResult qb_entity_removecomponent(qbEntity entity, qbComponent component) {
  return AS_PRIVATE(entity_removecomponent(entity, component));
}

qbId qb_entity_getid(qbEntity entity) {
  return entity;
}

qbResult qb_barrier_create(qbBarrier* barrier) {
  *barrier = AS_PRIVATE(barrier_create());
  return QB_OK;
}

qbResult qb_barrier_destroy(qbBarrier* barrier) {
  AS_PRIVATE(barrier_destroy(*barrier));
  return QB_OK;
}

qbResult qb_systemattr_create(qbSystemAttr* attr) {
  *attr = (qbSystemAttr)calloc(1, sizeof(qbSystemAttr_));
  new (*attr) qbSystemAttr_;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_destroy(qbSystemAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setprogram(qbSystemAttr attr, qbId program) {
  attr->program = program;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addconst(qbSystemAttr attr, qbComponent component) {
  attr->constants.push_back(component);
  attr->components.push_back(component);
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addmutable(qbSystemAttr attr, qbComponent component) {
  attr->mutables.push_back(component);
  attr->components.push_back(component);
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setfunction(qbSystemAttr attr, qbTransform transform) {
  attr->transform = transform;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setcallback(qbSystemAttr attr, qbCallback callback) {
  attr->callback = callback;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setcondition(qbSystemAttr attr, qbCondition condition) {
  attr->condition = condition;
  return qbResult::QB_OK;
}

qbResult qb_systemattr_settrigger(qbSystemAttr attr, qbTrigger trigger) {
  attr->trigger = trigger;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setpriority(qbSystemAttr attr, int16_t priority) {
  attr->priority = priority;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setjoin(qbSystemAttr attr, qbComponentJoin join) {
  attr->join = join;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setuserstate(qbSystemAttr attr, void* state) {
  attr->state = state;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addbarrier(qbSystemAttr attr,
                                  qbBarrier barrier) {
  qbTicket_* t = new qbTicket_;
  t->impl = ((Barrier*)barrier->impl)->MakeTicket().release();

  t->lock = [ticket{ t->impl }]() { ((Barrier::Ticket*)ticket)->lock(); };
  t->unlock = [ticket{ t->impl }]() { ((Barrier::Ticket*)ticket)->unlock(); };
  attr->tickets.push_back(t);
  return QB_OK;
}

qbResult qb_system_create(qbSystem* system, qbSystemAttr attr) {
  if (!attr->program) {
    attr->program = 0;
  }
#ifdef __ENGINE_DEBUG__
  DEBUG_ASSERT(attr->transform || attr->callback,
               qbResult::QB_ERROR_SYSTEMATTR_HAS_FUNCTION_OR_CALLBACK);
#endif
  AS_PRIVATE(system_create(system, *attr));
	return qbResult::QB_OK;
}

qbResult qb_system_destroy(qbSystem*) {
	return qbResult::QB_OK;
}

qbResult qb_eventattr_create(qbEventAttr* attr) {
  *attr = (qbEventAttr)calloc(1, sizeof(qbEventAttr_));
  new (*attr) qbEventAttr_;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_destroy(qbEventAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_setprogram(qbEventAttr attr, qbId program) {
  attr->program = program;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_setmessagesize(qbEventAttr attr, size_t size) {
  attr->message_size = size;
	return qbResult::QB_OK;
}

qbResult qb_event_create(qbEvent* event, qbEventAttr attr) {
  if (!attr->program) {
    attr->program = 0;
  }
#ifdef __ENGINE_DEBUG__
  DEBUG_ASSERT(attr->message_size > 0,
               qbResult::QB_ERROR_EVENTATTR_MESSAGE_SIZE_IS_ZERO);
#endif
	return AS_PRIVATE(event_create(event, attr));
}

qbResult qb_event_destroy(qbEvent* event) {
	return AS_PRIVATE(event_destroy(event));
}

qbResult qb_event_flushall(qbProgram program) {
	return AS_PRIVATE(event_flushall(program));
}

qbResult qb_event_subscribe(qbEvent event, qbSystem system) {
	return AS_PRIVATE(event_subscribe(event, system));
}

qbResult qb_event_unsubscribe(qbEvent event, qbSystem system) {
	return AS_PRIVATE(event_unsubscribe(event, system));
}

qbResult qb_event_send(qbEvent event, void* message) {
  return AS_PRIVATE(event_send(event, message));
}

qbResult qb_event_sendsync(qbEvent event, void* message) {
  return AS_PRIVATE(event_sendsync(event, message));
}

qbResult qb_instance_oncreate(qbComponent component,
                              qbInstanceOnCreate on_create) {
  return AS_PRIVATE(instance_oncreate(component, on_create));
}

qbResult qb_instance_ondestroy(qbComponent component,
                               qbInstanceOnDestroy on_destroy) {
  return AS_PRIVATE(instance_ondestroy(component, on_destroy));
}

qbEntity qb_instance_getentity(qbInstance instance) {
  return instance->entity;
}

qbResult qb_instance_getconst(qbInstance instance, void* pbuffer) {
  return AS_PRIVATE(instance_getconst(instance, pbuffer));
}

qbResult qb_instance_getmutable(qbInstance instance, void* pbuffer) {
  return AS_PRIVATE(instance_getmutable(instance, pbuffer));
}

qbResult qb_instance_getcomponent(qbInstance instance, qbComponent component, void* pbuffer) {
  return AS_PRIVATE(instance_getcomponent(instance, component, pbuffer));
}

bool qb_instance_hascomponent(qbInstance instance, qbComponent component) {
  return AS_PRIVATE(instance_hascomponent(instance, component));
}

qbResult qb_instance_find(qbComponent component, qbEntity entity, void* pbuffer) {
  return AS_PRIVATE(instance_find(component, entity, pbuffer));
}

qbCoro qb_coro_create(qbVar(*entry)(qbVar var)) {
  qbCoro ret = new qbCoro_();
  ret->ret = qbUnset;
  ret->main = coro_new(entry);
  return ret;
}

qbCoro qb_coro_create_unsafe(qbVar(*entry)(qbVar var), void* stack, size_t stack_size) {
  qbCoro ret = new qbCoro_();
  ret->ret = qbUnset;
  ret->main = coro_new_unsafe(entry, (uintptr_t)stack, stack_size);
  return ret;
}

qbResult qb_coro_destroy(qbCoro* coro) {
  coro_free((*coro)->main);
  delete *coro;
  *coro = nullptr;
  return QB_OK;
}

qbVar qb_coro_call(qbCoro coro, qbVar var) {
  coro->arg = var;
  return coro_call(coro->main, var);
}

qbCoro qb_coro_sync(qbVar(*entry)(qbVar), qbVar var) {
  return coro_scheduler->schedule_sync(entry, var);
}

qbCoro qb_coro_async(qbVar(*entry)(qbVar), qbVar var) {
  return coro_scheduler->schedule_async(entry, var);
}

qbVar qb_coro_await(qbCoro coro) {
  return coro_scheduler->await(coro);
}

qbVar qb_coro_peek(qbCoro coro) {
  return coro_scheduler->peek(coro);
}

qbVar qb_coro_yield(qbVar var) {
  return coro_yield(var);
}

void qb_coro_wait(double seconds) {
  double start = (double)qb_timer_query() / 1e9;
  double end = start + seconds;
  while ((double)qb_timer_query() / 1e9 < end) {
    qb_coro_yield(qbUnset);
  }
}

void qb_coro_waitframes(uint32_t frames) {
  uint32_t frames_waited = 0;
  while (frames_waited < frames) {
    qb_coro_yield(qbUnset);
    ++frames_waited;
  }
}

qbVar qbVoid(void* p) {
  qbVar v;
  v.tag = QB_TAG_VOID;
  v.p = p;
  return v;
}

qbVar qbUint(uint64_t u) {
  qbVar v;
  v.tag = QB_TAG_UINT;
  v.u = u;
  return v;
}

qbVar qbInt(int64_t i) {
  qbVar v;
  v.tag = QB_TAG_INT;
  v.i = i;
  return v;
}

qbVar qbDouble(double d) {
  qbVar v;
  v.tag = QB_TAG_DOUBLE;
  v.d = d;
  return v;
}

qbVar qbChar(char c) {
  qbVar v;
  v.tag = QB_TAG_CHAR;
  v.c = c;
  return v;
}
<commit_msg>Add qb_coro_done<commit_after>#include <cubez/cubez.h>
#include <cubez/utils.h>
#include "defs.h"
#include "private_universe.h"
#include "byte_vector.h"
#include "component.h"
#include "system_impl.h"
#include "utils_internal.h"
#include "coro_scheduler.h"

#define AS_PRIVATE(expr) ((PrivateUniverse*)(universe_->self))->expr

const qbVar qbNone = { QB_TAG_VOID, 0 };
const qbVar qbUnset = { QB_TAG_UNSET, 0 };

static qbUniverse* universe_ = nullptr;
Coro main;
CoroScheduler* coro_scheduler;

qbResult qb_init(qbUniverse* u) {
  utils_initialize();

  universe_ = u;
  universe_->self = new PrivateUniverse();

  main = coro_initialize();
  coro_scheduler = new CoroScheduler(4);

  return AS_PRIVATE(init());
}

qbResult qb_start() {
  return AS_PRIVATE(start());
}

qbResult qb_stop() {
  qbResult ret = AS_PRIVATE(stop());
  universe_ = nullptr;
  return ret;
}

qbResult qb_loop() {
  qbResult result = AS_PRIVATE(loop());
  coro_scheduler->run_sync();

  return result;
}

qbId qb_create_program(const char* name) {
  return AS_PRIVATE(create_program(name));
}

qbResult qb_run_program(qbId program) {
  return AS_PRIVATE(run_program(program));
}

qbResult qb_detach_program(qbId program) {
  return AS_PRIVATE(detach_program(program));
}

qbResult qb_join_program(qbId program) {
  return AS_PRIVATE(join_program(program));
}

qbResult qb_system_enable(qbSystem system) {
  return AS_PRIVATE(enable_system(system));
}

qbResult qb_system_disable(qbSystem system) {
  return AS_PRIVATE(disable_system(system));
}

qbResult qb_componentattr_create(qbComponentAttr* attr) {
  *attr = (qbComponentAttr)calloc(1, sizeof(qbComponentAttr_));
  new (*attr) qbComponentAttr_;
  (*attr)->is_shared = false;
  (*attr)->type = qbComponentType::QB_COMPONENT_TYPE_RAW;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_destroy(qbComponentAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_setdatasize(qbComponentAttr attr, size_t size) {
  attr->data_size = size;
  return qbResult::QB_OK;
}

qbResult qb_componentattr_settype(qbComponentAttr attr, qbComponentType type) {
  attr->type = type;
	return qbResult::QB_OK;
}

qbResult qb_componentattr_setshared(qbComponentAttr attr) {
  attr->is_shared = true;
  return qbResult::QB_OK;
}

qbResult qb_component_create(
    qbComponent* component, qbComponentAttr attr) {
  return AS_PRIVATE(component_create(component, attr));
}

qbResult qb_component_destroy(qbComponent*) {
	return qbResult::QB_OK;
}

size_t qb_component_getcount(qbComponent component) {
  return AS_PRIVATE(component_getcount(component));
}

qbResult qb_entityattr_create(qbEntityAttr* attr) {
  *attr = (qbEntityAttr)calloc(1, sizeof(qbEntityAttr_));
  new (*attr) qbEntityAttr_;
	return qbResult::QB_OK;
}

qbResult qb_entityattr_destroy(qbEntityAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_entityattr_addcomponent(qbEntityAttr attr, qbComponent component,
                                    void* instance_data) {
  attr->component_list.push_back({component, instance_data});
	return qbResult::QB_OK;
}

qbResult qb_entity_create(qbEntity* entity, qbEntityAttr attr) {
  return AS_PRIVATE(entity_create(entity, *attr));
}

qbResult qb_entity_destroy(qbEntity entity) {
  return AS_PRIVATE(entity_destroy(entity));
}

bool qb_entity_hascomponent(qbEntity entity, qbComponent component) {
  return AS_PRIVATE(entity_hascomponent(entity, component));
}

qbResult qb_entity_addcomponent(qbEntity entity, qbComponent component,
                                void* instance_data) {
  return AS_PRIVATE(entity_addcomponent(entity, component, instance_data));
}

qbResult qb_entity_removecomponent(qbEntity entity, qbComponent component) {
  return AS_PRIVATE(entity_removecomponent(entity, component));
}

qbId qb_entity_getid(qbEntity entity) {
  return entity;
}

qbResult qb_barrier_create(qbBarrier* barrier) {
  *barrier = AS_PRIVATE(barrier_create());
  return QB_OK;
}

qbResult qb_barrier_destroy(qbBarrier* barrier) {
  AS_PRIVATE(barrier_destroy(*barrier));
  return QB_OK;
}

qbResult qb_systemattr_create(qbSystemAttr* attr) {
  *attr = (qbSystemAttr)calloc(1, sizeof(qbSystemAttr_));
  new (*attr) qbSystemAttr_;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_destroy(qbSystemAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setprogram(qbSystemAttr attr, qbId program) {
  attr->program = program;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addconst(qbSystemAttr attr, qbComponent component) {
  attr->constants.push_back(component);
  attr->components.push_back(component);
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addmutable(qbSystemAttr attr, qbComponent component) {
  attr->mutables.push_back(component);
  attr->components.push_back(component);
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setfunction(qbSystemAttr attr, qbTransform transform) {
  attr->transform = transform;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setcallback(qbSystemAttr attr, qbCallback callback) {
  attr->callback = callback;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setcondition(qbSystemAttr attr, qbCondition condition) {
  attr->condition = condition;
  return qbResult::QB_OK;
}

qbResult qb_systemattr_settrigger(qbSystemAttr attr, qbTrigger trigger) {
  attr->trigger = trigger;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setpriority(qbSystemAttr attr, int16_t priority) {
  attr->priority = priority;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setjoin(qbSystemAttr attr, qbComponentJoin join) {
  attr->join = join;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_setuserstate(qbSystemAttr attr, void* state) {
  attr->state = state;
	return qbResult::QB_OK;
}

qbResult qb_systemattr_addbarrier(qbSystemAttr attr,
                                  qbBarrier barrier) {
  qbTicket_* t = new qbTicket_;
  t->impl = ((Barrier*)barrier->impl)->MakeTicket().release();

  t->lock = [ticket{ t->impl }]() { ((Barrier::Ticket*)ticket)->lock(); };
  t->unlock = [ticket{ t->impl }]() { ((Barrier::Ticket*)ticket)->unlock(); };
  attr->tickets.push_back(t);
  return QB_OK;
}

qbResult qb_system_create(qbSystem* system, qbSystemAttr attr) {
  if (!attr->program) {
    attr->program = 0;
  }
#ifdef __ENGINE_DEBUG__
  DEBUG_ASSERT(attr->transform || attr->callback,
               qbResult::QB_ERROR_SYSTEMATTR_HAS_FUNCTION_OR_CALLBACK);
#endif
  AS_PRIVATE(system_create(system, *attr));
	return qbResult::QB_OK;
}

qbResult qb_system_destroy(qbSystem*) {
	return qbResult::QB_OK;
}

qbResult qb_eventattr_create(qbEventAttr* attr) {
  *attr = (qbEventAttr)calloc(1, sizeof(qbEventAttr_));
  new (*attr) qbEventAttr_;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_destroy(qbEventAttr* attr) {
  delete *attr;
  *attr = nullptr;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_setprogram(qbEventAttr attr, qbId program) {
  attr->program = program;
	return qbResult::QB_OK;
}

qbResult qb_eventattr_setmessagesize(qbEventAttr attr, size_t size) {
  attr->message_size = size;
	return qbResult::QB_OK;
}

qbResult qb_event_create(qbEvent* event, qbEventAttr attr) {
  if (!attr->program) {
    attr->program = 0;
  }
#ifdef __ENGINE_DEBUG__
  DEBUG_ASSERT(attr->message_size > 0,
               qbResult::QB_ERROR_EVENTATTR_MESSAGE_SIZE_IS_ZERO);
#endif
	return AS_PRIVATE(event_create(event, attr));
}

qbResult qb_event_destroy(qbEvent* event) {
	return AS_PRIVATE(event_destroy(event));
}

qbResult qb_event_flushall(qbProgram program) {
	return AS_PRIVATE(event_flushall(program));
}

qbResult qb_event_subscribe(qbEvent event, qbSystem system) {
	return AS_PRIVATE(event_subscribe(event, system));
}

qbResult qb_event_unsubscribe(qbEvent event, qbSystem system) {
	return AS_PRIVATE(event_unsubscribe(event, system));
}

qbResult qb_event_send(qbEvent event, void* message) {
  return AS_PRIVATE(event_send(event, message));
}

qbResult qb_event_sendsync(qbEvent event, void* message) {
  return AS_PRIVATE(event_sendsync(event, message));
}

qbResult qb_instance_oncreate(qbComponent component,
                              qbInstanceOnCreate on_create) {
  return AS_PRIVATE(instance_oncreate(component, on_create));
}

qbResult qb_instance_ondestroy(qbComponent component,
                               qbInstanceOnDestroy on_destroy) {
  return AS_PRIVATE(instance_ondestroy(component, on_destroy));
}

qbEntity qb_instance_getentity(qbInstance instance) {
  return instance->entity;
}

qbResult qb_instance_getconst(qbInstance instance, void* pbuffer) {
  return AS_PRIVATE(instance_getconst(instance, pbuffer));
}

qbResult qb_instance_getmutable(qbInstance instance, void* pbuffer) {
  return AS_PRIVATE(instance_getmutable(instance, pbuffer));
}

qbResult qb_instance_getcomponent(qbInstance instance, qbComponent component, void* pbuffer) {
  return AS_PRIVATE(instance_getcomponent(instance, component, pbuffer));
}

bool qb_instance_hascomponent(qbInstance instance, qbComponent component) {
  return AS_PRIVATE(instance_hascomponent(instance, component));
}

qbResult qb_instance_find(qbComponent component, qbEntity entity, void* pbuffer) {
  return AS_PRIVATE(instance_find(component, entity, pbuffer));
}

qbCoro qb_coro_create(qbVar(*entry)(qbVar var)) {
  qbCoro ret = new qbCoro_();
  ret->ret = qbUnset;
  ret->main = coro_new(entry);
  return ret;
}

qbCoro qb_coro_create_unsafe(qbVar(*entry)(qbVar var), void* stack, size_t stack_size) {
  qbCoro ret = new qbCoro_();
  ret->ret = qbUnset;
  ret->main = coro_new_unsafe(entry, (uintptr_t)stack, stack_size);
  return ret;
}

qbResult qb_coro_destroy(qbCoro* coro) {
  coro_free((*coro)->main);
  delete *coro;
  *coro = nullptr;
  return QB_OK;
}

qbVar qb_coro_call(qbCoro coro, qbVar var) {
  coro->arg = var;
  return coro_call(coro->main, var);
}

qbCoro qb_coro_sync(qbVar(*entry)(qbVar), qbVar var) {
  return coro_scheduler->schedule_sync(entry, var);
}

qbCoro qb_coro_async(qbVar(*entry)(qbVar), qbVar var) {
  return coro_scheduler->schedule_async(entry, var);
}

qbVar qb_coro_await(qbCoro coro) {
  return coro_scheduler->await(coro);
}

qbVar qb_coro_peek(qbCoro coro) {
  return coro_scheduler->peek(coro);
}

qbVar qb_coro_yield(qbVar var) {
  return coro_yield(var);
}

void qb_coro_wait(double seconds) {
  double start = (double)qb_timer_query() / 1e9;
  double end = start + seconds;
  while ((double)qb_timer_query() / 1e9 < end) {
    qb_coro_yield(qbUnset);
  }
}

void qb_coro_waitframes(uint32_t frames) {
  uint32_t frames_waited = 0;
  while (frames_waited < frames) {
    qb_coro_yield(qbUnset);
    ++frames_waited;
  }
}

bool qb_coro_done(qbCoro coro) {
  return qb_coro_peek(coro).tag != QB_TAG_UNSET;
}

qbVar qbVoid(void* p) {
  qbVar v;
  v.tag = QB_TAG_VOID;
  v.p = p;
  return v;
}

qbVar qbUint(uint64_t u) {
  qbVar v;
  v.tag = QB_TAG_UINT;
  v.u = u;
  return v;
}

qbVar qbInt(int64_t i) {
  qbVar v;
  v.tag = QB_TAG_INT;
  v.i = i;
  return v;
}

qbVar qbDouble(double d) {
  qbVar v;
  v.tag = QB_TAG_DOUBLE;
  v.d = d;
  return v;
}

qbVar qbChar(char c) {
  qbVar v;
  v.tag = QB_TAG_CHAR;
  v.c = c;
  return v;
}
<|endoftext|>


<commit_before>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/reduce_precision_insertion.h"

#include "tensorflow/compiler/xla/service/hlo_module.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/logging.h"

namespace xla {

// For now, ReducePrecision is only implemented for F32 arrays, so this
// ignores instructions that produce other data.  In particular, this
// currently ignores instructions producing tuples, even if those tuples
// contain F32 arrays inside them.  The assumption is that in most cases
// equivalent behavior can be obtained by adding ReducePrecision
// instructions after the instructions that pull the F32 arrays out of
// the tuples.
//
// TODO(b/64093391): Remove the IsScalar check once this won't cause
// failures on the GPU backend if the ReducePrecision instruction ends up
// inserted between a scalar constant and the init_value argument of a
// Reduce operation.
std::vector<HloInstruction*> ReducePrecisionInsertion::instructions_to_suffix(
    const HloComputation* computation) {
  std::vector<HloInstruction*> instructions_to_suffix;

  switch (pass_timing_) {
    case HloReducePrecisionOptions::BEFORE_OP_FUSION:
    case HloReducePrecisionOptions::AFTER_OP_FUSION:
      for (auto& instruction : computation->instructions()) {
        VLOG(3) << "Visited instruction: " << instruction->ToString();

        if (instruction->shape().element_type() == PrimitiveType::F32 &&
            !ShapeUtil::IsScalar(instruction->shape()) &&
            instruction_filter_function_(instruction.get())) {
          instructions_to_suffix.push_back(instruction.get());
        }
      }
      break;

    case HloReducePrecisionOptions::FUSION_BY_CONTENT:
      for (auto& instruction : computation->instructions()) {
        VLOG(3) << "Visited instruction: " << instruction->ToString();

        if (instruction->opcode() != HloOpcode::kFusion ||
            instruction->shape().element_type() != PrimitiveType::F32 ||
            ShapeUtil::IsScalar(instruction->shape())) {
          continue;
        }

        for (auto& fused_instruction :
             instruction->fused_instructions_computation()->instructions()) {
          VLOG(3) << "Checking sub-instruction: "
                  << fused_instruction->ToString();
          if (instruction_filter_function_(fused_instruction.get())) {
            instructions_to_suffix.push_back(instruction.get());
            break;
          }
        }
      }
      break;

    default:
      break;
  }
  VLOG(1) << "Adding " << instructions_to_suffix.size()
          << " reduce-precision operations.";

  return instructions_to_suffix;
}

StatusOr<bool> ReducePrecisionInsertion::Run(HloModule* module) {
  bool changed = false;
  VLOG(1) << "Running ReducePrecisionInsertion pass on " << module->name();

  for (auto& computation : module->computations()) {
    if (computation->IsFusionComputation()) {
      continue;
    }

    for (auto& instruction : instructions_to_suffix(computation.get())) {
      HloInstruction* reduced =
          computation->AddInstruction(HloInstruction::CreateReducePrecision(
              instruction->shape(), instruction, exponent_bits_,
              mantissa_bits_));
      TF_RETURN_IF_ERROR(
          computation->ReplaceUsesOfInstruction(instruction, reduced));
      VLOG(2) << "Inserted new op after instruction: "
              << instruction->ToString();
      changed = true;
    }
  }
  return changed;
}

ReducePrecisionInsertion::InstructionFilterFunction
ReducePrecisionInsertion::make_filter_function(
    const HloReducePrecisionOptions& reduce_precision_options) {
  // Implement the filter function with a lookup table.
  std::vector<bool> opcode_filter(HloOpcodeCount(), false);
  for (const auto& opcode : reduce_precision_options.opcodes_to_suffix()) {
    opcode_filter[opcode] = true;
  }
  if (reduce_precision_options.opname_substrings_to_suffix_size() == 0) {
    return [opcode_filter](const HloInstruction* instruction) {
      return opcode_filter[static_cast<unsigned int>(instruction->opcode())];
    };
  } else {
    std::vector<string> opname_substrings;
    for (const auto& substring :
         reduce_precision_options.opname_substrings_to_suffix()) {
      opname_substrings.push_back(substring);
    }
    return [opcode_filter,
            opname_substrings](const HloInstruction* instruction) {
      if (!opcode_filter[static_cast<unsigned int>(instruction->opcode())]) {
        return false;
      }
      const auto& opname = instruction->metadata().op_name();
      for (const auto& substring : opname_substrings) {
        if (opname.find(substring) != string::npos) {
          return true;
        }
      }
      return false;
    };
  }
}

HloReducePrecisionOptions ReducePrecisionInsertion::make_options_proto(
    const HloReducePrecisionOptions::PassTiming pass_timing,
    const int exponent_bits, const int mantissa_bits,
    const std::function<bool(HloOpcode)>& opcode_filter_function,
    const std::vector<string>& opname_substring_list) {
  HloReducePrecisionOptions options;
  options.set_pass_timing(pass_timing);
  options.set_exponent_bits(exponent_bits);
  options.set_mantissa_bits(mantissa_bits);
  for (uint32_t opcode = 0; opcode < HloOpcodeCount(); opcode++) {
    if (opcode_filter_function(static_cast<HloOpcode>(opcode))) {
      options.add_opcodes_to_suffix(opcode);
    }
  }
  for (auto& string : opname_substring_list) {
    options.add_opname_substrings_to_suffix(string);
  }
  return options;
}

bool ReducePrecisionInsertion::AddPasses(
    HloPassPipeline* pipeline, const DebugOptions& debug_options,
    const HloReducePrecisionOptions::PassTiming pass_timing) {
  bool passes_added = false;
  for (const auto& pass_options :
       debug_options.hlo_reduce_precision_options()) {
    if (pass_options.pass_timing() == pass_timing) {
      pipeline->AddPass<ReducePrecisionInsertion>(pass_options);
      passes_added = true;
    }
  }
  return passes_added;
}

}  // namespace xla
<commit_msg>[XLA] Optionally log computations that have had reduce-precision instructions added.<commit_after>/* Copyright 2017 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/compiler/xla/service/reduce_precision_insertion.h"

#include "tensorflow/compiler/xla/service/hlo_module.h"
#include "tensorflow/compiler/xla/shape_util.h"
#include "tensorflow/core/platform/logging.h"

namespace xla {

// For now, ReducePrecision is only implemented for F32 arrays, so this
// ignores instructions that produce other data.  In particular, this
// currently ignores instructions producing tuples, even if those tuples
// contain F32 arrays inside them.  The assumption is that in most cases
// equivalent behavior can be obtained by adding ReducePrecision
// instructions after the instructions that pull the F32 arrays out of
// the tuples.
//
// TODO(b/64093391): Remove the IsScalar check once this won't cause
// failures on the GPU backend if the ReducePrecision instruction ends up
// inserted between a scalar constant and the init_value argument of a
// Reduce operation.
std::vector<HloInstruction*> ReducePrecisionInsertion::instructions_to_suffix(
    const HloComputation* computation) {
  std::vector<HloInstruction*> instructions_to_suffix;

  switch (pass_timing_) {
    case HloReducePrecisionOptions::BEFORE_OP_FUSION:
    case HloReducePrecisionOptions::AFTER_OP_FUSION:
      for (auto& instruction : computation->instructions()) {
        VLOG(4) << "Visited instruction: " << instruction->ToString();

        if (instruction->shape().element_type() == PrimitiveType::F32 &&
            !ShapeUtil::IsScalar(instruction->shape()) &&
            instruction_filter_function_(instruction.get())) {
          instructions_to_suffix.push_back(instruction.get());
        }
      }
      break;

    case HloReducePrecisionOptions::FUSION_BY_CONTENT:
      for (auto& instruction : computation->instructions()) {
        VLOG(4) << "Visited instruction: " << instruction->ToString();

        if (instruction->opcode() != HloOpcode::kFusion ||
            instruction->shape().element_type() != PrimitiveType::F32 ||
            ShapeUtil::IsScalar(instruction->shape())) {
          continue;
        }

        for (auto& fused_instruction :
             instruction->fused_instructions_computation()->instructions()) {
          VLOG(4) << "Checking sub-instruction: "
                  << fused_instruction->ToString();
          if (instruction_filter_function_(fused_instruction.get())) {
            instructions_to_suffix.push_back(instruction.get());
            break;
          }
        }
      }
      break;

    default:
      break;
  }
  VLOG(1) << "Adding " << instructions_to_suffix.size()
          << " reduce-precision operations.";

  return instructions_to_suffix;
}

StatusOr<bool> ReducePrecisionInsertion::Run(HloModule* module) {
  bool changed = false;
  VLOG(1) << "Running ReducePrecisionInsertion pass on " << module->name();

  for (auto& computation : module->computations()) {
    if (computation->IsFusionComputation()) {
      continue;
    }

    bool computation_changed = false;
    for (auto& instruction : instructions_to_suffix(computation.get())) {
      HloInstruction* reduced =
          computation->AddInstruction(HloInstruction::CreateReducePrecision(
              instruction->shape(), instruction, exponent_bits_,
              mantissa_bits_));
      TF_RETURN_IF_ERROR(
          computation->ReplaceUsesOfInstruction(instruction, reduced));
      VLOG(2) << "Inserted new op after instruction: "
              << instruction->ToString();
      computation_changed = true;
    }

    if (computation_changed) {
      changed = true;
      VLOG(3) << "Computation after reduce-precision insertion:";
      XLA_VLOG_LINES(3, computation->ToString());
    } else {
      VLOG(3) << "Computation " << computation->name() << " unchanged";
    }
  }

  return changed;
}

ReducePrecisionInsertion::InstructionFilterFunction
ReducePrecisionInsertion::make_filter_function(
    const HloReducePrecisionOptions& reduce_precision_options) {
  // Implement the filter function with a lookup table.
  std::vector<bool> opcode_filter(HloOpcodeCount(), false);
  for (const auto& opcode : reduce_precision_options.opcodes_to_suffix()) {
    opcode_filter[opcode] = true;
  }
  if (reduce_precision_options.opname_substrings_to_suffix_size() == 0) {
    return [opcode_filter](const HloInstruction* instruction) {
      return opcode_filter[static_cast<unsigned int>(instruction->opcode())];
    };
  } else {
    std::vector<string> opname_substrings;
    for (const auto& substring :
         reduce_precision_options.opname_substrings_to_suffix()) {
      opname_substrings.push_back(substring);
    }
    return [opcode_filter,
            opname_substrings](const HloInstruction* instruction) {
      if (!opcode_filter[static_cast<unsigned int>(instruction->opcode())]) {
        return false;
      }
      const auto& opname = instruction->metadata().op_name();
      for (const auto& substring : opname_substrings) {
        if (opname.find(substring) != string::npos) {
          return true;
        }
      }
      return false;
    };
  }
}

HloReducePrecisionOptions ReducePrecisionInsertion::make_options_proto(
    const HloReducePrecisionOptions::PassTiming pass_timing,
    const int exponent_bits, const int mantissa_bits,
    const std::function<bool(HloOpcode)>& opcode_filter_function,
    const std::vector<string>& opname_substring_list) {
  HloReducePrecisionOptions options;
  options.set_pass_timing(pass_timing);
  options.set_exponent_bits(exponent_bits);
  options.set_mantissa_bits(mantissa_bits);
  for (uint32_t opcode = 0; opcode < HloOpcodeCount(); opcode++) {
    if (opcode_filter_function(static_cast<HloOpcode>(opcode))) {
      options.add_opcodes_to_suffix(opcode);
    }
  }
  for (auto& string : opname_substring_list) {
    options.add_opname_substrings_to_suffix(string);
  }
  return options;
}

bool ReducePrecisionInsertion::AddPasses(
    HloPassPipeline* pipeline, const DebugOptions& debug_options,
    const HloReducePrecisionOptions::PassTiming pass_timing) {
  bool passes_added = false;
  for (const auto& pass_options :
       debug_options.hlo_reduce_precision_options()) {
    if (pass_options.pass_timing() == pass_timing) {
      pipeline->AddPass<ReducePrecisionInsertion>(pass_options);
      passes_added = true;
    }
  }
  return passes_added;
}

}  // namespace xla
<|endoftext|>


<commit_before>/*
* Daemon.node: A node.JS addon that allows creating Unix/Linux Daemons in pure Javascript.
 *
* Copyright 2010 (c) <arthur@norgic.com>
* Modified By: Pedro Teixeira  2010
* Modified By: James Haliday   2010
* Modified By: Charlie Robbins 2010
* Modified By: Zak Taylor      2010
* Modified By: Daniel Bartlett 2011
* Modified By: Charlie Robbins 2011
*
* Under MIT License. See LICENSE file.
*
*/

#include <v8.h>
#include <node.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pwd.h>

#define PID_MAXLEN 10

using namespace v8;
using namespace node;

//
// Go through special routines to become a daemon.
// if successful, returns daemon pid
//
static Handle<Value> Start(const Arguments& args) {
  HandleScope scope;

  pid_t sid, pid = fork();
  int i, new_fd;

  if (pid < 0)      exit(1);
  else if (pid > 0) exit(0);

  if (pid == 0) {
    // Child process: We need to tell libev that we are forking because
    // kqueue can't deal with this gracefully.
    //
    // See: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_fork_code_the_audacity_to_re
    ev_default_fork();

    sid = setsid();
    if(sid < 0) exit(1);

    // Close stdin
    freopen("/dev/null", "r", stdin);

    if (args.Length() > 0 && args[0]->IsInt32()) {
      new_fd = args[0]->Int32Value();
      dup2(new_fd, STDOUT_FILENO);
      dup2(new_fd, STDERR_FILENO);
    }
    else {
      freopen("/dev/null", "w", stderr);
      freopen("/dev/null", "w", stdout);
    }
  }

  return scope.Close(Number::New(getpid()));
}

//
// Close stdin by redirecting it to /dev/null
//
Handle<Value> CloseStdin(const Arguments& args) {
  freopen("/dev/null", "r", stdin);
}

//
// Close stderr by redirecting to /dev/null
//
Handle<Value> CloseStderr(const Arguments& args) {
  freopen("/dev/null", "w", stderr);
}

//
// Close stdout by redirecting to /dev/null
//
Handle<Value> CloseStdout(const Arguments& args) {
  freopen("/dev/null", "w", stdout);
}

//
// Closes all stdio by redirecting to /dev/null
//
Handle<Value> CloseStdio(const Arguments& args) {
  freopen("/dev/null", "r", stdin);
  freopen("/dev/null", "w", stderr);
  freopen("/dev/null", "w", stdout);
}

//
// File-lock to make sure that only one instance of daemon is running, also for storing pid
//   lock (filename)
//   @filename: a path to a lock-file.
//
//   Note: if filename doesn't exist, it will be created when function is called.
//
Handle<Value> LockD(const Arguments& args) {
  if (!args[0]->IsString())
    return Boolean::New(false);

  String::Utf8Value data(args[0]->ToString());
  char pid_str[PID_MAXLEN+1];

  int lfp = open(*data, O_RDWR | O_CREAT | O_TRUNC, 0640);
  if(lfp < 0) exit(1);
  if(lockf(lfp, F_TLOCK, 0) < 0) return Boolean::New(false);

  int len = snprintf(pid_str, PID_MAXLEN, "%d", getpid());
  write(lfp, pid_str, len);
  fsync(lfp);

  return Boolean::New(true);
}

Handle<Value> SetSid(const Arguments& args) {
  pid_t sid;
  sid = setsid();
  return Integer::New(sid);
}

const char* ToCString(const v8::String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

//
// Set the chroot of this process. You probably want to be sure stuff is in here.
//   chroot (folder)
//   @folder {string}: The new root
//
Handle<Value> Chroot(const Arguments& args) {
  if (args.Length() < 1) {
    return ThrowException(Exception::TypeError(
      String::New("Must have one argument; a string of the folder to chroot to.")
    ));
  }
  uid_t uid;
  int rv;

  String::Utf8Value folderUtf8(args[0]->ToString());
  const char *folder = ToCString(folderUtf8);
  rv = chroot(folder);
  if (rv != 0) {
    return ThrowException(ErrnoException(errno, "chroot"));
  }
  chdir("/");

  return Boolean::New(true);
}

//
// Allow changing the real and effective user ID of this process
// so a root process can become unprivileged
//
Handle<Value> SetReuid(const Arguments& args) {
  if (args.Length() == 0 || (!args[0]->IsString() && !args[0]->IsInt32()))
    return ThrowException(Exception::Error(
      String::New("Must give a uid or username to become")
    ));

  if (args[0]->IsString()) {
    String::AsciiValue username(args[0]);

    struct passwd* pwd_entry = getpwnam(*username);

    if (pwd_entry) {
      setreuid(pwd_entry->pw_uid, pwd_entry->pw_uid);
    }
    else {
      return ThrowException(Exception::Error(
        String::New("User not found")
      ));
    }
  }
  else if (args[0]->IsInt32()) {
    uid_t uid;
    uid = args[0]->Int32Value();
    setreuid(uid, uid);
  }
}

//
// Initialize this add-on
//
extern "C" void init(Handle<Object> target) {
  HandleScope scope;

  NODE_SET_METHOD(target, "start", Start);
  NODE_SET_METHOD(target, "lock", LockD);
  NODE_SET_METHOD(target, "setsid", SetSid);
  NODE_SET_METHOD(target, "chroot", Chroot);
  NODE_SET_METHOD(target, "setreuid", SetReuid);
  NODE_SET_METHOD(target, "closeStderr", CloseStderr);
  NODE_SET_METHOD(target, "closeStdout", CloseStdout);
  NODE_SET_METHOD(target, "closeStdin", CloseStdin);
  NODE_SET_METHOD(target, "closeStdio", CloseStdio);
}<commit_msg>[minor] Lets have return true on user change, so we know it's good.<commit_after>/*
* Daemon.node: A node.JS addon that allows creating Unix/Linux Daemons in pure Javascript.
 *
* Copyright 2010 (c) <arthur@norgic.com>
* Modified By: Pedro Teixeira  2010
* Modified By: James Haliday   2010
* Modified By: Charlie Robbins 2010
* Modified By: Zak Taylor      2010
* Modified By: Daniel Bartlett 2011
* Modified By: Charlie Robbins 2011
*
* Under MIT License. See LICENSE file.
*
*/

#include <v8.h>
#include <node.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <pwd.h>

#define PID_MAXLEN 10

using namespace v8;
using namespace node;

//
// Go through special routines to become a daemon.
// if successful, returns daemon pid
//
static Handle<Value> Start(const Arguments& args) {
  HandleScope scope;

  pid_t sid, pid = fork();
  int i, new_fd;

  if (pid < 0)      exit(1);
  else if (pid > 0) exit(0);

  if (pid == 0) {
    // Child process: We need to tell libev that we are forking because
    // kqueue can't deal with this gracefully.
    //
    // See: http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#code_ev_fork_code_the_audacity_to_re
    ev_default_fork();

    sid = setsid();
    if(sid < 0) exit(1);

    // Close stdin
    freopen("/dev/null", "r", stdin);

    if (args.Length() > 0 && args[0]->IsInt32()) {
      new_fd = args[0]->Int32Value();
      dup2(new_fd, STDOUT_FILENO);
      dup2(new_fd, STDERR_FILENO);
    }
    else {
      freopen("/dev/null", "w", stderr);
      freopen("/dev/null", "w", stdout);
    }
  }

  return scope.Close(Number::New(getpid()));
}

//
// Close stdin by redirecting it to /dev/null
//
Handle<Value> CloseStdin(const Arguments& args) {
  freopen("/dev/null", "r", stdin);
}

//
// Close stderr by redirecting to /dev/null
//
Handle<Value> CloseStderr(const Arguments& args) {
  freopen("/dev/null", "w", stderr);
}

//
// Close stdout by redirecting to /dev/null
//
Handle<Value> CloseStdout(const Arguments& args) {
  freopen("/dev/null", "w", stdout);
}

//
// Closes all stdio by redirecting to /dev/null
//
Handle<Value> CloseStdio(const Arguments& args) {
  freopen("/dev/null", "r", stdin);
  freopen("/dev/null", "w", stderr);
  freopen("/dev/null", "w", stdout);
}

//
// File-lock to make sure that only one instance of daemon is running, also for storing pid
//   lock (filename)
//   @filename: a path to a lock-file.
//
//   Note: if filename doesn't exist, it will be created when function is called.
//
Handle<Value> LockD(const Arguments& args) {
  if (!args[0]->IsString())
    return Boolean::New(false);

  String::Utf8Value data(args[0]->ToString());
  char pid_str[PID_MAXLEN+1];

  int lfp = open(*data, O_RDWR | O_CREAT | O_TRUNC, 0640);
  if(lfp < 0) exit(1);
  if(lockf(lfp, F_TLOCK, 0) < 0) return Boolean::New(false);

  int len = snprintf(pid_str, PID_MAXLEN, "%d", getpid());
  write(lfp, pid_str, len);
  fsync(lfp);

  return Boolean::New(true);
}

Handle<Value> SetSid(const Arguments& args) {
  pid_t sid;
  sid = setsid();
  return Integer::New(sid);
}

const char* ToCString(const v8::String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}

//
// Set the chroot of this process. You probably want to be sure stuff is in here.
//   chroot (folder)
//   @folder {string}: The new root
//
Handle<Value> Chroot(const Arguments& args) {
  if (args.Length() < 1) {
    return ThrowException(Exception::TypeError(
      String::New("Must have one argument; a string of the folder to chroot to.")
    ));
  }
  uid_t uid;
  int rv;

  String::Utf8Value folderUtf8(args[0]->ToString());
  const char *folder = ToCString(folderUtf8);
  rv = chroot(folder);
  if (rv != 0) {
    return ThrowException(ErrnoException(errno, "chroot"));
  }
  chdir("/");

  return Boolean::New(true);
}

//
// Allow changing the real and effective user ID of this process
// so a root process can become unprivileged
//
Handle<Value> SetReuid(const Arguments& args) {
  if (args.Length() == 0 || (!args[0]->IsString() && !args[0]->IsInt32()))
    return ThrowException(Exception::Error(
      String::New("Must give a uid or username to become")
    ));

  if (args[0]->IsString()) {
    String::AsciiValue username(args[0]);

    struct passwd* pwd_entry = getpwnam(*username);

    if (pwd_entry) {
      setreuid(pwd_entry->pw_uid, pwd_entry->pw_uid);
      return Boolean::New(true);
    }
    else {
      return ThrowException(Exception::Error(
        String::New("User not found")
      ));
    }
  }
  else if (args[0]->IsInt32()) {
    uid_t uid;
    uid = args[0]->Int32Value();
    setreuid(uid, uid);
    return Boolean::New(true);
  }
}

//
// Initialize this add-on
//
extern "C" void init(Handle<Object> target) {
  HandleScope scope;

  NODE_SET_METHOD(target, "start", Start);
  NODE_SET_METHOD(target, "lock", LockD);
  NODE_SET_METHOD(target, "setsid", SetSid);
  NODE_SET_METHOD(target, "chroot", Chroot);
  NODE_SET_METHOD(target, "setreuid", SetReuid);
  NODE_SET_METHOD(target, "closeStderr", CloseStderr);
  NODE_SET_METHOD(target, "closeStdout", CloseStdout);
  NODE_SET_METHOD(target, "closeStdin", CloseStdin);
  NODE_SET_METHOD(target, "closeStdio", CloseStdio);
}<|endoftext|>


<commit_before>#define CATCH_CONFIG_RUNNER
#include <QApplication>
#include <QCloseEvent>
#include <QDir>
#include <QMenu>
#include <QSignalSpy>
#include <QWindow>
#include <candevicemodel.h>
#include <canrawviewmodel.h>
#include <catch.hpp>
#include <fakeit.hpp>
#include <log.h>
#include <nodes/FlowScene>
#include <pcinterface.h>
#include <projectconfig.h>
#include <projectconfigvalidator.h>

#include "ui_projectconfig.h"
#include <QPushButton>
#include <iconlabel.h>
#include <plugins.hpp>

std::shared_ptr<spdlog::logger> kDefaultLogger;

TEST_CASE("Loading and saving", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    ProjectConfig pc(new QWidget);
    QByteArray outConfig;

    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    REQUIRE_NOTHROW(pc.load(inConfig));
    REQUIRE_NOTHROW(outConfig = pc.save());
    REQUIRE_NOTHROW(pc.clearGraphView());
    REQUIRE_NOTHROW(pc.load(outConfig));
}

TEST_CASE("Color mode", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    ProjectConfig pc(new QWidget);

    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();
    REQUIRE_NOTHROW(pc.load(inConfig));

    REQUIRE_NOTHROW(pc.setColorMode(true));
    REQUIRE_NOTHROW(pc.setColorMode(false));
}

TEST_CASE("Close event", "[projectconfig]")
{
    QCloseEvent e;
    ProjectConfig pc(new QWidget);
    QSignalSpy closeSpy(&pc, &ProjectConfig::closeProject);

    pc.closeEvent(&e);

    CHECK(closeSpy.count() == 1);
}

TEST_CASE("Validation schema parse error", "[projectconfig]")
{
    CHECK(ProjectConfigValidator::loadConfigSchema("Makefile") == false);
}

TEST_CASE("Validation JSON format error", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig_wrong.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.read(40);

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig) == false);
}

TEST_CASE("Validation schema validation failed", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig_wrong.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig) == false);
}

TEST_CASE("Validation succeeded", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig));
}

TEST_CASE("Validator validate", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    ProjectConfigValidator pcv;
    CHECK(pcv.loadConfigSchema());
    CHECK(pcv.validateConfiguration(inConfig));
}

TEST_CASE("callbacks test", "[projectconfig]")
{
    using namespace fakeit;
    PCInterface::node_t nodeCreated;
    PCInterface::node_t nodeDeleted;
    PCInterface::node_t nodeClicked;
    PCInterface::menu_t nodeMenu;
    QtNodes::FlowScene* fs;

    Mock<PCInterface> pcMock;

    When(Method(pcMock, setNodeCreatedCallback)).Do([&](auto flow, auto&& fn) {
        fs = flow;
        nodeCreated = fn;
    });
    When(Method(pcMock, setNodeDeletedCallback)).Do([&](auto, auto&& fn) { nodeDeleted = fn; });
    When(Method(pcMock, setNodeDoubleClickedCallback)).Do([&](auto, auto&& fn) { nodeClicked = fn; });
    When(Method(pcMock, setNodeContextMenuCallback)).Do([&](auto, auto&& fn) { nodeMenu = fn; });
    Fake(Method(pcMock, showContextMenu));
    Fake(Method(pcMock, openProperties));

    ProjectConfig pc(nullptr, ProjectConfigCtx(&pcMock.get()));
    pc.simulationStarted();

    auto& node = fs->createNode(std::make_unique<CanDeviceModel>());
    node.restore({});
    nodeCreated(node);
    nodeClicked(node);
    nodeMenu(node, QPointF());

    QSignalSpy showingSpy(&pc, &ProjectConfig::handleWidgetShowing);
    auto& node2 = fs->createNode(std::make_unique<CanRawViewModel>());
    nodeClicked(node2);
    nodeMenu(node2, QPointF());
    CHECK(showingSpy.count() == 1);

    pc.simulationStopped();

    nodeClicked(node);
    nodeMenu(node, QPointF());
    nodeClicked(node2);
    nodeMenu(node2, QPointF());

    fs->removeNode(node);
    fs->removeNode(node2);
}

TEST_CASE("Plugin loading - sections not initialized", "[common]")
{

    QtNodes::FlowScene graphScene;
    Plugins plugins(graphScene.registry());
    REQUIRE_NOTHROW(plugins.addWidgets({ 0x11223344 }));
}

int main(int argc, char* argv[])
{
    Q_INIT_RESOURCE(CANdevResources);
    bool haveDebug = std::getenv("CDS_DEBUG") != nullptr;
    kDefaultLogger = spdlog::stdout_color_mt("cds");
    if (haveDebug) {
        kDefaultLogger->set_level(spdlog::level::debug);
    }
    cds_debug("Staring unit tests");
    QApplication a(argc, argv);
    return Catch::Session().run(argc, argv);
}
<commit_msg>Fix typo<commit_after>#define CATCH_CONFIG_RUNNER
#include <QApplication>
#include <QCloseEvent>
#include <QDir>
#include <QMenu>
#include <QSignalSpy>
#include <QWindow>
#include <candevicemodel.h>
#include <canrawviewmodel.h>
#include <catch.hpp>
#include <fakeit.hpp>
#include <log.h>
#include <nodes/FlowScene>
#include <pcinterface.h>
#include <projectconfig.h>
#include <projectconfigvalidator.h>

#include "ui_projectconfig.h"
#include <QPushButton>
#include <iconlabel.h>
#include <plugins.hpp>

std::shared_ptr<spdlog::logger> kDefaultLogger;

TEST_CASE("Loading and saving", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    ProjectConfig pc(new QWidget);
    QByteArray outConfig;

    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    REQUIRE_NOTHROW(pc.load(inConfig));
    REQUIRE_NOTHROW(outConfig = pc.save());
    REQUIRE_NOTHROW(pc.clearGraphView());
    REQUIRE_NOTHROW(pc.load(outConfig));
}

TEST_CASE("Color mode", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    ProjectConfig pc(new QWidget);

    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();
    REQUIRE_NOTHROW(pc.load(inConfig));

    REQUIRE_NOTHROW(pc.setColorMode(true));
    REQUIRE_NOTHROW(pc.setColorMode(false));
}

TEST_CASE("Close event", "[projectconfig]")
{
    QCloseEvent e;
    ProjectConfig pc(new QWidget);
    QSignalSpy closeSpy(&pc, &ProjectConfig::closeProject);

    pc.closeEvent(&e);

    CHECK(closeSpy.count() == 1);
}

TEST_CASE("Validation schema parse error", "[projectconfig]")
{
    CHECK(ProjectConfigValidator::loadConfigSchema("Makefile") == false);
}

TEST_CASE("Validation JSON format error", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig_wrong.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.read(40);

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig) == false);
}

TEST_CASE("Validation schema validation failed", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig_wrong.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig) == false);
}

TEST_CASE("Validation succeeded", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    CHECK(ProjectConfigValidator::validateConfiguration(inConfig));
}

TEST_CASE("Validator validate", "[projectconfig]")
{
    QDir dir("configfiles");
    QFile file(dir.absoluteFilePath("projectconfig.cds"));
    CHECK(file.open(QIODevice::ReadOnly) == true);
    auto inConfig = file.readAll();

    ProjectConfigValidator pcv;
    CHECK(pcv.loadConfigSchema());
    CHECK(pcv.validateConfiguration(inConfig));
}

TEST_CASE("callbacks test", "[projectconfig]")
{
    using namespace fakeit;
    PCInterface::node_t nodeCreated;
    PCInterface::node_t nodeDeleted;
    PCInterface::node_t nodeClicked;
    PCInterface::menu_t nodeMenu;
    QtNodes::FlowScene* fs;

    Mock<PCInterface> pcMock;

    When(Method(pcMock, setNodeCreatedCallback)).Do([&](auto flow, auto&& fn) {
        fs = flow;
        nodeCreated = fn;
    });
    When(Method(pcMock, setNodeDeletedCallback)).Do([&](auto, auto&& fn) { nodeDeleted = fn; });
    When(Method(pcMock, setNodeDoubleClickedCallback)).Do([&](auto, auto&& fn) { nodeClicked = fn; });
    When(Method(pcMock, setNodeContextMenuCallback)).Do([&](auto, auto&& fn) { nodeMenu = fn; });
    Fake(Method(pcMock, showContextMenu));
    Fake(Method(pcMock, openProperties));

    ProjectConfig pc(nullptr, ProjectConfigCtx(&pcMock.get()));
    pc.simulationStarted();

    auto& node = fs->createNode(std::make_unique<CanDeviceModel>());
    node.restore({});
    nodeCreated(node);
    nodeClicked(node);
    nodeMenu(node, QPointF());

    QSignalSpy showingSpy(&pc, &ProjectConfig::handleWidgetShowing);
    auto& node2 = fs->createNode(std::make_unique<CanRawViewModel>());
    nodeClicked(node2);
    nodeMenu(node2, QPointF());
    CHECK(showingSpy.count() == 1);

    pc.simulationStopped();

    nodeClicked(node);
    nodeMenu(node, QPointF());
    nodeClicked(node2);
    nodeMenu(node2, QPointF());

    fs->removeNode(node);
    fs->removeNode(node2);
}

TEST_CASE("Plugin loading - sections not initialized", "[common]")
{

    QtNodes::FlowScene graphScene;
    Plugins plugins(graphScene.registry());
    REQUIRE_NOTHROW(plugins.addWidgets({ 0x11223344 }));
}

int main(int argc, char* argv[])
{
    Q_INIT_RESOURCE(CANdevResources);
    bool haveDebug = std::getenv("CDS_DEBUG") != nullptr;
    kDefaultLogger = spdlog::stdout_color_mt("cds");
    if (haveDebug) {
        kDefaultLogger->set_level(spdlog::level::debug);
    }
    cds_debug("Starting unit tests");
    QApplication a(argc, argv);
    return Catch::Session().run(argc, argv);
}
<|endoftext|>


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

#ifndef xeumeuleu_attribute_hpp
#define xeumeuleu_attribute_hpp

#include <string>

namespace xml
{
// =============================================================================
/** @class  attribute_manipulator
    @brief  Attribute manipulator
*/
// Created: MAT 2006-01-05
// =============================================================================
template< typename T >
class attribute_manipulator
{
public:
    //! @name Constructors/Destructor
    //@{
    attribute_manipulator( const std::string& name, T& value, bool skip = false )
        : name_ ( name )
        , value_( value )
        , skip_( skip )
    {}
    //@}

private:
    //! @name Copy/Assignment
    //@{
    attribute_manipulator& operator=( const attribute_manipulator& ); //!< Assignment operator
    //@}

public:
    //! @name Member data
    //@{
    std::string name_;
    T& value_;
    bool skip_;
    //@}
};

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2006-01-06
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< const T > attribute( const std::string& name, const T& value )
{
    return attribute_manipulator< const T >( name, value );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2017-03-21
// -----------------------------------------------------------------------------
template< typename T, typename F >
attribute_manipulator< const T > attribute( const std::string& name, const T& value, const F& fallback )
{
    return attribute_manipulator< const T >( name, value, value == fallback );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2017-03-21
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< const T* > attribute( const std::string& name, const T* value, std::nullptr_t )
{
    return attribute_manipulator< const T* >( name, value, !value );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2006-01-06
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< T > attribute( const std::string& name, T& value )
{
    return attribute_manipulator< T >( name, value );
}

}

#endif // xeumeuleu_attribute_hpp
<commit_msg>Fixed reference on local pointer<commit_after>/*
 *   Copyright (c) 2006, Mathieu Champlon
 *   All rights reserved.
 *
 *   Redistribution  and use  in source  and binary  forms, with  or without
 *   modification, are permitted provided  that the following conditions are
 *   met :
 *
 *   . Redistributions  of  source  code  must  retain  the  above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   . Redistributions in  binary form  must reproduce  the above  copyright
 *     notice, this list of conditions  and the following disclaimer in  the
 *     documentation and/or other materials provided with the distribution.
 *
 *   . Neither  the name  of  the  copyright  holders  nor the names  of the
 *     contributors may be used to endorse  or promote products derived from
 *     this software without specific prior written permission.
 *
 *   THIS SOFTWARE  IS  PROVIDED  BY THE  COPYRIGHT HOLDERS  AND CONTRIBUTORS
 *   ``AS IS''  AND ANY  EXPRESS OR  IMPLIED WARRANTIES,  INCLUDING,  BUT NOT
 *   LIMITED TO, THE IMPLIED  WARRANTIES  OF MERCHANTABILITY AND  FITNESS FOR
 *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE THE COPYRIGHT
 *   OWNERS OR CONTRIBUTORS  BE LIABLE FOR ANY  DIRECT, INDIRECT, INCIDENTAL,
 *   SPECIAL,  EXEMPLARY,  OR  CONSEQUENTIAL   DAMAGES  (INCLUDING,  BUT  NOT
 *   LIMITED TO,  PROCUREMENT OF SUBSTITUTE  GOODS OR SERVICES;  LOSS OF USE,
 *   DATA, OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED  AND ON  ANY
 *   THEORY  OF  LIABILITY,  WHETHER IN  CONTRACT,  STRICT LIABILITY, OR TORT
 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY  WAY  OUT OF  THE USE
 *   OF THIS SOFTWARE, EVEN  IF  ADVISED OF  THE POSSIBILITY  OF SUCH DAMAGE.
 */

#ifndef xeumeuleu_attribute_hpp
#define xeumeuleu_attribute_hpp

#include <string>

namespace xml
{
// =============================================================================
/** @class  attribute_manipulator
    @brief  Attribute manipulator
*/
// Created: MAT 2006-01-05
// =============================================================================
template< typename T >
class attribute_manipulator
{
public:
    //! @name Constructors/Destructor
    //@{
    attribute_manipulator( const std::string& name, T& value, bool skip = false )
        : name_ ( name )
        , value_( value )
        , skip_ ( skip )
    {}
    //@}

private:
    //! @name Copy/Assignment
    //@{
    attribute_manipulator& operator=( const attribute_manipulator& ); //!< Assignment operator
    //@}

public:
    //! @name Member data
    //@{
    std::string name_;
    T& value_;
    bool skip_;
    //@}
};

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2006-01-06
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< const T > attribute( const std::string& name, const T& value )
{
    return attribute_manipulator< const T >( name, value );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2017-03-21
// -----------------------------------------------------------------------------
template< typename T, typename F >
attribute_manipulator< const T > attribute( const std::string& name, const T& value, const F& fallback )
{
    return attribute_manipulator< const T >( name, value, value == fallback );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2017-03-21
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< const T > attribute( const std::string& name, const T& value, std::nullptr_t )
{
    return attribute_manipulator< const T >( name, value, !value );
}

// -----------------------------------------------------------------------------
// Name: attribute
// Created: MAT 2006-01-06
// -----------------------------------------------------------------------------
template< typename T >
attribute_manipulator< T > attribute( const std::string& name, T& value )
{
    return attribute_manipulator< T >( name, value );
}

}

#endif // xeumeuleu_attribute_hpp
<|endoftext|>


<commit_before>/*
 *  This file is part of Poedit (http://www.poedit.net)
 *
 *  Copyright (C) 1999-2008 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 *  $Id$
 *
 *  Application class
 *
 */

#include <wx/wxprec.h>

#include <wx/wx.h>
#include <wx/config.h>
#include <wx/fs_zip.h>
#include <wx/image.h>
#include <wx/cmdline.h>
#include <wx/log.h>
#include <wx/xrc/xmlres.h>
#include <wx/xrc/xh_all.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
#include <wx/sysopt.h>

#ifdef USE_SPARKLE
#include <Sparkle/SUCarbonAPI.h>
#endif // USE_SPARKLE

#if !wxUSE_UNICODE
    #error "Unicode build of wxWidgets is required by Poedit"
#endif

#include "edapp.h"
#include "edframe.h"
#include "manager.h"
#include "prefsdlg.h"
#include "parser.h"
#include "chooselang.h"
#include "icons.h"

IMPLEMENT_APP(PoeditApp);

wxString PoeditApp::GetAppPath() const
{
#if defined(__UNIX__)
    wxString home;
    if (!wxGetEnv(_T("POEDIT_PREFIX"), &home))
        home = wxString::FromAscii(POEDIT_PREFIX);
    return home;
#elif defined(__WXMSW__)
    wxString exedir;
    wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(),
                          &exedir, NULL, NULL);
    wxFileName fn = wxFileName::DirName(exedir);
    fn.RemoveLastDir();
    return fn.GetFullPath();
#else
#error "Unsupported platform!"
#endif
}

wxString PoeditApp::GetAppVersion() const
{
    wxString version(_T("1.4.0"));
    return version;
}

#ifndef __WXMAC__
static wxArrayString gs_filesToOpen;
#endif

extern void InitXmlResource();

bool PoeditApp::OnInit()
{
    if (!wxApp::OnInit())
        return false;

#if defined(__WXMAC__) && wxCHECK_VERSION(2,8,5)
    wxSystemOptions::SetOption(wxMAC_TEXTCONTROL_USE_SPELL_CHECKER, 1);
#endif

#ifdef __WXMAC__
    SetExitOnFrameDelete(false);
#endif

#if defined(__UNIX__) && !defined(__WXMAC__)
    wxString home = wxGetHomeDir() + _T("/");

    // create Poedit cfg dir, move ~/.poedit to ~/.poedit/config
    // (upgrade from older versions of Poedit which used ~/.poedit file)
    if (!wxDirExists(home + _T(".poedit")))
    {
        if (wxFileExists(home + _T(".poedit")))
            wxRenameFile(home + _T(".poedit"), home + _T(".poedit2"));
        wxMkdir(home + _T(".poedit"));
        if (wxFileExists(home + _T(".poedit2")))
            wxRenameFile(home + _T(".poedit2"), home + _T(".poedit/config"));
    }
#endif

    SetVendorName(_T("Vaclav Slavik"));
    SetAppName(_T("Poedit"));

#if defined(__WXMAC__)
    #define CFG_FILE (wxStandardPaths::Get().GetUserConfigDir() + _T("/net.poedit.Poedit.cfg"))
#elif defined(__UNIX__)
    #define CFG_FILE (home + _T(".poedit/config"))
#else
    #define CFG_FILE wxEmptyString
#endif

#ifdef __WXMAC__
    // upgrade from the old location of config file:
    wxString oldcfgfile = wxStandardPaths::Get().GetUserConfigDir() + _T("/poedit.cfg");
    if (wxFileExists(oldcfgfile) && !wxFileExists(CFG_FILE))
    {
        wxRenameFile(oldcfgfile, CFG_FILE);
    }
#endif

    wxConfigBase::Set(
        new wxConfig(wxEmptyString, wxEmptyString, CFG_FILE, wxEmptyString,
                     wxCONFIG_USE_GLOBAL_FILE | wxCONFIG_USE_LOCAL_FILE));
    wxConfigBase::Get()->SetExpandEnvVars(false);

    wxImage::AddHandler(new wxGIFHandler);
    wxImage::AddHandler(new wxPNGHandler);
    wxXmlResource::Get()->InitAllHandlers();
    InitXmlResource();

    SetDefaultCfg(wxConfig::Get());

#ifdef HAS_INSERT_PROVIDER
    wxArtProvider::Insert(new PoeditArtProvider);
#else
    wxArtProvider::PushProvider(new PoeditArtProvider);
#endif

#ifdef __WXMAC__
    wxLocale::AddCatalogLookupPathPrefix(
        wxStandardPaths::Get().GetResourcesDir() + _T("/locale"));
#else
    wxLocale::AddCatalogLookupPathPrefix(GetAppPath() + _T("/share/locale"));
#endif

    m_locale.Init(GetUILanguage());

    m_locale.AddCatalog(_T("poedit"));

    if (wxConfig::Get()->Read(_T("translator_name"), _T("nothing")) == _T("nothing"))
    {
        wxMessageBox(_("This is first time you run Poedit.\nPlease fill in your name and email address.\n(This information is used only in catalogs headers)"), _("Setup"),
                       wxOK | wxICON_INFORMATION);

        PreferencesDialog dlg;
        dlg.TransferTo(wxConfig::Get());
        if (dlg.ShowModal() == wxID_OK)
            dlg.TransferFrom(wxConfig::Get());
    }

    // opening files or creating empty window is handled differently on Macs,
    // using MacOpenFile() and MacNewFile(), so don't do it here:
#ifndef __WXMAC__
    if (gs_filesToOpen.GetCount() == 0)
    {
        OpenNewFile();
    }
    else
    {
        for (size_t i = 0; i < gs_filesToOpen.GetCount(); i++)
            OpenFile(gs_filesToOpen[i]);
        gs_filesToOpen.clear();
    }
#endif // !__WXMAC__

#ifdef USE_SPARKLE
    SUSparkleInitializeForCarbon();
#endif // USE_SPARKLE

    return true;
}

void PoeditApp::OpenNewFile()
{
    if (wxConfig::Get()->Read(_T("manager_startup"), (long)false))
        ManagerFrame::Create()->Show(true);
    else
        PoeditFrame::Create(wxEmptyString);
}

void PoeditApp::OpenFile(const wxString& name)
{
    PoeditFrame::Create(name);
}

void PoeditApp::SetDefaultParsers(wxConfigBase *cfg)
{
    ParsersDB pdb;
    bool changed = false;
    wxString defaultsVersion = cfg->Read(_T("Parsers/DefaultsVersion"),
                                         _T("1.2.x"));
    pdb.Read(cfg);

    // Add parsers for languages supported by gettext itself (but only if the
    // user didn't already add language with this name himself):
    static struct
    {
        const wxChar *name;
        const wxChar *exts;
    } s_gettextLangs[] = {
        { _T("C/C++"),    _T("*.c;*.cpp;*.h;*.hpp;*.cc;*.C;*.cxx;*.hxx") },
#ifndef __WINDOWS__
        // FIXME: not supported by 0.13.1 shipped with poedit on win32
        { _T("C#"),       _T("*.cs") },
#endif
        { _T("Java"),     _T("*.java") },
        { _T("Perl"),     _T("*.pl") },
        { _T("PHP"),      _T("*.php") },
        { _T("Python"),   _T("*.py") },
        { _T("TCL"),      _T("*.tcl") },
        { NULL, NULL }
    };

    for (size_t i = 0; s_gettextLangs[i].name != NULL; i++)
    {
        // if this lang is already registered, don't overwrite it:
        if (pdb.FindParser(s_gettextLangs[i].name) != -1)
            continue;

        // otherwise add new parser:
        Parser p;
        p.Name = s_gettextLangs[i].name;
        p.Extensions = s_gettextLangs[i].exts;
        p.Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
        p.KeywordItem = _T("-k%k");
        p.FileItem = _T("%f");
        p.CharsetItem = _T("--from-code=%c");
        pdb.Add(p);
        changed = true;
    }

    // If upgrading Poedit to 1.2.4, add dxgettext parser for Delphi:
#ifdef __WINDOWS__
    if (defaultsVersion == _T("1.2.x"))
    {
        Parser p;
        p.Name = _T("Delphi (dxgettext)");
        p.Extensions = _T("*.pas;*.dpr;*.xfm;*.dfm");
        p.Command = _T("dxgettext --so %o %F");
        p.KeywordItem = wxEmptyString;
        p.FileItem = _T("%f");
        pdb.Add(p);
        changed = true;
    }
#endif

    // If upgrading Poedit to 1.2.5, update C++ parser to handle --from-code:
    if (defaultsVersion == _T("1.2.x") || defaultsVersion == _T("1.2.4"))
    {
        int cpp = pdb.FindParser(_T("C/C++"));
        if (cpp != -1)
        {
            if (pdb[cpp].Command == _T("xgettext --force-po -o %o %K %F"))
            {
                pdb[cpp].Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
                pdb[cpp].CharsetItem = _T("--from-code=%c");
                changed = true;
            }
        }
    }

    // 1.4.0 adds --omit-header to parsers lines:
    for ( size_t i = 0; i < pdb.size(); ++i )
    {
        if ( pdb[i].Command == _T("xgettext --force-po -o %o %C %K %F") )
        {
            pdb[i].Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
            changed = true;
        }
    }

    if (changed)
    {
        pdb.Write(cfg);
        cfg->Write(_T("Parsers/DefaultsVersion"), GetAppVersion());
    }
}

void PoeditApp::SetDefaultCfg(wxConfigBase *cfg)
{
    SetDefaultParsers(cfg);

    if (cfg->Read(_T("version"), wxEmptyString) == GetAppVersion()) return;

    if (cfg->Read(_T("TM/database_path"), wxEmptyString).empty())
    {
        wxString dbpath;
#if defined(__WXMAC__)
        dbpath = wxStandardPaths::Get().GetUserDataDir() + _T("/tm");
#elif defined(__UNIX__)
        dbpath = wxGetHomeDir() + _T("/.poedit/tm");
#elif defined(__WXMSW__)
        dbpath = wxGetHomeDir() + _T("\\poedit_tm");
#endif
        cfg->Write(_T("TM/database_path"), dbpath);
    }

    if (cfg->Read(_T("TM/search_paths"), wxEmptyString).empty())
    {
        wxString paths;
#if defined(__UNIX__)
        paths = wxGetHomeDir() + _T(":/usr/share/locale:/usr/local/share/locale");
#elif defined(__WXMSW__)
        paths = _T("C:");
#endif
        cfg->Write(_T("TM/search_paths"), paths);
    }

    cfg->Write(_T("version"), GetAppVersion());
}

void PoeditApp::OnInitCmdLine(wxCmdLineParser& parser)
{
    wxApp::OnInitCmdLine(parser);
    parser.AddParam(_T("catalog.po"), wxCMD_LINE_VAL_STRING,
                    wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
}

bool PoeditApp::OnCmdLineParsed(wxCmdLineParser& parser)
{
    if (!wxApp::OnCmdLineParsed(parser))
        return false;

#ifndef __WXMAC__
    for (size_t i = 0; i < parser.GetParamCount(); i++)
        gs_filesToOpen.Add(parser.GetParam(i));
#endif

    return true;
}
<commit_msg>fixed duplicate Help menu on OS X when using non-English translation<commit_after>/*
 *  This file is part of Poedit (http://www.poedit.net)
 *
 *  Copyright (C) 1999-2008 Vaclav Slavik
 *
 *  Permission is hereby granted, free of charge, to any person obtaining a
 *  copy of this software and associated documentation files (the "Software"),
 *  to deal in the Software without restriction, including without limitation
 *  the rights to use, copy, modify, merge, publish, distribute, sublicense,
 *  and/or sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in
 *  all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 *  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 *  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 *  DEALINGS IN THE SOFTWARE.
 *
 *  $Id$
 *
 *  Application class
 *
 */

#include <wx/wxprec.h>

#include <wx/wx.h>
#include <wx/config.h>
#include <wx/fs_zip.h>
#include <wx/image.h>
#include <wx/cmdline.h>
#include <wx/log.h>
#include <wx/xrc/xmlres.h>
#include <wx/xrc/xh_all.h>
#include <wx/stdpaths.h>
#include <wx/filename.h>
#include <wx/sysopt.h>

#ifdef USE_SPARKLE
#include <Sparkle/SUCarbonAPI.h>
#endif // USE_SPARKLE

#if !wxUSE_UNICODE
    #error "Unicode build of wxWidgets is required by Poedit"
#endif

#include "edapp.h"
#include "edframe.h"
#include "manager.h"
#include "prefsdlg.h"
#include "parser.h"
#include "chooselang.h"
#include "icons.h"

IMPLEMENT_APP(PoeditApp);

wxString PoeditApp::GetAppPath() const
{
#if defined(__UNIX__)
    wxString home;
    if (!wxGetEnv(_T("POEDIT_PREFIX"), &home))
        home = wxString::FromAscii(POEDIT_PREFIX);
    return home;
#elif defined(__WXMSW__)
    wxString exedir;
    wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(),
                          &exedir, NULL, NULL);
    wxFileName fn = wxFileName::DirName(exedir);
    fn.RemoveLastDir();
    return fn.GetFullPath();
#else
#error "Unsupported platform!"
#endif
}

wxString PoeditApp::GetAppVersion() const
{
    wxString version(_T("1.4.0"));
    return version;
}

#ifndef __WXMAC__
static wxArrayString gs_filesToOpen;
#endif

extern void InitXmlResource();

bool PoeditApp::OnInit()
{
    if (!wxApp::OnInit())
        return false;

#if defined(__WXMAC__) && wxCHECK_VERSION(2,8,5)
    wxSystemOptions::SetOption(wxMAC_TEXTCONTROL_USE_SPELL_CHECKER, 1);
#endif

#ifdef __WXMAC__
    // so that help menu is correctly merged with system-provided menu
    // (see http://sourceforge.net/tracker/index.php?func=detail&aid=1600747&group_id=9863&atid=309863)
    s_macHelpMenuTitleName = _("&Help");

    SetExitOnFrameDelete(false);
#endif

#if defined(__UNIX__) && !defined(__WXMAC__)
    wxString home = wxGetHomeDir() + _T("/");

    // create Poedit cfg dir, move ~/.poedit to ~/.poedit/config
    // (upgrade from older versions of Poedit which used ~/.poedit file)
    if (!wxDirExists(home + _T(".poedit")))
    {
        if (wxFileExists(home + _T(".poedit")))
            wxRenameFile(home + _T(".poedit"), home + _T(".poedit2"));
        wxMkdir(home + _T(".poedit"));
        if (wxFileExists(home + _T(".poedit2")))
            wxRenameFile(home + _T(".poedit2"), home + _T(".poedit/config"));
    }
#endif

    SetVendorName(_T("Vaclav Slavik"));
    SetAppName(_T("Poedit"));

#if defined(__WXMAC__)
    #define CFG_FILE (wxStandardPaths::Get().GetUserConfigDir() + _T("/net.poedit.Poedit.cfg"))
#elif defined(__UNIX__)
    #define CFG_FILE (home + _T(".poedit/config"))
#else
    #define CFG_FILE wxEmptyString
#endif

#ifdef __WXMAC__
    // upgrade from the old location of config file:
    wxString oldcfgfile = wxStandardPaths::Get().GetUserConfigDir() + _T("/poedit.cfg");
    if (wxFileExists(oldcfgfile) && !wxFileExists(CFG_FILE))
    {
        wxRenameFile(oldcfgfile, CFG_FILE);
    }
#endif

    wxConfigBase::Set(
        new wxConfig(wxEmptyString, wxEmptyString, CFG_FILE, wxEmptyString,
                     wxCONFIG_USE_GLOBAL_FILE | wxCONFIG_USE_LOCAL_FILE));
    wxConfigBase::Get()->SetExpandEnvVars(false);

    wxImage::AddHandler(new wxGIFHandler);
    wxImage::AddHandler(new wxPNGHandler);
    wxXmlResource::Get()->InitAllHandlers();
    InitXmlResource();

    SetDefaultCfg(wxConfig::Get());

#ifdef HAS_INSERT_PROVIDER
    wxArtProvider::Insert(new PoeditArtProvider);
#else
    wxArtProvider::PushProvider(new PoeditArtProvider);
#endif

#ifdef __WXMAC__
    wxLocale::AddCatalogLookupPathPrefix(
        wxStandardPaths::Get().GetResourcesDir() + _T("/locale"));
#else
    wxLocale::AddCatalogLookupPathPrefix(GetAppPath() + _T("/share/locale"));
#endif

    m_locale.Init(GetUILanguage());

    m_locale.AddCatalog(_T("poedit"));

    if (wxConfig::Get()->Read(_T("translator_name"), _T("nothing")) == _T("nothing"))
    {
        wxMessageBox(_("This is first time you run Poedit.\nPlease fill in your name and email address.\n(This information is used only in catalogs headers)"), _("Setup"),
                       wxOK | wxICON_INFORMATION);

        PreferencesDialog dlg;
        dlg.TransferTo(wxConfig::Get());
        if (dlg.ShowModal() == wxID_OK)
            dlg.TransferFrom(wxConfig::Get());
    }

    // opening files or creating empty window is handled differently on Macs,
    // using MacOpenFile() and MacNewFile(), so don't do it here:
#ifndef __WXMAC__
    if (gs_filesToOpen.GetCount() == 0)
    {
        OpenNewFile();
    }
    else
    {
        for (size_t i = 0; i < gs_filesToOpen.GetCount(); i++)
            OpenFile(gs_filesToOpen[i]);
        gs_filesToOpen.clear();
    }
#endif // !__WXMAC__

#ifdef USE_SPARKLE
    SUSparkleInitializeForCarbon();
#endif // USE_SPARKLE

    return true;
}

void PoeditApp::OpenNewFile()
{
    if (wxConfig::Get()->Read(_T("manager_startup"), (long)false))
        ManagerFrame::Create()->Show(true);
    else
        PoeditFrame::Create(wxEmptyString);
}

void PoeditApp::OpenFile(const wxString& name)
{
    PoeditFrame::Create(name);
}

void PoeditApp::SetDefaultParsers(wxConfigBase *cfg)
{
    ParsersDB pdb;
    bool changed = false;
    wxString defaultsVersion = cfg->Read(_T("Parsers/DefaultsVersion"),
                                         _T("1.2.x"));
    pdb.Read(cfg);

    // Add parsers for languages supported by gettext itself (but only if the
    // user didn't already add language with this name himself):
    static struct
    {
        const wxChar *name;
        const wxChar *exts;
    } s_gettextLangs[] = {
        { _T("C/C++"),    _T("*.c;*.cpp;*.h;*.hpp;*.cc;*.C;*.cxx;*.hxx") },
#ifndef __WINDOWS__
        // FIXME: not supported by 0.13.1 shipped with poedit on win32
        { _T("C#"),       _T("*.cs") },
#endif
        { _T("Java"),     _T("*.java") },
        { _T("Perl"),     _T("*.pl") },
        { _T("PHP"),      _T("*.php") },
        { _T("Python"),   _T("*.py") },
        { _T("TCL"),      _T("*.tcl") },
        { NULL, NULL }
    };

    for (size_t i = 0; s_gettextLangs[i].name != NULL; i++)
    {
        // if this lang is already registered, don't overwrite it:
        if (pdb.FindParser(s_gettextLangs[i].name) != -1)
            continue;

        // otherwise add new parser:
        Parser p;
        p.Name = s_gettextLangs[i].name;
        p.Extensions = s_gettextLangs[i].exts;
        p.Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
        p.KeywordItem = _T("-k%k");
        p.FileItem = _T("%f");
        p.CharsetItem = _T("--from-code=%c");
        pdb.Add(p);
        changed = true;
    }

    // If upgrading Poedit to 1.2.4, add dxgettext parser for Delphi:
#ifdef __WINDOWS__
    if (defaultsVersion == _T("1.2.x"))
    {
        Parser p;
        p.Name = _T("Delphi (dxgettext)");
        p.Extensions = _T("*.pas;*.dpr;*.xfm;*.dfm");
        p.Command = _T("dxgettext --so %o %F");
        p.KeywordItem = wxEmptyString;
        p.FileItem = _T("%f");
        pdb.Add(p);
        changed = true;
    }
#endif

    // If upgrading Poedit to 1.2.5, update C++ parser to handle --from-code:
    if (defaultsVersion == _T("1.2.x") || defaultsVersion == _T("1.2.4"))
    {
        int cpp = pdb.FindParser(_T("C/C++"));
        if (cpp != -1)
        {
            if (pdb[cpp].Command == _T("xgettext --force-po -o %o %K %F"))
            {
                pdb[cpp].Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
                pdb[cpp].CharsetItem = _T("--from-code=%c");
                changed = true;
            }
        }
    }

    // 1.4.0 adds --omit-header to parsers lines:
    for ( size_t i = 0; i < pdb.size(); ++i )
    {
        if ( pdb[i].Command == _T("xgettext --force-po -o %o %C %K %F") )
        {
            pdb[i].Command = _T("xgettext --force-po --omit-header -o %o %C %K %F");
            changed = true;
        }
    }

    if (changed)
    {
        pdb.Write(cfg);
        cfg->Write(_T("Parsers/DefaultsVersion"), GetAppVersion());
    }
}

void PoeditApp::SetDefaultCfg(wxConfigBase *cfg)
{
    SetDefaultParsers(cfg);

    if (cfg->Read(_T("version"), wxEmptyString) == GetAppVersion()) return;

    if (cfg->Read(_T("TM/database_path"), wxEmptyString).empty())
    {
        wxString dbpath;
#if defined(__WXMAC__)
        dbpath = wxStandardPaths::Get().GetUserDataDir() + _T("/tm");
#elif defined(__UNIX__)
        dbpath = wxGetHomeDir() + _T("/.poedit/tm");
#elif defined(__WXMSW__)
        dbpath = wxGetHomeDir() + _T("\\poedit_tm");
#endif
        cfg->Write(_T("TM/database_path"), dbpath);
    }

    if (cfg->Read(_T("TM/search_paths"), wxEmptyString).empty())
    {
        wxString paths;
#if defined(__UNIX__)
        paths = wxGetHomeDir() + _T(":/usr/share/locale:/usr/local/share/locale");
#elif defined(__WXMSW__)
        paths = _T("C:");
#endif
        cfg->Write(_T("TM/search_paths"), paths);
    }

    cfg->Write(_T("version"), GetAppVersion());
}

void PoeditApp::OnInitCmdLine(wxCmdLineParser& parser)
{
    wxApp::OnInitCmdLine(parser);
    parser.AddParam(_T("catalog.po"), wxCMD_LINE_VAL_STRING,
                    wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE);
}

bool PoeditApp::OnCmdLineParsed(wxCmdLineParser& parser)
{
    if (!wxApp::OnCmdLineParsed(parser))
        return false;

#ifndef __WXMAC__
    for (size_t i = 0; i < parser.GetParamCount(); i++)
        gs_filesToOpen.Add(parser.GetParam(i));
#endif

    return true;
}
<|endoftext|>


<commit_before>// Lesson 13.cpp : Defines the entry point for the console application.

#include <render_framework\render_framework.h>
#include <chrono>
#pragma comment (lib , "Render Framework" )

using namespace std;
using namespace glm;
using namespace render_framework;
using namespace chrono;

#define OBJECTS 1

// Global scope box
shared_ptr<mesh> object[1];
shared_ptr<arc_ball_camera> cam;
shared_ptr<mesh> plane;
float dissolveFactor = 1.0f;

/*
 * userTranslation
 *
 * Moves the object around inside the window using the keyboard arrow keys.
 */
void userTranslation(float deltaTime)
{
	// Move the quad when arrow keys are pressed
	if (glfwGetKey(renderer::get_instance().get_window(), 'J')) {
		object[0]->trans.translate(vec3(-10.0, 0.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'L')) {
		object[0]->trans.translate(vec3(10.0, 0.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'I')) {
		object[0]->trans.translate(vec3(0.0, 0.0, -10.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'K')) {
		object[0]->trans.translate(vec3(0.0, 0.0, 10.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'U')) {
		object[0]->trans.translate(vec3(0.0, 10.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'O')) {
		object[0]->trans.translate(vec3(0.0, -10.0, 0.0) * deltaTime);
	}
} // userTranslation()

/*
 * cameraTranslation
 *
 * Moves the object around inside the window using the keyboard arrow keys.
 */
void cameraTranslation(float deltaTime)
{
	// Move the quad when arrow keys are pressed
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_RIGHT)) {
		cam->rotate(0.0, half_pi<float>() * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_LEFT)) {
		cam->rotate(0.0, -half_pi<float>() * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_UP)) {
		cam->move(-5.0f * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_DOWN)) {
		cam->move(5.0f * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'W')) {
		cam->rotate(half_pi<float>() * deltaTime, 0.0);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'S')) {
		cam->rotate(-half_pi<float>() * deltaTime, 0.0);
	}

} // cameraTranslation()

/*
 * Update routine
 *
 * Updates the application state
 */
void update(float deltaTime) {

	cameraTranslation(deltaTime);
	userTranslation(deltaTime);

	cam->set_target(object[0]->trans.position);
	cam->update(deltaTime);

} // update()

bool load_content() {

	int i = 0;
	for (i=0;i<OBJECTS;i++) {
		// Create plane
		plane = make_shared<mesh>();
		plane->geom = geometry_builder::create_plane();
		plane->trans.translate(vec3(0.0f, -1.0f, 0.0f));
		// Load in effect.  Start with shaders
		auto eff = make_shared<effect>();
		eff->add_shader("shader.vert", GL_VERTEX_SHADER);
		eff->add_shader("shader.frag", GL_FRAGMENT_SHADER);
		if (!effect_loader::build_effect(eff)) {
			return false;
		}
		// Attach effect to the plane mesh
		plane->mat = make_shared<material>();
		plane->mat->effect = eff;
		// Set the texture for shader
		plane->mat->set_texture("tex", texture_loader::load("Checkered.png"));

		// Create box
		object[i] = make_shared<mesh>();
		object[i]->geom = geometry_builder::create_torus();

		// Load in effect.  Start with shaders
		auto eff2 = make_shared<effect>();
		eff2->add_shader("cell.vert", GL_VERTEX_SHADER);
		eff2->add_shader("cell.frag", GL_FRAGMENT_SHADER);
		if (!effect_loader::build_effect(eff2)) {
			return false;
		}
		// Attach effect to the object
		object[i]->mat = make_shared<material>();
		object[i]->mat->effect = eff2;
		// Set textures for shader
		vector<vec4> colour;
		colour.push_back(vec4(0.12f, 0.0f, 0.0f, 1.0f));
		colour.push_back(vec4(0.25f, 0.0f, 0.0f, 1.0));
		colour.push_back(vec4(0.5f, 0.0f, 0.0f, 1.0));
		colour.push_back(vec4(1.0f, 0.0f, 0.0f, 1.0));
		auto tex = texture_generator::generate(colour, 4, 1, false, false);
		// Attach texture to the box effect

		object[i]->mat->set_texture("tex", tex);

	}

	return true;

} // load_content()

bool load_camera() {
	// Initialize the camera
	cam = make_shared<arc_ball_camera>();

	/* Set the projection matrix */
	// First get the aspect ratio (width/height)
	float aspect = (float)renderer::get_instance().get_screen_width() /
					(float)renderer::get_instance().get_screen_width();
	// Use this to set the camera projection matrix
	cam->set_projection(
						quarter_pi<float>(),			// FOV
						aspect,							// Aspect ratio
						2.414f,							// Near plane
						10000.0f);						// Far plane
	// Set the camera properties
	cam->set_position(vec3(0.0, 0.0, 0.0));
	cam->set_distance(20.0f);

	// Attach camera to renderer
	renderer::get_instance().set_camera(cam);

	// Set the view matrix
	auto view = lookAt(
					vec3(20.0f, 20.0f, 20.0f),	// Camera position
					vec3(0.0f, 0.0f, 0.0f),		// Target
					vec3(0.0f, 1.0f, 0.0f));	// Up vector
	renderer::get_instance().set_view(view);

	return true;
} // load_camera

int main()
{
	// Initialize the renderer
	if (!renderer::get_instance().initialise()) return -1;

	// Set the clear colour to cyan
	glClearColor(0.0f, 1.0f, 1.0f, 1.0f);

	if (!load_content()) {
		return -1;
	}

	if (!load_camera()) {
		return -1;
	}

	// Monitor the elapsed time per frame
	auto currentTimeStamp = system_clock::now();
	auto prevTimeStamp = system_clock::now();

	// Main render loop
	while (renderer::get_instance().is_running())
	{
		// Get current time
		currentTimeStamp = system_clock::now();
		// Calculate elapsed time
		auto elapsed = duration_cast<milliseconds>(currentTimeStamp - prevTimeStamp);
		// Convert to fractions of a second
		auto seconds = float(elapsed.count()) / 1000.0;

		// Update Scene
		update(seconds);

		// Check if running
		if (renderer::get_instance().begin_render())
		{
			// Render Cube
			int i = 0;
			for (i = 0; i <OBJECTS; i++) {
				renderer::get_instance().render(object[i]);
			}

			// Render plane
			renderer::get_instance().render(plane);

			// End the render
			renderer::get_instance().end_render();
		}

		prevTimeStamp = currentTimeStamp;

	} // Main render loop
}<commit_msg>Implemented mipmaps and anisstropic filtering<commit_after>// Lesson 13.cpp : Defines the entry point for the console application.

#include <render_framework\render_framework.h>
#include <chrono>
#pragma comment (lib , "Render Framework" )

using namespace std;
using namespace glm;
using namespace render_framework;
using namespace chrono;

#define OBJECTS 2

// Global scope box
shared_ptr<mesh> object[OBJECTS];
shared_ptr<target_camera> cam;
shared_ptr<mesh> plane;

/*
 * userTranslation
 *
 * Moves the object around inside the window using the keyboard arrow keys.
 */
void userTranslation(float deltaTime)
{
	// Move the quad when arrow keys are pressed
	if (glfwGetKey(renderer::get_instance().get_window(), 'J')) {
		object[0]->trans.translate(vec3(-10.0, 0.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'L')) {
		object[0]->trans.translate(vec3(10.0, 0.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'I')) {
		object[0]->trans.translate(vec3(0.0, 0.0, -10.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'K')) {
		object[0]->trans.translate(vec3(0.0, 0.0, 10.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'U')) {
		object[0]->trans.translate(vec3(0.0, 10.0, 0.0) * deltaTime);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), 'O')) {
		object[0]->trans.translate(vec3(0.0, -10.0, 0.0) * deltaTime);
	}
} // userTranslation()

/*
 * cameraTranslation
 *
 * Moves the object around inside the window using the keyboard arrow keys.
 */
void cameraTranslation(float deltaTime)
{
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_UP)) {
		cam->set_position(cam->get_position() - 1.0f);
	}
	if (glfwGetKey(renderer::get_instance().get_window(), GLFW_KEY_DOWN)) {
		cam->set_position(cam->get_position() + 1.0f);
	}

} // cameraTranslation()

/*
 * Update routine
 *
 * Updates the application state
 */
void update(float deltaTime) {

	cameraTranslation(deltaTime);
	userTranslation(deltaTime);

	cam->set_target(object[0]->trans.position);
	cam->update(deltaTime);

} // update()

bool load_content() {

		// Create plane
		plane = make_shared<mesh>();
		plane->geom = geometry_builder::create_plane();
		plane->trans.translate(vec3(0.0f, -1.0f, 0.0f));
		// Load in effect.  Start with shaders
		auto eff = make_shared<effect>();
		eff->add_shader("shader.vert", GL_VERTEX_SHADER);
		eff->add_shader("shader.frag", GL_FRAGMENT_SHADER);
		if (!effect_loader::build_effect(eff)) {
			return false;
		}
		// Attach effect to the plane mesh
		plane->mat = make_shared<material>();
		plane->mat->effect = eff;
		// Set the texture for shader
		plane->mat->set_texture("tex", texture_loader::load("Checkered.png", true, true));

		// Create box
		object[0] = make_shared<mesh>();
		object[0]->geom = geometry_builder::create_box();

		// Attach effect to the object
		object[0]->mat = make_shared<material>();
		object[0]->mat->effect = eff;
		// Set the texture for shader
		object[0]->mat->set_texture("tex", texture_loader::load("Checkered.png", false, false));
		// Scale and move object
		object[0]->trans.scale = vec3(10.0, 20.0, 0.5);
		object[0]->trans.translate(vec3(0.0, 9.5, 0.0));

		// Create box
		object[1] = make_shared<mesh>();
		object[1]->geom = geometry_builder::create_box();

		// Attach effect to the object
		object[1]->mat = make_shared<material>();
		object[1]->mat->effect = eff;
		// Set the texture for shader
		object[1]->mat->set_texture("tex", texture_loader::load("Checkered.png", true, false));
		object[1]->trans.scale = vec3(10.0, 20.0, 0.5);
		object[1]->trans.translate(vec3(10.0, 9.5, 0.0));

	return true;

} // load_content()

bool load_camera() {
	// Initialize the camera
	cam = make_shared<target_camera>();

	/* Set the projection matrix */
	// First get the aspect ratio (width/height)
	float aspect = (float)renderer::get_instance().get_screen_width() /
					(float)renderer::get_instance().get_screen_width();
	// Use this to set the camera projection matrix
	cam->set_projection(
						quarter_pi<float>(),			// FOV
						aspect,							// Aspect ratio
						2.414f,							// Near plane
						10000.0f);						// Far plane
	// Set the camera properties
	cam->set_position(vec3(0.0, 5.0, 20.0));
	cam->set_target(vec3(0.0, 0.0, 0.0));
	cam->set_up(vec3(0.0, 1.0, 0.0));

	// Attach camera to renderer
	renderer::get_instance().set_camera(cam);

	// Set the view matrix
	auto view = lookAt(
					vec3(20.0f, 20.0f, 20.0f),	// Camera position
					vec3(0.0f, 0.0f, 0.0f),		// Target
					vec3(0.0f, 1.0f, 0.0f));	// Up vector
	renderer::get_instance().set_view(view);

	return true;
} // load_camera

int main()
{
	// Initialize the renderer
	if (!renderer::get_instance().initialise()) return -1;

	// Set the clear colour to cyan
	glClearColor(0.0f, 1.0f, 1.0f, 1.0f);

	if (!load_content()) {
		return -1;
	}

	if (!load_camera()) {
		return -1;
	}

	// Monitor the elapsed time per frame
	auto currentTimeStamp = system_clock::now();
	auto prevTimeStamp = system_clock::now();

	// Main render loop
	while (renderer::get_instance().is_running())
	{
		// Get current time
		currentTimeStamp = system_clock::now();
		// Calculate elapsed time
		auto elapsed = duration_cast<milliseconds>(currentTimeStamp - prevTimeStamp);
		// Convert to fractions of a second
		auto seconds = float(elapsed.count()) / 1000.0;

		// Update Scene
		update(seconds);

		// Check if running
		if (renderer::get_instance().begin_render())
		{
			// Render Cube
			int i = 0;
			for (i = 0; i <OBJECTS; i++) {
				renderer::get_instance().render(object[i]);
			}

			// Render plane
			renderer::get_instance().render(plane);

			// End the render
			renderer::get_instance().end_render();
		}

		prevTimeStamp = currentTimeStamp;

	} // Main render loop
}<|endoftext|>