Initial commit of the synergy trunk sources from sf.net

This commit is contained in:
Sorin Sbarnea
2009-02-27 11:54:59 +00:00
commit 958fa80d1d
429 changed files with 96848 additions and 0 deletions

98
lib/base/CEvent.cpp Normal file
View File

@@ -0,0 +1,98 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CEvent.h"
#include "CEventQueue.h"
//
// CEvent
//
CEvent::CEvent() :
m_type(kUnknown),
m_target(NULL),
m_data(NULL),
m_flags(0)
{
// do nothing
}
CEvent::CEvent(Type type, void* target, void* data, Flags flags) :
m_type(type),
m_target(target),
m_data(data),
m_flags(flags)
{
// do nothing
}
CEvent::Type
CEvent::getType() const
{
return m_type;
}
void*
CEvent::getTarget() const
{
return m_target;
}
void*
CEvent::getData() const
{
return m_data;
}
CEvent::Flags
CEvent::getFlags() const
{
return m_flags;
}
CEvent::Type
CEvent::registerType(const char* name)
{
return EVENTQUEUE->registerType(name);
}
CEvent::Type
CEvent::registerTypeOnce(Type& type, const char* name)
{
return EVENTQUEUE->registerTypeOnce(type, name);
}
const char*
CEvent::getTypeName(Type type)
{
return EVENTQUEUE->getTypeName(type);
}
void
CEvent::deleteData(const CEvent& event)
{
switch (event.getType()) {
case kUnknown:
case kQuit:
case kSystem:
case kTimer:
break;
default:
if ((event.getFlags() & kDontFreeData) == 0) {
free(event.getData());
}
break;
}
}

123
lib/base/CEvent.h Normal file
View File

@@ -0,0 +1,123 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CEVENT_H
#define CEVENT_H
#include "BasicTypes.h"
#include "stdmap.h"
//! Event
/*!
A \c CEvent holds an event type and a pointer to event data.
*/
class CEvent {
public:
typedef UInt32 Type;
enum {
kUnknown, //!< The event type is unknown
kQuit, //!< The quit event
kSystem, //!< The data points to a system event type
kTimer, //!< The data points to timer info
kLast //!< Must be last
};
typedef UInt32 Flags;
enum {
kNone = 0x00, //!< No flags
kDeliverImmediately = 0x01, //!< Dispatch and free event immediately
kDontFreeData = 0x02 //!< Don't free data in deleteData
};
CEvent();
//! Create \c CEvent with data
/*!
The \p type must have been registered using \c registerType().
The \p data must be POD (plain old data) allocated by malloc(),
which means it cannot have a constructor, destructor or be
composed of any types that do. \p target is the intended
recipient of the event. \p flags is any combination of \c Flags.
*/
CEvent(Type type, void* target = NULL, void* data = NULL,
UInt32 flags = kNone);
//! @name manipulators
//@{
//! Creates a new event type
/*!
Returns a unique event type id.
*/
static Type registerType(const char* name);
//! Creates a new event type
/*!
If \p type contains \c kUnknown then it is set to a unique event
type id otherwise it is left alone. The final value of \p type
is returned.
*/
static Type registerTypeOnce(Type& type, const char* name);
//! Get name for event
/*!
Returns the name for the event \p type. This is primarily for
debugging.
*/
static const char* getTypeName(Type type);
//! Release event data
/*!
Deletes event data for the given event (using free()).
*/
static void deleteData(const CEvent&);
//@}
//! @name accessors
//@{
//! Get event type
/*!
Returns the event type.
*/
Type getType() const;
//! Get the event target
/*!
Returns the event target.
*/
void* getTarget() const;
//! Get the event data
/*!
Returns the event data.
*/
void* getData() const;
//! Get event flags
/*!
Returns the event flags.
*/
Flags getFlags() const;
//@}
private:
Type m_type;
void* m_target;
void* m_data;
Flags m_flags;
};
#endif

526
lib/base/CEventQueue.cpp Normal file
View File

@@ -0,0 +1,526 @@
;/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CEventQueue.h"
#include "CLog.h"
#include "CSimpleEventQueueBuffer.h"
#include "CStopwatch.h"
#include "IEventJob.h"
#include "CArch.h"
// interrupt handler. this just adds a quit event to the queue.
static
void
interrupt(CArch::ESignal, void*)
{
EVENTQUEUE->addEvent(CEvent(CEvent::kQuit));
}
//
// CEventQueue
//
CEventQueue::CEventQueue() :
m_nextType(CEvent::kLast)
{
setInstance(this);
m_mutex = ARCH->newMutex();
ARCH->setSignalHandler(CArch::kINTERRUPT, &interrupt, NULL);
ARCH->setSignalHandler(CArch::kTERMINATE, &interrupt, NULL);
m_buffer = new CSimpleEventQueueBuffer;
}
CEventQueue::~CEventQueue()
{
delete m_buffer;
ARCH->setSignalHandler(CArch::kINTERRUPT, NULL, NULL);
ARCH->setSignalHandler(CArch::kTERMINATE, NULL, NULL);
ARCH->closeMutex(m_mutex);
setInstance(NULL);
}
CEvent::Type
CEventQueue::registerType(const char* name)
{
CArchMutexLock lock(m_mutex);
m_typeMap.insert(std::make_pair(m_nextType, name));
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
return m_nextType++;
}
CEvent::Type
CEventQueue::registerTypeOnce(CEvent::Type& type, const char* name)
{
CArchMutexLock lock(m_mutex);
if (type == CEvent::kUnknown) {
m_typeMap.insert(std::make_pair(m_nextType, name));
LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType));
type = m_nextType++;
}
return type;
}
const char*
CEventQueue::getTypeName(CEvent::Type type)
{
switch (type) {
case CEvent::kUnknown:
return "nil";
case CEvent::kQuit:
return "quit";
case CEvent::kSystem:
return "system";
case CEvent::kTimer:
return "timer";
default:
CTypeMap::const_iterator i = m_typeMap.find(type);
if (i == m_typeMap.end()) {
return "<unknown>";
}
else {
return i->second;
}
}
}
void
CEventQueue::adoptBuffer(IEventQueueBuffer* buffer)
{
CArchMutexLock lock(m_mutex);
// discard old buffer and old events
delete m_buffer;
for (CEventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) {
CEvent::deleteData(i->second);
}
m_events.clear();
m_oldEventIDs.clear();
// use new buffer
m_buffer = buffer;
if (m_buffer == NULL) {
m_buffer = new CSimpleEventQueueBuffer;
}
}
bool
CEventQueue::getEvent(CEvent& event, double timeout)
{
CStopwatch timer(true);
retry:
// if no events are waiting then handle timers and then wait
while (m_buffer->isEmpty()) {
// handle timers first
if (hasTimerExpired(event)) {
return true;
}
// get time remaining in timeout
double timeLeft = timeout - timer.getTime();
if (timeout >= 0.0 && timeLeft <= 0.0) {
return false;
}
// get time until next timer expires. if there is a timer
// and it'll expire before the client's timeout then use
// that duration for our timeout instead.
double timerTimeout = getNextTimerTimeout();
if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) {
timeLeft = timerTimeout;
}
// wait for an event
m_buffer->waitForEvent(timeLeft);
}
// get the event
UInt32 dataID;
IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID);
switch (type) {
case IEventQueueBuffer::kNone:
if (timeout < 0.0 || timeout <= timer.getTime()) {
// don't want to fail if client isn't expecting that
// so if getEvent() fails with an infinite timeout
// then just try getting another event.
goto retry;
}
return false;
case IEventQueueBuffer::kSystem:
return true;
case IEventQueueBuffer::kUser:
{
CArchMutexLock lock(m_mutex);
event = removeEvent(dataID);
return true;
}
default:
assert(0 && "invalid event type");
return false;
}
}
bool
CEventQueue::dispatchEvent(const CEvent& event)
{
void* target = event.getTarget();
IEventJob* job = getHandler(event.getType(), target);
if (job == NULL) {
job = getHandler(CEvent::kUnknown, target);
}
if (job != NULL) {
job->run(event);
return true;
}
return false;
}
void
CEventQueue::addEvent(const CEvent& event)
{
// discard bogus event types
switch (event.getType()) {
case CEvent::kUnknown:
case CEvent::kSystem:
case CEvent::kTimer:
return;
default:
break;
}
if ((event.getFlags() & CEvent::kDeliverImmediately) != 0) {
dispatchEvent(event);
CEvent::deleteData(event);
}
else {
CArchMutexLock lock(m_mutex);
// store the event's data locally
UInt32 eventID = saveEvent(event);
// add it
if (!m_buffer->addEvent(eventID)) {
// failed to send event
removeEvent(eventID);
CEvent::deleteData(event);
}
}
}
CEventQueueTimer*
CEventQueue::newTimer(double duration, void* target)
{
assert(duration > 0.0);
CEventQueueTimer* timer = m_buffer->newTimer(duration, false);
if (target == NULL) {
target = timer;
}
CArchMutexLock lock(m_mutex);
m_timers.insert(timer);
// initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(CTimer(timer, duration,
duration + m_time.getTime(), target, false));
return timer;
}
CEventQueueTimer*
CEventQueue::newOneShotTimer(double duration, void* target)
{
assert(duration > 0.0);
CEventQueueTimer* timer = m_buffer->newTimer(duration, true);
if (target == NULL) {
target = timer;
}
CArchMutexLock lock(m_mutex);
m_timers.insert(timer);
// initial duration is requested duration plus whatever's on
// the clock currently because the latter will be subtracted
// the next time we check for timers.
m_timerQueue.push(CTimer(timer, duration,
duration + m_time.getTime(), target, true));
return timer;
}
void
CEventQueue::deleteTimer(CEventQueueTimer* timer)
{
CArchMutexLock lock(m_mutex);
for (CTimerQueue::iterator index = m_timerQueue.begin();
index != m_timerQueue.end(); ++index) {
if (index->getTimer() == timer) {
m_timerQueue.erase(index);
break;
}
}
CTimers::iterator index = m_timers.find(timer);
if (index != m_timers.end()) {
m_timers.erase(index);
}
m_buffer->deleteTimer(timer);
}
void
CEventQueue::adoptHandler(CEvent::Type type, void* target, IEventJob* handler)
{
CArchMutexLock lock(m_mutex);
IEventJob*& job = m_handlers[target][type];
delete job;
job = handler;
}
void
CEventQueue::removeHandler(CEvent::Type type, void* target)
{
IEventJob* handler = NULL;
{
CArchMutexLock lock(m_mutex);
CHandlerTable::iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
CTypeHandlerTable& typeHandlers = index->second;
CTypeHandlerTable::iterator index2 = typeHandlers.find(type);
if (index2 != typeHandlers.end()) {
handler = index2->second;
typeHandlers.erase(index2);
}
}
}
delete handler;
}
void
CEventQueue::removeHandlers(void* target)
{
std::vector<IEventJob*> handlers;
{
CArchMutexLock lock(m_mutex);
CHandlerTable::iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
// copy to handlers array and clear table for target
CTypeHandlerTable& typeHandlers = index->second;
for (CTypeHandlerTable::iterator index2 = typeHandlers.begin();
index2 != typeHandlers.end(); ++index2) {
handlers.push_back(index2->second);
}
typeHandlers.clear();
}
}
// delete handlers
for (std::vector<IEventJob*>::iterator index = handlers.begin();
index != handlers.end(); ++index) {
delete *index;
}
}
bool
CEventQueue::isEmpty() const
{
return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0);
}
IEventJob*
CEventQueue::getHandler(CEvent::Type type, void* target) const
{
CArchMutexLock lock(m_mutex);
CHandlerTable::const_iterator index = m_handlers.find(target);
if (index != m_handlers.end()) {
const CTypeHandlerTable& typeHandlers = index->second;
CTypeHandlerTable::const_iterator index2 = typeHandlers.find(type);
if (index2 != typeHandlers.end()) {
return index2->second;
}
}
return NULL;
}
UInt32
CEventQueue::saveEvent(const CEvent& event)
{
// choose id
UInt32 id;
if (!m_oldEventIDs.empty()) {
// reuse an id
id = m_oldEventIDs.back();
m_oldEventIDs.pop_back();
}
else {
// make a new id
id = static_cast<UInt32>(m_events.size());
}
// save data
m_events[id] = event;
return id;
}
CEvent
CEventQueue::removeEvent(UInt32 eventID)
{
// look up id
CEventTable::iterator index = m_events.find(eventID);
if (index == m_events.end()) {
return CEvent();
}
// get data
CEvent event = index->second;
m_events.erase(index);
// save old id for reuse
m_oldEventIDs.push_back(eventID);
return event;
}
bool
CEventQueue::hasTimerExpired(CEvent& event)
{
// return true if there's a timer in the timer priority queue that
// has expired. if returning true then fill in event appropriately
// and reset and reinsert the timer.
if (m_timerQueue.empty()) {
return false;
}
// get time elapsed since last check
const double time = m_time.getTime();
m_time.reset();
// countdown elapsed time
for (CTimerQueue::iterator index = m_timerQueue.begin();
index != m_timerQueue.end(); ++index) {
(*index) -= time;
}
// done if no timers are expired
if (m_timerQueue.top() > 0.0) {
return false;
}
// remove timer from queue
CTimer timer = m_timerQueue.top();
m_timerQueue.pop();
// prepare event and reset the timer's clock
timer.fillEvent(m_timerEvent);
event = CEvent(CEvent::kTimer, timer.getTarget(), &m_timerEvent);
timer.reset();
// reinsert timer into queue if it's not a one-shot
if (!timer.isOneShot()) {
m_timerQueue.push(timer);
}
return true;
}
double
CEventQueue::getNextTimerTimeout() const
{
// return -1 if no timers, 0 if the top timer has expired, otherwise
// the time until the top timer in the timer priority queue will
// expire.
if (m_timerQueue.empty()) {
return -1.0;
}
if (m_timerQueue.top() <= 0.0) {
return 0.0;
}
return m_timerQueue.top();
}
//
// CEventQueue::CTimer
//
CEventQueue::CTimer::CTimer(CEventQueueTimer* timer, double timeout,
double initialTime, void* target, bool oneShot) :
m_timer(timer),
m_timeout(timeout),
m_target(target),
m_oneShot(oneShot),
m_time(initialTime)
{
assert(m_timeout > 0.0);
}
CEventQueue::CTimer::~CTimer()
{
// do nothing
}
void
CEventQueue::CTimer::reset()
{
m_time = m_timeout;
}
CEventQueue::CTimer&
CEventQueue::CTimer::operator-=(double dt)
{
m_time -= dt;
return *this;
}
CEventQueue::CTimer::operator double() const
{
return m_time;
}
bool
CEventQueue::CTimer::isOneShot() const
{
return m_oneShot;
}
CEventQueueTimer*
CEventQueue::CTimer::getTimer() const
{
return m_timer;
}
void*
CEventQueue::CTimer::getTarget() const
{
return m_target;
}
void
CEventQueue::CTimer::fillEvent(CTimerEvent& event) const
{
event.m_timer = m_timer;
event.m_count = 0;
if (m_time <= 0.0) {
event.m_count = static_cast<UInt32>((m_timeout - m_time) / m_timeout);
}
}
bool
CEventQueue::CTimer::operator<(const CTimer& t) const
{
return m_time < t.m_time;
}

