mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-15 14:16:07 -06:00
999 lines
19 KiB
C++
999 lines
19 KiB
C++
#include "Core.h"
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
# include <winnls.h>
|
|
#endif
|
|
|
|
#ifdef flagSTACKTRACE // On Panic (e.g. failed ASSERT) try to print stack back-trace
|
|
#if defined(PLATFORM_POSIX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID)
|
|
# include <execinfo.h>
|
|
# include <cxxabi.h>
|
|
#endif
|
|
#endif
|
|
|
|
namespace Upp {
|
|
|
|
bool PanicMode;
|
|
|
|
bool IsPanicMode() { return PanicMode; }
|
|
|
|
static void (*sPanicMessageBox)(const char *title, const char *text);
|
|
|
|
void InstallPanicMessageBox(void (*mb)(const char *title, const char *text))
|
|
{
|
|
sPanicMessageBox = mb;
|
|
}
|
|
|
|
void PanicMessageBox(const char *title, const char *text)
|
|
{
|
|
PanicMode = true;
|
|
if(sPanicMessageBox)
|
|
(*sPanicMessageBox)(title, text);
|
|
else {
|
|
IGNORE_RESULT(
|
|
write(2, text, (int)strlen(text))
|
|
);
|
|
IGNORE_RESULT(
|
|
write(2, "\n", 1)
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID) && defined(flagSTACKTRACE)
|
|
void AddStackTrace(char * str, int len)
|
|
{
|
|
const size_t max_depth = 100;
|
|
void *stack_addrs[max_depth];
|
|
char **stack_strings;
|
|
const char msg[] = "\nStack trace:\n";
|
|
|
|
size_t stack_depth = backtrace(stack_addrs, max_depth);
|
|
stack_strings = backtrace_symbols(stack_addrs, stack_depth);
|
|
|
|
int space = len - strlen(str);
|
|
strncat(str, msg, max(space, 0));
|
|
space -= sizeof(msg) - 1;
|
|
|
|
for (size_t i = 0; i < stack_depth && space > 0; i++) {
|
|
|
|
char * start = strchr(stack_strings[i], '(');
|
|
if (start == NULL) continue;
|
|
|
|
size_t len;
|
|
int stat;
|
|
|
|
char * end = strchr(start, '+');
|
|
if (end != NULL) *end = '\0';
|
|
|
|
char * demangled = abi::__cxa_demangle(start+1, NULL, &len, &stat);
|
|
|
|
if (stat == 0 && demangled != NULL){
|
|
strncat(str, demangled, max(space, 0));
|
|
space -= len;
|
|
}else{
|
|
strncat(str, start, max(space, 0));
|
|
space -= strlen(start);
|
|
}
|
|
if (demangled != NULL) free(demangled);
|
|
|
|
strncat(str, "\n", max(space, 0));
|
|
space -= 1;
|
|
}
|
|
|
|
free(stack_strings);
|
|
}
|
|
#endif
|
|
|
|
|
|
void Panic(const char *msg)
|
|
{
|
|
#ifdef PLATFORM_POSIX
|
|
signal(SIGILL, SIG_DFL);
|
|
signal(SIGSEGV, SIG_DFL);
|
|
signal(SIGBUS, SIG_DFL);
|
|
signal(SIGFPE, SIG_DFL);
|
|
#endif
|
|
if(PanicMode)
|
|
return;
|
|
PanicMode = true;
|
|
RLOG("****************** PANIC: " << msg << "\n");
|
|
PanicMessageBox("Fatal error", msg);
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
# ifdef __NOASSEMBLY__
|
|
# if defined(PLATFORM_WINCE) || defined(WIN64)
|
|
DebugBreak();
|
|
# endif
|
|
# else
|
|
# if defined(_DEBUG) && defined(CPU_X86)
|
|
# ifdef COMPILER_MSC
|
|
_asm int 3
|
|
# endif
|
|
# ifdef COMPILER_GCC
|
|
asm("int $3");
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#else
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
raise(SIGTRAP);
|
|
#endif
|
|
#ifdef _DEBUG
|
|
__BREAK__;
|
|
#endif
|
|
abort();
|
|
}
|
|
|
|
static void (*s_assert_hook)(const char *);
|
|
|
|
void SetAssertFailedHook(void (*h)(const char *))
|
|
{
|
|
s_assert_hook = h;
|
|
}
|
|
|
|
void AssertFailed(const char *file, int line, const char *cond)
|
|
{
|
|
if(PanicMode)
|
|
return;
|
|
PanicMode = true;
|
|
char s[2048];
|
|
snprintf(s, 2048, "Assertion failed in %s, line %d\n%s\n", file, line, cond);
|
|
#if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && defined(flagSTACKTRACE)
|
|
AddStackTrace(s, sizeof(s));
|
|
#endif
|
|
|
|
if(s_assert_hook)
|
|
(*s_assert_hook)(s);
|
|
RLOG("****************** ASSERT FAILED: " << s << "\n");
|
|
#ifdef PLATFORM_POSIX
|
|
RLOG("LastErrorMessage: " << strerror(errno)); // do not translate
|
|
#else
|
|
RLOG("LastErrorMessage: " << GetLastErrorMessage());
|
|
#endif
|
|
|
|
PanicMessageBox("Fatal error", s);
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
# ifdef __NOASSEMBLY__
|
|
# if defined(PLATFORM_WINCE) || defined(WIN64)
|
|
DebugBreak();
|
|
# endif
|
|
# else
|
|
# if defined(_DEBUG) && defined(CPU_X86)
|
|
# ifdef COMPILER_MSC
|
|
_asm int 3
|
|
# endif
|
|
# ifdef COMPILER_GCC
|
|
asm("int $3");
|
|
# endif
|
|
# endif
|
|
# endif
|
|
#else
|
|
#endif
|
|
#ifdef PLATFORM_POSIX
|
|
raise(SIGTRAP);
|
|
#endif
|
|
#ifdef _DEBUG
|
|
__BREAK__;
|
|
#endif
|
|
abort();
|
|
}
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
dword GetTickCount() {
|
|
#if _POSIX_C_SOURCE >= 199309L
|
|
struct timespec tp;
|
|
if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
|
|
{
|
|
return (dword)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000));
|
|
}
|
|
return 0; // ?? (errno is set)
|
|
#else
|
|
struct timeval tv[1];
|
|
struct timezone tz[1];
|
|
memset(tz, 0, sizeof(tz));
|
|
gettimeofday(tv, tz);
|
|
return (dword)tv->tv_sec * 1000 + tv->tv_usec / 1000;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
int64 usecs(int64 prev)
|
|
{
|
|
auto p2 = std::chrono::high_resolution_clock::now();
|
|
return std::chrono::duration_cast<std::chrono::microseconds>(p2.time_since_epoch()).count() - prev;
|
|
}
|
|
|
|
int msecs(int from) { return GetTickCount() - (dword)from; }
|
|
|
|
/* // it looks like there might be a problem with std::chrono in llvm-mingw, reverting to original implementation for now
|
|
int msecs(int prev)
|
|
{
|
|
auto p2 = std::chrono::steady_clock::now();
|
|
return (int)std::chrono::duration_cast<std::chrono::milliseconds>(p2.time_since_epoch()).count() - prev;
|
|
}
|
|
*/
|
|
|
|
void TimeStop::Reset()
|
|
{
|
|
starttime = (double)usecs();
|
|
}
|
|
|
|
TimeStop::TimeStop()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
String TimeStop::ToString() const
|
|
{
|
|
double time = Elapsed();
|
|
if(time < 1e3)
|
|
return String() << time << " us";
|
|
if(time < 1e6)
|
|
return String() << time / 1e3 << " ms";
|
|
return String() << time / 1e6 << " s";
|
|
}
|
|
|
|
int RegisterTypeNo__(const char *type)
|
|
{
|
|
INTERLOCKED {
|
|
static Index<String> types;
|
|
return types.FindAdd(type);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
char *PermanentCopy(const char *s)
|
|
{
|
|
char *t = (char *)MemoryAllocPermanent(strlen(s) + 1);
|
|
strcpy(t, s);
|
|
return t;
|
|
}
|
|
|
|
#ifndef PLATFORM_WIN32
|
|
void Sleep(int msec)
|
|
{
|
|
::timespec tval;
|
|
tval.tv_sec = msec / 1000;
|
|
tval.tv_nsec = (msec % 1000) * 1000000;
|
|
nanosleep(&tval, NULL);
|
|
}
|
|
#endif
|
|
|
|
int MemICmp(const void *dest, const void *src, int count)
|
|
{
|
|
|
|
const byte *a = (const byte *)dest;
|
|
const byte *b = (const byte *)src;
|
|
const byte *l = a + count;
|
|
while(a < l) {
|
|
if(ToUpper(*a) != ToUpper(*b))
|
|
return ToUpper(*a) - ToUpper(*b);
|
|
a++;
|
|
b++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Stream& Pack16(Stream& s, Point& p) {
|
|
return Pack16(s, p.x, p.y);
|
|
}
|
|
|
|
Stream& Pack16(Stream& s, Size& sz) {
|
|
return Pack16(s, sz.cx, sz.cy);
|
|
}
|
|
|
|
Stream& Pack16(Stream& s, Rect& r) {
|
|
return Pack16(s, r.left, r.top, r.right, r.bottom);
|
|
}
|
|
|
|
int InScListIndex(const char *s, const char *list)
|
|
{
|
|
int ii = 0;
|
|
for(;;) {
|
|
const char *q = s;
|
|
for(;;) {
|
|
if(*q == '\0' && *list == '\0') return ii;
|
|
if(*q != *list) {
|
|
if(*q == '\0' && *list == ';') return ii;
|
|
if(*list == '\0') return -1;
|
|
break;
|
|
}
|
|
q++;
|
|
list++;
|
|
}
|
|
while(*list && *list != ';') list++;
|
|
if(*list == '\0') return -1;
|
|
list++;
|
|
ii++;
|
|
}
|
|
}
|
|
|
|
bool InScList(const char *s, const char *list)
|
|
{
|
|
return InScListIndex(s, list) >= 0;
|
|
}
|
|
|
|
String timeFormat(double s) {
|
|
if(s < 0.000001) return Sprintf("%5.2f ns", s * 1.0e9);
|
|
if(s < 0.001) return Sprintf("%5.2f us", s * 1.0e6);
|
|
if(s < 1) return Sprintf("%5.2f ms", s * 1.0e3);
|
|
return Sprintf("%5.2f s ", s);
|
|
}
|
|
|
|
String Garble(const char *s, const char *e)
|
|
{
|
|
int c = 0xAA;
|
|
String result;
|
|
if(!e)
|
|
e = s + strlen(s);
|
|
while(s != e)
|
|
{
|
|
result.Cat(*s++ ^ (char)c);
|
|
if((c <<= 1) & 0x100)
|
|
c ^= 0x137;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
String Garble(const String& s)
|
|
{
|
|
return Garble(~s, ~s + s.GetLength());
|
|
}
|
|
|
|
String Encode64(const String& s)
|
|
{
|
|
String enc;
|
|
int l = s.GetLength();
|
|
enc << l << ':';
|
|
for(int i = 0; i < l;)
|
|
{
|
|
char a = 0, b = 0, c = 0;
|
|
if(i < l) a = s[i++];
|
|
if(i < l) b = s[i++];
|
|
if(i < l) c = s[i++];
|
|
enc.Cat(' ' + 1 + ((a >> 2) & 0x3F));
|
|
enc.Cat(' ' + 1 + ((a << 4) & 0x30) + ((b >> 4) & 0x0F));
|
|
enc.Cat(' ' + 1 + ((b << 2) & 0x3C) + ((c >> 6) & 0x03));
|
|
enc.Cat(' ' + 1 + (c & 0x3F));
|
|
}
|
|
return enc;
|
|
}
|
|
|
|
String Decode64(const String& s)
|
|
{
|
|
if(!IsDigit(*s))
|
|
return s;
|
|
const char *p = s;
|
|
char *h;
|
|
int len = strtol(p, &h, 10);
|
|
p = h;
|
|
if(*p++ != ':' || len < 0 || (len + 2) / 3 * 4 > (s.End() - p))
|
|
return s; // invalid encoding
|
|
if(len == 0)
|
|
return Null;
|
|
String dec;
|
|
for(;;)
|
|
{
|
|
byte ea = *p++ - ' ' - 1, eb = *p++ - ' ' - 1, ec = *p++ - ' ' - 1, ed = *p++ - ' ' - 1;
|
|
byte out[3] = { byte((ea << 2) | (eb >> 4)), byte((eb << 4) | (ec >> 2)), byte((ec << 6) | (ed >> 0)) };
|
|
switch(len)
|
|
{
|
|
case 1: dec.Cat(out[0]); return dec;
|
|
case 2: dec.Cat(out, 2); return dec;
|
|
case 3: dec.Cat(out, 3); return dec;
|
|
default: dec.Cat(out, 3); len -= 3; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
String HexString(const byte *s, int count, int sep, int sepchr)
|
|
{
|
|
ASSERT(count >= 0);
|
|
if(count == 0)
|
|
return String();
|
|
StringBuffer b(2 * count + (count - 1) / sep);
|
|
static const char itoc[] = "0123456789abcdef";
|
|
int i = 0;
|
|
char *t = b;
|
|
for(;;) {
|
|
for(int q = 0; q < sep; q++) {
|
|
if(i >= count)
|
|
return String(b);
|
|
*t++ = itoc[(s[i] & 0xf0) >> 4];
|
|
*t++ = itoc[s[i] & 0x0f];
|
|
i++;
|
|
}
|
|
if(i >= count)
|
|
return String(b);
|
|
*t++ = sepchr;
|
|
}
|
|
}
|
|
|
|
String HexString(const String& s, int sep, int sepchr)
|
|
{
|
|
return HexString(~s, s.GetCount(), sep, sepchr);
|
|
}
|
|
|
|
String HexEncode(const byte *s, int count, int sep, int sepchr)
|
|
{
|
|
return HexString(s, count, sep, sepchr);
|
|
}
|
|
|
|
String HexEncode(const String& s, int sep, int sepchr)
|
|
{
|
|
return HexString(s, sep, sepchr);
|
|
}
|
|
|
|
String ScanHexString(const char *s, const char *lim)
|
|
{
|
|
String r;
|
|
r.Reserve(int(lim - s) / 2);
|
|
for(;;) {
|
|
byte b = 0;
|
|
while(!IsXDigit(*s)) {
|
|
if(s >= lim)
|
|
return r;
|
|
s++;
|
|
}
|
|
b = ctoi(*s++);
|
|
if(s >= lim)
|
|
return r;
|
|
while(!IsXDigit(*s)) {
|
|
if(s >= lim) {
|
|
r.Cat(b);
|
|
return r;
|
|
}
|
|
s++;
|
|
}
|
|
b = (b << 4) + ctoi(*s++);
|
|
r.Cat(b);
|
|
if(s >= lim)
|
|
return r;
|
|
}
|
|
}
|
|
|
|
String HexDecode(const char *s, const char *lim)
|
|
{
|
|
return ScanHexString(s, lim);
|
|
}
|
|
|
|
|
|
String NormalizeSpaces(const char *s)
|
|
{
|
|
StringBuffer r;
|
|
while(*s && (byte)*s <= ' ')
|
|
s++;
|
|
while(*s) {
|
|
if((byte)*s <= ' ') {
|
|
while(*s && (byte)*s <= ' ')
|
|
s++;
|
|
if(*s)
|
|
r.Cat(' ');
|
|
}
|
|
else
|
|
r.Cat(*s++);
|
|
}
|
|
return String(r);
|
|
}
|
|
|
|
String NormalizeSpaces(const char *s, const char *end)
|
|
{
|
|
StringBuffer r;
|
|
while(*s && (byte)*s <= ' ')
|
|
s++;
|
|
while(s < end) {
|
|
if((byte)*s <= ' ') {
|
|
while(s < end && (byte)*s <= ' ')
|
|
s++;
|
|
if(*s)
|
|
r.Cat(' ');
|
|
}
|
|
else
|
|
r.Cat(*s++);
|
|
}
|
|
return String(r);
|
|
}
|
|
|
|
String CsvString(const String& text)
|
|
{
|
|
String r;
|
|
r << '\"';
|
|
const char *s = text;
|
|
while(*s) {
|
|
if(*s == '\"')
|
|
r << "\"\"";
|
|
else
|
|
r.Cat(*s);
|
|
s++;
|
|
}
|
|
r << '\"';
|
|
return r;
|
|
}
|
|
|
|
Vector<String> GetCsvLine(Stream& s, int separator, byte charset)
|
|
{
|
|
Vector<String> r;
|
|
bool instring = false;
|
|
String val;
|
|
byte dcs = GetDefaultCharset();
|
|
for(;;) {
|
|
int c = s.Get();
|
|
if(c == '\n' && instring)
|
|
val.Cat(c);
|
|
else
|
|
if(c == '\n' || c < 0) {
|
|
if(val.GetCount())
|
|
r.Add(ToCharset(dcs, val, charset));
|
|
return r;
|
|
}
|
|
else
|
|
if(c == separator && !instring) {
|
|
r.Add(ToCharset(dcs, val, charset));
|
|
val.Clear();
|
|
}
|
|
else
|
|
if(c == '\"') {
|
|
if(instring && s.Term() == '\"') {
|
|
s.Get();
|
|
val.Cat('\"');
|
|
}
|
|
else
|
|
instring = !instring;
|
|
}
|
|
else
|
|
if(c != '\r')
|
|
val.Cat(c);
|
|
}
|
|
}
|
|
|
|
String CompressLog(const char *s)
|
|
{
|
|
static bool breaker[256];
|
|
ONCELOCK {
|
|
for(int i = 0; i < 256; i++)
|
|
breaker[i] = IsSpace(i) || findarg(i, '<', '>', '\"', '\'', ',', '.', '[', ']', '{', '}', '(', ')') >= 0;
|
|
}
|
|
|
|
StringBuffer result;
|
|
while(*s) {
|
|
const char *b = s;
|
|
while(breaker[(byte)*s])
|
|
s++;
|
|
result.Cat(b, s);
|
|
if(!*s)
|
|
break;
|
|
b = s;
|
|
while(*s && !breaker[(byte)*s])
|
|
s++;
|
|
if(s - b > 200) {
|
|
result.Cat(b, 20);
|
|
result.Cat("....", 4);
|
|
result << "[" << int(s - b) << " bytes]";
|
|
result.Cat("....", 4);
|
|
result.Cat(s - 20, 20);
|
|
}
|
|
else
|
|
result.Cat(b, s);
|
|
}
|
|
return String(result);
|
|
}
|
|
|
|
int ChNoInvalid(int c)
|
|
{
|
|
return c == DEFAULTCHAR ? '_' : c;
|
|
}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
String ToSystemCharset(const String& src, int cp)
|
|
{
|
|
Vector<char16> s = ToUtf16(src);
|
|
int l = s.GetCount() * 8;
|
|
StringBuffer b(l);
|
|
int q = WideCharToMultiByte(cp, 0, s, s.GetCount(), b, l, NULL, NULL);
|
|
if(q <= 0)
|
|
return src;
|
|
b.SetCount(q);
|
|
return String(b);
|
|
}
|
|
|
|
String ToSystemCharset(const String& src)
|
|
{
|
|
return ToSystemCharset(src, CP_ACP);
|
|
}
|
|
|
|
String FromWin32Charset(const String& src, int cp)
|
|
{
|
|
Buffer<char16> b(src.GetLength());
|
|
int q = MultiByteToWideChar(cp, MB_PRECOMPOSED, ~src, src.GetLength(), b, src.GetLength());
|
|
if(q <= 0)
|
|
return src;
|
|
return ToUtf8(b, q);
|
|
}
|
|
|
|
String FromOEMCharset(const String& src)
|
|
{
|
|
return FromWin32Charset(src, CP_OEMCP);
|
|
}
|
|
|
|
String FromSystemCharset(const String& src)
|
|
{
|
|
return FromWin32Charset(src, CP_ACP);
|
|
}
|
|
|
|
#else
|
|
String ToSystemCharset(const String& src)
|
|
{
|
|
return IsMainRunning() ? Filter(ToCharset(GetLNGCharset(GetSystemLNG()), src), ChNoInvalid)
|
|
: src;
|
|
}
|
|
|
|
String FromSystemCharset(const String& src)
|
|
{
|
|
return IsMainRunning() ? Filter(ToCharset(CHARSET_DEFAULT, src, GetLNGCharset(GetSystemLNG())), ChNoInvalid) : src;
|
|
}
|
|
#endif
|
|
|
|
Vector<char16> ToSystemCharsetW(const WString& src)
|
|
{
|
|
Vector<char16> h = ToUtf16(src);
|
|
h.Add(0);
|
|
return h;
|
|
}
|
|
|
|
Vector<char16> ToSystemCharsetW(const String& src)
|
|
{
|
|
Vector<char16> h = ToUtf16(src);
|
|
h.Add(0);
|
|
return h;
|
|
}
|
|
|
|
Vector<char16> ToSystemCharsetW(const wchar *src)
|
|
{
|
|
Vector<char16> h = ToUtf16(src);
|
|
h.Add(0);
|
|
return h;
|
|
}
|
|
|
|
Vector<char16> ToSystemCharsetW(const char *src)
|
|
{
|
|
Vector<char16> h = ToUtf16(src);
|
|
h.Add(0);
|
|
return h;
|
|
}
|
|
|
|
String FromSystemCharsetW(const char16 *src)
|
|
{
|
|
return ToUtf8(src);
|
|
}
|
|
|
|
static StaticMutex sGCfgLock;
|
|
|
|
static VectorMap<String, String>& sGCfg()
|
|
{
|
|
static VectorMap<String, String> h;
|
|
return h;
|
|
}
|
|
|
|
static Vector<Event<>>& sGFlush()
|
|
{
|
|
static Vector<Event<>> h;
|
|
return h;
|
|
}
|
|
|
|
static VectorMap<String, Event<Stream&>>& sGSerialize()
|
|
{
|
|
static VectorMap<String, Event<Stream&>> h;
|
|
return h;
|
|
}
|
|
|
|
void RegisterGlobalConfig(const char *name)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
ASSERT(sGCfg().Find(name) < 0);
|
|
sGCfg().Add(name);
|
|
}
|
|
|
|
void RegisterGlobalSerialize(const char *name, Event<Stream&> WhenSerialize)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
RegisterGlobalConfig(name);
|
|
sGSerialize().Add(name, WhenSerialize);
|
|
}
|
|
|
|
void RegisterGlobalConfig(const char *name, Event<> WhenFlush)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
RegisterGlobalConfig(name);
|
|
sGFlush().Add(WhenFlush);
|
|
}
|
|
|
|
String GetGlobalConfigData(const char *name)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
return sGCfg().GetAdd(name);
|
|
}
|
|
|
|
void SetGlobalConfigData(const char *name, const String& data)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
sGCfg().GetAdd(name) = data;
|
|
}
|
|
|
|
bool LoadFromGlobal(Event<Stream&> x, const char *name)
|
|
{
|
|
StringStream ss(GetGlobalConfigData(name));
|
|
return ss.IsEof() || Load(x, ss);
|
|
}
|
|
|
|
void StoreToGlobal(Event<Stream&> x, const char *name)
|
|
{
|
|
StringStream ss;
|
|
Store(x, ss);
|
|
SetGlobalConfigData(name, ss);
|
|
}
|
|
|
|
void SerializeGlobalConfigs(Stream& s)
|
|
{
|
|
Mutex::Lock __(sGCfgLock);
|
|
for(int i = 0; i < sGFlush().GetCount(); i++)
|
|
sGFlush()[i]();
|
|
int version = 0;
|
|
s / version;
|
|
int count = sGCfg().GetCount();
|
|
s / count;
|
|
for(int i = 0; i < count; i++) {
|
|
String name;
|
|
if(s.IsStoring())
|
|
name = sGCfg().GetKey(i);
|
|
s % name;
|
|
int q = sGCfg().Find(name);
|
|
if(q >= 0) {
|
|
int w = sGSerialize().Find(name);
|
|
if(w >= 0) {
|
|
String h;
|
|
if(s.IsStoring()) {
|
|
StringStream ss;
|
|
sGSerialize()[w](ss);
|
|
h = ss;
|
|
}
|
|
s % h;
|
|
if(s.IsLoading()) {
|
|
StringStream ss(h);
|
|
sGSerialize()[w](ss);
|
|
}
|
|
}
|
|
else
|
|
s % sGCfg()[q];
|
|
}
|
|
else {
|
|
String dummy;
|
|
s % dummy;
|
|
}
|
|
}
|
|
s.Magic();
|
|
}
|
|
|
|
AbortExc::AbortExc() :
|
|
Exc(t_("Aborted by user.")) {}
|
|
|
|
#ifdef PLATFORM_WIN32
|
|
|
|
String GetErrorMessage(DWORD dwError) {
|
|
char h[2048];
|
|
sprintf(h, "%08x", (int)dwError);
|
|
#ifdef PLATFORM_WINCE //TODO
|
|
return h;
|
|
#else
|
|
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL, dwError, 0, h, 2048, NULL);
|
|
String result = h;
|
|
String modf;
|
|
const char* s = result;
|
|
BYTE c;
|
|
while((c = *s++) != 0)
|
|
if(c <= ' ') {
|
|
if(!modf.IsEmpty() && modf[modf.GetLength() - 1] != ' ')
|
|
modf += ' ';
|
|
}
|
|
else if(c == '%' && *s >= '0' && *s <= '9') {
|
|
s++;
|
|
modf += "<###>";
|
|
}
|
|
else
|
|
modf += (char)c;
|
|
const char* p = modf;
|
|
for(s = p + modf.GetLength(); s > p && s[-1] == ' '; s--);
|
|
return FromSystemCharset(modf.Left((int)(s - p)));
|
|
#endif
|
|
}
|
|
|
|
String GetLastErrorMessage() {
|
|
return GetErrorMessage(GetLastError()) + " (" + AsString(GetLastError()) + ")";
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
|
|
String GetErrorMessage(int errorno)
|
|
{
|
|
// Linux strerror_r declaration might be different than posix
|
|
// hence we are using strerror with mutex... (cxl 2008-07-17)
|
|
static StaticMutex m;
|
|
Mutex::Lock __(m);
|
|
return FromSystemCharset(strerror(errorno));
|
|
}
|
|
|
|
String GetLastErrorMessage() {
|
|
return GetErrorMessage(errno) + " (" + AsString(errno) + ")";
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef PLATFORM_POSIX
|
|
#ifndef PLATFORM_COCOA
|
|
|
|
String CurrentSoundTheme = "freedesktop";
|
|
|
|
static void LinuxBeep(const char *name)
|
|
{
|
|
static String player;
|
|
ONCELOCK {
|
|
const char *players[] = { "play", "ogg123", "gst123", "gst-play-1.0" };
|
|
for(int i = 0; i < __countof(players); i++)
|
|
if(Sys("which " + String(players[i])).GetCount()) {
|
|
player = players[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(player.GetCount()) {
|
|
String fn = "/usr/share/sounds/" + CurrentSoundTheme + "/stereo/dialog-" + name;
|
|
IGNORE_RESULT(system(player + " -q " + fn +
|
|
(FileExists(fn + ".ogg") ? ".ogg" :
|
|
FileExists(fn + ".oga") ? ".oga" :
|
|
FileExists(fn + ".wav") ? ".wav" :
|
|
".*")
|
|
+ " >/dev/null 2>/dev/null&"));
|
|
}
|
|
}
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef PLATFORM_COCOA
|
|
void (*CocoBeepFn)();
|
|
|
|
void DoCocoBeep()
|
|
{
|
|
if(CocoBeepFn)
|
|
(*CocoBeepFn)();
|
|
}
|
|
|
|
#endif
|
|
|
|
void BeepInformation()
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
MessageBeep(MB_ICONINFORMATION);
|
|
#elif defined(PLATFORM_COCOA)
|
|
DoCocoBeep();
|
|
#else
|
|
LinuxBeep("information");
|
|
#endif
|
|
}
|
|
|
|
void BeepExclamation()
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
#elif defined(PLATFORM_COCOA)
|
|
DoCocoBeep();
|
|
#else
|
|
LinuxBeep("warning");
|
|
#endif
|
|
}
|
|
|
|
void BeepError()
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
MessageBeep(MB_ICONERROR);
|
|
#elif defined(PLATFORM_COCOA)
|
|
DoCocoBeep();
|
|
#else
|
|
LinuxBeep("error");
|
|
#endif
|
|
}
|
|
|
|
void BeepQuestion()
|
|
{
|
|
#ifdef PLATFORM_WIN32
|
|
MessageBeep(MB_ICONQUESTION);
|
|
#elif defined(PLATFORM_COCOA)
|
|
DoCocoBeep();
|
|
#else
|
|
LinuxBeep("question");
|
|
#endif
|
|
}
|
|
|
|
#if defined(COMPILER_MSC) && (_MSC_VER < 1300)
|
|
//hack for linking libraries built using VC7 with VC6 standard lib's
|
|
extern "C" long _ftol( double );
|
|
extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); }
|
|
#endif
|
|
|
|
#ifdef PLATFORM_WINCE
|
|
int errno; // missing and zlib needs it
|
|
#endif
|
|
|
|
|
|
template <class CHR, class T>
|
|
T Replace__(const T& s, const Vector<T>& find, const Vector<T>& replace)
|
|
{
|
|
ASSERT(find.GetCount() == replace.GetCount());
|
|
|
|
T r;
|
|
int i = 0;
|
|
while(i < s.GetCount()) {
|
|
int best = -1;
|
|
int bestlen = 0;
|
|
int len = s.GetCount() - i;
|
|
const CHR *q = ~s + i;
|
|
for(int j = 0; j < replace.GetCount(); j++) {
|
|
const T& m = find[j];
|
|
int l = m.GetCount();
|
|
if(l <= len && l > bestlen && memcmp(~m, q, l * sizeof(CHR)) == 0) {
|
|
bestlen = l;
|
|
best = j;
|
|
}
|
|
}
|
|
if(best >= 0) {
|
|
i += bestlen;
|
|
r.Cat(replace[best]);
|
|
}
|
|
else {
|
|
r.Cat(*q);
|
|
i++;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
String Replace(const String& s, const Vector<String>& find, const Vector<String>& replace)
|
|
{
|
|
return Replace__<char>(s, find, replace);
|
|
}
|
|
|
|
String Replace(const String& s, const VectorMap<String, String>& fr)
|
|
{
|
|
return Replace__<char>(s, fr.GetKeys(), fr.GetValues());
|
|
}
|
|
|
|
WString Replace(const WString& s, const Vector<WString>& find, const Vector<WString>& replace)
|
|
{
|
|
return Replace__<wchar>(s, find, replace);
|
|
}
|
|
|
|
WString Replace(const WString& s, const VectorMap<WString, WString>& fr)
|
|
{
|
|
return Replace__<wchar>(s, fr.GetKeys(), fr.GetValues());
|
|
}
|
|
|
|
|
|
String (*GetP7Signature__)(const void *data, int length, const String& cert_pem, const String& pkey_pem);
|
|
|
|
String GetP7Signature(const void *data, int length, const String& cert_pem, const String& pkey_pem)
|
|
{
|
|
ASSERT_(GetP7Signature__, "Missing SSL support (Core/SSL)");
|
|
return (*GetP7Signature__)(data, length, cert_pem, pkey_pem);
|
|
}
|
|
|
|
String GetP7Signature(const String& data, const String& cert_pem, const String& pkey_pem)
|
|
{
|
|
return GetP7Signature(data, data.GetLength(), cert_pem, pkey_pem);
|
|
}
|
|
|
|
}
|