Files
barrier/base/CLog.cpp
crs beda89fd53 changes to add command line arguments. also added automatic
restarting and daemonizing on unix.  daemon sends log messages
to syslog.  unix now reads config file from file named on
command line;  if no command line arg then uses effective
user's config file and if that's not there it finally tries
/etc/synergy.conf.  if there are no screens configured then
one is added for the primary screen.  broke some startup
stuff on win32.

also now timing out if X primary screen can't grab the mouse
and keyboard.  the server will just give up trying to switch
screens.  the grabs will fail is some other app has a grab
and won't release it.  note that kdm grabs the keyboard for
the duration that the login window is displayed, effectively
disabling synergy.
2002-06-03 18:53:18 +00:00

299 lines
6.6 KiB
C++

#include "CLog.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#if defined(CONFIG_PLATFORM_WIN32)
#include <windows.h>
#define vsnprintf _vsnprintf
#endif
static const char* g_priority[] = {
"FATAL",
"ERROR",
"WARNING",
"NOTE",
"INFO",
"DEBUG",
"DEBUG1",
"DEBUG2"
};
static const int g_numPriority = (int)(sizeof(g_priority) /
sizeof(g_priority[0]));
#if defined(NDEBUG)
static const int g_defaultMaxPriority = 4;
#else
static const int g_defaultMaxPriority = 5;
#endif
static const int g_maxPriorityLength = 7; // length of longest string
static const int g_prioritySuffixLength = 2;
static const int g_priorityPad = g_maxPriorityLength +
g_prioritySuffixLength;
static const int g_newlineLength = 2;
//
// CLog
//
CLog::Outputter CLog::s_outputter = NULL;
CLog::Lock CLog::s_lock = &CLog::dummyLock;
int CLog::s_maxPriority = -1;
void CLog::print(const char* fmt, ...)
{
// check if fmt begins with a priority argument
int priority = 4;
if (fmt[0] == '%' && fmt[1] == 'z') {
priority = fmt[2] - '\060';
fmt += 3;
}
// compute prefix padding length
int pad = g_priorityPad;
// print to buffer
char stack[1024];
va_list args;
va_start(args, fmt);
char* buffer = vsprint(pad, stack,
sizeof(stack) / sizeof(stack[0]), fmt, args);
va_end(args);
// output buffer
output(priority, buffer);
// clean up
if (buffer != stack)
delete[] buffer;
}
void CLog::printt(const char* file, int line,
const char* fmt, ...)
{
// check if fmt begins with a priority argument
int priority = 4;
if (fmt[0] == '%' && fmt[1] == 'z') {
priority = fmt[2] - '\060';
fmt += 3;
}
// compute prefix padding length
char stack[1024];
sprintf(stack, "%d", line);
int pad = strlen(file) + 1 /* comma */ +
strlen(stack) + 1 /* colon */ + 1 /* space */ +
g_priorityPad;
// print to buffer, leaving space for a newline at the end
va_list args;
va_start(args, fmt);
char* buffer = vsprint(pad, stack,
sizeof(stack) / sizeof(stack[0]), fmt, args);
va_end(args);
// print the prefix to the buffer. leave space for priority label.
sprintf(buffer + g_priorityPad, "%s,%d:", file, line);
buffer[pad - 1] = ' ';
// discard file and line if priority < 0
if (priority < 0) {
buffer += pad - g_priorityPad;
}
// output buffer
output(priority, buffer);
// clean up
if (buffer != stack)
delete[] buffer;
}
void CLog::setOutputter(Outputter outputter)
{
CHoldLock lock(s_lock);
s_outputter = outputter;
}
CLog::Outputter CLog::getOutputter()
{
CHoldLock lock(s_lock);
return s_outputter;
}
void CLog::setLock(Lock newLock)
{
CHoldLock lock(s_lock);
s_lock = (newLock == NULL) ? dummyLock : newLock;
}
CLog::Lock CLog::getLock()
{
CHoldLock lock(s_lock);
return (s_lock == dummyLock) ? NULL : s_lock;
}
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)
{
CHoldLock lock(s_lock);
s_maxPriority = maxPriority;
}
int CLog::getFilter()
{
CHoldLock lock(s_lock);
return getMaxPriority();
}
void CLog::dummyLock(bool)
{
// do nothing
}
int CLog::getMaxPriority()
{
CHoldLock lock(s_lock);
if (s_maxPriority == -1) {
s_maxPriority = g_defaultMaxPriority;
setFilter(getenv("SYN_LOG_PRI"));
}
return s_maxPriority;
}
void CLog::output(int priority, char* msg)
{
assert(priority >= -1 && priority < g_numPriority);
assert(msg != 0);
if (priority <= getMaxPriority()) {
// insert priority label
int n = -g_prioritySuffixLength;
if (priority >= 0) {
n = strlen(g_priority[priority]);
sprintf(msg + g_maxPriorityLength - n,
"%s:", g_priority[priority]);
msg[g_maxPriorityLength + 1] = ' ';
}
// put a newline at the end
#if defined(CONFIG_PLATFORM_WIN32)
strcat(msg + g_priorityPad, "\r\n");
#else
strcat(msg + g_priorityPad, "\n");
#endif
// print it
CHoldLock lock(s_lock);
if (s_outputter) {
s_outputter(priority, msg + g_maxPriorityLength - n);
}
else {
#if defined(CONFIG_PLATFORM_WIN32)
openConsole();
#endif
fprintf(stderr, "%s", msg + g_maxPriorityLength - n);
}
}
}
char* CLog::vsprint(int pad, char* buffer, int len,
const char* fmt, va_list args)
{
assert(len > 0);
// try writing to input buffer
int n;
if (len >= pad) {
n = vsnprintf(buffer + pad, len - pad, fmt, args);
if (n != -1 && n <= len - pad + g_newlineLength)
return buffer;
}
// start allocating buffers until we write the whole string
buffer = 0;
do {
delete[] buffer;
len *= 2;
buffer = new char[len + pad];
n = vsnprintf(buffer + pad, len - pad, fmt, args);
} while (n == -1 || n > len - pad + g_newlineLength);
return buffer;
}
#if defined(CONFIG_PLATFORM_WIN32)
static DWORD s_thread = 0;
static BOOL WINAPI CLogSignalHandler(DWORD)
{
// terminate cleanly and skip remaining handlers
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
return TRUE;
}
void CLog::openConsole()
{
static bool s_hasConsole = false;
// ignore if already created
if (s_hasConsole)
return;
// remember the current thread. when we get a ctrl+break or the
// console is closed we'll post WM_QUIT to this thread to shutdown
// cleanly.
// note -- win95/98/me are broken and will not receive a signal
// when the console is closed nor during logoff or shutdown,
// see microsoft articles Q130717 and Q134284. we could work
// around this in a painful way using hooks and hidden windows
// (as apache does) but it's not worth it. the app will still
// quit, just not cleanly. users in-the-know can use ctrl+c.
s_thread = GetCurrentThreadId();
// open a console
if (!AllocConsole())
return;
// get the handle for error output
HANDLE herr = GetStdHandle(STD_ERROR_HANDLE);
// prep console. windows 95 and its ilk have braindead
// consoles that can't even resize independently of the
// buffer size. use a 25 line buffer for those systems.
OSVERSIONINFO osInfo;
COORD size = { 80, 1000 };
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
if (GetVersionEx(&osInfo) &&
osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
size.Y = 25;
SetConsoleScreenBufferSize(herr, size);
SetConsoleTextAttribute(herr,
FOREGROUND_RED |
FOREGROUND_GREEN |
FOREGROUND_BLUE);
SetConsoleCtrlHandler(CLogSignalHandler, TRUE);
// reopen stderr to point at console
freopen("con", "w", stderr);
s_hasConsole = true;
}
#endif