123
lib/base/CEventQueue.h Normal file
View File

@@ -0,0 +1,123 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CEVENTQUEUE_H
#define CEVENTQUEUE_H
#include "IEventQueue.h"
#include "CEvent.h"
#include "CPriorityQueue.h"
#include "CStopwatch.h"
#include "IArchMultithread.h"
#include "stdmap.h"
#include "stdset.h"
//! Event queue
/*!
An event queue that implements the platform independent parts and
delegates the platform dependent parts to a subclass.
*/
class CEventQueue : public IEventQueue {
public:
CEventQueue();
virtual ~CEventQueue();
// IEventQueue overrides
virtual void adoptBuffer(IEventQueueBuffer*);
virtual bool getEvent(CEvent& event, double timeout = -1.0);
virtual bool dispatchEvent(const CEvent& event);
virtual void addEvent(const CEvent& event);
virtual CEventQueueTimer*
newTimer(double duration, void* target);
virtual CEventQueueTimer*
newOneShotTimer(double duration, void* target);
virtual void deleteTimer(CEventQueueTimer*);
virtual void adoptHandler(CEvent::Type type,
void* target, IEventJob* handler);
virtual void removeHandler(CEvent::Type type, void* target);
virtual void removeHandlers(void* target);
virtual CEvent::Type
registerType(const char* name);
virtual CEvent::Type
registerTypeOnce(CEvent::Type& type, const char* name);
virtual bool isEmpty() const;
virtual IEventJob* getHandler(CEvent::Type type, void* target) const;
virtual const char* getTypeName(CEvent::Type type);
private:
UInt32 saveEvent(const CEvent& event);
CEvent removeEvent(UInt32 eventID);
bool hasTimerExpired(CEvent& event);
double getNextTimerTimeout() const;
private:
class CTimer {
public:
CTimer(CEventQueueTimer*, double timeout, double initialTime,
void* target, bool oneShot);
~CTimer();
void reset();
CTimer& operator-=(double);
operator double() const;
bool isOneShot() const;
CEventQueueTimer*
getTimer() const;
void* getTarget() const;
void fillEvent(CTimerEvent&) const;
bool operator<(const CTimer&) const;
private:
CEventQueueTimer* m_timer;
double m_timeout;
void* m_target;
bool m_oneShot;
double m_time;
};
typedef std::set<CEventQueueTimer*> CTimers;
typedef CPriorityQueue<CTimer> CTimerQueue;
typedef std::map<UInt32, CEvent> CEventTable;
typedef std::vector<UInt32> CEventIDList;
typedef std::map<CEvent::Type, const char*> CTypeMap;
typedef std::map<CEvent::Type, IEventJob*> CTypeHandlerTable;
typedef std::map<void*, CTypeHandlerTable> CHandlerTable;
CArchMutex m_mutex;
// registered events
CEvent::Type m_nextType;
CTypeMap m_typeMap;
// buffer of events
IEventQueueBuffer* m_buffer;
// saved events
CEventTable m_events;
CEventIDList m_oldEventIDs;
// timers
CStopwatch m_time;
CTimers m_timers;
CTimerQueue m_timerQueue;
CTimerEvent m_timerEvent;
// event handlers
CHandlerTable m_handlers;
};
#endif

View File

@@ -0,0 +1,40 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CFunctionEventJob.h"
//
// CFunctionEventJob
//
CFunctionEventJob::CFunctionEventJob(
void (*func)(const CEvent&, void*), void* arg) :
m_func(func),
m_arg(arg)
{
// do nothing
}
CFunctionEventJob::~CFunctionEventJob()
{
// do nothing
}
void
CFunctionEventJob::run(const CEvent& event)
{
if (m_func != NULL) {
m_func(event, m_arg);
}
}

View File

@@ -0,0 +1,38 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CFUNCTIONEVENTJOB_H
#define CFUNCTIONEVENTJOB_H
#include "IEventJob.h"
//! Use a function as an event job
/*!
An event job class that invokes a function.
*/
class CFunctionEventJob : public IEventJob {
public:
//! run() invokes \c func(arg)
CFunctionEventJob(void (*func)(const CEvent&, void*), void* arg = NULL);
virtual ~CFunctionEventJob();
// IEventJob overrides
virtual void run(const CEvent&);
private:
void (*m_func)(const CEvent&, void*);
void* m_arg;
};
#endif

39
lib/base/CFunctionJob.cpp Normal file
View File

@@ -0,0 +1,39 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CFunctionJob.h"
//
// CFunctionJob
//
CFunctionJob::CFunctionJob(void (*func)(void*), void* arg) :
m_func(func),
m_arg(arg)
{
// do nothing
}
CFunctionJob::~CFunctionJob()
{
// do nothing
}
void
CFunctionJob::run()
{
if (m_func != NULL) {
m_func(m_arg);
}
}

38
lib/base/CFunctionJob.h Normal file
View File

@@ -0,0 +1,38 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CFUNCTIONJOB_H
#define CFUNCTIONJOB_H
#include "IJob.h"
//! Use a function as a job
/*!
A job class that invokes a function.
*/
class CFunctionJob : public IJob {
public:
//! run() invokes \c func(arg)
CFunctionJob(void (*func)(void*), void* arg = NULL);
virtual ~CFunctionJob();
// IJob overrides
virtual void run();
private:
void (*m_func)(void*);
void* m_arg;
};
#endif

293
lib/base/CLog.cpp Normal file
View File

