1 #include "Core.h"
2
3 #ifdef PLATFORM_WIN32
4 # include <winnls.h>
5 #endif
6
7 #if defined(PLATFORM_POSIX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID) && defined(flagSTACKTRACE)
8 # include <execinfo.h>
9 # include <cxxabi.h>
10 #endif
11
12 namespace Upp {
13
14 bool PanicMode;
15
IsPanicMode()16 bool IsPanicMode() { return PanicMode; }
17
18 static void (*sPanicMessageBox)(const char *title, const char *text);
19
InstallPanicMessageBox(void (* mb)(const char * title,const char * text))20 void InstallPanicMessageBox(void (*mb)(const char *title, const char *text))
21 {
22 sPanicMessageBox = mb;
23 }
24
PanicMessageBox(const char * title,const char * text)25 void PanicMessageBox(const char *title, const char *text)
26 {
27 PanicMode = true;
28 if(sPanicMessageBox)
29 (*sPanicMessageBox)(title, text);
30 else {
31 IGNORE_RESULT(
32 write(2, text, (int)strlen(text))
33 );
34 IGNORE_RESULT(
35 write(2, "\n", 1)
36 );
37 }
38 }
39
40
41 #if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && !defined(PLATFORM_ANDROID) && defined(flagSTACKTRACE)
AddStackTrace(char * str,int len)42 void AddStackTrace(char * str, int len)
43 {
44 const size_t max_depth = 100;
45 void *stack_addrs[max_depth];
46 char **stack_strings;
47 const char msg[] = "\nStack trace:\n";
48
49 size_t stack_depth = backtrace(stack_addrs, max_depth);
50 stack_strings = backtrace_symbols(stack_addrs, stack_depth);
51
52 int space = len - strlen(str);
53 strncat(str, msg, max(space, 0));
54 space -= sizeof(msg) - 1;
55
56 for (size_t i = 0; i < stack_depth && space > 0; i++) {
57
58 char * start = strchr(stack_strings[i], '(');
59 if (start == NULL) continue;
60
61 size_t len;
62 int stat;
63
64 char * end = strchr(start, '+');
65 if (end != NULL) *end = '\0';
66
67 char * demangled = abi::__cxa_demangle(start+1, NULL, &len, &stat);
68
69 if (stat == 0 && demangled != NULL){
70 strncat(str, demangled, max(space, 0));
71 space -= len;
72 }else{
73 strncat(str, start, max(space, 0));
74 space -= strlen(start);
75 }
76 if (demangled != NULL) free(demangled);
77
78 strncat(str, "\n", max(space, 0));
79 space -= 1;
80 }
81
82 free(stack_strings);
83 }
84 #endif
85
86
Panic(const char * msg)87 void Panic(const char *msg)
88 {
89 #ifdef PLATFORM_POSIX
90 signal(SIGILL, SIG_DFL);
91 signal(SIGSEGV, SIG_DFL);
92 signal(SIGBUS, SIG_DFL);
93 signal(SIGFPE, SIG_DFL);
94 #endif
95 if(PanicMode)
96 return;
97 PanicMode = true;
98 RLOG("****************** PANIC: " << msg << "\n");
99 PanicMessageBox("Fatal error", msg);
100
101 #ifdef PLATFORM_WIN32
102 # ifdef __NOASSEMBLY__
103 # if defined(PLATFORM_WINCE) || defined(WIN64)
104 DebugBreak();
105 # endif
106 # else
107 # if defined(_DEBUG) && defined(CPU_X86)
108 # ifdef COMPILER_MSC
109 _asm int 3
110 # endif
111 # ifdef COMPILER_GCC
112 asm("int $3");
113 # endif
114 # endif
115 # endif
116 #else
117 #endif
118 #ifdef _DEBUG
119 __BREAK__;
120 #endif
121 abort();
122 }
123
124 static void (*s_assert_hook)(const char *);
125
SetAssertFailedHook(void (* h)(const char *))126 void SetAssertFailedHook(void (*h)(const char *))
127 {
128 s_assert_hook = h;
129 }
130
AssertFailed(const char * file,int line,const char * cond)131 void AssertFailed(const char *file, int line, const char *cond)
132 {
133 if(PanicMode)
134 return;
135 PanicMode = true;
136 char s[2048];
137 sprintf(s, "Assertion failed in %s, line %d\n%s\n", file, line, cond);
138 #if defined(PLATFORM_LINUX) && defined(COMPILER_GCC) && defined(flagSTACKTRACE)
139 AddStackTrace(s, sizeof(s));
140 #endif
141
142 if(s_assert_hook)
143 (*s_assert_hook)(s);
144 RLOG("****************** ASSERT FAILED: " << s << "\n");
145 #ifdef PLATFORM_POSIX
146 RLOG("LastErrorMessage: " << strerror(errno)); // do not translate
147 #else
148 RLOG("LastErrorMessage: " << GetLastErrorMessage());
149 #endif
150
151 PanicMessageBox("Fatal error", s);
152
153 #ifdef PLATFORM_WIN32
154 # ifdef __NOASSEMBLY__
155 # if defined(PLATFORM_WINCE) || defined(WIN64)
156 DebugBreak();
157 # endif
158 # else
159 # if defined(_DEBUG) && defined(CPU_X86)
160 # ifdef COMPILER_MSC
161 _asm int 3
162 # endif
163 # ifdef COMPILER_GCC
164 asm("int $3");
165 # endif
166 # endif
167 # endif
168 #else
169 #endif
170
171 __BREAK__;
172 abort();
173 }
174
175 #ifdef PLATFORM_POSIX
GetTickCount()176 dword GetTickCount() {
177 #if _POSIX_C_SOURCE >= 199309L
178 struct timespec tp;
179 if (clock_gettime(CLOCK_MONOTONIC, &tp) == 0)
180 {
181 return (dword)((tp.tv_sec * 1000) + (tp.tv_nsec / 1000000));
182 }
183 return 0; // ?? (errno is set)
184 #else
185 struct timeval tv[1];
186 struct timezone tz[1];
187 memset(tz, 0, sizeof(tz));
188 gettimeofday(tv, tz);
189 return (dword)tv->tv_sec * 1000 + tv->tv_usec / 1000;
190 #endif
191 }
192 #endif
193
usecs(int64 prev)194 int64 usecs(int64 prev)
195 {
196 auto p2 = std::chrono::high_resolution_clock::now();
197 return std::chrono::duration_cast<std::chrono::microseconds>(p2.time_since_epoch()).count() - prev;
198 }
199
msecs(int from)200 int msecs(int from) { return GetTickCount() - (dword)from; }
201
202 /* // it looks like there might be a problem with std::chrono in llvm-mingw, reverting to original implementation for now
203 int msecs(int prev)
204 {
205 auto p2 = std::chrono::steady_clock::now();
206 return (int)std::chrono::duration_cast<std::chrono::milliseconds>(p2.time_since_epoch()).count() - prev;
207 }
208 */
209
Reset()210 void TimeStop::Reset()
211 {
212 starttime = (double)usecs();
213 }
214
TimeStop()215 TimeStop::TimeStop()
216 {
217 Reset();
218 }
219
ToString() const220 String TimeStop::ToString() const
221 {
222 double time = Elapsed();
223 if(time < 1e3)
224 return String() << time << " us";
225 if(time < 1e6)
226 return String() << time / 1e3 << " ms";
227 return String() << time / 1e6 << " s";
228 }
229
RegisterTypeNo__(const char * type)230 int RegisterTypeNo__(const char *type)
231 {
232 INTERLOCKED {
233 static Index<String> types;
234 return types.FindAdd(type);
235 }
236 return -1;
237 }
238
PermanentCopy(const char * s)239 char *PermanentCopy(const char *s)
240 {
241 char *t = (char *)MemoryAllocPermanent(strlen(s) + 1);
242 strcpy(t, s);
243 return t;
244 }
245
246 #ifndef PLATFORM_WIN32
Sleep(int msec)247 void Sleep(int msec)
248 {
249 ::timespec tval;
250 tval.tv_sec = msec / 1000;
251 tval.tv_nsec = (msec % 1000) * 1000000;
252 nanosleep(&tval, NULL);
253 }
254 #endif
255
MemICmp(const void * dest,const void * src,int count)256 int MemICmp(const void *dest, const void *src, int count)
257 {
258
259 const byte *a = (const byte *)dest;
260 const byte *b = (const byte *)src;
261 const byte *l = a + count;
262 while(a < l) {
263 if(ToUpper(*a) != ToUpper(*b))
264 return ToUpper(*a) - ToUpper(*b);
265 a++;
266 b++;
267 }
268 return 0;
269 }
270
Pack16(Stream & s,Point & p)271 Stream& Pack16(Stream& s, Point& p) {
272 return Pack16(s, p.x, p.y);
273 }
274
Pack16(Stream & s,Size & sz)275 Stream& Pack16(Stream& s, Size& sz) {
276 return Pack16(s, sz.cx, sz.cy);
277 }
278
Pack16(Stream & s,Rect & r)279 Stream& Pack16(Stream& s, Rect& r) {
280 return Pack16(s, r.left, r.top, r.right, r.bottom);
281 }
282
InScListIndex(const char * s,const char * list)283 int InScListIndex(const char *s, const char *list)
284 {
285 int ii = 0;
286 for(;;) {
287 const char *q = s;
288 for(;;) {
289 if(*q == '\0' && *list == '\0') return ii;
290 if(*q != *list) {
291 if(*q == '\0' && *list == ';') return ii;
292 if(*list == '\0') return -1;
293 break;
294 }
295 q++;
296 list++;
297 }
298 while(*list && *list != ';') list++;
299 if(*list == '\0') return -1;
300 list++;
301 ii++;
302 }
303 }
304
InScList(const char * s,const char * list)305 bool InScList(const char *s, const char *list)
306 {
307 return InScListIndex(s, list) >= 0;
308 }
309
timeFormat(double s)310 String timeFormat(double s) {
311 if(s < 0.000001) return Sprintf("%5.2f ns", s * 1.0e9);
312 if(s < 0.001) return Sprintf("%5.2f us", s * 1.0e6);
313 if(s < 1) return Sprintf("%5.2f ms", s * 1.0e3);
314 return Sprintf("%5.2f s ", s);
315 }
316
Garble(const char * s,const char * e)317 String Garble(const char *s, const char *e)
318 {
319 int c = 0xAA;
320 String result;
321 if(!e)
322 e = s + strlen(s);
323 while(s != e)
324 {
325 result.Cat(*s++ ^ (char)c);
326 if((c <<= 1) & 0x100)
327 c ^= 0x137;
328 }
329 return result;
330 }
331
Garble(const String & s)332 String Garble(const String& s)
333 {
334 return Garble(~s, ~s + s.GetLength());
335 }
336
Encode64(const String & s)337 String Encode64(const String& s)
338 {
339 String enc;
340 int l = s.GetLength();
341 enc << l << ':';
342 for(int i = 0; i < l;)
343 {
344 char a = 0, b = 0, c = 0;
345 if(i < l) a = s[i++];
346 if(i < l) b = s[i++];
347 if(i < l) c = s[i++];
348 enc.Cat(' ' + 1 + ((a >> 2) & 0x3F));
349 enc.Cat(' ' + 1 + ((a << 4) & 0x30) + ((b >> 4) & 0x0F));
350 enc.Cat(' ' + 1 + ((b << 2) & 0x3C) + ((c >> 6) & 0x03));
351 enc.Cat(' ' + 1 + (c & 0x3F));
352 }
353 return enc;
354 }
355
Decode64(const String & s)356 String Decode64(const String& s)
357 {
358 if(!IsDigit(*s))
359 return s;
360 const char *p = s;
361 char *h;
362 int len = strtol(p, &h, 10);
363 p = h;
364 if(*p++ != ':' || len < 0 || (len + 2) / 3 * 4 > (s.End() - p))
365 return s; // invalid encoding
366 if(len == 0)
367 return Null;
368 String dec;
369 for(;;)
370 {
371 byte ea = *p++ - ' ' - 1, eb = *p++ - ' ' - 1, ec = *p++ - ' ' - 1, ed = *p++ - ' ' - 1;
372 byte out[3] = { byte((ea << 2) | (eb >> 4)), byte((eb << 4) | (ec >> 2)), byte((ec << 6) | (ed >> 0)) };
373 switch(len)
374 {
375 case 1: dec.Cat(out[0]); return dec;
376 case 2: dec.Cat(out, 2); return dec;
377 case 3: dec.Cat(out, 3); return dec;
378 default: dec.Cat(out, 3); len -= 3; break;
379 }
380 }
381 }
382
HexString(const byte * s,int count,int sep,int sepchr)383 String HexString(const byte *s, int count, int sep, int sepchr)
384 {
385 ASSERT(count >= 0);
386 if(count == 0)
387 return String();
388 StringBuffer b(2 * count + (count - 1) / sep);
389 static const char itoc[] = "0123456789abcdef";
390 int i = 0;
391 char *t = b;
392 for(;;) {
393 for(int q = 0; q < sep; q++) {
394 if(i >= count)
395 return String(b);
396 *t++ = itoc[(s[i] & 0xf0) >> 4];
397 *t++ = itoc[s[i] & 0x0f];
398 i++;
399 }
400 if(i >= count)
401 return String(b);
402 *t++ = sepchr;
403 }
404 }
405
HexString(const String & s,int sep,int sepchr)406 String HexString(const String& s, int sep, int sepchr)
407 {
408 return HexString(~s, s.GetCount(), sep, sepchr);
409 }
410
HexEncode(const byte * s,int count,int sep,int sepchr)411 String HexEncode(const byte *s, int count, int sep, int sepchr)
412 {
413 return HexString(s, count, sep, sepchr);
414 }
415
HexEncode(const String & s,int sep,int sepchr)416 String HexEncode(const String& s, int sep, int sepchr)
417 {
418 return HexString(s, sep, sepchr);
419 }
420
ScanHexString(const char * s,const char * lim)421 String ScanHexString(const char *s, const char *lim)
422 {
423 String r;
424 r.Reserve(int(lim - s) / 2);
425 for(;;) {
426 byte b = 0;
427 while(!IsXDigit(*s)) {
428 if(s >= lim)
429 return r;
430 s++;
431 }
432 b = ctoi(*s++);
433 if(s >= lim)
434 return r;
435 while(!IsXDigit(*s)) {
436 if(s >= lim) {
437 r.Cat(b);
438 return r;
439 }
440 s++;
441 }
442 b = (b << 4) + ctoi(*s++);
443 r.Cat(b);
444 if(s >= lim)
445 return r;
446 }
447 }
448
HexDecode(const char * s,const char * lim)449 String HexDecode(const char *s, const char *lim)
450 {
451 return ScanHexString(s, lim);
452 }
453
454
NormalizeSpaces(const char * s)455 String NormalizeSpaces(const char *s)
456 {
457 StringBuffer r;
458 while(*s && (byte)*s <= ' ')
459 s++;
460 while(*s) {
461 if((byte)*s <= ' ') {
462 while(*s && (byte)*s <= ' ')
463 s++;
464 if(*s)
465 r.Cat(' ');
466 }
467 else
468 r.Cat(*s++);
469 }
470 return String(r);
471 }
472
NormalizeSpaces(const char * s,const char * end)473 String NormalizeSpaces(const char *s, const char *end)
474 {
475 StringBuffer r;
476 while(*s && (byte)*s <= ' ')
477 s++;
478 while(s < end) {
479 if((byte)*s <= ' ') {
480 while(s < end && (byte)*s <= ' ')
481 s++;
482 if(*s)
483 r.Cat(' ');
484 }
485 else
486 r.Cat(*s++);
487 }
488 return String(r);
489 }
490
CsvString(const String & text)491 String CsvString(const String& text)
492 {
493 String r;
494 r << '\"';
495 const char *s = text;
496 while(*s) {
497 if(*s == '\"')
498 r << "\"\"";
499 else
500 r.Cat(*s);
501 s++;
502 }
503 r << '\"';
504 return r;
505 }
506
GetCsvLine(Stream & s,int separator,byte charset)507 Vector<String> GetCsvLine(Stream& s, int separator, byte charset)
508 {
509 Vector<String> r;
510 bool instring = false;
511 String val;
512 byte dcs = GetDefaultCharset();
513 for(;;) {
514 int c = s.Get();
515 if(c == '\n' && instring)
516 val.Cat(c);
517 else
518 if(c == '\n' || c < 0) {
519 if(val.GetCount())
520 r.Add(ToCharset(dcs, val, charset));
521 return r;
522 }
523 else
524 if(c == separator && !instring) {
525 r.Add(ToCharset(dcs, val, charset));
526 val.Clear();
527 }
528 else
529 if(c == '\"') {
530 if(instring && s.Term() == '\"') {
531 s.Get();
532 val.Cat('\"');
533 }
534 else
535 instring = !instring;
536 }
537 else
538 if(c != '\r')
539 val.Cat(c);
540 }
541 }
542
CompressLog(const char * s)543 String CompressLog(const char *s)
544 {
545 static bool breaker[256];
546 ONCELOCK {
547 for(int i = 0; i < 256; i++)
548 breaker[i] = IsSpace(i) || findarg(i, '<', '>', '\"', '\'', ',', '.', '[', ']', '{', '}', '(', ')') >= 0;
549 }
550
551 StringBuffer result;
552 while(*s) {
553 const char *b = s;
554 while(breaker[(byte)*s])
555 s++;
556 result.Cat(b, s);
557 if(!*s)
558 break;
559 b = s;
560 while(*s && !breaker[(byte)*s])
561 s++;
562 if(s - b > 200) {
563 result.Cat(b, 20);
564 result.Cat("....", 4);
565 result << "[" << int(s - b) << " bytes]";
566 result.Cat("....", 4);
567 result.Cat(s - 20, 20);
568 }
569 else
570 result.Cat(b, s);
571 }
572 return String(result);
573 }
574
ChNoInvalid(int c)575 int ChNoInvalid(int c)
576 {
577 return c == DEFAULTCHAR ? '_' : c;
578 }
579
580 #ifdef PLATFORM_WINCE
ToSystemCharset(const String & src)581 WString ToSystemCharset(const String& src)
582 {
583 return src.ToWString();
584 }
585
FromSystemCharset(const WString & src)586 String FromSystemCharset(const WString& src)
587 {
588 return src.ToString();
589 }
590 #else
591
592 #ifdef PLATFORM_WIN32
ToSystemCharset(const String & src,int cp)593 String ToSystemCharset(const String& src, int cp)
594 {
595 WString s = src.ToWString();
596 int l = s.GetLength() * 5;
597 StringBuffer b(l);
598 int q = WideCharToMultiByte(cp, 0, (const WCHAR *)~s, s.GetLength(), b, l, NULL, NULL);
599 if(q <= 0)
600 return src;
601 b.SetCount(q);
602 return String(b);
603 }
604
ToSystemCharset(const String & src)605 String ToSystemCharset(const String& src)
606 {
607 return ToSystemCharset(src, CP_ACP);
608 }
609
FromWin32Charset(const String & src,int cp)610 String FromWin32Charset(const String& src, int cp)
611 {
612 WStringBuffer b(src.GetLength());
613 int q = MultiByteToWideChar(cp, MB_PRECOMPOSED, ~src, src.GetLength(), (WCHAR*)~b, src.GetLength());
614 if(q <= 0)
615 return src;
616 b.SetCount(q);
617 return WString(b).ToString();
618 }
619
FromOEMCharset(const String & src)620 String FromOEMCharset(const String& src)
621 {
622 return FromWin32Charset(src, CP_OEMCP);
623 }
624
FromSystemCharset(const String & src)625 String FromSystemCharset(const String& src)
626 {
627 return FromWin32Charset(src, CP_ACP);
628 }
629
ToSystemCharsetW(const char * src)630 WString ToSystemCharsetW(const char *src)
631 {
632 return String(src).ToWString();
633 }
634
FromSystemCharsetW(const wchar * src)635 String FromSystemCharsetW(const wchar *src)
636 {
637 return WString(src).ToString();
638 }
639
640 #else
ToSystemCharset(const String & src)641 String ToSystemCharset(const String& src)
642 {
643 return IsMainRunning() ? Filter(ToCharset(GetLNGCharset(GetSystemLNG()), src), ChNoInvalid)
644 : src;
645 }
646
FromSystemCharset(const String & src)647 String FromSystemCharset(const String& src)
648 {
649 return IsMainRunning() ? Filter(ToCharset(CHARSET_DEFAULT, src, GetLNGCharset(GetSystemLNG())), ChNoInvalid) : src;
650 }
651 #endif
652 #endif
653
654
655 static StaticMutex sGCfgLock;
656
sGCfg()657 static VectorMap<String, String>& sGCfg()
658 {
659 static VectorMap<String, String> h;
660 return h;
661 }
662
sGFlush()663 static Vector<Event<>>& sGFlush()
664 {
665 static Vector<Event<>> h;
666 return h;
667 }
668
sGSerialize()669 static VectorMap<String, Event<Stream&>>& sGSerialize()
670 {
671 static VectorMap<String, Event<Stream&>> h;
672 return h;
673 }
674
RegisterGlobalConfig(const char * name)675 void RegisterGlobalConfig(const char *name)
676 {
677 Mutex::Lock __(sGCfgLock);
678 ASSERT(sGCfg().Find(name) < 0);
679 sGCfg().Add(name);
680 }
681
RegisterGlobalSerialize(const char * name,Event<Stream &> WhenSerialize)682 void RegisterGlobalSerialize(const char *name, Event<Stream&> WhenSerialize)
683 {
684 Mutex::Lock __(sGCfgLock);
685 RegisterGlobalConfig(name);
686 sGSerialize().Add(name, WhenSerialize);
687 }
688
RegisterGlobalConfig(const char * name,Event<> WhenFlush)689 void RegisterGlobalConfig(const char *name, Event<> WhenFlush)
690 {
691 Mutex::Lock __(sGCfgLock);
692 RegisterGlobalConfig(name);
693 sGFlush().Add(WhenFlush);
694 }
695
GetGlobalConfigData(const char * name)696 String GetGlobalConfigData(const char *name)
697 {
698 Mutex::Lock __(sGCfgLock);
699 return sGCfg().GetAdd(name);
700 }
701
SetGlobalConfigData(const char * name,const String & data)702 void SetGlobalConfigData(const char *name, const String& data)
703 {
704 Mutex::Lock __(sGCfgLock);
705 sGCfg().GetAdd(name) = data;
706 }
707
LoadFromGlobal(Event<Stream &> x,const char * name)708 bool LoadFromGlobal(Event<Stream&> x, const char *name)
709 {
710 StringStream ss(GetGlobalConfigData(name));
711 return ss.IsEof() || Load(x, ss);
712 }
713
StoreToGlobal(Event<Stream &> x,const char * name)714 void StoreToGlobal(Event<Stream&> x, const char *name)
715 {
716 StringStream ss;
717 Store(x, ss);
718 SetGlobalConfigData(name, ss);
719 }
720
SerializeGlobalConfigs(Stream & s)721 void SerializeGlobalConfigs(Stream& s)
722 {
723 Mutex::Lock __(sGCfgLock);
724 for(int i = 0; i < sGFlush().GetCount(); i++)
725 sGFlush()[i]();
726 int version = 0;
727 s / version;
728 int count = sGCfg().GetCount();
729 s / count;
730 for(int i = 0; i < count; i++) {
731 String name;
732 if(s.IsStoring())
733 name = sGCfg().GetKey(i);
734 s % name;
735 int q = sGCfg().Find(name);
736 if(q >= 0) {
737 int w = sGSerialize().Find(name);
738 if(w >= 0) {
739 String h;
740 if(s.IsStoring()) {
741 StringStream ss;
742 sGSerialize()[w](ss);
743 h = ss;
744 }
745 s % h;
746 if(s.IsLoading()) {
747 StringStream ss(h);
748 sGSerialize()[w](ss);
749 }
750 }
751 else
752 s % sGCfg()[q];
753 }
754 else {
755 String dummy;
756 s % dummy;
757 }
758 }
759 s.Magic();
760 }
761
AbortExc()762 AbortExc::AbortExc() :
763 Exc(t_("Aborted by user.")) {}
764
765 #ifdef PLATFORM_WIN32
766
GetErrorMessage(DWORD dwError)767 String GetErrorMessage(DWORD dwError) {
768 char h[2048];
769 sprintf(h, "%08x", (int)dwError);
770 #ifdef PLATFORM_WINCE //TODO
771 return h;
772 #else
773 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
774 NULL, dwError, 0, h, 2048, NULL);
775 String result = h;
776 String modf;
777 const char* s = result;
778 BYTE c;
779 while((c = *s++) != 0)
780 if(c <= ' ') {
781 if(!modf.IsEmpty() && modf[modf.GetLength() - 1] != ' ')
782 modf += ' ';
783 }
784 else if(c == '%' && *s >= '0' && *s <= '9') {
785 s++;
786 modf += "<###>";
787 }
788 else
789 modf += (char)c;
790 const char* p = modf;
791 for(s = p + modf.GetLength(); s > p && s[-1] == ' '; s--);
792 return FromSystemCharset(modf.Left((int)(s - p)));
793 #endif
794 }
795
GetLastErrorMessage()796 String GetLastErrorMessage() {
797 return GetErrorMessage(GetLastError()) + " (" + AsString(GetLastError()) + ")";
798 }
799
800 #endif
801
802 #ifdef PLATFORM_POSIX
803
GetErrorMessage(int errorno)804 String GetErrorMessage(int errorno)
805 {
806 // Linux strerror_r declaration might be different than posix
807 // hence we are using strerror with mutex... (cxl 2008-07-17)
808 static StaticMutex m;
809 Mutex::Lock __(m);
810 return FromSystemCharset(strerror(errorno));
811 }
812
GetLastErrorMessage()813 String GetLastErrorMessage() {
814 return GetErrorMessage(errno) + " (" + AsString(errno) + ")";
815 }
816
817 #endif
818
819 #ifdef PLATFORM_POSIX
820 #ifndef PLATFORM_COCOA
821
822 String CurrentSoundTheme = "freedesktop";
823
LinuxBeep(const char * name)824 static void LinuxBeep(const char *name)
825 {
826 static String player;
827 ONCELOCK {
828 const char *players[] = { "play", "ogg123", "gst123" };
829 for(int i = 0; i < __countof(players); i++)
830 if(Sys("which " + String(players[i])).GetCount()) {
831 player = players[i];
832 break;
833 }
834 }
835
836 if(player.GetCount()) {
837 String fn = "/usr/share/sounds/" + CurrentSoundTheme + "/stereo/dialog-" + name;
838 IGNORE_RESULT(system(player + " -q " + fn +
839 (FileExists(fn + ".ogg") ? ".ogg" :
840 FileExists(fn + ".oga") ? ".oga" :
841 FileExists(fn + ".wav") ? ".wav" :
842 ".*")
843 + " >/dev/null 2>/dev/null&"));
844 }
845 }
846
847 #endif
848 #endif
849
850 #ifdef PLATFORM_COCOA
851 void (*CocoBeepFn)();
852
DoCocoBeep()853 void DoCocoBeep()
854 {
855 if(CocoBeepFn)
856 (*CocoBeepFn)();
857 }
858
859 #endif
860
BeepInformation()861 void BeepInformation()
862 {
863 #ifdef PLATFORM_WIN32
864 MessageBeep(MB_ICONINFORMATION);
865 #elif defined(PLATFORM_COCOA)
866 DoCocoBeep();
867 #else
868 LinuxBeep("information");
869 #endif
870 }
871
BeepExclamation()872 void BeepExclamation()
873 {
874 #ifdef PLATFORM_WIN32
875 MessageBeep(MB_ICONEXCLAMATION);
876 #elif defined(PLATFORM_COCOA)
877 DoCocoBeep();
878 #else
879 LinuxBeep("warning");
880 #endif
881 }
882
BeepError()883 void BeepError()
884 {
885 #ifdef PLATFORM_WIN32
886 MessageBeep(MB_ICONERROR);
887 #elif defined(PLATFORM_COCOA)
888 DoCocoBeep();
889 #else
890 LinuxBeep("error");
891 #endif
892 }
893
BeepQuestion()894 void BeepQuestion()
895 {
896 #ifdef PLATFORM_WIN32
897 MessageBeep(MB_ICONQUESTION);
898 #elif defined(PLATFORM_COCOA)
899 DoCocoBeep();
900 #else
901 LinuxBeep("question");
902 #endif
903 }
904
905 #if defined(COMPILER_MSC) && (_MSC_VER < 1300)
906 //hack for linking libraries built using VC7 with VC6 standard lib's
907 extern "C" long _ftol( double );
_ftol2(double dblSource)908 extern "C" long _ftol2( double dblSource ) { return _ftol( dblSource ); }
909 #endif
910
911 #ifdef PLATFORM_WINCE
912 int errno; // missing and zlib needs it
913 #endif
914
915
916 template <class CHR, class T>
Replace__(const T & s,const Vector<T> & find,const Vector<T> & replace)917 T Replace__(const T& s, const Vector<T>& find, const Vector<T>& replace)
918 {
919 ASSERT(find.GetCount() == replace.GetCount());
920
921 T r;
922 int i = 0;
923 while(i < s.GetCount()) {
924 int best = -1;
925 int bestlen = 0;
926 int len = s.GetCount() - i;
927 const CHR *q = ~s + i;
928 for(int j = 0; j < replace.GetCount(); j++) {
929 const T& m = find[j];
930 int l = m.GetCount();
931 if(l <= len && l > bestlen && memcmp(~m, q, l * sizeof(CHR)) == 0) {
932 bestlen = l;
933 best = j;
934 }
935 }
936 if(best >= 0) {
937 i += bestlen;
938 r.Cat(replace[best]);
939 }
940 else {
941 r.Cat(*q);
942 i++;
943 }
944 }
945 return r;
946 }
947
Replace(const String & s,const Vector<String> & find,const Vector<String> & replace)948 String Replace(const String& s, const Vector<String>& find, const Vector<String>& replace)
949 {
950 return Replace__<char>(s, find, replace);
951 }
952
Replace(const String & s,const VectorMap<String,String> & fr)953 String Replace(const String& s, const VectorMap<String, String>& fr)
954 {
955 return Replace__<char>(s, fr.GetKeys(), fr.GetValues());
956 }
957
Replace(const WString & s,const Vector<WString> & find,const Vector<WString> & replace)958 WString Replace(const WString& s, const Vector<WString>& find, const Vector<WString>& replace)
959 {
960 return Replace__<wchar>(s, find, replace);
961 }
962
Replace(const WString & s,const VectorMap<WString,WString> & fr)963 WString Replace(const WString& s, const VectorMap<WString, WString>& fr)
964 {
965 return Replace__<wchar>(s, fr.GetKeys(), fr.GetValues());
966 }
967
968
969 String (*GetP7Signature__)(const void *data, int length, const String& cert_pem, const String& pkey_pem);
970
GetP7Signature(const void * data,int length,const String & cert_pem,const String & pkey_pem)971 String GetP7Signature(const void *data, int length, const String& cert_pem, const String& pkey_pem)
972 {
973 ASSERT_(GetP7Signature__, "Missing SSL support (Core/SSL)");
974 return (*GetP7Signature__)(data, length, cert_pem, pkey_pem);
975 }
976
GetP7Signature(const String & data,const String & cert_pem,const String & pkey_pem)977 String GetP7Signature(const String& data, const String& cert_pem, const String& pkey_pem)
978 {
979 return GetP7Signature(data, data.GetLength(), cert_pem, pkey_pem);
980 }
981
982 }
983