added quote character escape in function AgentGetParameterArg
[public/netxms.git] / src / libnetxms / tools.cpp
CommitLineData
bac74bf7 1/*
5039dede 2** NetXMS - Network Management System
de4c0511 3** Copyright (C) 2003-2015 Victor Kirhenshtein
5039dede
AK
4**
5** This program is free software; you can redistribute it and/or modify
68f384ea
VK
6** it under the terms of the GNU Lesser General Public License as published
7** by the Free Software Foundation; either version 3 of the License, or
5039dede
AK
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
68f384ea 15** You should have received a copy of the GNU Lesser General Public License
5039dede
AK
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18**
19** File: tools.cpp
20**
21**/
22
23#include "libnetxms.h"
24#include <stdarg.h>
25#include <nms_agent.h>
26#include <nms_threads.h>
5e08c6db 27#include <netxms-regex.h>
d77c193c 28#include <nxstat.h>
29
5039dede 30#ifdef _WIN32
11606542 31#include <psapi.h>
7b33ff5d
VK
32#define read _read
33#define close _close
289d126b 34#define wcsicmp _wcsicmp
5039dede
AK
35#endif
36
37#if !defined(_WIN32) && !defined(UNDER_CE)
38#include <sys/time.h>
39#endif
40
41#if HAVE_SYS_UTSNAME_H
42#include <sys/utsname.h>
43#endif
44
45#if HAVE_POLL_H
46#include <poll.h>
47#endif
48
c65eb156 49#if HAVE_MALLOC_H && !WITH_JEMALLOC
5962498b
VK
50#include <malloc.h>
51#endif
52
fe8ea784
VK
53#if HAVE_LOCALE_H
54#include <locale.h>
55#endif
56
5039dede
AK
57#ifdef _WIN32
58# ifndef __GNUC__
59# define EPOCHFILETIME (116444736000000000i64)
60# else
61# define EPOCHFILETIME (116444736000000000LL)
62# endif
63#endif
64
289d126b 65/**
fe8ea784
VK
66 * Common initialization for any NetXMS process
67 */
68void LIBNETXMS_EXPORTABLE InitNetXMSProcess()
69{
70 InitThreadLibrary();
71
72 // Set locale to C. It shouldn't be needed, according to
73 // documentation, but I've seen the cases when agent formats
74 // floating point numbers by sprintf inserting comma in place
75 // of a dot, as set by system's regional settings.
76#if HAVE_SETLOCALE
77 setlocale(LC_NUMERIC, "C");
78#if defined(UNICODE) && !defined(_WIN32)
79 const char *locale = getenv("LC_CTYPE");
80 if (locale == NULL)
81 locale = getenv("LC_ALL");
82 if (locale == NULL)
83 locale = getenv("LANG");
84 if (locale != NULL)
85 setlocale(LC_CTYPE, locale);
86#endif
87#endif
88
89#ifdef NETXMS_MEMORY_DEBUG
90 InitMemoryDebugger();
91#endif
92
93#ifdef _WIN32
94 SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
95#endif
96}
97
98/**
289d126b
VK
99 * Calculate number of bits in netmask (in host byte order)
100 */
967893bb 101int LIBNETXMS_EXPORTABLE BitsInMask(UINT32 dwMask)
5039dede
AK
102{
103 int bits;
967893bb 104 UINT32 dwTemp;
5039dede
AK
105
106 for(bits = 0, dwTemp = dwMask; dwTemp != 0; bits++, dwTemp <<= 1);
107 return bits;
108}
109
289d126b
VK
110/**
111 * Convert IP address from binary form (host bytes order) to string
112 */
967893bb 113TCHAR LIBNETXMS_EXPORTABLE *IpToStr(UINT32 dwAddr, TCHAR *szBuffer)
5039dede
AK
114{
115 static TCHAR szInternalBuffer[32];
116 TCHAR *szBufPtr;
117
e0f99bf0 118 szBufPtr = (szBuffer == NULL) ? szInternalBuffer : szBuffer;
8d131dda
VK
119 _sntprintf(szBufPtr, 32, _T("%d.%d.%d.%d"), (int)(dwAddr >> 24), (int)((dwAddr >> 16) & 255),
120 (int)((dwAddr >> 8) & 255), (int)(dwAddr & 255));
5039dede
AK
121 return szBufPtr;
122}
123
e0f99bf0
VK
124#ifdef UNICODE
125
967893bb 126char LIBNETXMS_EXPORTABLE *IpToStrA(UINT32 dwAddr, char *szBuffer)
e0f99bf0
VK
127{
128 static char szInternalBuffer[32];
129 char *szBufPtr;
130
131 szBufPtr = (szBuffer == NULL) ? szInternalBuffer : szBuffer;
132 snprintf(szBufPtr, 32, "%d.%d.%d.%d", (int)(dwAddr >> 24), (int)((dwAddr >> 16) & 255),
133 (int)((dwAddr >> 8) & 255), (int)(dwAddr & 255));
134 return szBufPtr;
135}
136
137#endif
138
c7853753
VK
139/**
140 * Universal IPv4/IPv6 to string converter
141 */
60557d06
VK
142TCHAR LIBNETXMS_EXPORTABLE *SockaddrToStr(struct sockaddr *addr, TCHAR *buffer)
143{
144 switch(addr->sa_family)
145 {
146 case AF_INET:
147 return IpToStr(ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr), buffer);
148 case AF_INET6:
149 return Ip6ToStr(((struct sockaddr_in6 *)addr)->sin6_addr.s6_addr, buffer);
150 default:
151 buffer[0] = 0;
152 return buffer;
153 }
154}
155
605fc935
VK
156/**
157 * Convert IPv6 address from binary form to string
158 */
8c75ad41 159TCHAR LIBNETXMS_EXPORTABLE *Ip6ToStr(const BYTE *addr, TCHAR *buffer)
36e44abe
VK
160{
161 static TCHAR internalBuffer[64];
162 TCHAR *bufPtr = (buffer == NULL) ? internalBuffer : buffer;
163
164 if (!memcmp(addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
165 {
166 _tcscpy(bufPtr, _T("::"));
167 return bufPtr;
168 }
169
170 TCHAR *out = bufPtr;
171 WORD *curr = (WORD *)addr;
172 bool hasNulls = false;
173 for(int i = 0; i < 8; i++)
174 {
175 WORD value = ntohs(*curr);
176 if ((value != 0) || hasNulls)
177 {
178 if (out != bufPtr)
179 *out++ = _T(':');
180 _sntprintf(out, 5, _T("%x"), value);
181 out = bufPtr + _tcslen(bufPtr);
182 curr++;
183 }
184 else
185 {
186 *out++ = _T(':');
187 do
188 {
189 i++;
190 curr++;
191 }
192 while((*curr == 0) && (i < 8));
6e021e67
VK
193 if (i == 8)
194 {
195 *out++ = _T(':');
196 break;
197 }
36e44abe
VK
198 i--;
199 hasNulls = true;
200 }
201 }
202 *out = 0;
203 return bufPtr;
204}
205
af4a09df
VK
206#ifdef UNICODE
207
208/**
209 * Convert IPv6 address from binary form to string
210 */
211char LIBNETXMS_EXPORTABLE *Ip6ToStrA(const BYTE *addr, char *buffer)
212{
213 static char internalBuffer[64];
214 char *bufPtr = (buffer == NULL) ? internalBuffer : buffer;
215
216 if (!memcmp(addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
217 {
218 strcpy(bufPtr, "::");
219 return bufPtr;
220 }
221
222 char *out = bufPtr;
223 WORD *curr = (WORD *)addr;
224 bool hasNulls = false;
225 for(int i = 0; i < 8; i++)
226 {
227 WORD value = ntohs(*curr);
228 if ((value != 0) || hasNulls)
229 {
230 if (out != bufPtr)
231 *out++ = ':';
232 snprintf(out, 5, "%x", value);
233 out = bufPtr + strlen(bufPtr);
234 curr++;
235 }
236 else
237 {
238 *out++ = ':';
239 do
240 {
241 i++;
242 curr++;
243 }
244 while((*curr == 0) && (i < 8));
245 if (i == 8)
246 {
247 *out++ = ':';
248 break;
249 }
250 i--;
251 hasNulls = true;
252 }
253 }
254 *out = 0;
255 return bufPtr;
256}
257
258#endif
259
605fc935
VK
260/**
261 * Duplicate memory block
262 */
e0471fad 263void LIBNETXMS_EXPORTABLE *nx_memdup(const void *data, size_t size)
5039dede 264{
e0471fad 265 void *newData;
5039dede 266
e0471fad
VK
267 newData = malloc(size);
268 memcpy(newData, data, size);
269 return newData;
5039dede
AK
270}
271
e0471fad
VK
272/**
273 * Swap two memory blocks
274 */
275void LIBNETXMS_EXPORTABLE nx_memswap(void *block1, void *block2, size_t size)
5039dede 276{
e0471fad 277 void *temp;
5039dede 278
e0471fad
VK
279 temp = malloc(size);
280 memcpy(temp, block1, size);
281 memcpy(block1, block2, size);
282 memcpy(block2, temp, size);
283 free(temp);
5039dede
AK
284}
285
8ff13508
VK
286#if defined(_WIN32) && defined(USE_WIN32_HEAP)
287
e0471fad
VK
288/**
289 * Copy string
290 */
8ff13508
VK
291char LIBNETXMS_EXPORTABLE *nx_strdup(const char *src)
292{
fd72502a 293 return (char *)nx_memdup(src, strlen(src) + 1);
8ff13508
VK
294}
295
e0471fad
VK
296/**
297 * Copy string
298 */
8ff13508
VK
299WCHAR LIBNETXMS_EXPORTABLE *nx_wcsdup(const WCHAR *src)
300{
fd72502a 301 return (WCHAR *)nx_memdup(src, (wcslen(src) + 1) * sizeof(WCHAR));
8ff13508
VK
302}
303
304#endif
305
fa88627b 306#if !HAVE_WCSDUP && !defined(_WIN32)
37861c72 307
e0471fad
VK
308/**
309 * Copy string
310 */
37861c72
VK
311WCHAR LIBNETXMS_EXPORTABLE *wcsdup(const WCHAR *src)
312{
313 return (WCHAR *)nx_memdup(src, (wcslen(src) + 1) * sizeof(WCHAR));
314}
315
fd72502a
VK
316#elif defined(_AIX)
317
318/**
319 * Copy string
320 */
321WCHAR LIBNETXMS_EXPORTABLE *nx_wcsdup(const WCHAR *src)
322{
323 return (WCHAR *)nx_memdup(src, (wcslen(src) + 1) * sizeof(WCHAR));
324}
325
37861c72
VK
326#endif
327
240816b0
VK
328/**
329 * Compare pattern with possible ? characters with given text
330 */
331static bool CompareTextBlocks(const TCHAR *pattern, const TCHAR *text, size_t size)
332{
333 const TCHAR *p = pattern;
334 const TCHAR *t = text;
335 for(size_t i = size; i > 0; i--, p++, t++)
336 {
337 if (*p == _T('?'))
338 continue;
339 if (*p != *t)
340 return false;
341 }
342 return true;
343}
8ff13508 344
240816b0
VK
345/**
346 * Match string against pattern with * and ? metasymbols - implementation
347 */
348static bool MatchStringEngine(const TCHAR *pattern, const TCHAR *string)
5039dede
AK
349{
350 const TCHAR *SPtr, *MPtr, *BPtr, *EPtr;
240816b0
VK
351 size_t bsize;
352 bool finishScan;
5039dede
AK
353
354 SPtr = string;
355 MPtr = pattern;
356
357 while(*MPtr != 0)
358 {
359 switch(*MPtr)
360 {
361 case _T('?'):
362 if (*SPtr != 0)
363 {
364 SPtr++;
365 MPtr++;
366 }
367 else
240816b0
VK
368 {
369 return false;
370 }
5039dede
AK
371 break;
372 case _T('*'):
373 while(*MPtr == _T('*'))
374 MPtr++;
375 if (*MPtr == 0)
240816b0 376 return true;
75df9a20 377 while(*MPtr == _T('?')) // Handle "*?" case
5039dede
AK
378 {
379 if (*SPtr != 0)
380 SPtr++;
381 else
240816b0 382 return false;
75df9a20 383 MPtr++;
5039dede
AK
384 }
385 BPtr = MPtr; // Text block begins here
240816b0 386 while((*MPtr != 0) && (*MPtr != _T('*')))
5039dede
AK
387 MPtr++; // Find the end of text block
388 // Try to find rightmost matching block
240816b0 389 bsize = (size_t)(MPtr - BPtr);
5039dede 390 EPtr = NULL;
240816b0 391 finishScan = false;
5039dede
AK
392 do
393 {
394 while(1)
395 {
396 while((*SPtr != 0) && (*SPtr != *BPtr))
397 SPtr++;
240816b0 398 if (_tcslen(SPtr) < bsize)
5039dede
AK
399 {
400 if (EPtr == NULL)
401 {
240816b0 402 return false; // Length of remained text less than remaining pattern
5039dede
AK
403 }
404 else
405 {
240816b0
VK
406 SPtr = EPtr; // Revert back to point after last match
407 finishScan = true;
5039dede
AK
408 break;
409 }
410 }
240816b0 411 if (CompareTextBlocks(BPtr, SPtr, bsize))
5039dede
AK
412 break;
413 SPtr++;
414 }
240816b0 415 if (!finishScan)
5039dede 416 {
240816b0
VK
417 EPtr = SPtr + bsize; // Remember point after last match
418 SPtr++; // continue scan at next character
5039dede
AK
419 }
420 }
240816b0 421 while(!finishScan);
5039dede
AK
422 break;
423 default:
424 if (*MPtr == *SPtr)
425 {
426 SPtr++;
427 MPtr++;
428 }
429 else
240816b0
VK
430 {
431 return false;
432 }
5039dede
AK
433 break;
434 }
435 }
436
240816b0 437 return *SPtr == 0;
5039dede
AK
438}
439
240816b0
VK
440/**
441 * Match string against pattern with * and ? metasymbols
442 *
443 * @param pattern pattern to match against
444 * @param str string to match
445 * @param matchCase set to true for case-sensetive match
446 * @return true if string matches given pattern
447 */
448bool LIBNETXMS_EXPORTABLE MatchString(const TCHAR *pattern, const TCHAR *str, bool matchCase)
5039dede
AK
449{
450 if (matchCase)
240816b0
VK
451 return MatchStringEngine(pattern, str);
452
453 TCHAR *tp, *ts;
454 bool bResult;
455
456 tp = _tcsdup(pattern);
457 ts = _tcsdup(str);
458 _tcsupr(tp);
459 _tcsupr(ts);
460 bResult = MatchStringEngine(tp, ts);
461 free(tp);
462 free(ts);
463 return bResult;
5039dede
AK
464}
465
240816b0
VK
466/**
467 * Strip whitespaces and tabs off the string
468 */
b07c50cc 469void LIBNETXMS_EXPORTABLE StrStripA(char *str)
5039dede
AK
470{
471 int i;
472
b07c50cc
VK
473 for(i = 0; (str[i]!=0) && ((str[i] == ' ') || (str[i] == '\t')); i++);
474 if (i > 0)
475 memmove(str, &str[i], strlen(&str[i]) + 1);
476 for(i = (int)strlen(str) - 1; (i >= 0) && ((str[i] == ' ') || (str[i] == '\t')); i--);
477 str[i + 1] = 0;
478}
479
240816b0
VK
480/**
481 * Strip whitespaces and tabs off the string
482 */
b07c50cc
VK
483void LIBNETXMS_EXPORTABLE StrStripW(WCHAR *str)
484{
485 int i;
486
487 for(i = 0; (str[i]!=0) && ((str[i] == L' ') || (str[i] == L'\t')); i++);
488 if (i > 0)
489 memmove(str, &str[i], (wcslen(&str[i]) + 1) * sizeof(WCHAR));
490 for(i = (int)wcslen(str) - 1; (i >= 0) && ((str[i] == L' ') || (str[i] == L'\t')); i--);
491 str[i + 1] = 0;
5039dede
AK
492}
493
240816b0 494/**
818f8c94
VK
495 * Strip whitespaces and tabs off the string.
496 *
497 * @param str string to trim
498 * @return str for convenience
240816b0 499 */
818f8c94 500TCHAR LIBNETXMS_EXPORTABLE *Trim(TCHAR *str)
0bbab9d3 501{
818f8c94
VK
502 if (str == NULL)
503 return NULL;
0bbab9d3 504
818f8c94 505 int i;
0bbab9d3
VK
506 for(i = 0; (str[i] != 0) && _istspace(str[i]); i++);
507 if (i > 0)
508 memmove(str, &str[i], (_tcslen(&str[i]) + 1) * sizeof(TCHAR));
509 for(i = (int)_tcslen(str) - 1; (i >= 0) && _istspace(str[i]); i--);
510 str[i + 1] = 0;
818f8c94 511 return str;
0bbab9d3
VK
512}
513
25aa9db1
VK
514/**
515 * Remove trailing CR/LF or LF from string (multibyte version)
516 */
35f836fe 517void LIBNETXMS_EXPORTABLE RemoveTrailingCRLFA(char *str)
3783d300
VK
518{
519 if (*str == 0)
520 return;
521
35f836fe 522 char *p = str + strlen(str) - 1;
3783d300
VK
523 if (*p == '\n')
524 p--;
525 if (*p == '\r')
526 p--;
527 *(p + 1) = 0;
528}
529
25aa9db1
VK
530/**
531 * Remove trailing CR/LF or LF from string (UNICODE version)
532 */
35f836fe
VK
533void LIBNETXMS_EXPORTABLE RemoveTrailingCRLFW(WCHAR *str)
534{
535 if (*str == 0)
536 return;
537
538 WCHAR *p = str + wcslen(str) - 1;
539 if (*p == L'\n')
540 p--;
541 if (*p == L'\r')
542 p--;
543 *(p + 1) = 0;
544}
545
ec9c39ea 546/**
5e368b2f 547 * Expand file name. Source and destiation may point to same location.
ec9c39ea
VK
548 * Can be used strftime placeholders and external commands enclosed in ``
549 */
5e368b2f 550const TCHAR LIBNETXMS_EXPORTABLE *ExpandFileName(const TCHAR *name, TCHAR *buffer, size_t bufSize, bool allowShellCommands)
a73a4403
AK
551{
552 time_t t;
553 struct tm *ltm;
554#if HAVE_LOCALTIME_R
555 struct tm tmBuff;
556#endif
557 TCHAR temp[8192], command[1024];
558 size_t outpos = 0;
559
560 t = time(NULL);
561#if HAVE_LOCALTIME_R
562 ltm = localtime_r(&t, &tmBuff);
563#else
564 ltm = localtime(&t);
565#endif
566 if (_tcsftime(temp, 8192, name, ltm) <= 0)
567 return NULL;
568
569 for(int i = 0; (temp[i] != 0) && (outpos < bufSize - 1); i++)
570 {
5e368b2f 571 if (temp[i] == _T('`') && allowShellCommands)
a73a4403
AK
572 {
573 int j = ++i;
574 while((temp[j] != _T('`')) && (temp[j] != 0))
575 j++;
576 int len = min(j - i, 1023);
577 memcpy(command, &temp[i], len * sizeof(TCHAR));
578 command[len] = 0;
579
580 FILE *p = _tpopen(command, _T("r"));
581 if (p != NULL)
582 {
583 char result[1024];
584
585 int rc = (int)fread(result, 1, 1023, p);
586 pclose(p);
587
588 if (rc > 0)
589 {
590 result[rc] = 0;
591 char *lf = strchr(result, '\n');
592 if (lf != NULL)
593 *lf = 0;
594
595 len = (int)min(strlen(result), bufSize - outpos - 1);
596#ifdef UNICODE
597 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, result, len, &buffer[outpos], len);
598#else
599 memcpy(&buffer[outpos], result, len);
600#endif
601 outpos += len;
602 }
603 }
604
605 i = j;
606 }
ec9c39ea 607 else if (temp[i] == _T('$') && temp[i + 1] == _T('{'))
edb6e808
AK
608 {
609 i += 2;
610 int j = i;
611 while((temp[j] != _T('}')) && (temp[j] != 0))
612 j++;
613
614 int len = min(j - i, 1023);
615
616 TCHAR varName[256];
617 memcpy(varName, &temp[i], len * sizeof(TCHAR));
618 varName[len] = 0;
619
b26eb6ad 620 TCHAR *result = _tgetenv(varName);
edb6e808
AK
621 if (result != NULL)
622 {
b26eb6ad
AK
623 len = (int)min(_tcslen(result), bufSize - outpos - 1);
624 memcpy(&buffer[outpos], result, len * sizeof(TCHAR));
edb6e808 625 }
420c9ff3 626 else
99877e7b 627 {
edb6e808
AK
628 len = 0;
629 }
b26eb6ad 630
edb6e808 631 outpos += len;
edb6e808
AK
632 i = j;
633 }
634 else
a73a4403
AK
635 {
636 buffer[outpos++] = temp[i];
637 }
638 }
639
640 buffer[outpos] = 0;
641 return buffer;
642}
643
bf7f9e18 644/**
d77c193c 645 * Create folder
646 */
647BOOL LIBNETXMS_EXPORTABLE CreateFolder(const TCHAR *directory)
648{
649 NX_STAT_STRUCT st;
650 TCHAR *previous = _tcsdup(directory);
651 TCHAR *ptr = _tcsrchr(previous, FS_PATH_SEPARATOR_CHAR);
652 BOOL result = FALSE;
653 if (ptr != NULL)
654 {
655 *ptr = 0;
656 if (CALL_STAT(previous, &st) != 0)
657 {
658 result = CreateFolder(previous);
659 if (result)
660 {
661 result = (CALL_STAT(previous, &st) == 0);
662 }
663 }
664 else
665 {
666 if (S_ISDIR(st.st_mode))
667 {
668 result = TRUE;
669 }
670 }
671 }
672 else
673 {
674 result = true;
675 st.st_mode = 0700;
676 }
677 safe_free(previous);
678
679 if (result)
680 {
681#ifdef _WIN32
682 result = CreateDirectory(directory, NULL);
683#else
684 result = (_tmkdir(directory, st.st_mode) == 0);
685#endif /* _WIN32 */
686 }
687
688 return result;
689}
690
691/**
bf7f9e18
VK
692 * Get current time in milliseconds
693 * Based on timeval.h by Wu Yongwei
694 */
21b6cca9 695INT64 LIBNETXMS_EXPORTABLE GetCurrentTimeMs()
5039dede
AK
696{
697#ifdef _WIN32
698 FILETIME ft;
699 LARGE_INTEGER li;
700 __int64 t;
701
702 GetSystemTimeAsFileTime(&ft);
703 li.LowPart = ft.dwLowDateTime;
704 li.HighPart = ft.dwHighDateTime;
705 t = li.QuadPart; // In 100-nanosecond intervals
706 t -= EPOCHFILETIME; // Offset to the Epoch time
707 t /= 10000; // Convert to milliseconds
708#else
709 struct timeval tv;
710 INT64 t;
711
712 gettimeofday(&tv, NULL);
21b6cca9 713 t = (INT64)tv.tv_sec * 1000 + (INT64)(tv.tv_usec / 1000);
5039dede
AK
714#endif
715
716 return t;
717}
718
bf7f9e18
VK
719/**
720 * Extract word from line (UNICODE version). Extracted word will be placed in buffer.
721 * Returns pointer to the next word or to the null character if end
722 * of line reached.
723 */
ada97259 724const WCHAR LIBNETXMS_EXPORTABLE *ExtractWordW(const WCHAR *line, WCHAR *buffer)
5039dede 725{
ada97259
VK
726 const WCHAR *ptr;
727 WCHAR *bptr;
5039dede 728
ada97259 729 for(ptr = line; (*ptr == L' ') || (*ptr == L'\t'); ptr++); // Skip initial spaces
5039dede 730 // Copy word to buffer
ada97259
VK
731 for(bptr = buffer; (*ptr != L' ') && (*ptr != L'\t') && (*ptr != 0); ptr++, bptr++)
732 *bptr = *ptr;
42e93542 733 *bptr = 0;
ada97259
VK
734 return ptr;
735}
736
bf7f9e18
VK
737/**
738 * Extract word from line (multibyte version). Extracted word will be placed in buffer.
739 * Returns pointer to the next word or to the null character if end
740 * of line reached.
741 */
ada97259
VK
742const char LIBNETXMS_EXPORTABLE *ExtractWordA(const char *line, char *buffer)
743{
744 const char *ptr;
745 char *bptr;
746
747 for(ptr = line; (*ptr == ' ') || (*ptr == '\t'); ptr++); // Skip initial spaces
748 // Copy word to buffer
749 for(bptr = buffer; (*ptr != ' ') && (*ptr != '\t') && (*ptr != 0); ptr++, bptr++)
750 *bptr = *ptr;
42e93542 751 *bptr = 0;
5039dede
AK
752 return ptr;
753}
754
5039dede
AK
755#if defined(_WIN32)
756
bf7f9e18
VK
757/**
758 * Get system error string by call to FormatMessage
759 * (Windows only)
760 */
967893bb 761TCHAR LIBNETXMS_EXPORTABLE *GetSystemErrorText(UINT32 dwError, TCHAR *pszBuffer, size_t iBufSize)
5039dede
AK
762{
763 TCHAR *msgBuf;
764
bac74bf7 765 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
766 FORMAT_MESSAGE_FROM_SYSTEM |
5039dede
AK
767 FORMAT_MESSAGE_IGNORE_INSERTS,
768 NULL, dwError,
769 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
770 (LPTSTR)&msgBuf, 0, NULL) > 0)
771 {
772 msgBuf[_tcscspn(msgBuf, _T("\r\n"))] = 0;
773 nx_strncpy(pszBuffer, msgBuf, iBufSize);
774 LocalFree(msgBuf);
775 }
776 else
777 {
3973f74b 778 _sntprintf(pszBuffer, iBufSize, _T("MSG 0x%08X - Unable to find message text"), dwError);
5039dede
AK
779 }
780 return pszBuffer;
781}
782
783#endif
784
de4c0511 785#if (!HAVE_DAEMON || !HAVE_DECL_DAEMON) && !defined(_NETWARE) && !defined(_WIN32)
5039dede 786
de4c0511
VK
787/**
788 * daemon() implementation for systems which doesn't have one
789 */
790int LIBNETXMS_EXPORTABLE __daemon(int nochdir, int noclose)
5039dede
AK
791{
792 int pid;
793
794 if ((pid = fork()) < 0)
795 return -1;
796 if (pid != 0)
797 exit(0); // Terminate parent
798
799 setsid();
800
801 if (!nochdir)
802 chdir("/");
803
bac74bf7 804 if (!noclose)
5039dede
AK
805 {
806 fclose(stdin); // don't need stdin, stdout, stderr
807 fclose(stdout);
808 fclose(stderr);
809 }
810
811 return 0;
812}
813
814#endif
815
f1989a3a
VK
816/**
817 * Check if given name is a valid object name
818 */
5039dede
AK
819BOOL LIBNETXMS_EXPORTABLE IsValidObjectName(const TCHAR *pszName, BOOL bExtendedChars)
820{
821 static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_- @()./");
822 static TCHAR szInvalidCharacters[] = _T("\x01\x02\x03\x04\x05\x06\x07")
823 _T("\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F")
824 _T("\x10\x11\x12\x13\x14\x15\x16\x17")
825 _T("\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F")
826 _T("|\"'*%#\\`;?<>=");
827
828 return (pszName[0] != 0) && (bExtendedChars ? (_tcscspn(pszName, szInvalidCharacters) == _tcslen(pszName)) : (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName)));
829}
830
f1989a3a
VK
831/**
832 * Check if given name is a valid script name
833 */
5039dede
AK
834BOOL LIBNETXMS_EXPORTABLE IsValidScriptName(const TCHAR *pszName)
835{
836 static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_:");
837 return (pszName[0] != 0) && (!isdigit(pszName[0])) && (pszName[0] != ':') &&
838 (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName));
839}
840
f1989a3a
VK
841/**
842 * Convert 6-byte MAC address to text representation
843 */
f42b8099 844TCHAR LIBNETXMS_EXPORTABLE *MACToStr(const BYTE *pData, TCHAR *pStr)
5039dede 845{
967893bb 846 UINT32 i;
5039dede
AK
847 TCHAR *pCurr;
848
849 for(i = 0, pCurr = pStr; i < 6; i++)
850 {
851 *pCurr++ = bin2hex(pData[i] >> 4);
852 *pCurr++ = bin2hex(pData[i] & 15);
853 *pCurr++ = _T(':');
854 }
855 *(pCurr - 1) = 0;
f42b8099 856 return pStr;
5039dede
AK
857}
858
8715a84c
VK
859/**
860 * Convert byte array to text representation (wide character version)
861 */
e0471fad 862WCHAR LIBNETXMS_EXPORTABLE *BinToStrW(const BYTE *pData, size_t size, WCHAR *pStr)
5039dede 863{
e0471fad 864 size_t i;
d7970ee7
VK
865 WCHAR *pCurr;
866
e0471fad 867 for(i = 0, pCurr = pStr; i < size; i++)
d7970ee7
VK
868 {
869 *pCurr++ = bin2hex(pData[i] >> 4);
870 *pCurr++ = bin2hex(pData[i] & 15);
871 }
872 *pCurr = 0;
873 return pStr;
874}
875
8715a84c
VK
876/**
877 * Convert byte array to text representation (multibyte character version)
878 */
e0471fad 879char LIBNETXMS_EXPORTABLE *BinToStrA(const BYTE *pData, size_t size, char *pStr)
d7970ee7 880{
e0471fad 881 size_t i;
d7970ee7 882 char *pCurr;
5039dede 883
e0471fad 884 for(i = 0, pCurr = pStr; i < size; i++)
5039dede
AK
885 {
886 *pCurr++ = bin2hex(pData[i] >> 4);
887 *pCurr++ = bin2hex(pData[i] & 15);
888 }
889 *pCurr = 0;
890 return pStr;
891}
892
8715a84c 893/**
52db3ed1 894 * Convert string of hexadecimal digits to byte array (wide character version)
8715a84c
VK
895 * Returns number of bytes written to destination
896 */
ac14e3e6 897size_t LIBNETXMS_EXPORTABLE StrToBinW(const WCHAR *pStr, BYTE *pData, size_t size)
5039dede 898{
ac14e3e6 899 size_t i;
52db3ed1 900 const WCHAR *pCurr;
5039dede 901
e0471fad
VK
902 memset(pData, 0, size);
903 for(i = 0, pCurr = pStr; (i < size) && (*pCurr != 0); i++)
5039dede
AK
904 {
905 pData[i] = hex2bin(*pCurr) << 4;
906 pCurr++;
1e6b68a6
VK
907 if (*pCurr != 0)
908 {
909 pData[i] |= hex2bin(*pCurr);
910 pCurr++;
911 }
5039dede
AK
912 }
913 return i;
914}
915
52db3ed1
VK
916/**
917 * Convert string of hexadecimal digits to byte array (multibyte character version)
918 * Returns number of bytes written to destination
919 */
ac14e3e6 920size_t LIBNETXMS_EXPORTABLE StrToBinA(const char *pStr, BYTE *pData, size_t size)
52db3ed1 921{
ac14e3e6 922 size_t i;
52db3ed1 923 const char *pCurr;
5039dede 924
e0471fad
VK
925 memset(pData, 0, size);
926 for(i = 0, pCurr = pStr; (i < size) && (*pCurr != 0); i++)
52db3ed1
VK
927 {
928 pData[i] = hex2bin(*pCurr) << 4;
929 pCurr++;
930 if (*pCurr != 0)
931 {
932 pData[i] |= hex2bin(*pCurr);
933 pCurr++;
934 }
935 }
936 return i;
937}
5039dede 938
52db3ed1
VK
939/**
940 * Translate string
941 * NOTE: replacement string shouldn't be longer than original
942 */
5039dede
AK
943void LIBNETXMS_EXPORTABLE TranslateStr(TCHAR *pszString, const TCHAR *pszSubStr, const TCHAR *pszReplace)
944{
945 TCHAR *pszSrc, *pszDst;
946 int iSrcLen, iRepLen;
947
948 iSrcLen = (int)_tcslen(pszSubStr);
949 iRepLen = (int)_tcslen(pszReplace);
950 for(pszSrc = pszString, pszDst = pszString; *pszSrc != 0;)
951 {
952 if (!_tcsncmp(pszSrc, pszSubStr, iSrcLen))
953 {
954 memcpy(pszDst, pszReplace, sizeof(TCHAR) * iRepLen);
955 pszSrc += iSrcLen;
956 pszDst += iRepLen;
957 }
958 else
959 {
960 *pszDst++ = *pszSrc++;
961 }
962 }
963 *pszDst = 0;
964}
965
1defb62e
VK
966/**
967 * Get size of file in bytes
968 */
d35ed0aa 969QWORD LIBNETXMS_EXPORTABLE FileSizeW(const WCHAR *pszFileName)
5039dede
AK
970{
971#ifdef _WIN32
972 HANDLE hFind;
d35ed0aa 973 WIN32_FIND_DATAW fd;
5039dede
AK
974#else
975 struct stat fileInfo;
976#endif
977
978#ifdef _WIN32
d35ed0aa 979 hFind = FindFirstFileW(pszFileName, &fd);
5039dede
AK
980 if (hFind == INVALID_HANDLE_VALUE)
981 return 0;
982 FindClose(hFind);
983
984 return (unsigned __int64)fd.nFileSizeLow + ((unsigned __int64)fd.nFileSizeHigh << 32);
985#else
d35ed0aa
VK
986 if (wstat(pszFileName, &fileInfo) == -1)
987 return 0;
988
989 return (QWORD)fileInfo.st_size;
990#endif
991}
992
1defb62e
VK
993/**
994 * Get size of file in bytes
995 */
d35ed0aa
VK
996QWORD LIBNETXMS_EXPORTABLE FileSizeA(const char *pszFileName)
997{
998#ifdef _WIN32
999 HANDLE hFind;
1000 WIN32_FIND_DATAA fd;
1001#else
1002 struct stat fileInfo;
1003#endif
1004
1005#ifdef _WIN32
1006 hFind = FindFirstFileA(pszFileName, &fd);
1007 if (hFind == INVALID_HANDLE_VALUE)
1008 return 0;
1009 FindClose(hFind);
1010
1011 return (unsigned __int64)fd.nFileSizeLow + ((unsigned __int64)fd.nFileSizeHigh << 32);
1012#else
1013 if (stat(pszFileName, &fileInfo) == -1)
5039dede
AK
1014 return 0;
1015
1016 return (QWORD)fileInfo.st_size;
1017#endif
1018}
1019
5e60b759
VK
1020/**
1021 * Get pointer to clean file name (without path specification)
1022 */
1a5e0c22 1023const TCHAR LIBNETXMS_EXPORTABLE *GetCleanFileName(const TCHAR *pszFileName)
5039dede 1024{
1a5e0c22 1025 const TCHAR *ptr;
5039dede
AK
1026
1027 ptr = pszFileName + _tcslen(pszFileName);
1028 while((ptr >= pszFileName) && (*ptr != _T('/')) && (*ptr != _T('\\')) && (*ptr != _T(':')))
1029 ptr--;
1030 return (ptr + 1);
1031}
1032
5e60b759
VK
1033/**
1034 * Translate DCI data type from text form to code
1035 */
5039dede
AK
1036int LIBNETXMS_EXPORTABLE NxDCIDataTypeFromText(const TCHAR *pszText)
1037{
1038 static const TCHAR *m_pszValidTypes[] = { _T("INT"), _T("UINT"), _T("INT64"),
1039 _T("UINT64"), _T("STRING"),
1040 _T("FLOAT"), NULL };
1041 int i;
1042
1043 for(i = 0; m_pszValidTypes[i] != NULL; i++)
1044 if (!_tcsicmp(pszText, m_pszValidTypes[i]))
1045 return i;
1046 return -1; // Invalid data type
1047}
1048
bd8cc790
VK
1049/**
1050 * Extended send() - send all data even if single call to send()
1051 * cannot handle them all
1052 */
5e60b759 1053int LIBNETXMS_EXPORTABLE SendEx(SOCKET hSocket, const void *data, size_t len, int flags, MUTEX mutex)
5039dede 1054{
5e60b759 1055 int nLeft = (int)len;
5039dede
AK
1056 int nRet;
1057
7b8b337e 1058 if (mutex != NULL)
c17f6cbc 1059 MutexLock(mutex);
7b8b337e 1060
5039dede
AK
1061 do
1062 {
1063retry:
3632f8df 1064#ifdef MSG_NOSIGNAL
5e60b759 1065 nRet = send(hSocket, ((char *)data) + (len - nLeft), nLeft, flags | MSG_NOSIGNAL);
3632f8df 1066#else
5e60b759 1067 nRet = send(hSocket, ((char *)data) + (len - nLeft), nLeft, flags);
3632f8df 1068#endif
5039dede
AK
1069 if (nRet <= 0)
1070 {
6e102d6e 1071 if ((WSAGetLastError() == WSAEWOULDBLOCK)
79ca7ae6 1072#ifndef _WIN32
6e102d6e 1073 || (errno == EAGAIN)
79ca7ae6 1074#endif
6e102d6e 1075 )
5039dede 1076 {
04fb0d6b
VK
1077 // Wait until socket becomes available for writing
1078 struct timeval tv;
1079 fd_set wfds;
1080
1081 tv.tv_sec = 60;
1082 tv.tv_usec = 0;
1083 FD_ZERO(&wfds);
5e60b759
VK
1084 FD_SET(hSocket, &wfds);
1085 nRet = select(SELECT_NFDS(hSocket + 1), NULL, &wfds, NULL, &tv);
04fb0d6b
VK
1086 if ((nRet > 0) || ((nRet == -1) && (errno == EINTR)))
1087 goto retry;
5039dede
AK
1088 }
1089 break;
1090 }
1091 nLeft -= nRet;
1092 } while (nLeft > 0);
1093
7b8b337e
VK
1094 if (mutex != NULL)
1095 MutexUnlock(mutex);
1096
5e60b759 1097 return nLeft == 0 ? (int)len : nRet;
5039dede
AK
1098}
1099
bd8cc790
VK
1100/**
1101 * Extended recv() - receive data with timeout
bac74bf7 1102 *
5e60b759
VK
1103 * @param hSocket socket handle
1104 * @param data data buffer
1105 * @param len buffer length in bytes
1106 * @param flags flags to be passed to recv() call
1107 * @param timeout waiting timeout in milliseconds
1108 * @return number of bytes read on success, 0 if socket was closed, -1 on error, -2 on timeout
bd8cc790 1109 */
5e60b759 1110int LIBNETXMS_EXPORTABLE RecvEx(SOCKET hSocket, void *data, size_t len, int flags, UINT32 timeout)
5039dede
AK
1111{
1112 int iErr;
1113#if HAVE_POLL
1114 struct pollfd fds;
1115#else
1116 struct timeval tv;
1117 fd_set rdfs;
1118#endif
1119#ifndef _WIN32
1120 QWORD qwStartTime;
967893bb 1121 UINT32 dwElapsed;
5039dede
AK
1122#endif
1123
1124 // I've seen on Linux that poll() may hang if fds.fd == -1,
1125 // so we check this ourselves
5e60b759 1126 if (hSocket == INVALID_SOCKET)
5039dede
AK
1127 return -1;
1128
5e60b759 1129 if (timeout != INFINITE)
5039dede
AK
1130 {
1131#if HAVE_POLL
5e60b759 1132 fds.fd = hSocket;
5039dede
AK
1133 fds.events = POLLIN;
1134 fds.revents = POLLIN;
1135 do
1136 {
1137 qwStartTime = GetCurrentTimeMs();
5e60b759 1138 iErr = poll(&fds, 1, timeout);
5039dede
AK
1139 if ((iErr != -1) || (errno != EINTR))
1140 break;
1141 dwElapsed = GetCurrentTimeMs() - qwStartTime;
5e60b759
VK
1142 timeout -= min(timeout, dwElapsed);
1143 } while(timeout > 0);
5039dede
AK
1144#else
1145 FD_ZERO(&rdfs);
5e60b759 1146 FD_SET(hSocket, &rdfs);
5039dede 1147#ifdef _WIN32
5e60b759
VK
1148 tv.tv_sec = timeout / 1000;
1149 tv.tv_usec = (timeout % 1000) * 1000;
1150 iErr = select(SELECT_NFDS(hSocket + 1), &rdfs, NULL, NULL, &tv);
5039dede
AK
1151#else
1152 do
1153 {
5e60b759
VK
1154 tv.tv_sec = timeout / 1000;
1155 tv.tv_usec = (timeout % 1000) * 1000;
5039dede 1156 qwStartTime = GetCurrentTimeMs();
5e60b759 1157 iErr = select(SELECT_NFDS(hSocket + 1), &rdfs, NULL, NULL, &tv);
5039dede
AK
1158 if ((iErr != -1) || (errno != EINTR))
1159 break;
1160 dwElapsed = GetCurrentTimeMs() - qwStartTime;
5e60b759
VK
1161 timeout -= min(timeout, dwElapsed);
1162 } while(timeout > 0);
5039dede
AK
1163#endif
1164#endif
1165 if (iErr > 0)
1166 {
1167#ifdef _WIN32
5e60b759 1168 iErr = recv(hSocket, (char *)data, (int)len, flags);
5039dede
AK
1169#else
1170 do
1171 {
5e60b759 1172 iErr = recv(hSocket, (char *)data, len, flags);
5039dede
AK
1173 } while((iErr == -1) && (errno == EINTR));
1174#endif
1175 }
1176 else
1177 {
1178 iErr = -2;
1179 }
1180 }
1181 else
1182 {
1183#ifdef _WIN32
5e60b759 1184 iErr = recv(hSocket, (char *)data, (int)len, flags);
5039dede
AK
1185#else
1186 do
1187 {
5e60b759 1188 iErr = recv(hSocket, (char *)data, (int)len, flags);
5039dede
AK
1189 } while((iErr == -1) && (errno == EINTR));
1190#endif
1191 }
1192
1193 return iErr;
1194}
1195
5e60b759 1196/**
18c575eb
VK
1197 * Read exact number of bytes from socket
1198 */
1199bool RecvAll(SOCKET s, void *buffer, size_t size, UINT32 timeout)
1200{
1201 size_t bytes = 0;
1202 char *pos = (char *)buffer;
1203 while(bytes < size)
1204 {
1205 int b = RecvEx(s, pos, size - bytes, 0, timeout);
1206 if (b <= 0)
1207 return false;
1208 bytes += b;
1209 pos += b;
1210 }
1211 return true;
1212}
1213
1214/**
5e60b759
VK
1215 * Connect with given timeout
1216 * Sets socket to non-blocking mode
1217 */
967893bb 1218int LIBNETXMS_EXPORTABLE ConnectEx(SOCKET s, struct sockaddr *addr, int len, UINT32 timeout)
7c521895
VK
1219{
1220 SetSocketNonBlocking(s);
1ddf3f0c 1221
7c521895
VK
1222 int rc = connect(s, addr, len);
1223 if (rc == -1)
1224 {
1225 if ((WSAGetLastError() == WSAEWOULDBLOCK) || (WSAGetLastError() == WSAEINPROGRESS))
1226 {
1227#ifndef _WIN32
1228 QWORD qwStartTime;
967893bb 1229 UINT32 dwElapsed;
7c521895
VK
1230#endif
1231
1232#if HAVE_POLL
1233 struct pollfd fds;
1234
1235 fds.fd = s;
1236 fds.events = POLLOUT;
1237 fds.revents = POLLOUT;
1238 do
1239 {
1240 qwStartTime = GetCurrentTimeMs();
13a69acd 1241 rc = poll(&fds, 1, timeout);
7c521895
VK
1242 if ((rc != -1) || (errno != EINTR))
1243 break;
1244 dwElapsed = GetCurrentTimeMs() - qwStartTime;
1245 timeout -= min(timeout, dwElapsed);
1246 } while(timeout > 0);
fd57e1e6
AK
1247
1248 if (rc > 0)
1249 {
1250 if (fds.revents == POLLOUT)
1251 {
1252 rc = 0;
1253 }
1254 else
1255 {
1256 rc = -1;
1257 }
1258 }
1259 else if (rc == 0) // timeout, return error
1260 {
1261 rc = -1;
1262 }
7c521895
VK
1263#else
1264 struct timeval tv;
1ddf3f0c 1265 fd_set wrfs, exfs;
7c521895
VK
1266
1267 FD_ZERO(&wrfs);
1268 FD_SET(s, &wrfs);
1ddf3f0c
VK
1269
1270 FD_ZERO(&exfs);
1271 FD_SET(s, &exfs);
1272
7c521895
VK
1273#ifdef _WIN32
1274 tv.tv_sec = timeout / 1000;
1275 tv.tv_usec = (timeout % 1000) * 1000;
1ddf3f0c 1276 rc = select(SELECT_NFDS(s + 1), NULL, &wrfs, &exfs, &tv);
7c521895
VK
1277#else
1278 do
1279 {
1280 tv.tv_sec = timeout / 1000;
1281 tv.tv_usec = (timeout % 1000) * 1000;
1282 qwStartTime = GetCurrentTimeMs();
1ddf3f0c 1283 rc = select(SELECT_NFDS(s + 1), NULL, &wrfs, &exfs, &tv);
7c521895
VK
1284 if ((rc != -1) || (errno != EINTR))
1285 break;
1286 dwElapsed = GetCurrentTimeMs() - qwStartTime;
1287 timeout -= min(timeout, dwElapsed);
1288 } while(timeout > 0);
1289#endif
1ddf3f0c
VK
1290 if (rc > 0)
1291 {
94b0e4b0
VK
1292 if (FD_ISSET(s, &exfs))
1293 {
1294#ifdef _WIN32
1295 int err, len = sizeof(int);
1296 if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char *)&err, &len) == 0)
1297 WSASetLastError(err);
1298#endif
1299 rc = -1;
1300 }
1301 else
1302 {
1303 rc = 0;
1304 }
1ddf3f0c
VK
1305 }
1306 else if (rc == 0) // timeout, return error
1307 {
7c521895 1308 rc = -1;
94b0e4b0
VK
1309#ifdef _WIN32
1310 WSASetLastError(WSAETIMEDOUT);
1311#endif
1ddf3f0c 1312 }
fd57e1e6 1313#endif
7c521895
VK
1314 }
1315 }
1316 return rc;
1317}
1318
22d657d2 1319/**
b42c9187
VK
1320 * Connect to given host/port
1321 *
1322 * @return connected socket on success or INVALID_SOCKET on error
1323 */
1324SOCKET LIBNETXMS_EXPORTABLE ConnectToHost(const InetAddress& addr, UINT16 port, UINT32 timeout)
1325{
1326 SOCKET s = socket(addr.getFamily(), SOCK_STREAM, 0);
1327 if (s == INVALID_SOCKET)
1328 return INVALID_SOCKET;
1329
1330 SockAddrBuffer saBuffer;
1331 struct sockaddr *sa = addr.fillSockAddr(&saBuffer, port);
1332 if (ConnectEx(s, sa, SA_LEN(sa), timeout) == -1)
1333 {
1334 closesocket(s);
1335 s = INVALID_SOCKET;
1336 }
1337 return s;
1338}
1339
1340/**
cfe20cce 1341 * Resolve host name to IP address (UNICODE version)
22d657d2 1342 *
cfe20cce 1343 * @param name host name or IP address
22d657d2
VK
1344 * @return IP address in network byte order
1345 */
cfe20cce 1346UINT32 LIBNETXMS_EXPORTABLE ResolveHostNameW(const WCHAR *name)
5039dede 1347{
cfe20cce
VK
1348 char mbName[256];
1349 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, name, -1, mbName, 256, NULL, NULL);
1350 return ResolveHostNameA(mbName);
5039dede
AK
1351}
1352
cfe20cce
VK
1353/**
1354 * Resolve host name to IP address (multibyte version)
1355 *
1356 * @param name host name or IP address
1357 * @return IP address in network byte order
1358 */
1359UINT32 LIBNETXMS_EXPORTABLE ResolveHostNameA(const char *name)
08b214c6 1360{
17cfa4f1
VK
1361 UINT32 addr = inet_addr(name);
1362 if ((addr == INADDR_NONE) || (addr == INADDR_ANY))
08b214c6 1363 {
17cfa4f1
VK
1364#if HAVE_GETHOSTBYNAME2_R
1365 struct hostent h, *hs = NULL;
1366 char buffer[1024];
1367 int err;
1368 gethostbyname2_r(name, AF_INET, &h, buffer, 1024, &hs, &err);
1369#else
1370 struct hostent *hs = gethostbyname(name);
1371#endif
08b214c6
VK
1372 if (hs != NULL)
1373 {
17cfa4f1 1374 memcpy(&addr, hs->h_addr, sizeof(UINT32));
08b214c6
VK
1375 }
1376 else
1377 {
17cfa4f1 1378 addr = INADDR_NONE;
08b214c6
VK
1379 }
1380 }
1381
17cfa4f1 1382 return addr;
08b214c6
VK
1383}
1384
5039dede
AK
1385#ifndef VER_PLATFORM_WIN32_WINDOWS
1386#define VER_PLATFORM_WIN32_WINDOWS 1
1387#endif
1388#ifndef VER_PLATFORM_WIN32_CE
1389#define VER_PLATFORM_WIN32_CE 3
1390#endif
6d738067
VK
1391#ifndef SM_SERVERR2
1392#define SM_SERVERR2 89
1393#endif
1394
5e60b759
VK
1395/**
1396 * Get OS name and version
1397 */
5039dede
AK
1398void LIBNETXMS_EXPORTABLE GetOSVersionString(TCHAR *pszBuffer, int nBufSize)
1399{
1400 int nSize = nBufSize - 1;
1401
1402 memset(pszBuffer, 0, nBufSize * sizeof(TCHAR));
1403
1404#if defined(_WIN32)
1405 OSVERSIONINFO ver;
1406
1407 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
1408 GetVersionEx(&ver);
1409 switch(ver.dwPlatformId)
1410 {
1411 case VER_PLATFORM_WIN32_WINDOWS:
1412 _sntprintf(pszBuffer, nSize, _T("Win%s"), ver.dwMinorVersion == 0 ? _T("95") :
1413 (ver.dwMinorVersion == 10 ? _T("98") :
1414 (ver.dwMinorVersion == 90 ? _T("Me") : _T("9x"))));
1415 break;
1416 case VER_PLATFORM_WIN32_NT:
1417 _sntprintf(pszBuffer, nSize, _T("WinNT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
1418 break;
1419#ifdef VER_PLATFORM_WIN32_CE
1420 case VER_PLATFORM_WIN32_CE:
1421 _sntprintf(pszBuffer, nSize, _T("WinCE %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
1422 break;
1423#endif
1424 default:
1425 _sntprintf(pszBuffer, nSize, _T("WinX %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
1426 break;
1427 }
1428#elif defined(_NETWARE)
1429 struct utsname un;
1430
1431 uname(&un);
1432 _sntprintf(pszBuffer, nSize, _T("NetWare %d.%d"), un.netware_major, un.netware_minor);
1433 if (un.servicepack > 0)
1434 {
1435 int nLen = (int)_tcslen(pszBuffer);
1436 nSize -= nLen;
1437 if (nSize > 0)
1438 _sntprintf(&pszBuffer[nLen], nSize, _T(" sp%d"), un.servicepack);
1439 }
1440#else
1441 struct utsname un;
1442
1443 uname(&un);
1444#ifdef UNICODE
1445 char buf[1024];
1446 snprintf(buf, 1024, "%s %s", un.sysname, un.release);
1447 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, buf, -1, pszBuffer, nSize);
1448#else
1449 snprintf(pszBuffer, nSize, "%s %s", un.sysname, un.release);
1450#endif
1451#endif
1452}
1453
6d738067
VK
1454#ifdef _WIN32
1455
6d74c7b7
VK
1456/**
1457 * Get more specific Windows version string
1458 */
6d738067
VK
1459BOOL LIBNETXMS_EXPORTABLE GetWindowsVersionString(TCHAR *versionString, int strSize)
1460{
1461 OSVERSIONINFOEX ver;
1462 TCHAR buffer[256];
1463
1464 ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1465 if (!GetVersionEx((OSVERSIONINFO *)&ver))
1466 return FALSE;
1467
1468 switch(ver.dwMajorVersion)
1469 {
1470 case 5:
1471 switch(ver.dwMinorVersion)
1472 {
1473 case 0:
1474 _tcscpy(buffer, _T("2000"));
1475 break;
1476 case 1:
1477 _tcscpy(buffer, _T("XP"));
1478 break;
1479 case 2:
1480 _tcscpy(buffer, (GetSystemMetrics(SM_SERVERR2) != 0) ? _T("Server 2003 R2") : _T("Server 2003"));
1481 break;
1482 default:
1483 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
1484 break;
1485 }
1486 break;
1487 case 6:
1488 switch(ver.dwMinorVersion)
1489 {
1490 case 0:
1491 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("Vista") : _T("Server 2008"));
1492 break;
1493 case 1:
1494 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("7") : _T("Server 2008 R2"));
1495 break;
6d74c7b7
VK
1496 case 2:
1497 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("8") : _T("Server 2012"));
1498 break;
1499 case 3:
1500 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("8.1") : _T("Server 2012 R2"));
1501 break;
6d738067
VK
1502 default:
1503 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
b2556fa8
VK
1504 break;
1505 }
1506 break;
1507 case 10:
1508 switch(ver.dwMinorVersion)
1509 {
1510 case 0:
1511 _tcscpy(buffer, (ver.wProductType == VER_NT_WORKSTATION) ? _T("10") : _T("Server"));
1512 break;
1513 default:
1514 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
6d738067
VK
1515 break;
1516 }
1517 break;
1518 default:
1519 _sntprintf(buffer, 256, _T("NT %d.%d"), ver.dwMajorVersion, ver.dwMinorVersion);
1520 break;
1521 }
1522
1523 _sntprintf(versionString, strSize, _T("Windows %s Build %d %s"), buffer, ver.dwBuildNumber, ver.szCSDVersion);
1524 StrStrip(versionString);
1525 return TRUE;
1526}
1527
1528#endif
1529
1530
1531//
5039dede
AK
1532// Count number of characters in string
1533//
1534
3583a400 1535int LIBNETXMS_EXPORTABLE NumCharsW(const WCHAR *pszStr, WCHAR ch)
5039dede 1536{
3583a400
VK
1537 const WCHAR *p;
1538 int nCount;
1539
1540 for(p = pszStr, nCount = 0; *p != 0; p++)
1541 if (*p == ch)
1542 nCount++;
1543 return nCount;
1544}
1545
1546int LIBNETXMS_EXPORTABLE NumCharsA(const char *pszStr, char ch)
1547{
1548 const char *p;
5039dede
AK
1549 int nCount;
1550
1551 for(p = pszStr, nCount = 0; *p != 0; p++)
1552 if (*p == ch)
1553 nCount++;
1554 return nCount;
1555}
1556
4893b4aa
VK
1557/**
1558 * Match string against regexp (UNICODE version)
1559 */
1560BOOL LIBNETXMS_EXPORTABLE RegexpMatchW(const WCHAR *str, const WCHAR *expr, bool matchCase)
5039dede 1561{
5039dede 1562 regex_t preg;
4893b4aa 1563 bool result = false;
5039dede 1564
4893b4aa 1565 if (tre_regwcomp(&preg, expr, matchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
5039dede 1566 {
4893b4aa
VK
1567 if (tre_regwexec(&preg, str, 0, NULL, 0) == 0) // MATCH
1568 result = true;
cafe592d
VK
1569 regfree(&preg);
1570 }
1571
4893b4aa 1572 return result;
cafe592d
VK
1573}
1574
4893b4aa
VK
1575/**
1576 * Match string against regexp (multibyte version)
1577 */
1578BOOL LIBNETXMS_EXPORTABLE RegexpMatchA(const char *str, const char *expr, bool matchCase)
cafe592d
VK
1579{
1580 regex_t preg;
4893b4aa 1581 bool result = false;
cafe592d 1582
4893b4aa 1583 if (tre_regcomp(&preg, expr, matchCase ? REG_EXTENDED | REG_NOSUB : REG_EXTENDED | REG_NOSUB | REG_ICASE) == 0)
cafe592d 1584 {
4893b4aa
VK
1585 if (tre_regexec(&preg, str, 0, NULL, 0) == 0) // MATCH
1586 result = true;
5039dede
AK
1587 regfree(&preg);
1588 }
1589
4893b4aa 1590 return result;
5039dede
AK
1591}
1592
4893b4aa
VK
1593/**
1594 * Translate given code to text
1595 */
5039dede
AK
1596const TCHAR LIBNETXMS_EXPORTABLE *CodeToText(int iCode, CODE_TO_TEXT *pTranslator, const TCHAR *pszDefaultText)
1597{
1598 int i;
1599
1600 for(i = 0; pTranslator[i].text != NULL; i++)
1601 if (pTranslator[i].code == iCode)
1602 return pTranslator[i].text;
1603 return pszDefaultText;
1604}
1605
289d126b
VK
1606/**
1607 * Extract option value from string of form option=value;option=value;... (UNICODE version)
1608 */
1609bool LIBNETXMS_EXPORTABLE ExtractNamedOptionValueW(const WCHAR *optString, const WCHAR *option, WCHAR *buffer, int bufSize)
1610{
1611 int state, pos;
1612 const WCHAR *curr, *start;
1613 WCHAR temp[256];
5039dede 1614
289d126b
VK
1615 for(curr = start = optString, pos = 0, state = 0; *curr != 0; curr++)
1616 {
1617 switch(*curr)
1618 {
1619 case L';': // Next option
1620 if (state == 1)
1621 {
1622 buffer[pos] = 0;
1623 StrStripW(buffer);
1624 return true;
1625 }
1626 state = 0;
1627 start = curr + 1;
1628 break;
1629 case L'=':
1630 if (state == 0)
1631 {
1632 wcsncpy(temp, start, curr - start);
1633 temp[curr - start] = 0;
1634 StrStripW(temp);
1635 if (!wcsicmp(option, temp))
1636 state = 1;
1637 else
1638 state = 2;
1639 }
1640 else if ((state == 1) && (pos < bufSize - 1))
1641 {
1642 buffer[pos++] = L'=';
1643 }
1644 break;
1645 default:
1646 if ((state == 1) && (pos < bufSize - 1))
1647 buffer[pos++] = *curr;
1648 break;
1649 }
1650 }
bac74bf7 1651
289d126b
VK
1652 if (state == 1)
1653 {
1654 buffer[pos] = 0;
1655 StrStripW(buffer);
1656 return true;
1657 }
bac74bf7 1658
289d126b
VK
1659 return false;
1660}
5039dede 1661
289d126b
VK
1662/**
1663 * Extract option value from string of form option=value;option=value;... (multibyte version)
1664 */
1665bool LIBNETXMS_EXPORTABLE ExtractNamedOptionValueA(const char *optString, const char *option, char *buffer, int bufSize)
5039dede
AK
1666{
1667 int state, pos;
289d126b
VK
1668 const char *curr, *start;
1669 char temp[256];
5039dede
AK
1670
1671 for(curr = start = optString, pos = 0, state = 0; *curr != 0; curr++)
1672 {
1673 switch(*curr)
1674 {
289d126b 1675 case ';': // Next option
5039dede
AK
1676 if (state == 1)
1677 {
1678 buffer[pos] = 0;
289d126b
VK
1679 StrStripA(buffer);
1680 return true;
5039dede
AK
1681 }
1682 state = 0;
1683 start = curr + 1;
1684 break;
289d126b 1685 case '=':
5039dede
AK
1686 if (state == 0)
1687 {
289d126b 1688 strncpy(temp, start, curr - start);
5039dede 1689 temp[curr - start] = 0;
289d126b
VK
1690 StrStripA(temp);
1691 if (!stricmp(option, temp))
5039dede
AK
1692 state = 1;
1693 else
1694 state = 2;
1695 }
1696 else if ((state == 1) && (pos < bufSize - 1))
1697 {
289d126b 1698 buffer[pos++] = '=';
5039dede
AK
1699 }
1700 break;
1701 default:
1702 if ((state == 1) && (pos < bufSize - 1))
1703 buffer[pos++] = *curr;
1704 break;
1705 }
1706 }
bac74bf7 1707
5039dede
AK
1708 if (state == 1)
1709 {
1710 buffer[pos] = 0;
289d126b
VK
1711 StrStripA(buffer);
1712 return true;
5039dede 1713 }
bac74bf7 1714
289d126b 1715 return false;
5039dede
AK
1716}
1717
289d126b
VK
1718/**
1719 * Extract named option value as boolean (UNICODE version)
1720 */
1721bool LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsBoolW(const WCHAR *optString, const WCHAR *option, bool defVal)
5039dede 1722{
289d126b
VK
1723 WCHAR buffer[256];
1724 if (ExtractNamedOptionValueW(optString, option, buffer, 256))
1725 return !wcsicmp(buffer, L"yes") || !wcsicmp(buffer, L"true");
1726 return defVal;
1727}
1728
1729/**
1730 * Extract named option value as boolean (multibyte version)
1731 */
1732bool LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsBoolA(const char *optString, const char *option, bool defVal)
1733{
1734 char buffer[256];
1735 if (ExtractNamedOptionValueA(optString, option, buffer, 256))
1736 return !stricmp(buffer, "yes") || !stricmp(buffer, "true");
1737 return defVal;
1738}
1739
1740/**
1741 * Extract named option value as integer (UNICODE version)
1742 */
1743long LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsIntW(const WCHAR *optString, const WCHAR *option, long defVal)
1744{
1745 WCHAR buffer[256], *eptr;
1746 long val;
1747
1748 if (ExtractNamedOptionValueW(optString, option, buffer, 256))
5039dede 1749 {
289d126b
VK
1750 val = wcstol(buffer, &eptr, 0);
1751 if (*eptr == 0)
1752 return val;
5039dede
AK
1753 }
1754 return defVal;
1755}
1756
289d126b
VK
1757/**
1758 * Extract named option value as integer (multibyte version)
1759 */
1760long LIBNETXMS_EXPORTABLE ExtractNamedOptionValueAsIntA(const char *optString, const char *option, long defVal)
5039dede 1761{
289d126b 1762 char buffer[256], *eptr;
5039dede
AK
1763 long val;
1764
289d126b 1765 if (ExtractNamedOptionValueA(optString, option, buffer, 256))
5039dede 1766 {
289d126b 1767 val = strtol(buffer, &eptr, 0);
5039dede
AK
1768 if (*eptr == 0)
1769 return val;
1770 }
1771 return defVal;
1772}
1773
22aaa779
VK
1774/**
1775 * Split string
1776 */
f3cdd1c5
VK
1777TCHAR LIBNETXMS_EXPORTABLE **SplitString(const TCHAR *source, TCHAR sep, int *numStrings)
1778{
1779 TCHAR **strings;
1780
1781 *numStrings = NumChars(source, sep) + 1;
1782 strings = (TCHAR **)malloc(sizeof(TCHAR *) * (*numStrings));
1783 for(int n = 0, i = 0; n < *numStrings; n++, i++)
1784 {
1785 int start = i;
1786 while((source[i] != sep) && (source[i] != 0))
1787 i++;
1788 int len = i - start;
1789 strings[n] = (TCHAR *)malloc(sizeof(TCHAR) * (len + 1));
1790 memcpy(strings[n], &source[start], len * sizeof(TCHAR));
1791 strings[n][len] = 0;
1792 }
1793 return strings;
1794}
1795
f2436b76 1796/**
0a145c10 1797 * Get step size for "%" and "/" crontab cases
1798 */
1799static int GetStepSize(TCHAR *str)
1800{
1801 int step = 0;
1802 if (str != NULL)
1803 {
1804 *str = 0;
1805 str++;
1806 step = *str == _T('\0') ? 1 : _tcstol(str, NULL, 10);
1807 }
1808
1809 if (step <= 0)
1810 {
1811 step = 1;
1812 }
1813
1814 return step;
1815}
1816
1817/**
1818 * Get last day of current month
1819 */
1820int LIBNETXMS_EXPORTABLE GetLastMonthDay(struct tm *currTime)
1821{
1822 switch(currTime->tm_mon)
1823 {
1824 case 1: // February
1825 if (((currTime->tm_year % 4) == 0) && (((currTime->tm_year % 100) != 0) || (((currTime->tm_year + 1900) % 400) == 0)))
1826 return 29;
1827 return 28;
1828 case 0: // January
1829 case 2: // March
1830 case 4: // May
1831 case 6: // July
1832 case 7: // August
1833 case 9: // October
1834 case 11: // December
1835 return 31;
1836 default:
1837 return 30;
1838 }
1839}
1840
1841/**
1842 * Match schedule element
1843 * NOTE: We assume that pattern can be modified during processing
1844 */
1845bool LIBNETXMS_EXPORTABLE MatchScheduleElement(TCHAR *pszPattern, int nValue, int maxValue, struct tm *localTime, time_t currTime)
1846{
1847 TCHAR *ptr, *curr;
1848 int nStep, nCurr, nPrev;
1849 bool bRun = true, bRange = false;
1850
1851 // Check for "last" pattern
1852 if (*pszPattern == _T('L'))
1853 return nValue == maxValue;
1854
1855 // Check if time() step was specified (% - special syntax)
1856 ptr = _tcschr(pszPattern, _T('%'));
1857 if (ptr != NULL)
1858 return (currTime % GetStepSize(ptr)) != 0;
1859
1860 // Check if step was specified
1861 ptr = _tcschr(pszPattern, _T('/'));
1862 nStep = GetStepSize(ptr);
1863
1864 if (*pszPattern == _T('*'))
1865 goto check_step;
1866
1867 for(curr = pszPattern; bRun; curr = ptr + 1)
1868 {
1869 for(ptr = curr; (*ptr != 0) && (*ptr != '-') && (*ptr != ','); ptr++);
1870 switch(*ptr)
1871 {
1872 case '-':
1873 if (bRange)
1874 return false; // Form like 1-2-3 is invalid
1875 bRange = true;
1876 *ptr = 0;
1877 nPrev = _tcstol(curr, NULL, 10);
1878 break;
1879 case 'L': // special case for last day ow week in a month (like 5L - last Friday)
1880 if (bRange || (localTime == NULL))
1881 return false; // Range with L is not supported; nL form supported only for day of week
1882 *ptr = 0;
1883 nCurr = _tcstol(curr, NULL, 10);
1884 if ((nValue == nCurr) && (localTime->tm_mday + 7 > GetLastMonthDay(localTime)))
1885 return true;
1886 ptr++;
1887 if (*ptr != ',')
1888 bRun = false;
1889 break;
1890 case 0:
1891 bRun = false;
1892 /* no break */
1893 case ',':
1894 *ptr = 0;
1895 nCurr = _tcstol(curr, NULL, 10);
1896 if (bRange)
1897 {
1898 if ((nValue >= nPrev) && (nValue <= nCurr))
1899 goto check_step;
1900 bRange = false;
1901 }
1902 else
1903 {
1904 if (nValue == nCurr)
1905 return true;
1906 }
1907 break;
1908 }
1909 }
1910
1911 return false;
1912
1913check_step:
1914 return (nValue % nStep) == 0;
1915}
1916
1917/**
f2436b76
VK
1918 * Failure handler for DecryptPassword
1919 */
1920inline bool DecryptPasswordFail(const TCHAR *encryptedPasswd, TCHAR *decryptedPasswd, size_t bufferLenght)
07ca7d19 1921{
f2436b76
VK
1922 if (decryptedPasswd != encryptedPasswd)
1923 nx_strncpy(decryptedPasswd, encryptedPasswd, bufferLenght);
1924 return false;
07ca7d19 1925}
1926
0b80fccb 1927/**
07ca7d19 1928 * Decrypt password encrypted with nxencpassw.
1929 * In case when it was not possible to decrypt password as the decrypted password will be set the original one.
1930 * The buffer length for encryptedPasswd and decryptedPasswd should be the same.
0b80fccb 1931 */
f2436b76 1932bool LIBNETXMS_EXPORTABLE DecryptPassword(const TCHAR *login, const TCHAR *encryptedPasswd, TCHAR *decryptedPasswd, size_t bufferLenght)
6b1282e7 1933{
07ca7d19 1934 //check that lenght is correct
6b1282e7 1935 if (_tcslen(encryptedPasswd) != 44)
07ca7d19 1936 return DecryptPasswordFail(encryptedPasswd, decryptedPasswd, bufferLenght);
1937
5f5cb134
VK
1938 // check that password contains only allowed symbols
1939 int invalidSymbolIndex = (int)_tcsspn(encryptedPasswd, _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"));
1940 if ((invalidSymbolIndex < 42) || ((invalidSymbolIndex != 44) && ((encryptedPasswd[invalidSymbolIndex] != _T('=')) || ((invalidSymbolIndex == 42) && (encryptedPasswd[43] != _T('='))))))
07ca7d19 1941 return DecryptPasswordFail(encryptedPasswd, decryptedPasswd, bufferLenght);
6b1282e7
VK
1942
1943#ifdef UNICODE
1944 char *mbencrypted = MBStringFromWideString(encryptedPasswd);
1945 char *mblogin = MBStringFromWideString(login);
1946#else
1947 const char *mbencrypted = encryptedPasswd;
1948 const char *mblogin = login;
1949#endif
1950
1951 BYTE encrypted[32], decrypted[32], key[16];
0b80fccb 1952 size_t encSize = 32;
6b1282e7
VK
1953 base64_decode(mbencrypted, strlen(mbencrypted), (char *)encrypted, &encSize);
1954 if (encSize != 32)
07ca7d19 1955 return DecryptPasswordFail(encryptedPasswd, decryptedPasswd, bufferLenght);
6b1282e7
VK
1956
1957 CalculateMD5Hash((BYTE *)mblogin, strlen(mblogin), key);
1958 ICEDecryptData(encrypted, 32, decrypted, key);
1959 decrypted[31] = 0;
bac74bf7 1960
6b1282e7 1961#ifdef UNICODE
5f5cb134 1962 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, (char *)decrypted, -1, decryptedPasswd, (int)bufferLenght);
f2436b76 1963 decryptedPasswd[bufferLenght - 1] = 0;
6b1282e7
VK
1964 free(mbencrypted);
1965 free(mblogin);
1966#else
f2436b76 1967 nx_strncpy(decryptedPasswd, (char *)decrypted, bufferLenght);
6b1282e7
VK
1968#endif
1969
f2436b76 1970 return true;
6b1282e7
VK
1971}
1972
5039dede
AK
1973#ifndef UNDER_CE
1974
0b80fccb
VK
1975/**
1976 * Load file content into memory
1977 */
967893bb 1978static BYTE *LoadFileContent(int fd, UINT32 *pdwFileSize)
5039dede 1979{
08b214c6 1980 int iBufPos, iNumBytes, iBytesRead;
5039dede
AK
1981 BYTE *pBuffer = NULL;
1982 struct stat fs;
1983
08b214c6 1984 if (fstat(fd, &fs) != -1)
5039dede 1985 {
08b214c6
VK
1986 pBuffer = (BYTE *)malloc(fs.st_size + 1);
1987 if (pBuffer != NULL)
5039dede 1988 {
08b214c6
VK
1989 *pdwFileSize = fs.st_size;
1990 for(iBufPos = 0; iBufPos < fs.st_size; iBufPos += iBytesRead)
5039dede 1991 {
08b214c6
VK
1992 iNumBytes = min(16384, fs.st_size - iBufPos);
1993 if ((iBytesRead = read(fd, &pBuffer[iBufPos], iNumBytes)) < 0)
5039dede 1994 {
08b214c6
VK
1995 free(pBuffer);
1996 pBuffer = NULL;
1997 break;
5039dede
AK
1998 }
1999 }
926c5e72
VK
2000 if (pBuffer != NULL)
2001 pBuffer[fs.st_size] = 0;
5039dede 2002 }
08b214c6
VK
2003 }
2004 close(fd);
2005 return pBuffer;
2006}
2007
967893bb 2008BYTE LIBNETXMS_EXPORTABLE *LoadFile(const TCHAR *pszFileName, UINT32 *pdwFileSize)
08b214c6
VK
2009{
2010 int fd;
2011 BYTE *pBuffer = NULL;
2012
2013 fd = _topen(pszFileName, O_RDONLY | O_BINARY);
2014 if (fd != -1)
2015 {
2016 pBuffer = LoadFileContent(fd, pdwFileSize);
5039dede
AK
2017 }
2018 return pBuffer;
2019}
2020
08b214c6
VK
2021#ifdef UNICODE
2022
967893bb 2023BYTE LIBNETXMS_EXPORTABLE *LoadFileA(const char *pszFileName, UINT32 *pdwFileSize)
08b214c6
VK
2024{
2025 int fd;
2026 BYTE *pBuffer = NULL;
2027
2028#ifdef _WIN32
2029 fd = _open(pszFileName, O_RDONLY | O_BINARY);
2030#else
2031 fd = open(pszFileName, O_RDONLY | O_BINARY);
2032#endif
2033 if (fd != -1)
2034 {
926c5e72 2035 pBuffer = LoadFileContent(fd, pdwFileSize);
08b214c6
VK
2036 }
2037 return pBuffer;
2038}
2039
2040#endif
2041
5039dede
AK
2042#endif
2043
11606542
VK
2044#ifdef _WIN32
2045
a65409fe
VK
2046/**
2047 * Get memory consumed by current process
2048 */
11606542
VK
2049INT64 LIBNETXMS_EXPORTABLE GetProcessRSS()
2050{
2051 PROCESS_MEMORY_COUNTERS pmc;
2052
2053 if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc)))
2054 return pmc.WorkingSetSize;
2055 return 0;
2056}
2057
a65409fe
VK
2058#define BG_MASK 0xF0
2059#define FG_MASK 0x0F
f669df41 2060
f375019e
VK
2061/**
2062 * Apply terminal attributes to console - Win32 API specific
2063 */
f669df41
VK
2064static WORD ApplyTerminalAttribute(HANDLE out, WORD currAttr, long code)
2065{
2066 WORD attr = currAttr;
2067 switch(code)
2068 {
2069 case 0: // reset attribute
2070 attr = 0x07;
2071 break;
2072 case 1: // bold/bright
2073 attr = currAttr | FOREGROUND_INTENSITY;
2074 break;
2075 case 22: // normal color
2076 attr = currAttr & ~FOREGROUND_INTENSITY;
2077 break;
2078 case 30: // black foreground
2079 attr = (currAttr & BG_MASK);
2080 break;
2081 case 31: // red foreground
2082 attr = (currAttr & BG_MASK) | 0x04;
2083 break;
2084 case 32: // green foreground
2085 attr = (currAttr & BG_MASK) | 0x02;
2086 break;
2087 case 33: // yellow foreground
2088 attr = (currAttr & BG_MASK) | 0x06;
2089 break;
2090 case 34: // blue foreground
2091 attr = (currAttr & BG_MASK) | 0x01;
2092 break;
2093 case 35: // magenta foreground
2094 attr = (currAttr & BG_MASK) | 0x05;
2095 break;
2096 case 36: // cyan foreground
2097 attr = (currAttr & BG_MASK) | 0x03;
2098 break;
2099 case 37: // white (gray) foreground
2100 attr = (currAttr & BG_MASK) | 0x07;
2101 break;
2102 case 40: // black background
2103 attr = (currAttr & FG_MASK);
2104 break;
2105 case 41: // red background
2106 attr = (currAttr & FG_MASK) | 0x40;
2107 break;
2108 case 42: // green background
2109 attr = (currAttr & FG_MASK) | 0x20;
2110 break;
2111 case 43: // yellow background
2112 attr = (currAttr & FG_MASK) | 0x60;
2113 break;
2114 case 44: // blue background
2115 attr = (currAttr & FG_MASK) | 0x10;
2116 break;
2117 case 45: // magenta background
2118 attr = (currAttr & FG_MASK) | 0x50;
2119 break;
2120 case 46: // cyan background
2121 attr = (currAttr & FG_MASK) | 0x30;
2122 break;
2123 case 47: // white (gray) background
2124 attr = (currAttr & FG_MASK) | 0x70;
2125 break;
2126 default:
2127 break;
2128 }
2129 SetConsoleTextAttribute(out, attr);
2130 return attr;
2131}
2132
2133#endif
2134
f375019e
VK
2135/**
2136 * Write to terminal with support for ANSI color codes
2137 */
f669df41
VK
2138void LIBNETXMS_EXPORTABLE WriteToTerminal(const TCHAR *text)
2139{
2140#ifdef _WIN32
2141 HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
2142
3993eba0
VK
2143 DWORD mode;
2144 if (!GetConsoleMode(out, &mode))
2145 {
2146 // Assume output is redirected
2147#ifdef UNICODE
2148 char *mbText = MBStringFromWideString(text);
967893bb 2149 WriteFile(out, mbText, (UINT32)strlen(mbText), &mode, NULL);
3993eba0
VK
2150 free(mbText);
2151#else
967893bb 2152 WriteFile(out, text, (UINT32)strlen(text), &mode, NULL);
3993eba0
VK
2153#endif
2154 return;
2155 }
2156
f669df41
VK
2157 CONSOLE_SCREEN_BUFFER_INFO csbi;
2158 GetConsoleScreenBufferInfo(out, &csbi);
bac74bf7 2159
f669df41
VK
2160 const TCHAR *curr = text;
2161 while(*curr != 0)
2162 {
2163 const TCHAR *esc = _tcschr(curr, 27); // Find ESC
2164 if (esc != NULL)
2165 {
2166 esc++;
2167 if (*esc == _T('['))
2168 {
2169 // write everything up to ESC char
2170 DWORD chars;
967893bb 2171 WriteConsole(out, curr, (UINT32)(esc - curr - 1), &chars, NULL);
f669df41
VK
2172
2173 esc++;
2174
2175 TCHAR code[64];
2176 int pos = 0;
2177 while((*esc != 0) && (*esc != _T('m')))
2178 {
2179 if (*esc == _T(';'))
2180 {
2181 code[pos] = 0;
2182 csbi.wAttributes = ApplyTerminalAttribute(out, csbi.wAttributes, _tcstol(code, NULL, 10));
2183 pos = 0;
2184 }
2185 else
2186 {
2187 if (pos < 63)
2188 code[pos++] = *esc;
2189 }
2190 esc++;
2191 }
2192 if (pos > 0)
2193 {
2194 code[pos] = 0;
2195 csbi.wAttributes = ApplyTerminalAttribute(out, csbi.wAttributes, _tcstol(code, NULL, 10));
2196 }
2197 esc++;
2198 }
2199 else
2200 {
2201 DWORD chars;
967893bb 2202 WriteConsole(out, curr, (UINT32)(esc - curr), &chars, NULL);
f669df41
VK
2203 }
2204 curr = esc;
2205 }
2206 else
2207 {
2208 DWORD chars;
967893bb 2209 WriteConsole(out, curr, (UINT32)_tcslen(curr), &chars, NULL);
f669df41
VK
2210 break;
2211 }
2212 }
2213#else
d7970ee7 2214#ifdef UNICODE
d6217efa
VK
2215#if HAVE_FPUTWS
2216 fputws(text, stdout);
2217#else
fe8ea784 2218 char *mbtext = MBStringFromWideStringSysLocale(text);
d7970ee7
VK
2219 fputs(mbtext, stdout);
2220 free(mbtext);
d6217efa 2221#endif
d7970ee7
VK
2222#else
2223 fputs(text, stdout);
2224#endif
f669df41
VK
2225#endif
2226}
2227
f375019e
VK
2228/**
2229 * Write to terminal with support for ANSI color codes
2230 */
f669df41
VK
2231void LIBNETXMS_EXPORTABLE WriteToTerminalEx(const TCHAR *format, ...)
2232{
2233 TCHAR buffer[8192];
2234 va_list args;
2235
2236 va_start(args, format);
2237 _vsntprintf(buffer, 8192, format, args);
2238 va_end(args);
2239 WriteToTerminal(buffer);
2240}
7f632dfe 2241
f375019e 2242/**
f375019e
VK
2243 * mkstemp() implementation for Windows
2244 */
37a7a862
VK
2245#ifdef _WIN32
2246
2247int LIBNETXMS_EXPORTABLE mkstemp(char *tmpl)
2248{
2249 char *name = _mktemp(tmpl);
2250 if (name == NULL)
2251 return -1;
2252 return _open(name, O_RDWR | O_BINARY | O_CREAT | O_EXCL| _O_SHORT_LIVED, _S_IREAD | _S_IWRITE);
2253}
2254
2255int LIBNETXMS_EXPORTABLE wmkstemp(WCHAR *tmpl)
2256{
2257 WCHAR *name = _wmktemp(tmpl);
2258 if (name == NULL)
2259 return -1;
2260 return _wopen(name, O_RDWR | O_BINARY | O_CREAT | O_EXCL| _O_SHORT_LIVED, _S_IREAD | _S_IWRITE);
2261}
2262
2263#endif
9b13553b 2264
9b13553b
VK
2265#ifndef _WIN32
2266
7785322f
VK
2267/**
2268 * strcat_s implementation
2269 */
9b13553b
VK
2270int LIBNETXMS_EXPORTABLE strcat_s(char *dst, size_t dstSize, const char *src)
2271{
2272 if (strlen(dst) + strlen(src) + 1 >= dstSize)
2273 return EINVAL;
2274 strcat(dst, src);
2275 return 0;
2276}
2277
7785322f
VK
2278/**
2279 * wcscat_s implementation
2280 */
9b13553b
VK
2281int LIBNETXMS_EXPORTABLE wcscat_s(WCHAR *dst, size_t dstSize, const WCHAR *src)
2282{
2283 if (wcslen(dst) + wcslen(src) + 1 >= dstSize)
2284 return EINVAL;
2285 wcscat(dst, src);
2286 return 0;
2287}
2288
2289#endif
b549a0f8
VK
2290
2291/**
2292 * Destructor for RefCountObject
2293 */
2294RefCountObject::~RefCountObject()
2295{
2296}
3bf0df9f
VK
2297
2298/**
2299 * Safe _fgetts implementation which will work
2300 * with handles opened by popen
2301 */
2302TCHAR LIBNETXMS_EXPORTABLE *safe_fgetts(TCHAR *buffer, int len, FILE *f)
2303{
2304#ifdef UNICODE
2305#if SAFE_FGETWS_WITH_POPEN
2306 return fgetws(buffer, len, f);
2307#else
2308 char *mbBuffer = (char *)alloca(len);
2309 char *s = fgets(mbBuffer, len, f);
2310 if (s == NULL)
2311 return NULL;
2312 mbBuffer[len - 1] = 0;
2313 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbBuffer, -1, buffer, len);
2314 return buffer;
2315#endif
2316#else
2317 return fgets(buffer, len, f);
2318#endif
2319}
fdf1ed50 2320
e8b3beef 2321#if !HAVE_WCSLWR && !defined(_WIN32)
fdf1ed50
VK
2322
2323/**
2324 * Convert UNICODE string to lowercase
2325 */
2326WCHAR LIBNETXMS_EXPORTABLE *wcslwr(WCHAR *str)
2327{
2328 for(WCHAR *p = str; *p != 0; p++)
2329 {
2330#if HAVE_TOWLOWER
2331 *p = towlower(*p);
2332#else
2333 if ((*p >= 'a') && (*p <= 'z'))
2334 *p = *p - ('a' - 'A');
2335#endif
2336 }
2337 return str;
2338}
2339
2340#endif
9138dfe2 2341
75b4d48e
VK
2342#if !defined(_WIN32) && (!HAVE_WCSFTIME || !WORKING_WCSFTIME)
2343
2344/**
2345 * wide char version of strftime
2346 */
2347size_t LIBNETXMS_EXPORTABLE nx_wcsftime(WCHAR *buffer, size_t bufsize, const WCHAR *format, const struct tm *t)
2348{
2349#if HAVE_ALLOCA
2350 char *mbuf = (char *)alloca(bufsize);
2351 size_t flen = wcslen(format) + 1;
2352 char *mfmt = (char *)alloca(flen);
2353 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, format, -1, mfmt, flen, NULL, NULL);
2354#else
2355 char *mbuf = (char *)malloc(bufsize);
2356 char *mfmt = MBStringFromWideString(format);
2357#endif
2358 size_t rc = strftime(mbuf, bufsize, mfmt, t);
2359 if (rc > 0)
2360 {
2361 MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, mbuf, -1, buffer, (int)bufsize);
2362 buffer[bufsize - 1] = 0;
2363 }
2364 else
2365 {
2366 buffer[0] = 0;
2367 }
2368#if !HAVE_ALLOCA
2369 free(mbuf);
2370 free(mfmt);
2371#endif
2372 return rc;
2373}
2374
2375#endif
2376
9138dfe2
VK
2377#if !HAVE__ITOA && !defined(_WIN32)
2378
2379/**
2380 * _itoa() implementation
2381 */
2382char LIBNETXMS_EXPORTABLE *_itoa(int value, char *str, int base)
2383{
2384 char *p = str;
2385 if (value < 0)
2386 {
2387 *p++ = '-';
2388 value = -value;
2389 }
420c9ff3 2390
9138dfe2
VK
2391 char buffer[64];
2392 char *t = buffer;
2393 do
2394 {
2395 int rem = value % base;
2396 *t++ = (rem < 10) ? (rem + '0') : (rem - 10 + 'a');
2397 value = value / base;
2398 } while(value > 0);
2399
2400 t--;
2401 while(t >= buffer)
2402 *p++ = *t--;
2403 *p = 0;
2404 return str;
2405}
2406
2407#endif
2408
2409#if !HAVE__ITOA && !defined(_WIN32)
2410
2411/**
2412 * _itow() implementation
2413 */
2414WCHAR LIBNETXMS_EXPORTABLE *_itow(int value, WCHAR *str, int base)
2415{
2416 WCHAR *p = str;
2417 if (value < 0)
2418 {
2419 *p++ = '-';
2420 value = -value;
2421 }
420c9ff3 2422
9138dfe2
VK
2423 WCHAR buffer[64];
2424 WCHAR *t = buffer;
2425 do
2426 {
2427 int rem = value % base;
2428 *t++ = (rem < 10) ? (rem + '0') : (rem - 10 + 'a');
2429 value = value / base;
2430 } while(value > 0);
2431
2432 t--;
2433 while(t >= buffer)
2434 *p++ = *t--;
2435 *p = 0;
2436 return str;
2437}
2438
2439#endif
b06ae508
VK
2440
2441/**
2442 * Get sleep time until specific time
2443 */
2444int LIBNETXMS_EXPORTABLE GetSleepTime(int hour, int minute, int second)
2445{
2446 time_t now = time(NULL);
2447
2448 struct tm localTime;
2449#if HAVE_LOCALTIME_R
2450 localtime_r(&now, &localTime);
2451#else
2452 memcpy(&localTime, localtime(&now), sizeof(struct tm));
2453#endif
2454
2455 int target = hour * 3600 + minute * 60 + second;
2456 int curr = localTime.tm_hour * 3600 + localTime.tm_min * 60 + localTime.tm_sec;
2457 return (target >= curr) ? target - curr : 86400 - (curr - target);
2458}
b60584cf
VK
2459
2460/**
2461 * Parse timestamp (should be in form YYMMDDhhmmss or YYYYMMDDhhmmss), local time
2462 * If timestamp string is invalid returns default value
2463 */
2464time_t LIBNETXMS_EXPORTABLE ParseDateTimeA(const char *text, time_t defaultValue)
2465{
2466 int len = (int)strlen(text);
2467 if ((len != 12) && (len != 14))
2468 return defaultValue;
2469
2470 struct tm t;
2471 char buffer[16], *curr;
2472
2473 strncpy(buffer, text, 16);
2474 curr = &buffer[len - 2];
2475
2476 memset(&t, 0, sizeof(struct tm));
2477 t.tm_isdst = -1;
420c9ff3 2478
b60584cf
VK
2479 t.tm_sec = strtol(curr, NULL, 10);
2480 *curr = 0;
2481 curr -= 2;
2482
2483 t.tm_min = strtol(curr, NULL, 10);
2484 *curr = 0;
2485 curr -= 2;
2486
2487 t.tm_hour = strtol(curr, NULL, 10);
2488 *curr = 0;
2489 curr -= 2;
2490
2491 t.tm_mday = strtol(curr, NULL, 10);
2492 *curr = 0;
2493 curr -= 2;
2494
2495 t.tm_mon = strtol(curr, NULL, 10) - 1;
2496 *curr = 0;
2497
2498 if (len == 12)
2499 {
2500 curr -= 2;
2501 t.tm_year = strtol(curr, NULL, 10) + 100; // Assuming XXI century
2502 }
2503 else
2504 {
2505 curr -= 4;
2506 t.tm_year = strtol(curr, NULL, 10) - 1900;
2507 }
2508
2509 return mktime(&t);
2510}
2511
2512/**
2513 * Parse timestamp (should be in form YYMMDDhhmmss or YYYYMMDDhhmmss), local time
2514 * If timestamp string is invalid returns default value
2515 * (UNICODE version)
2516 */
2517time_t LIBNETXMS_EXPORTABLE ParseDateTimeW(const WCHAR *text, time_t defaultValue)
2518{
2519 char buffer[16];
2520 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, text, -1, buffer, 16, NULL, NULL);
2521 buffer[15] = 0;
2522 return ParseDateTimeA(buffer, defaultValue);
2523}
a97f02e1
VK
2524
2525/**
2526 * Get NetXMS directory
2527 */
2528void LIBNETXMS_EXPORTABLE GetNetXMSDirectory(nxDirectoryType type, TCHAR *dir)
2529{
2530 *dir = 0;
2531
2532 const TCHAR *homeDir = _tgetenv(_T("NETXMS_HOME"));
2533 if (homeDir != NULL)
2534 {
2535#ifdef _WIN32
2536 switch(type)
2537 {
2538 case nxDirBin:
2539 _sntprintf(dir, MAX_PATH, _T("%s\\bin"), homeDir);
2540 break;
2541 case nxDirData:
2542 _sntprintf(dir, MAX_PATH, _T("%s\\var"), homeDir);
2543 break;
2544 case nxDirEtc:
2545 _sntprintf(dir, MAX_PATH, _T("%s\\etc"), homeDir);
2546 break;
2547 case nxDirLib:
2548 _sntprintf(dir, MAX_PATH, _T("%s\\lib"), homeDir);
2549 break;
1039d7ee
VK
2550 case nxDirShare:
2551 _sntprintf(dir, MAX_PATH, _T("%s\\share"), homeDir);
2552 break;
a97f02e1
VK
2553 default:
2554 nx_strncpy(dir, homeDir, MAX_PATH);
2555 break;
2556 }
2557#else
2558 switch(type)
2559 {
2560 case nxDirBin:
2561 _sntprintf(dir, MAX_PATH, _T("%s/bin"), homeDir);
2562 break;
2563 case nxDirData:
1039d7ee 2564 _sntprintf(dir, MAX_PATH, _T("%s/var/lib/netxms"), homeDir);
a97f02e1
VK
2565 break;
2566 case nxDirEtc:
2567 _sntprintf(dir, MAX_PATH, _T("%s/etc"), homeDir);
2568 break;
2569 case nxDirLib:
2570 _sntprintf(dir, MAX_PATH, _T("%s/lib/netxms"), homeDir);
2571 break;
1039d7ee
VK
2572 case nxDirShare:
2573 _sntprintf(dir, MAX_PATH, _T("%s/share/netxms"), homeDir);
2574 break;
a97f02e1
VK
2575 default:
2576 nx_strncpy(dir, homeDir, MAX_PATH);
2577 break;
2578 }
2579#endif
2580 return;
2581 }
2582
2583#ifdef _WIN32
2584 TCHAR installPath[MAX_PATH] = _T("");
2585 HKEY hKey;
2586 bool found = false;
2587 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Server"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
2588 {
2589 DWORD size = MAX_PATH * sizeof(TCHAR);
2590 found = (RegQueryValueEx(hKey, _T("InstallPath"), NULL, NULL, (BYTE *)installPath, &size) == ERROR_SUCCESS);
2591 RegCloseKey(hKey);
2592 }
2593
2594 if (!found)
2595 {
2596 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\NetXMS\\Agent"), 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
2597 {
2598 DWORD size = MAX_PATH * sizeof(TCHAR);
2599 found = (RegQueryValueEx(hKey, _T("InstallPath"), NULL, NULL, (BYTE *)installPath, &size) == ERROR_SUCCESS);
2600 RegCloseKey(hKey);
2601 }
2602 }
2603
2604 if (!found && (GetModuleFileName(NULL, installPath, MAX_PATH) > 0))
2605 {
2606 TCHAR *p = _tcsrchr(installPath, _T('\\'));
2607 if (p != NULL)
2608 {
2609 *p = 0;
2610 p = _tcsrchr(installPath, _T('\\'));
2611 if (p != NULL)
2612 {
2613 *p = 0;
2614 found = true;
2615 }
2616 }
2617 }
2618
2619 if (!found)
2620 {
2621 _tcscpy(installPath, _T("C:\\NetXMS"));
2622 }
2623
2624 switch(type)
2625 {
2626 case nxDirBin:
2627 _sntprintf(dir, MAX_PATH, _T("%s\\bin"), installPath);
2628 break;
2629 case nxDirData:
2630 _sntprintf(dir, MAX_PATH, _T("%s\\var"), installPath);
2631 break;
2632 case nxDirEtc:
2633 _sntprintf(dir, MAX_PATH, _T("%s\\etc"), installPath);
2634 break;
2635 case nxDirLib:
2636 _sntprintf(dir, MAX_PATH, _T("%s\\lib"), installPath);
2637 break;
1039d7ee
VK
2638 case nxDirShare:
2639 _sntprintf(dir, MAX_PATH, _T("%s\\share"), installPath);
2640 break;
a97f02e1
VK
2641 default:
2642 nx_strncpy(dir, installPath, MAX_PATH);
2643 break;
2644 }
2645#else
2646 switch(type)
2647 {
2648 case nxDirBin:
2649#ifdef PREFIX
2650 _tcscpy(dir, PREFIX _T("/bin"));
2651#else
2652 _tcscpy(dir, _T("/usr/bin"));
2653#endif
2654 break;
2655 case nxDirData:
1039d7ee
VK
2656#ifdef STATEDIR
2657 _tcscpy(dir, STATEDIR);
a97f02e1
VK
2658#else
2659 _tcscpy(dir, _T("/var/lib/netxms"));
2660#endif
2661 break;
2662 case nxDirEtc:
2663#ifdef PREFIX
2664 _tcscpy(dir, PREFIX _T("/etc"));
2665#else
2666 _tcscpy(dir, _T("/etc"));
2667#endif
2668 break;
2669 case nxDirLib:
2670#ifdef PKGLIBDIR
2671 _tcscpy(dir, PKGLIBDIR);
2672#else
2673 _tcscpy(dir, _T("/usr/lib/netxms"));
2674#endif
2675 break;
1039d7ee
VK
2676 case nxDirShare:
2677#ifdef DATADIR
2678 _tcscpy(dir, DATADIR);
2679#else
2680 _tcscpy(dir, _T("/usr/share/netxms"));
2681#endif
2682 break;
a97f02e1
VK
2683 default:
2684 _tcscpy(dir, _T("/usr"));
2685 break;
2686 }
2687#endif
2688}
5962498b 2689
f92a016a
VK
2690#if WITH_JEMALLOC
2691
2692/**
2693 * Callback for jemalloc's malloc_stats_print
2694 */
2695static void jemalloc_stats_cb(void *arg, const char *text)
2696{
2697 fwrite(text, 1, strlen(text), (FILE *)arg);
2698}
2699
2700#endif
2701
5962498b
VK
2702/**
2703 * Get heap information using system-specific functions (if available)
2704 */
2705TCHAR LIBNETXMS_EXPORTABLE *GetHeapInfo()
2706{
f92a016a 2707#if WITH_JEMALLOC || HAVE_MALLOC_INFO
5962498b
VK
2708 char *buffer = NULL;
2709 size_t size = 0;
2710 FILE *f = open_memstream(&buffer, &size);
2711 if (f == NULL)
2712 return NULL;
f92a016a
VK
2713#if WITH_JEMALLOC
2714 malloc_stats_print(jemalloc_stats_cb, f, NULL);
2715#else
5962498b 2716 malloc_info(0, f);
f92a016a 2717#endif
5962498b
VK
2718 fclose(f);
2719#ifdef UNICODE
2720 WCHAR *wtext = WideStringFromMBString(buffer);
2721 free(buffer);
2722 return wtext;
2723#else
2724 return buffer;
2725#endif
2726#else
2727 return _tcsdup(_T("No heap information API available"));
2728#endif
2729}
c5e1f0bb
VK
2730
2731/**
2732 * Destructor for abstract iterator
2733 */
2734AbstractIterator::~AbstractIterator()
2735{
2736}
0356b995
VK
2737
2738/**
2739 * Escape string for JSON
2740 */
2741String LIBNETXMS_EXPORTABLE EscapeStringForJSON(const TCHAR *s)
2742{
2743 String js;
2744 if (s == NULL)
2745 return js;
2746 for(const TCHAR *p = s; *p != 0; p++)
2747 {
2748 if (*p == _T('"') || *p == _T('\\'))
2749 js.append(_T('\\'));
2750 js.append(*p);
2751 }
2752 return js;
2753}
1d919454
VK
2754
2755/**
2756 * Escape string for agent parameter
2757 */
2758String LIBNETXMS_EXPORTABLE EscapeStringForAgent(const TCHAR *s)
2759{
2760 String out;
2761 if (s == NULL)
2762 return out;
2763 for(const TCHAR *p = s; *p != 0; p++)
2764 {
2765 if (*p == _T('"'))
2766 out.append(_T('"'));
2767 out.append(*p);
2768 }
2769 return out;
2770}