@@ -0,0 +1,293 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CLog.h"
#include "CString.h"
#include "CStringUtil.h"
#include "LogOutputters.h"
#include "CArch.h"
#include "Version.h"
#include <cstdio>
#include <cstring>
// names of priorities
static const char* g_priority[] = {
"FATAL",
"ERROR",
"WARNING",
"NOTE",
"INFO",
"DEBUG",
"DEBUG1",
"DEBUG2"
};
// number of priorities
static const int g_numPriority = (int)(sizeof(g_priority) /
sizeof(g_priority[0]));
// the default priority
#if defined(NDEBUG)
static const int g_defaultMaxPriority = 4;
#else
static const int g_defaultMaxPriority = 5;
#endif
// length of longest string in g_priority
static const int g_maxPriorityLength = 7;
// length of suffix string (": ")
static const int g_prioritySuffixLength = 2;
// amount of padded required to fill in the priority prefix
static const int g_priorityPad = g_maxPriorityLength +
g_prioritySuffixLength;
//
// CLog
//
CLog* CLog::s_log = NULL;
CLog::CLog()
{
assert(s_log == NULL);
// create mutex for multithread safe operation
m_mutex = ARCH->newMutex();
// other initalization
m_maxPriority = g_defaultMaxPriority;
m_maxNewlineLength = 0;
insert(new CConsoleLogOutputter);
}
CLog::~CLog()
{
// clean up
for (COutputterList::iterator index = m_outputters.begin();
index != m_outputters.end(); ++index) {
delete *index;
}
for (COutputterList::iterator index = m_alwaysOutputters.begin();
index != m_alwaysOutputters.end(); ++index) {
delete *index;
}
ARCH->closeMutex(m_mutex);
s_log = NULL;
}
CLog*
CLog::getInstance()
{
// note -- not thread safe; client must initialize log safely
if (s_log == NULL) {
s_log = new CLog;
}
return s_log;
}
void
CLog::print(const char* file, int line, const char* fmt, ...) const
{
// check if fmt begins with a priority argument
int priority = 4;
if (fmt[0] == '%' && fmt[1] == 'z') {
priority = fmt[2] - '\060';
fmt += 3;
}
// done if below priority threshold
if (priority > getFilter()) {
return;
}
// compute prefix padding length
char stack[1024];
int pPad = g_priorityPad;
if (file != NULL) {
sprintf(stack, "%d", line);
pPad += strlen(file) + 1 /* comma */ +
strlen(stack) + 1 /* colon */ + 1 /* space */;
}
// compute suffix padding length
int sPad = m_maxNewlineLength;
// print to buffer, leaving space for a newline at the end and prefix
// at the beginning.
char* buffer = stack;
int len = (int)(sizeof(stack) / sizeof(stack[0]));
while (true) {
// try printing into the buffer
va_list args;
va_start(args, fmt);
int n = ARCH->vsnprintf(buffer + pPad, len - pPad - sPad, fmt, args);
va_end(args);
// if the buffer wasn't big enough then make it bigger and try again
if (n < 0 || n > (int)len) {
if (buffer != stack) {
delete[] buffer;
}
len *= 2;
buffer = new char[len];
}
// if the buffer was big enough then continue
else {
break;
}
}
// print the prefix to the buffer. leave space for priority label.
char* message = buffer;
if (file != NULL) {
sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
buffer[pPad - 1] = ' ';
// discard file and line if priority < 0
if (priority < 0) {
message += pPad - g_priorityPad;
}
}
// output buffer
output(priority, message);
// clean up
if (buffer != stack) {
delete[] buffer;
}
}
void
CLog::insert(ILogOutputter* outputter, bool alwaysAtHead)
{
assert(outputter != NULL);
assert(outputter->getNewline() != NULL);
CArchMutexLock lock(m_mutex);
if (alwaysAtHead) {
m_alwaysOutputters.push_front(outputter);
}
else {
m_outputters.push_front(outputter);
}
int newlineLength = strlen(outputter->getNewline());
if (newlineLength > m_maxNewlineLength) {
m_maxNewlineLength = newlineLength;
}
outputter->open(kAppVersion);
outputter->show(false);
}
void
CLog::remove(ILogOutputter* outputter)
{
CArchMutexLock lock(m_mutex);
m_outputters.remove(outputter);
m_alwaysOutputters.remove(outputter);
}
void
CLog::pop_front(bool alwaysAtHead)
{
CArchMutexLock lock(m_mutex);
COutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters;
if (!list->empty()) {
delete list->front();
list->pop_front();
}
}
bool
CLog::setFilter(const char* maxPriority)
{
if (maxPriority != NULL) {
for (int i = 0; i < g_numPriority; ++i) {
if (strcmp(maxPriority, g_priority[i]) == 0) {
setFilter(i);
return true;
}
}
return false;
}
return true;
}
void
CLog::setFilter(int maxPriority)
{
CArchMutexLock lock(m_mutex);
m_maxPriority = maxPriority;
}
int
CLog::getFilter() const
{
CArchMutexLock lock(m_mutex);
return m_maxPriority;
}
void
CLog::output(int priority, char* msg) const
{
assert(priority >= -1 && priority < g_numPriority);
assert(msg != NULL);
// insert priority label
int n = -g_prioritySuffixLength;
if (priority >= 0) {
n = strlen(g_priority[priority]);
strcpy(msg + g_maxPriorityLength - n, g_priority[priority]);
msg[g_maxPriorityLength + 0] = ':';
msg[g_maxPriorityLength + 1] = ' ';
msg[g_maxPriorityLength + 1] = ' ';
}
// find end of message
char* end = msg + g_priorityPad + strlen(msg + g_priorityPad);
// write to each outputter
CArchMutexLock lock(m_mutex);
for (COutputterList::const_iterator index = m_alwaysOutputters.begin();
index != m_alwaysOutputters.end();
++index) {
// get outputter
ILogOutputter* outputter = *index;
// put an appropriate newline at the end
strcpy(end, outputter->getNewline());
// write message
outputter->write(static_cast<ILogOutputter::ELevel>(priority),
msg + g_maxPriorityLength - n);
}
for (COutputterList::const_iterator index = m_outputters.begin();
index != m_outputters.end(); ++index) {
// get outputter
ILogOutputter* outputter = *index;
// put an appropriate newline at the end
strcpy(end, outputter->getNewline());
// write message and break out of loop if it returns false
if (!outputter->write(static_cast<ILogOutputter::ELevel>(priority),
msg + g_maxPriorityLength - n)) {
break;
}
}
}

202
lib/base/CLog.h Normal file
View File

@@ -0,0 +1,202 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CLOG_H
#define CLOG_H
#include "common.h"
#include "IArchMultithread.h"
#include "stdlist.h"
#include <stdarg.h>
#define CLOG (CLog::getInstance())
class ILogOutputter;
//! Logging facility
/*!
The logging class; all console output should go through this class.
It supports multithread safe operation, several message priority levels,
filtering by priority, and output redirection. The macros LOG() and
LOGC() provide convenient access.
*/
class CLog {
public:
//! Log levels
/*!
The logging priority levels in order of highest to lowest priority.
*/
enum ELevel {
kFATAL, //!< For fatal errors
kERROR, //!< For serious errors
kWARNING, //!< For minor errors and warnings
kNOTE, //!< For messages about notable events
kINFO, //!< For informational messages
kDEBUG, //!< For important debugging messages
kDEBUG1, //!< For more detailed debugging messages
kDEBUG2 //!< For even more detailed debugging messages
};
~CLog();
//! @name manipulators
//@{
//! Add an outputter to the head of the list
/*!
Inserts an outputter to the head of the outputter list. When the
logger writes a message, it goes to the outputter at the head of
the outputter list. If that outputter's \c write() method returns
true then it also goes to the next outputter, as so on until an
outputter returns false or there are no more outputters. Outputters
still in the outputter list when the log is destroyed will be
deleted. If \c alwaysAtHead is true then the outputter is always
called before all outputters with \c alwaysAtHead false and the
return value of the outputter is ignored.
By default, the logger has one outputter installed which writes to
the console.
*/
void insert(ILogOutputter* adopted,
bool alwaysAtHead = false);
//! Remove an outputter from the list
/*!
Removes the first occurrence of the given outputter from the
outputter list. It does nothing if the outputter is not in the
list. The outputter is not deleted.
*/
void remove(ILogOutputter* orphaned);
//! Remove the outputter from the head of the list
/*!
Removes and deletes the outputter at the head of the outputter list.
This does nothing if the outputter list is empty. Only removes
outputters that were inserted with the matching \c alwaysAtHead.
*/
void pop_front(bool alwaysAtHead = false);
//! Set the minimum priority filter.
/*!
Set the filter. Messages below this priority are discarded.
The default priority is 4 (INFO) (unless built without NDEBUG
in which case it's 5 (DEBUG)). setFilter(const char*) returns
true if the priority \c name was recognized; if \c name is NULL
then it simply returns true.
*/
bool setFilter(const char* name);
void setFilter(int);
//@}
//! @name accessors
//@{
//! Print a log message
/*!
Print a log message using the printf-like \c format and arguments
preceded by the filename and line number. If \c file is NULL then
neither the file nor the line are printed.
*/
void print(const char* file, int line,
const char* format, ...) const;
//! Get the minimum priority level.
int getFilter() const;
//! Get the singleton instance of the log
static CLog* getInstance();
//@}
private:
CLog();
void output(int priority, char* msg) const;
private:
typedef std::list<ILogOutputter*> COutputterList;
static CLog* s_log;
CArchMutex m_mutex;
COutputterList m_outputters;
COutputterList m_alwaysOutputters;
int m_maxNewlineLength;
int m_maxPriority;
};
/*!
\def LOG(arg)
Write to the log. Because macros cannot accept variable arguments, this
should be invoked like so:
\code
LOG((CLOG_XXX "%d and %d are %s", x, y, x == y ? "equal" : "not equal"));
\endcode
In particular, notice the double open and close parentheses. Also note
that there is no comma after the \c CLOG_XXX. The \c XXX should be
replaced by one of enumerants in \c CLog::ELevel without the leading
\c k. For example, \c CLOG_INFO. The special \c CLOG_PRINT level will
not be filtered and is never prefixed by the filename and line number.
If \c NOLOGGING is defined during the build then this macro expands to
nothing. If \c NDEBUG is defined during the build then it expands to a
call to CLog::print. Otherwise it expands to a call to CLog::printt,
which includes the filename and line number.
*/
/*!
\def LOGC(expr, arg)
Write to the log if and only if expr is true. Because macros cannot accept
variable arguments, this should be invoked like so:
\code
LOGC(x == y, (CLOG_XXX "%d and %d are equal", x, y));
\endcode
In particular, notice the parentheses around everything after the boolean
expression. Also note that there is no comma after the \c CLOG_XXX.
The \c XXX should be replaced by one of enumerants in \c CLog::ELevel
without the leading \c k. For example, \c CLOG_INFO. The special
\c CLOG_PRINT level will not be filtered and is never prefixed by the
filename and line number.
If \c NOLOGGING is defined during the build then this macro expands to
nothing. If \c NDEBUG is not defined during the build then it expands
to a call to CLog::print that prints the filename and line number,
otherwise it expands to a call that doesn't.
*/
#if defined(NOLOGGING)
#define LOG(_a1)
#define LOGC(_a1, _a2)
#define CLOG_TRACE
#elif defined(NDEBUG)
#define LOG(_a1) CLOG->print _a1
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
#define CLOG_TRACE NULL, 0,
#else
#define LOG(_a1) CLOG->print _a1
#define LOGC(_a1, _a2) if (_a1) CLOG->print _a2
#define CLOG_TRACE __FILE__, __LINE__,
#endif
#define CLOG_PRINT CLOG_TRACE "%z\057"
#define CLOG_CRIT CLOG_TRACE "%z\060"
#define CLOG_ERR CLOG_TRACE "%z\061"
#define CLOG_WARN CLOG_TRACE "%z\062"
#define CLOG_NOTE CLOG_TRACE "%z\063"
#define CLOG_INFO CLOG_TRACE "%z\064"
#define CLOG_DEBUG CLOG_TRACE "%z\065"
#define CLOG_DEBUG1 CLOG_TRACE "%z\066"
#define CLOG_DEBUG2 CLOG_TRACE "%z\067"
#endif

136
lib/base/CPriorityQueue.h Normal file
View File

@@ -0,0 +1,136 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CPRIORITYQUEUE_H
#define CPRIORITYQUEUE_H
#include "stdvector.h"
#include <algorithm>
#include <functional>
//! A priority queue with an iterator
/*!
This priority queue is the same as a standard priority queue except:
it sorts by std::greater, it has a forward iterator through the elements
(which can appear in any order), and its contents can be swapped.
*/
template <class T, class Container = std::vector<T>,
#if defined(_MSC_VER)
class Compare = std::greater<Container::value_type> >
#else
class Compare = std::greater<typename Container::value_type> >
#endif
class CPriorityQueue {
public:
typedef typename Container::value_type value_type;
typedef typename Container::size_type size_type;
typedef typename Container::iterator iterator;
typedef typename Container::const_iterator const_iterator;
typedef Container container_type;
CPriorityQueue() { }
CPriorityQueue(Container& swappedIn) { swap(swappedIn); }
~CPriorityQueue() { }
//! @name manipulators
//@{
//! Add element
void push(const value_type& v)
{
c.push_back(v);
std::push_heap(c.begin(), c.end(), comp);
}
//! Remove head element
void pop()
{
std::pop_heap(c.begin(), c.end(), comp);
c.pop_back();
}
//! Erase element
void erase(iterator i)
{
c.erase(i);
std::make_heap(c.begin(), c.end(), comp);
}
//! Get start iterator
iterator begin()
{
return c.begin();
}
//! Get end iterator
iterator end()
{
return c.end();
}
//! Swap contents with another priority queue
void swap(CPriorityQueue<T, Container, Compare>& q)
{
c.swap(q.c);
}
//! Swap contents with another container
void swap(Container& c2)
{
c.swap(c2);
std::make_heap(c.begin(), c.end(), comp);
}
//@}
//! @name accessors
//@{
//! Returns true if there are no elements
bool empty() const
{
return c.empty();
}
//! Returns the number of elements
size_type size() const
{
return c.size();
}
//! Returns the head element
const value_type& top() const
{
return c.front();
}
//! Get start iterator
const_iterator begin() const
{
return c.begin();
}
//! Get end iterator
const_iterator end() const
{
return c.end();
}
//@}
private:
Container c;
Compare comp;
};
#endif

View File

@@ -0,0 +1,97 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CSimpleEventQueueBuffer.h"
#include "CStopwatch.h"
#include "CArch.h"
class CEventQueueTimer { };
//
// CSimpleEventQueueBuffer
//
CSimpleEventQueueBuffer::CSimpleEventQueueBuffer()
{
m_queueMutex = ARCH->newMutex();
m_queueReadyCond = ARCH->newCondVar();
m_queueReady = false;
}
CSimpleEventQueueBuffer::~CSimpleEventQueueBuffer()
{
ARCH->closeCondVar(m_queueReadyCond);
ARCH->closeMutex(m_queueMutex);
}
void
CSimpleEventQueueBuffer::waitForEvent(double timeout)
{
CArchMutexLock lock(m_queueMutex);
CStopwatch timer(true);
while (!m_queueReady) {
double timeLeft = timeout;
if (timeLeft >= 0.0) {
timeLeft -= timer.getTime();
if (timeLeft < 0.0) {
return;
}
}
ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft);
}
}
IEventQueueBuffer::Type
CSimpleEventQueueBuffer::getEvent(CEvent&, UInt32& dataID)
{
CArchMutexLock lock(m_queueMutex);
if (!m_queueReady) {
return kNone;
}
dataID = m_queue.back();
m_queue.pop_back();
m_queueReady = !m_queue.empty();
return kUser;
}
bool
CSimpleEventQueueBuffer::addEvent(UInt32 dataID)
{
CArchMutexLock lock(m_queueMutex);
m_queue.push_front(dataID);
if (!m_queueReady) {
m_queueReady = true;
ARCH->broadcastCondVar(m_queueReadyCond);
}
return true;
}
bool
CSimpleEventQueueBuffer::isEmpty() const
{
CArchMutexLock lock(m_queueMutex);
return !m_queueReady;
}
CEventQueueTimer*
CSimpleEventQueueBuffer::newTimer(double, bool) const
{
return new CEventQueueTimer;
}
void
CSimpleEventQueueBuffer::deleteTimer(CEventQueueTimer* timer) const
{
delete timer;
}

View File

@@ -0,0 +1,49 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CSIMPLEEVENTQUEUEBUFFER_H
#define CSIMPLEEVENTQUEUEBUFFER_H
#include "IEventQueueBuffer.h"
#include "IArchMultithread.h"
#include "stddeque.h"
//! In-memory event queue buffer
/*!
An event queue buffer provides a queue of events for an IEventQueue.
*/
class CSimpleEventQueueBuffer : public IEventQueueBuffer {
public:
CSimpleEventQueueBuffer();
~CSimpleEventQueueBuffer();
// IEventQueueBuffer overrides
virtual void waitForEvent(double timeout);
virtual Type getEvent(CEvent& event, UInt32& dataID);
virtual bool addEvent(UInt32 dataID);
virtual bool isEmpty() const;
virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const;
virtual void deleteTimer(CEventQueueTimer*) const;
private:
typedef std::deque<UInt32> CEventDeque;
CArchMutex m_queueMutex;
CArchCond m_queueReadyCond;
bool m_queueReady;
CEventDeque m_queue;
};
#endif

126
lib/base/CStopwatch.cpp Normal file
View File

@@ -0,0 +1,126 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CStopwatch.h"
#include "CArch.h"
//
// CStopwatch
//
CStopwatch::CStopwatch(bool triggered) :
m_mark(0.0),
m_triggered(triggered),
m_stopped(triggered)
{
if (!triggered) {
m_mark = ARCH->time();
}
}
CStopwatch::~CStopwatch()
{
// do nothing
}
double
CStopwatch::reset()
{
if (m_stopped) {
const double dt = m_mark;
m_mark = 0.0;
return dt;
}
else {
const double t = ARCH->time();
const double dt = t - m_mark;
m_mark = t;
return dt;
}
}
void
CStopwatch::stop()
{
if (m_stopped) {
return;
}
// save the elapsed time
m_mark = ARCH->time() - m_mark;
m_stopped = true;
}
void
CStopwatch::start()
{
m_triggered = false;
if (!m_stopped) {
return;
}
// set the mark such that it reports the time elapsed at stop()
m_mark = ARCH->time() - m_mark;
m_stopped = false;
}
void
CStopwatch::setTrigger()
{
stop();
m_triggered = true;
}
double
CStopwatch::getTime()
{
if (m_triggered) {
const double dt = m_mark;
start();
return dt;
}
else if (m_stopped) {
return m_mark;
}
else {
return ARCH->time() - m_mark;
}
}
CStopwatch::operator double()
{
return getTime();
}
bool
CStopwatch::isStopped() const
{
return m_stopped;
}
double
CStopwatch::getTime() const
{
if (m_stopped) {
return m_mark;
}
else {
return ARCH->time() - m_mark;
}
}
CStopwatch::operator double() const
{
return getTime();
}

108
lib/base/CStopwatch.h Normal file
View File

@@ -0,0 +1,108 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CSTOPWATCH_H
#define CSTOPWATCH_H
#include "common.h"
//! A timer class
/*!
This class measures time intervals. All time interval measurement
should use this class.
*/
class CStopwatch {
public:
/*!
The default constructor does an implicit reset() or setTrigger().
If triggered == false then the clock starts ticking.
*/
CStopwatch(bool triggered = false);
~CStopwatch();
//! @name manipulators
//@{
//! Reset the timer to zero
/*!
Set the start time to the current time, returning the time since
the last reset. This does not remove the trigger if it's set nor
does it start a stopped clock. If the clock is stopped then
subsequent reset()'s will return 0.
*/
double reset();
//! Stop the timer
/*!
Stop the stopwatch. The time interval while stopped is not
counted by the stopwatch. stop() does not remove the trigger.
Has no effect if already stopped.
*/
void stop();
//! Start the timer
/*!
Start the stopwatch. start() removes the trigger, even if the
stopwatch was already started.
*/
void start();
//! Stop the timer and set the trigger
/*!
setTrigger() stops the clock like stop() except there's an
implicit start() the next time (non-const) getTime() is called.
This is useful when you want the clock to start the first time
you check it.
*/
void setTrigger();
//! Get elapsed time
/*!
Returns the time since the last reset() (or calls reset() and
returns zero if the trigger is set).
*/
double getTime();
//! Same as getTime()
operator double();
//@}
//! @name accessors
//@{
//! Check if timer is stopped
/*!
Returns true if the stopwatch is stopped.
*/
bool isStopped() const;
// return the time since the last reset().
//! Get elapsed time
/*!
Returns the time since the last reset(). This cannot trigger the
stopwatch to start and will not clear the trigger.
*/
double getTime() const;
//! Same as getTime() const
operator double() const;
//@}
private:
double getClock() const;
private:
double m_mark;
bool m_triggered;
bool m_stopped;
};
#endif

25
lib/base/CString.h Normal file
View File

@@ -0,0 +1,25 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CSTRING_H
#define CSTRING_H
#include "common.h"
#include "stdstring.h"
// use standard C++ string class for our string class
typedef std::string CString;
#endif

194
lib/base/CStringUtil.cpp Normal file
View File

@@ -0,0 +1,194 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CStringUtil.h"
#include "CArch.h"
#include "common.h"
#include "stdvector.h"
#include <cctype>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
//
// CStringUtil
//
CString
CStringUtil::format(const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
CString result = vformat(fmt, args);
va_end(args);
return result;
}
CString
CStringUtil::vformat(const char* fmt, va_list args)
{
// find highest indexed substitution and the locations of substitutions
std::vector<size_t> pos;
std::vector<size_t> width;
std::vector<int> index;
int maxIndex = 0;
for (const char* scan = fmt; *scan != '\0'; ++scan) {
if (*scan == '%') {
++scan;
if (*scan == '\0') {
break;
}
else if (*scan == '%') {
// literal
index.push_back(0);
pos.push_back(static_cast<int>(scan - 1 - fmt));
width.push_back(2);
}
else if (*scan == '{') {
// get argument index
char* end;
int i = static_cast<int>(strtol(scan + 1, &end, 10));
if (*end != '}') {
// invalid index -- ignore
scan = end - 1;
}
else {
index.push_back(i);
pos.push_back(static_cast<int>(scan - 1 - fmt));
width.push_back(static_cast<int>(end - scan + 2));
if (i > maxIndex) {
maxIndex = i;
}
scan = end;
}
}
else {
// improper escape -- ignore
}
}
}
// get args
std::vector<const char*> value;
std::vector<size_t> length;
value.push_back("%");
length.push_back(1);
for (int i = 0; i < maxIndex; ++i) {
const char* arg = va_arg(args, const char*);
size_t len = strlen(arg);
value.push_back(arg);
length.push_back(len);
}
// compute final length
size_t resultLength = strlen(fmt);
const int n = static_cast<int>(pos.size());
for (int i = 0; i < n; ++i) {
resultLength -= width[i];
resultLength += length[index[i]];
}
// substitute
CString result;
result.reserve(resultLength);
size_t src = 0;
for (int i = 0; i < n; ++i) {
result.append(fmt + src, pos[i] - src);
result.append(value[index[i]]);
src = pos[i] + width[i];
}
result.append(fmt + src);
return result;
}
CString
CStringUtil::print(const char* fmt, ...)
{
char tmp[1024];
char* buffer = tmp;
int len = (int)(sizeof(tmp) / sizeof(tmp[0]));
CString result;
while (buffer != NULL) {
// try printing into the buffer
va_list args;
va_start(args, fmt);
int n = ARCH->vsnprintf(buffer, len, fmt, args);
va_end(args);
// if the buffer wasn't big enough then make it bigger and try again
if (n < 0 || n > len) {
if (buffer != tmp) {
delete[] buffer;
}
len *= 2;
buffer = new char[len];
}
// if it was big enough then save the string and don't try again
else {
result = buffer;
if (buffer != tmp) {
delete[] buffer;
}
buffer = NULL;
}
}
return result;
}
//
// CStringUtil::CaselessCmp
//
bool
CStringUtil::CaselessCmp::cmpEqual(
const CString::value_type& a,
const CString::value_type& b)
{
// should use std::tolower but not in all versions of libstdc++ have it
return tolower(a) == tolower(b);
}
bool
CStringUtil::CaselessCmp::cmpLess(
const CString::value_type& a,
const CString::value_type& b)
{
// should use std::tolower but not in all versions of libstdc++ have it
return tolower(a) < tolower(b);
}
bool
CStringUtil::CaselessCmp::less(const CString& a, const CString& b)
{
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
&CStringUtil::CaselessCmp::cmpLess);
}
bool
CStringUtil::CaselessCmp::equal(const CString& a, const CString& b)
{
return !(less(a, b) || less(b, a));
}
bool
CStringUtil::CaselessCmp::operator()(const CString& a, const CString& b) const
{
return less(a, b);
}

77
lib/base/CStringUtil.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CSTRINGUTIL_H
#define CSTRINGUTIL_H
#include "CString.h"
#include <stdarg.h>
//! String utilities
/*!
This class provides various functions for string manipulation.
*/
class CStringUtil {
public:
//! Format positional arguments
/*!
Format a string using positional arguments. fmt has literal
characters and conversion specifications introduced by `\%':
- \c\%\% -- literal `\%'
- \c\%{n} -- positional element n, n a positive integer, {} are literal
All arguments in the variable list are const char*. Positional
elements are indexed from 1.
*/
static CString format(const char* fmt, ...);
//! Format positional arguments
/*!
Same as format() except takes va_list.
*/
static CString vformat(const char* fmt, va_list);
//! Print a string using printf-style formatting
/*!
Equivalent to printf() except the result is returned as a CString.
*/
static CString print(const char* fmt, ...);
//! Case-insensitive comparisons
/*!
This class provides case-insensitve comparison functions.
*/
class CaselessCmp {
public:
//! Same as less()
bool operator()(const CString& a, const CString& b) const;
//! Returns true iff \c a is lexicographically less than \c b
static bool less(const CString& a, const CString& b);
//! Returns true iff \c a is lexicographically equal to \c b
static bool equal(const CString& a, const CString& b);
//! Returns true iff \c a is lexicographically less than \c b
static bool cmpLess(const CString::value_type& a,
const CString::value_type& b);
//! Returns true iff \c a is lexicographically equal to \c b
static bool cmpEqual(const CString::value_type& a,
const CString::value_type& b);
};
};
#endif

779
lib/base/CUnicode.cpp Normal file
View File

@@ -0,0 +1,779 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CUnicode.h"
#include "CArch.h"
#include <string.h>
//
// local utility functions
//
inline
static
UInt16
decode16(const UInt8* n, bool byteSwapped)
{
union x16 {
UInt8 n8[2];
UInt16 n16;
} c;
if (byteSwapped) {
c.n8[0] = n[1];
c.n8[1] = n[0];
}
else {
c.n8[0] = n[0];
c.n8[1] = n[1];
}
return c.n16;
}
inline
static
UInt32
decode32(const UInt8* n, bool byteSwapped)
{
union x32 {
UInt8 n8[4];
UInt32 n32;
} c;
if (byteSwapped) {
c.n8[0] = n[3];
c.n8[1] = n[2];
c.n8[2] = n[1];
c.n8[3] = n[0];
}
else {
c.n8[0] = n[0];
c.n8[1] = n[1];
c.n8[2] = n[2];
c.n8[3] = n[3];
}
return c.n32;
}
inline
static
void
resetError(bool* errors)
{
if (errors != NULL) {
*errors = false;
}
}
inline
static
void
setError(bool* errors)
{
if (errors != NULL) {
*errors = true;
}
}
//
// CUnicode
//
UInt32 CUnicode::s_invalid = 0x0000ffff;
UInt32 CUnicode::s_replacement = 0x0000fffd;
bool
CUnicode::isUTF8(const CString& src)
{
// convert and test each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
for (UInt32 n = src.size(); n > 0; ) {
if (fromUTF8(data, n) == s_invalid) {
return false;
}
}
return true;
}
CString
CUnicode::UTF8ToUCS2(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// get size of input string and reserve some space in output
UInt32 n = src.size();
CString dst;
dst.reserve(2 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c == s_invalid) {
c = s_replacement;
}
else if (c >= 0x00010000) {
setError(errors);
c = s_replacement;
}
UInt16 ucs2 = static_cast<UInt16>(c);
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
}
return dst;
}
CString
CUnicode::UTF8ToUCS4(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// get size of input string and reserve some space in output
UInt32 n = src.size();
CString dst;
dst.reserve(4 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c == s_invalid) {
c = s_replacement;
}
dst.append(reinterpret_cast<const char*>(&c), 4);
}
return dst;
}
CString
CUnicode::UTF8ToUTF16(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// get size of input string and reserve some space in output
UInt32 n = src.size();
CString dst;
dst.reserve(2 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c == s_invalid) {
c = s_replacement;
}
else if (c >= 0x00110000) {
setError(errors);
c = s_replacement;
}
if (c < 0x00010000) {
UInt16 ucs2 = static_cast<UInt16>(c);
dst.append(reinterpret_cast<const char*>(&ucs2), 2);
}
else {
c -= 0x00010000;
UInt16 utf16h = static_cast<UInt16>((c >> 10) + 0xd800);
UInt16 utf16l = static_cast<UInt16>((c & 0x03ff) + 0xdc00);
dst.append(reinterpret_cast<const char*>(&utf16h), 2);
dst.append(reinterpret_cast<const char*>(&utf16l), 2);
}
}
return dst;
}
CString
CUnicode::UTF8ToUTF32(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// get size of input string and reserve some space in output
UInt32 n = src.size();
CString dst;
dst.reserve(4 * n);
// convert each character
const UInt8* data = reinterpret_cast<const UInt8*>(src.c_str());
while (n > 0) {
UInt32 c = fromUTF8(data, n);
if (c == s_invalid) {
c = s_replacement;
}
else if (c >= 0x00110000) {
setError(errors);
c = s_replacement;
}
dst.append(reinterpret_cast<const char*>(&c), 4);
}
return dst;
}
CString
CUnicode::UTF8ToText(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert to wide char
UInt32 size;
wchar_t* tmp = UTF8ToWideChar(src, size, errors);
// convert string to multibyte
int len = ARCH->convStringWCToMB(NULL, tmp, size, errors);
char* mbs = new char[len + 1];
ARCH->convStringWCToMB(mbs, tmp, size, errors);
CString text(mbs, len);
// clean up
delete[] mbs;
delete[] tmp;
return text;
}
CString
CUnicode::UCS2ToUTF8(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert
UInt32 n = src.size() >> 1;
return doUCS2ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n, errors);
}
CString
CUnicode::UCS4ToUTF8(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert
UInt32 n = src.size() >> 2;
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n, errors);
}
CString
CUnicode::UTF16ToUTF8(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert
UInt32 n = src.size() >> 1;
return doUTF16ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n, errors);
}
CString
CUnicode::UTF32ToUTF8(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert
UInt32 n = src.size() >> 2;
return doUTF32ToUTF8(reinterpret_cast<const UInt8*>(src.data()), n, errors);
}
CString
CUnicode::textToUTF8(const CString& src, bool* errors)
{
// default to success
resetError(errors);
// convert string to wide characters
UInt32 n = src.size();
int len = ARCH->convStringMBToWC(NULL, src.c_str(), n, errors);
wchar_t* wcs = new wchar_t[len + 1];
ARCH->convStringMBToWC(wcs, src.c_str(), n, errors);
// convert to UTF8
CString utf8 = wideCharToUTF8(wcs, len, errors);
// clean up
delete[] wcs;
return utf8;
}
wchar_t*
CUnicode::UTF8ToWideChar(const CString& src, UInt32& size, bool* errors)
{
// convert to platform's wide character encoding
CString tmp;
switch (ARCH->getWideCharEncoding()) {
case IArchString::kUCS2:
tmp = UTF8ToUCS2(src, errors);
size = tmp.size() >> 1;
break;
case IArchString::kUCS4:
tmp = UTF8ToUCS4(src, errors);
size = tmp.size() >> 2;
break;
case IArchString::kUTF16:
tmp = UTF8ToUTF16(src, errors);
size = tmp.size() >> 1;
break;
case IArchString::kUTF32:
tmp = UTF8ToUTF32(src, errors);
size = tmp.size() >> 2;
break;
default:
assert(0 && "unknown wide character encoding");
}
// copy to a wchar_t array
wchar_t* dst = new wchar_t[size];
::memcpy(dst, tmp.data(), sizeof(wchar_t) * size);
return dst;
}
CString
CUnicode::wideCharToUTF8(const wchar_t* src, UInt32 size, bool* errors)
{
// convert from platform's wide character encoding.
// note -- this must include a wide nul character (independent of
// the CString's nul character).
switch (ARCH->getWideCharEncoding()) {
case IArchString::kUCS2:
return doUCS2ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
case IArchString::kUCS4:
return doUCS4ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
case IArchString::kUTF16:
return doUTF16ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
case IArchString::kUTF32:
return doUTF32ToUTF8(reinterpret_cast<const UInt8*>(src), size, errors);
default:
assert(0 && "unknown wide character encoding");
return CString();
}
}
CString
CUnicode::doUCS2ToUTF8(const UInt8* data, UInt32 n, bool* errors)
{
// make some space
CString dst;
dst.reserve(n);
// check if first character is 0xfffe or 0xfeff
bool byteSwapped = false;
if (n >= 1) {
switch (decode16(data, false)) {
case 0x0000feff:
data += 2;
--n;
break;
case 0x0000fffe:
byteSwapped = true;
data += 2;
--n;
break;
default:
break;
}
}
// convert each character
for (; n > 0; data += 2, --n) {
UInt32 c = decode16(data, byteSwapped);
toUTF8(dst, c, errors);
}
return dst;
}
CString
CUnicode::doUCS4ToUTF8(const UInt8* data, UInt32 n, bool* errors)
{
// make some space
CString dst;
dst.reserve(n);
// check if first character is 0xfffe or 0xfeff
bool byteSwapped = false;
if (n >= 1) {
switch (decode32(data, false)) {
case 0x0000feff:
data += 4;
--n;
break;
case 0x0000fffe:
byteSwapped = true;
data += 4;
--n;
break;
default:
break;
}
}
// convert each character
for (; n > 0; data += 4, --n) {
UInt32 c = decode32(data, byteSwapped);
toUTF8(dst, c, errors);
}
return dst;
}
CString
CUnicode::doUTF16ToUTF8(const UInt8* data, UInt32 n, bool* errors)
{
// make some space
CString dst;
dst.reserve(n);
// check if first character is 0xfffe or 0xfeff
bool byteSwapped = false;
if (n >= 1) {
switch (decode16(data, false)) {
case 0x0000feff:
data += 2;
--n;
break;
case 0x0000fffe:
byteSwapped = true;
data += 2;
--n;
break;
default:
break;
}
}
// convert each character
for (; n > 0; data += 2, --n) {
UInt32 c = decode16(data, byteSwapped);
if (c < 0x0000d800 || c > 0x0000dfff) {
toUTF8(dst, c, errors);
}
else if (n == 1) {
// error -- missing second word
setError(errors);
toUTF8(dst, s_replacement, NULL);
}
else if (c >= 0x0000d800 && c <= 0x0000dbff) {
UInt32 c2 = decode16(data, byteSwapped);
data += 2;
--n;
if (c2 < 0x0000dc00 || c2 > 0x0000dfff) {
// error -- [d800,dbff] not followed by [dc00,dfff]
setError(errors);
toUTF8(dst, s_replacement, NULL);
}
else {
c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000;
toUTF8(dst, c, errors);
}
}
else {
// error -- [dc00,dfff] without leading [d800,dbff]
setError(errors);
toUTF8(dst, s_replacement, NULL);
}
}
return dst;
}
CString
CUnicode::doUTF32ToUTF8(const UInt8* data, UInt32 n, bool* errors)
{
// make some space
CString dst;
dst.reserve(n);
// check if first character is 0xfffe or 0xfeff
bool byteSwapped = false;
if (n >= 1) {
switch (decode32(data, false)) {
case 0x0000feff:
data += 4;
--n;
break;
case 0x0000fffe:
byteSwapped = true;
data += 4;
--n;
break;
default:
break;
}
}
// convert each character
for (; n > 0; data += 4, --n) {
UInt32 c = decode32(data, byteSwapped);
if (c >= 0x00110000) {
setError(errors);
c = s_replacement;
}
toUTF8(dst, c, errors);
}
return dst;
}
UInt32
CUnicode::fromUTF8(const UInt8*& data, UInt32& n)
{
assert(data != NULL);
assert(n != 0);
// compute character encoding length, checking for overlong
// sequences (i.e. characters that don't use the shortest
// possible encoding).
UInt32 size;
if (data[0] < 0x80) {
// 0xxxxxxx
size = 1;
}
else if (data[0] < 0xc0) {
// 10xxxxxx -- in the middle of a multibyte character. counts
// as one invalid character.
--n;
++data;
return s_invalid;
}
else if (data[0] < 0xe0) {
// 110xxxxx
size = 2;
}
else if (data[0] < 0xf0) {
// 1110xxxx
size = 3;
}
else if (data[0] < 0xf8) {
// 11110xxx
size = 4;
}
else if (data[0] < 0xfc) {
// 111110xx
size = 5;
}
else if (data[0] < 0xfe) {
// 1111110x
size = 6;
}
else {
// invalid sequence. dunno how many bytes to skip so skip one.
--n;
++data;
return s_invalid;
}
// make sure we have enough data
if (size > n) {
data += n;
n = 0;
return s_invalid;
}
// extract character
UInt32 c;
switch (size) {
case 1:
c = static_cast<UInt32>(data[0]);
break;
case 2:
c = ((static_cast<UInt32>(data[0]) & 0x1f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 3:
c = ((static_cast<UInt32>(data[0]) & 0x0f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[2]) & 0x3f) );
break;
case 4:
c = ((static_cast<UInt32>(data[0]) & 0x07) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 5:
c = ((static_cast<UInt32>(data[0]) & 0x03) << 24) |
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
case 6:
c = ((static_cast<UInt32>(data[0]) & 0x01) << 30) |
((static_cast<UInt32>(data[1]) & 0x3f) << 24) |
((static_cast<UInt32>(data[1]) & 0x3f) << 18) |
((static_cast<UInt32>(data[1]) & 0x3f) << 12) |
((static_cast<UInt32>(data[1]) & 0x3f) << 6) |
((static_cast<UInt32>(data[1]) & 0x3f) );
break;
default:
assert(0 && "invalid size");
return s_invalid;
}
// check that all bytes after the first have the pattern 10xxxxxx.
// truncated sequences are treated as a single malformed character.
bool truncated = false;
switch (size) {
case 6:
if ((data[5] & 0xc0) != 0x80) {
truncated = true;
size = 5;
}
// fall through
case 5:
if ((data[4] & 0xc0) != 0x80) {
truncated = true;
size = 4;
}
// fall through
case 4:
if ((data[3] & 0xc0) != 0x80) {
truncated = true;
size = 3;
}
// fall through
case 3:
if ((data[2] & 0xc0) != 0x80) {
truncated = true;
size = 2;
}
// fall through
case 2:
if ((data[1] & 0xc0) != 0x80) {
truncated = true;
size = 1;
}
}
// update parameters
data += size;
n -= size;
// invalid if sequence was truncated
if (truncated) {
return s_invalid;
}
// check for characters that didn't use the smallest possible encoding
static UInt32 s_minChar[] = {
0,
0x00000000,
0x00000080,
0x00000800,
0x00010000,
0x00200000,
0x04000000
};
if (c < s_minChar[size]) {
return s_invalid;
}
// check for characters not in ISO-10646
if (c >= 0x0000d800 && c <= 0x0000dfff) {
return s_invalid;
}
if (c >= 0x0000fffe && c <= 0x0000ffff) {
return s_invalid;
}
return c;
}
void
CUnicode::toUTF8(CString& dst, UInt32 c, bool* errors)
{
UInt8 data[6];
// handle characters outside the valid range
if ((c >= 0x0000d800 && c <= 0x0000dfff) || c >= 0x80000000) {
setError(errors);
c = s_replacement;
}
// convert to UTF-8
if (c < 0x00000080) {
data[0] = static_cast<UInt8>(c);
dst.append(reinterpret_cast<char*>(data), 1);
}
else if (c < 0x00000800) {
data[0] = static_cast<UInt8>(((c >> 6) & 0x0000001f) + 0xc0);
data[1] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
dst.append(reinterpret_cast<char*>(data), 2);
}
else if (c < 0x00010000) {
data[0] = static_cast<UInt8>(((c >> 12) & 0x0000000f) + 0xe0);
data[1] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
data[2] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
dst.append(reinterpret_cast<char*>(data), 3);
}
else if (c < 0x00200000) {
data[0] = static_cast<UInt8>(((c >> 18) & 0x00000007) + 0xf0);
data[1] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
data[2] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
data[3] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
dst.append(reinterpret_cast<char*>(data), 4);
}
else if (c < 0x04000000) {
data[0] = static_cast<UInt8>(((c >> 24) & 0x00000003) + 0xf8);
data[1] = static_cast<UInt8>(((c >> 18) & 0x0000003f) + 0x80);
data[2] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
data[3] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
data[4] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
dst.append(reinterpret_cast<char*>(data), 5);
}
else if (c < 0x80000000) {
data[0] = static_cast<UInt8>(((c >> 30) & 0x00000001) + 0xfc);
data[1] = static_cast<UInt8>(((c >> 24) & 0x0000003f) + 0x80);
data[2] = static_cast<UInt8>(((c >> 18) & 0x0000003f) + 0x80);
data[3] = static_cast<UInt8>(((c >> 12) & 0x0000003f) + 0x80);
data[4] = static_cast<UInt8>(((c >> 6) & 0x0000003f) + 0x80);
data[5] = static_cast<UInt8>((c & 0x0000003f) + 0x80);
dst.append(reinterpret_cast<char*>(data), 6);
}
else {
assert(0 && "character out of range");
}
}

143
lib/base/CUnicode.h Normal file
View File

@@ -0,0 +1,143 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CUNICODE_H
#define CUNICODE_H
#include "CString.h"
#include "BasicTypes.h"
//! Unicode utility functions
/*!
This class provides functions for converting between various Unicode
encodings and the current locale encoding.
*/
class CUnicode {
public:
//! @name accessors
//@{
//! Test UTF-8 string for validity
/*!
Returns true iff the string contains a valid sequence of UTF-8
encoded characters.
*/
static bool isUTF8(const CString&);
//! Convert from UTF-8 to UCS-2 encoding
/*!
Convert from UTF-8 to UCS-2. If errors is not NULL then *errors
is set to true iff any character could not be encoded in UCS-2.
Decoding errors do not set *errors.
*/
static CString UTF8ToUCS2(const CString&, bool* errors = NULL);
//! Convert from UTF-8 to UCS-4 encoding
/*!
Convert from UTF-8 to UCS-4. If errors is not NULL then *errors
is set to true iff any character could not be encoded in UCS-4.
Decoding errors do not set *errors.
*/
static CString UTF8ToUCS4(const CString&, bool* errors = NULL);
//! Convert from UTF-8 to UTF-16 encoding
/*!
Convert from UTF-8 to UTF-16. If errors is not NULL then *errors
is set to true iff any character could not be encoded in UTF-16.
Decoding errors do not set *errors.
*/
static CString UTF8ToUTF16(const CString&, bool* errors = NULL);
//! Convert from UTF-8 to UTF-32 encoding
/*!
Convert from UTF-8 to UTF-32. If errors is not NULL then *errors
is set to true iff any character could not be encoded in UTF-32.
Decoding errors do not set *errors.
*/
static CString UTF8ToUTF32(const CString&, bool* errors = NULL);
//! Convert from UTF-8 to the current locale encoding
/*!
Convert from UTF-8 to the current locale encoding. If errors is not
NULL then *errors is set to true iff any character could not be encoded.
Decoding errors do not set *errors.
*/
static CString UTF8ToText(const CString&, bool* errors = NULL);
//! Convert from UCS-2 to UTF-8
/*!
Convert from UCS-2 to UTF-8. If errors is not NULL then *errors is
set to true iff any character could not be decoded.
*/
static CString UCS2ToUTF8(const CString&, bool* errors = NULL);
//! Convert from UCS-4 to UTF-8
/*!
Convert from UCS-4 to UTF-8. If errors is not NULL then *errors is
set to true iff any character could not be decoded.
*/
static CString UCS4ToUTF8(const CString&, bool* errors = NULL);
//! Convert from UTF-16 to UTF-8
/*!
Convert from UTF-16 to UTF-8. If errors is not NULL then *errors is
set to true iff any character could not be decoded.
*/
static CString UTF16ToUTF8(const CString&, bool* errors = NULL);
//! Convert from UTF-32 to UTF-8
/*!
Convert from UTF-32 to UTF-8. If errors is not NULL then *errors is
set to true iff any character could not be decoded.
*/
static CString UTF32ToUTF8(const CString&, bool* errors = NULL);
//! Convert from the current locale encoding to UTF-8
/*!
Convert from the current locale encoding to UTF-8. If errors is not
NULL then *errors is set to true iff any character could not be decoded.
*/
static CString textToUTF8(const CString&, bool* errors = NULL);
//@}
private:
// convert UTF8 to wchar_t string (using whatever encoding is native
// to the platform). caller must delete[] the returned string. the
// string is *not* nul terminated; the length (in characters) is
// returned in size.
static wchar_t* UTF8ToWideChar(const CString&,
UInt32& size, bool* errors);
// convert nul terminated wchar_t string (in platform's native
// encoding) to UTF8.
static CString wideCharToUTF8(const wchar_t*,
UInt32 size, bool* errors);
// internal conversion to UTF8
static CString doUCS2ToUTF8(const UInt8* src, UInt32 n, bool* errors);
static CString doUCS4ToUTF8(const UInt8* src, UInt32 n, bool* errors);
static CString doUTF16ToUTF8(const UInt8* src, UInt32 n, bool* errors);
static CString doUTF32ToUTF8(const UInt8* src, UInt32 n, bool* errors);
// convert characters to/from UTF8
static UInt32 fromUTF8(const UInt8*& src, UInt32& size);
static void toUTF8(CString& dst, UInt32 c, bool* errors);
private:
static UInt32 s_invalid;
static UInt32 s_replacement;
};
#endif

32
lib/base/IEventJob.h Normal file
View File

@@ -0,0 +1,32 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IEVENTJOB_H
#define IEVENTJOB_H
#include "IInterface.h"
class CEvent;
//! Event handler interface
/*!
An event job is an interface for executing a event handler.
*/
class IEventJob : public IInterface {
public:
//! Run the job
virtual void run(const CEvent&) = 0;
};
#endif

43
lib/base/IEventQueue.cpp Normal file
View File

@@ -0,0 +1,43 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "IEventQueue.h"
//
// IEventQueue
//
static int g_systemTarget = 0;
IEventQueue* IEventQueue::s_instance = NULL;
void*
IEventQueue::getSystemTarget()
{
// any unique arbitrary pointer will do
return &g_systemTarget;
}
IEventQueue*
IEventQueue::getInstance()
{
assert(s_instance != NULL);
return s_instance;
}
void
IEventQueue::setInstance(IEventQueue* instance)
{
assert(s_instance == NULL || instance == NULL);
s_instance = instance;
}

213
lib/base/IEventQueue.h Normal file
View File

@@ -0,0 +1,213 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IEVENTQUEUE_H
#define IEVENTQUEUE_H
#include "IInterface.h"
#include "CEvent.h"
#define EVENTQUEUE IEventQueue::getInstance()
class IEventJob;
class IEventQueueBuffer;
// Opaque type for timer info. This is defined by subclasses of
// IEventQueueBuffer.
class CEventQueueTimer;
//! Event queue interface
/*!
An event queue provides a queue of CEvents. Clients can block waiting
on any event becoming available at the head of the queue and can place
new events at the end of the queue. Clients can also add and remove
timers which generate events periodically.
*/
class IEventQueue : public IInterface {
public:
class CTimerEvent {
public:
CEventQueueTimer* m_timer; //!< The timer
UInt32 m_count; //!< Number of repeats
};
//! @name manipulators
//@{
//! Set the buffer
/*!
Replace the current event queue buffer. Any queued events are
discarded. The queue takes ownership of the buffer.
*/
virtual void adoptBuffer(IEventQueueBuffer*) = 0;
//! Remove event from queue
/*!
Returns the next event on the queue into \p event. If no event is
available then blocks for up to \p timeout seconds, or forever if
\p timeout is negative. Returns true iff an event was available.
*/
virtual bool getEvent(CEvent& event, double timeout = -1.0) = 0;
//! Dispatch an event
/*!
Looks up the dispatcher for the event's target and invokes it.
Returns true iff a dispatcher exists for the target.
*/
virtual bool dispatchEvent(const CEvent& event) = 0;
//! Add event to queue
/*!
Adds \p event to the end of the queue.
*/
virtual void addEvent(const CEvent& event) = 0;
//! Create a recurring timer
/*!
Creates and returns a timer. An event is returned after \p duration
seconds and the timer is reset to countdown again. When a timer event
is returned the data points to a \c CTimerEvent. The client must pass
the returned timer to \c deleteTimer() (whether or not the timer has
expired) to release the timer. The returned timer event uses the
given \p target. If \p target is NULL it uses the returned timer as
the target.
Events for a single timer don't accumulate in the queue, even if the
client reading events can't keep up. Instead, the \c m_count member
of the \c CTimerEvent indicates how many events for the timer would
have been put on the queue since the last event for the timer was
removed (or since the timer was added).
*/
virtual CEventQueueTimer*
newTimer(double duration, void* target) = 0;
//! Create a one-shot timer
/*!
Creates and returns a one-shot timer. An event is returned when
the timer expires and the timer is removed from further handling.
When a timer event is returned the data points to a \c CTimerEvent.
The \m c_count member of the \c CTimerEvent is always 1. The client
must pass the returned timer to \c deleteTimer() (whether or not the
timer has expired) to release the timer. The returned timer event
uses the given \p target. If \p target is NULL it uses the returned
timer as the target.
*/
virtual CEventQueueTimer*
newOneShotTimer(double duration,
void* target) = 0;
//! Destroy a timer
/*!
Destroys a previously created timer. The timer is removed from the
queue and will not generate event, even if the timer has expired.
*/
virtual void deleteTimer(CEventQueueTimer*) = 0;
//! Register an event handler for an event type
/*!
Registers an event handler for \p type and \p target. The \p handler
is adopted. Any existing handler for the type,target pair is deleted.
\c dispatchEvent() will invoke \p handler for any event for \p target
of type \p type. If no such handler exists it will use the handler
for \p target and type \p kUnknown if it exists.
*/
virtual void adoptHandler(CEvent::Type type,
void* target, IEventJob* handler) = 0;
//! Unregister an event handler for an event type
/*!
Unregisters an event handler for the \p type, \p target pair and
deletes it.
*/
virtual void removeHandler(CEvent::Type type, void* target) = 0;
//! Unregister all event handlers for an event target
/*!
Unregisters all event handlers for the \p target and deletes them.
*/
virtual void removeHandlers(void* target) = 0;
//! Creates a new event type
/*!
Returns a unique event type id.
*/
virtual CEvent::Type
registerType(const char* name) = 0;
//! Creates a new event type
/*!
If \p type contains \c kUnknown then it is set to a unique event
type id otherwise it is left alone. The final value of \p type
is returned.
*/
virtual CEvent::Type
registerTypeOnce(CEvent::Type& type,
const char* name) = 0;
//@}
//! @name accessors
//@{
//! Test if queue is empty
/*!
Returns true iff the queue has no events in it, including timer
events.
*/
virtual bool isEmpty() const = 0;
//! Get an event handler
/*!
Finds and returns the event handler for the \p type, \p target pair
if it exists, otherwise it returns NULL.
*/
virtual IEventJob* getHandler(CEvent::Type type, void* target) const = 0;
//! Get name for event
/*!
Returns the name for the event \p type. This is primarily for
debugging.
*/
virtual const char* getTypeName(CEvent::Type type) = 0;
//! Get the system event type target
/*!
Returns the target to use for dispatching \c CEvent::kSystem events.
*/
static void* getSystemTarget();
//! Get the singleton instance
/*!
Returns the singleton instance of the event queue
*/
static IEventQueue* getInstance();
//@}
protected:
//! @name manipulators
//@{
//! Set the singleton instance
/*!
Sets the singleton instance of the event queue
*/
static void setInstance(IEventQueue*);
//@}
private:
static IEventQueue* s_instance;
};
#endif

View File

@@ -0,0 +1,94 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IEVENTQUEUEBUFFER_H
#define IEVENTQUEUEBUFFER_H
#include "IInterface.h"
#include "BasicTypes.h"
class CEvent;
class CEventQueueTimer;
//! Event queue buffer interface
/*!
An event queue buffer provides a queue of events for an IEventQueue.
*/
class IEventQueueBuffer : public IInterface {
public:
enum Type {
kNone, //!< No event is available
kSystem, //!< Event is a system event
kUser //!< Event is a user event
};
//! @name manipulators
//@{
//! Block waiting for an event
/*!
Wait for an event in the event queue buffer for up to \p timeout
seconds.
*/
virtual void waitForEvent(double timeout) = 0;
//! Get the next event
/*!
Get the next event from the buffer. Return kNone if no event is
available. If a system event is next, return kSystem and fill in
event. The event data in a system event can point to a static
buffer (because CEvent::deleteData() will not attempt to delete
data in a kSystem event). Otherwise, return kUser and fill in
\p dataID with the value passed to \c addEvent().
*/
virtual Type getEvent(CEvent& event, UInt32& dataID) = 0;
//! Post an event
/*!
Add the given event to the end of the queue buffer. This is a user
event and \c getEvent() must be able to identify it as such and
return \p dataID. This method must cause \c waitForEvent() to
return at some future time if it's blocked waiting on an event.
*/
virtual bool addEvent(UInt32 dataID) = 0;
//@}
//! @name accessors
//@{
//! Check if event queue buffer is empty
/*!
Return true iff the event queue buffer is empty.
*/
virtual bool isEmpty() const = 0;
//! Create a timer object
/*!
Create and return a timer object. The object is opaque and is
used only by the buffer but it must be a valid object (i.e.
not NULL).
*/
virtual CEventQueueTimer*
newTimer(double duration, bool oneShot) const = 0;
//! Destroy a timer object
/*!
Destroy a timer object previously returned by \c newTimer().
*/
virtual void deleteTimer(CEventQueueTimer*) const = 0;
//@}
};
#endif

30
lib/base/IJob.h Normal file
View File

@@ -0,0 +1,30 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IJOB_H
#define IJOB_H
#include "IInterface.h"
//! Job interface
/*!
A job is an interface for executing some function.
*/
class IJob : public IInterface {
public:
//! Run the job
virtual void run() = 0;
};
#endif

81
lib/base/ILogOutputter.h Normal file
View File

@@ -0,0 +1,81 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ILOGOUTPUTTER_H
#define ILOGOUTPUTTER_H
#include "IInterface.h"
#include "CLog.h"
//! Outputter interface
/*!
Type of outputter interface. The logger performs all output through
outputters. ILogOutputter overrides must not call any log functions
directly or indirectly.
*/
class ILogOutputter : public IInterface {
public:
typedef CLog::ELevel ELevel;
//! @name manipulators
//@{
//! Open the outputter
/*!
Opens the outputter for writing. Calling this method on an
already open outputter must have no effect.
*/
virtual void open(const char* title) = 0;
//! Close the outputter
/*!
Close the outputter. Calling this method on an already closed
outputter must have no effect.
*/
virtual void close() = 0;
//! Show the outputter
/*!
Causes the output to become visible. This generally only makes sense
for a logger in a graphical user interface. Other implementations
will do nothing. Iff \p showIfEmpty is \c false then the implementation
may optionally only show the log if it's not empty.
*/
virtual void show(bool showIfEmpty) = 0;
//! Write a message with level
/*!
Writes \c message, which has the given \c level, to a log.
If this method returns true then CLog will stop passing the
message to all outputters in the outputter chain, otherwise
it continues. Most implementations should return true.
*/
virtual bool write(ELevel level, const char* message) = 0;
//@}
//! @name accessors
//@{
//! Returns the newline sequence for the outputter
/*!
Different outputters use different character sequences for newlines.
This method returns the appropriate newline sequence for this
outputter.
*/
virtual const char* getNewline() const = 0;
//@}
};
#endif

267
lib/base/LogOutputters.cpp Normal file
View File

@@ -0,0 +1,267 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "LogOutputters.h"
#include "CArch.h"
//
// CStopLogOutputter
//
CStopLogOutputter::CStopLogOutputter()
{
// do nothing
}
CStopLogOutputter::~CStopLogOutputter()
{
// do nothing
}
void
CStopLogOutputter::open(const char*)
{
// do nothing
}
void
CStopLogOutputter::close()
{
// do nothing
}
void
CStopLogOutputter::show(bool)
{
// do nothing
}
bool
CStopLogOutputter::write(ELevel, const char*)
{
return false;
}
const char*
CStopLogOutputter::getNewline() const
{
return "";
}
//
// CConsoleLogOutputter
//
CConsoleLogOutputter::CConsoleLogOutputter()
{
// do nothing
}
CConsoleLogOutputter::~CConsoleLogOutputter()
{
// do nothing
}
void
CConsoleLogOutputter::open(const char* title)
{
ARCH->openConsole(title);
}
void
CConsoleLogOutputter::close()
{
ARCH->closeConsole();
}
void
CConsoleLogOutputter::show(bool showIfEmpty)
{
ARCH->showConsole(showIfEmpty);
}
bool
CConsoleLogOutputter::write(ELevel, const char* msg)
{
ARCH->writeConsole(msg);
return true;
}
const char*
CConsoleLogOutputter::getNewline() const
{
return ARCH->getNewlineForConsole();
}
//
// CSystemLogOutputter
//
CSystemLogOutputter::CSystemLogOutputter()
{
// do nothing
}
CSystemLogOutputter::~CSystemLogOutputter()
{
// do nothing
}
void
CSystemLogOutputter::open(const char* title)
{
ARCH->openLog(title);
}
void
CSystemLogOutputter::close()
{
ARCH->closeLog();
}
void
CSystemLogOutputter::show(bool showIfEmpty)
{
ARCH->showLog(showIfEmpty);
}
bool
CSystemLogOutputter::write(ELevel level, const char* msg)
{
IArchLog::ELevel archLogLevel;
switch (level) {
case CLog::kFATAL:
case CLog::kERROR:
archLogLevel = IArchLog::kERROR;
break;
case CLog::kWARNING:
archLogLevel = IArchLog::kWARNING;
break;
case CLog::kNOTE:
archLogLevel = IArchLog::kNOTE;
break;
case CLog::kINFO:
archLogLevel = IArchLog::kINFO;
break;
default:
archLogLevel = IArchLog::kDEBUG;
break;
};
ARCH->writeLog(archLogLevel, msg);
return true;
}
const char*
CSystemLogOutputter::getNewline() const
{
return "";
}
//
// CSystemLogger
//
CSystemLogger::CSystemLogger(const char* title, bool blockConsole) :
m_stop(NULL)
{
// redirect log messages
if (blockConsole) {
m_stop = new CStopLogOutputter;
CLOG->insert(m_stop);
}
m_syslog = new CSystemLogOutputter;
m_syslog->open(title);
CLOG->insert(m_syslog);
}
CSystemLogger::~CSystemLogger()
{
CLOG->remove(m_syslog);
delete m_syslog;
if (m_stop != NULL) {
CLOG->remove(m_stop);
delete m_stop;
}
}
//
// CBufferedLogOutputter
//
CBufferedLogOutputter::CBufferedLogOutputter(UInt32 maxBufferSize) :
m_maxBufferSize(maxBufferSize)
{
// do nothing
}
CBufferedLogOutputter::~CBufferedLogOutputter()
{
// do nothing
}
CBufferedLogOutputter::const_iterator
CBufferedLogOutputter::begin() const
{
return m_buffer.begin();
}
CBufferedLogOutputter::const_iterator
CBufferedLogOutputter::end() const
{
return m_buffer.end();
}
void
CBufferedLogOutputter::open(const char*)
{
// do nothing
}
void
CBufferedLogOutputter::close()
{
// remove all elements from the buffer
m_buffer.clear();
}
void
CBufferedLogOutputter::show(bool)
{
// do nothing
}
bool
CBufferedLogOutputter::write(ELevel, const char* message)
{
while (m_buffer.size() >= m_maxBufferSize) {
m_buffer.pop_front();
}
m_buffer.push_back(CString(message));
return true;
}
const char*
CBufferedLogOutputter::getNewline() const
{
return "";
}

132
lib/base/LogOutputters.h Normal file
View File

@@ -0,0 +1,132 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef LOGOUTPUTTERS_H
#define LOGOUTPUTTERS_H
#include "BasicTypes.h"
#include "ILogOutputter.h"
#include "CString.h"
#include "stddeque.h"
//! Stop traversing log chain outputter
/*!
This outputter performs no output and returns false from \c write(),
causing the logger to stop traversing the outputter chain. Insert
this to prevent already inserted outputters from writing.
*/
class CStopLogOutputter : public ILogOutputter {
public:
CStopLogOutputter();
virtual ~CStopLogOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const;
};
//! Write log to console
/*!
This outputter writes output to the console. The level for each
message is ignored.
*/
class CConsoleLogOutputter : public ILogOutputter {
public:
CConsoleLogOutputter();
virtual ~CConsoleLogOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const;
};
//! Write log to system log
/*!
This outputter writes output to the system log.
*/
class CSystemLogOutputter : public ILogOutputter {
public:
CSystemLogOutputter();
virtual ~CSystemLogOutputter();
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const;
};
//! Write log to system log only
/*!
Creating an object of this type inserts a CStopLogOutputter followed
by a CSystemLogOutputter into CLog. The destructor removes those
outputters. Add one of these to any scope that needs to write to
the system log (only) and restore the old outputters when exiting
the scope.
*/
class CSystemLogger {
public:
CSystemLogger(const char* title, bool blockConsole);
~CSystemLogger();
private:
ILogOutputter* m_syslog;
ILogOutputter* m_stop;
};
//! Save log history
/*!
This outputter records the last N log messages.
*/
class CBufferedLogOutputter : public ILogOutputter {
private:
typedef std::deque<CString> CBuffer;
public:
typedef CBuffer::const_iterator const_iterator;
CBufferedLogOutputter(UInt32 maxBufferSize);
virtual ~CBufferedLogOutputter();
//! @name accessors
//@{
//! Get start of buffer
const_iterator begin() const;
//! Get end of buffer
const_iterator end() const;
//@}
// ILogOutputter overrides
virtual void open(const char* title);
virtual void close();
virtual void show(bool showIfEmpty);
virtual bool write(ELevel level, const char* message);
virtual const char* getNewline() const;
private:
UInt32 m_maxBufferSize;
CBuffer m_buffer;
};
#endif

62
lib/base/Makefile.am Normal file
View File

@@ -0,0 +1,62 @@
# synergy -- mouse and keyboard sharing utility
# Copyright (C) 2002 Chris Schoeneman
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file COPYING that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
## Process this file with automake to produce Makefile.in
NULL =
EXTRA_DIST = \
Makefile.win \
$(NULL)
MAINTAINERCLEANFILES = \
Makefile.in \
$(NULL)
noinst_LIBRARIES = libbase.a
libbase_a_SOURCES = \
CEvent.cpp \
CEventQueue.cpp \
CFunctionEventJob.cpp \
CFunctionJob.cpp \
CLog.cpp \
CSimpleEventQueueBuffer.cpp \
CStopwatch.cpp \
CStringUtil.cpp \
CUnicode.cpp \
IEventQueue.cpp \
LogOutputters.cpp \
XBase.cpp \
CEvent.h \
CEventQueue.h \
CFunctionEventJob.h \
CFunctionJob.h \
CLog.h \
CPriorityQueue.h \
CSimpleEventQueueBuffer.h \
CStopwatch.h \
CString.h \
CStringUtil.h \
CUnicode.h \
IEventJob.h \
IEventQueue.h \
IEventQueueBuffer.h \
IJob.h \
ILogOutputter.h \
LogOutputters.h \
TMethodEventJob.h \
TMethodJob.h \
XBase.h \
$(NULL)
INCLUDES = \
-I$(top_srcdir)/lib/common \
-I$(top_srcdir)/lib/arch \
$(NULL)

77
lib/base/Makefile.win Normal file
View File

@@ -0,0 +1,77 @@
# synergy -- mouse and keyboard sharing utility
# Copyright (C) 2007 Chris Schoeneman
#
# This package is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# found in the file COPYING that should have accompanied this file.
#
# This package is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
LIB_BASE_SRC = lib\base
LIB_BASE_DST = $(BUILD_DST)\$(LIB_BASE_SRC)
LIB_BASE_LIB = "$(LIB_BASE_DST)\base.lib"
LIB_BASE_CPP = \
"CEvent.cpp" \
"CEventQueue.cpp" \
"CFunctionEventJob.cpp" \
"CFunctionJob.cpp" \
"CLog.cpp" \
"CSimpleEventQueueBuffer.cpp" \
"CStopwatch.cpp" \
"CStringUtil.cpp" \
"CUnicode.cpp" \
"IEventQueue.cpp" \
"LogOutputters.cpp" \
"XBase.cpp" \
$(NULL)
LIB_BASE_OBJ = \
"$(LIB_BASE_DST)\CEvent.obj" \
"$(LIB_BASE_DST)\CEventQueue.obj" \
"$(LIB_BASE_DST)\CFunctionEventJob.obj" \
"$(LIB_BASE_DST)\CFunctionJob.obj" \
"$(LIB_BASE_DST)\CLog.obj" \
"$(LIB_BASE_DST)\CSimpleEventQueueBuffer.obj" \
"$(LIB_BASE_DST)\CStopwatch.obj" \
"$(LIB_BASE_DST)\CStringUtil.obj" \
"$(LIB_BASE_DST)\CUnicode.obj" \
"$(LIB_BASE_DST)\IEventQueue.obj" \
"$(LIB_BASE_DST)\LogOutputters.obj" \
"$(LIB_BASE_DST)\XBase.obj" \
$(NULL)
LIB_BASE_INC = \
/I"lib\common" \
/I"lib\arch" \
$(NULL)
CPP_FILES = $(CPP_FILES) $(LIB_BASE_CPP)
OBJ_FILES = $(OBJ_FILES) $(LIB_BASE_OBJ)
LIB_FILES = $(LIB_FILES) $(LIB_BASE_LIB)
# Dependency rules
$(LIB_BASE_OBJ): $(AUTODEP)
!if EXIST($(LIB_BASE_DST)\deps.mak)
!include $(LIB_BASE_DST)\deps.mak
!endif
# Build rules. Use batch-mode rules if possible.
!if DEFINED(_NMAKE_VER)
{$(LIB_BASE_SRC)\}.cpp{$(LIB_BASE_DST)\}.obj::
!else
{$(LIB_BASE_SRC)\}.cpp{$(LIB_BASE_DST)\}.obj:
!endif
@$(ECHO) Compile in $(LIB_BASE_SRC)
-@$(MKDIR) $(LIB_BASE_DST) 2>NUL:
$(cpp) $(cppdebug) $(cppflags) $(cppvarsmt) /showIncludes \
$(LIB_BASE_INC) \
/Fo$(LIB_BASE_DST)\ \
/Fd$(LIB_BASE_LIB:.lib=.pdb) \
$< | $(AUTODEP) $(LIB_BASE_SRC) $(LIB_BASE_DST)
$(LIB_BASE_LIB): $(LIB_BASE_OBJ)
@$(ECHO) Link $(@F)
$(implib) $(ildebug) $(ilflags) \
/out:$@ \
$**
$(AUTODEP) $(LIB_BASE_SRC) $(LIB_BASE_DST) $(**:.obj=.d)

View File

@@ -0,0 +1,70 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2004 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CMETHODEVENTJOB_H
#define CMETHODEVENTJOB_H
#include "IEventJob.h"
//! Use a member function as an event job
/*!
An event job class that invokes a member function.
*/
template <class T>
class TMethodEventJob : public IEventJob {
public:
//! run(event) invokes \c object->method(event, arg)
TMethodEventJob(T* object,
void (T::*method)(const CEvent&, void*),
void* arg = NULL);
virtual ~TMethodEventJob();
// IJob overrides
virtual void run(const CEvent&);
private:
T* m_object;
void (T::*m_method)(const CEvent&, void*);
void* m_arg;
};
template <class T>
inline
TMethodEventJob<T>::TMethodEventJob(T* object,
void (T::*method)(const CEvent&, void*), void* arg) :
m_object(object),
m_method(method),
m_arg(arg)
{
// do nothing
}
template <class T>
inline
TMethodEventJob<T>::~TMethodEventJob()
{
// do nothing
}
template <class T>
inline
void
TMethodEventJob<T>::run(const CEvent& event)
{
if (m_object != NULL) {
(m_object->*m_method)(event, m_arg);
}
}
#endif

67
lib/base/TMethodJob.h Normal file
View File

@@ -0,0 +1,67 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CMETHODJOB_H
#define CMETHODJOB_H
#include "IJob.h"
//! Use a function as a job
/*!
A job class that invokes a member function.
*/
template <class T>
class TMethodJob : public IJob {
public:
//! run() invokes \c object->method(arg)
TMethodJob(T* object, void (T::*method)(void*), void* arg = NULL);
virtual ~TMethodJob();
// IJob overrides
virtual void run();
private:
T* m_object;
void (T::*m_method)(void*);
void* m_arg;
};
template <class T>
inline
TMethodJob<T>::TMethodJob(T* object, void (T::*method)(void*), void* arg) :
m_object(object),
m_method(method),
m_arg(arg)
{
// do nothing
}
template <class T>
inline
TMethodJob<T>::~TMethodJob()
{
// do nothing
}
template <class T>
inline
void
TMethodJob<T>::run()
{
if (m_object != NULL) {
(m_object->*m_method)(m_arg);
}
}
#endif

69
lib/base/XBase.cpp Normal file
View File

@@ -0,0 +1,69 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "XBase.h"
#include "CStringUtil.h"
#include <cerrno>
#include <cstdarg>
//
// XBase
//
XBase::XBase() :
m_what()
{
// do nothing
}
XBase::XBase(const CString& msg) :
m_what(msg)
{
// do nothing
}
XBase::~XBase()
{
// do nothing
}
const char*
XBase::what() const
{
if (m_what.empty()) {
m_what = getWhat();
}
return m_what.c_str();
}
CString
XBase::format(const char* /*id*/, const char* fmt, ...) const throw()
{
// FIXME -- lookup message string using id as an index. set
// fmt to that string if it exists.
// format
CString result;
va_list args;
va_start(args, fmt);
try {
result = CStringUtil::vformat(fmt, args);
}
catch (...) {
// ignore
}
va_end(args);
return result;
}

121
lib/base/XBase.h Normal file
View File

@@ -0,0 +1,121 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2002 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef XBASE_H
#define XBASE_H
#include "CString.h"
//! Exception base class
/*!
This is the base class of most exception types.
*/
class XBase {
public:
//! Use getWhat() as the result of what()
XBase();
//! Use \c msg as the result of what()
XBase(const CString& msg);
virtual ~XBase();
//! Reason for exception
virtual const char* what() const;
protected:
//! Get a human readable string describing the exception
virtual CString getWhat() const throw() = 0;
//! Format a string
/*!
Looks up a message format using \c id, using \c defaultFormat if
no format can be found, then replaces positional parameters in
the format string and returns the result.
*/
virtual CString format(const char* id,
const char* defaultFormat, ...) const throw();
private:
mutable CString m_what;
};
/*!
\def XBASE_SUBCLASS
Convenience macro to subclass from XBase (or a subclass of it),
providing the c'tor taking a const CString&. getWhat() is not
declared.
*/
#define XBASE_SUBCLASS(name_, super_) \
class name_ : public super_ { \
public: \
name_() : super_() { } \
name_(const CString& msg) : super_(msg) { } \
}
/*!
\def XBASE_SUBCLASS
Convenience macro to subclass from XBase (or a subclass of it),
providing the c'tor taking a const CString&. getWhat() must be
implemented.
*/
#define XBASE_SUBCLASS_WHAT(name_, super_) \
class name_ : public super_ { \
public: \
name_() : super_() { } \
name_(const CString& msg) : super_(msg) { } \
\
protected: \
virtual CString getWhat() const throw(); \
}
/*!
\def XBASE_SUBCLASS_FORMAT
Convenience macro to subclass from XBase (or a subclass of it),
providing the c'tor taking a const CString&. what() is overridden
to call getWhat() when first called; getWhat() can format the
error message and can call what() to get the message passed to the
c'tor.
*/
#define XBASE_SUBCLASS_FORMAT(name_, super_) \
class name_ : public super_ { \
private: \
enum EState { kFirst, kFormat, kDone }; \
\
public: \
name_() : super_(), m_state(kDone) { } \
name_(const CString& msg) : super_(msg), m_state(kFirst) { } \
\
virtual const char* what() const \
{ \
if (m_state == kFirst) { \
m_state = kFormat; \
m_formatted = getWhat(); \
m_state = kDone; \
} \
if (m_state == kDone) { \
return m_formatted.c_str(); \
} \
else { \
return super_::what(); \
} \
} \
\
protected: \
virtual CString getWhat() const throw(); \
\
private: \
mutable EState m_state; \
mutable std::string m_formatted; \
}
#endif