libnetxms changed to unicode
[public/netxms.git] / src / libnetxms / tools.cpp
1 /*
2 ** Project X - Network Management System
3 ** Copyright (C) 2003 Victor Kirhenshtein
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
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 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 **
19 ** $module: tools.cpp
20 **
21 **/
22
23 #include "libnetxms.h"
24
25 #if !defined(_WIN32) || !defined(UNDER_CE)
26 #include <sys/time.h>
27 #endif
28
29 #ifdef _WIN32
30 #ifndef __GNUC__
31 #define EPOCHFILETIME (116444736000000000i64)
32 #else
33 #define EPOCHFILETIME (116444736000000000LL)
34 #endif
35 #endif
36
37
38 //
39 // Calculate number of bits in netmask
40 //
41
42 int LIBNETXMS_EXPORTABLE BitsInMask(DWORD dwMask)
43 {
44 int bits;
45 DWORD dwTemp;
46
47 for(bits = 0, dwTemp = ntohl(dwMask); dwTemp != 0; bits++, dwTemp <<= 1);
48 return bits;
49 }
50
51
52 //
53 // Convert IP address from binary form (network bytes order) to string
54 //
55
56 TCHAR LIBNETXMS_EXPORTABLE *IpToStr(DWORD dwAddr, TCHAR *szBuffer)
57 {
58 static TCHAR szInternalBuffer[32];
59 TCHAR *szBufPtr;
60
61 szBufPtr = szBuffer == NULL ? szInternalBuffer : szBuffer;
62 #if WORDS_BIGENDIAN
63 _stprintf(szBufPtr, _T("%ld.%ld.%ld.%ld"), dwAddr >> 24, (dwAddr >> 16) & 255,
64 (dwAddr >> 8) & 255, dwAddr & 255);
65 #else
66 _stprintf(szBufPtr, _T("%ld.%ld.%ld.%ld"), dwAddr & 255, (dwAddr >> 8) & 255,
67 (dwAddr >> 16) & 255, dwAddr >> 24);
68 #endif
69 return szBufPtr;
70 }
71
72
73 //
74 // Duplicate memory block
75 //
76
77 void LIBNETXMS_EXPORTABLE *nx_memdup(const void *pData, DWORD dwSize)
78 {
79 void *pNewData;
80
81 pNewData = malloc(dwSize);
82 memcpy(pNewData, pData, dwSize);
83 return pNewData;
84 }
85
86
87 //
88 // Match string against pattern with * and ? metasymbols
89 //
90
91 static BOOL MatchStringEngine(const TCHAR *pattern, const TCHAR *string)
92 {
93 const TCHAR *SPtr,*MPtr,*BPtr;
94
95 SPtr = string;
96 MPtr = pattern;
97
98 while(*MPtr != 0)
99 {
100 switch(*MPtr)
101 {
102 case _T('?'):
103 if (*SPtr != 0)
104 {
105 SPtr++;
106 MPtr++;
107 }
108 else
109 return FALSE;
110 break;
111 case _T('*'):
112 while(*MPtr == _T('*'))
113 MPtr++;
114 if (*MPtr==0)
115 return TRUE;
116 if (*MPtr==_T('?')) // Handle "*?" case
117 {
118 if (*SPtr!=0)
119 SPtr++;
120 else
121 return FALSE;
122 break;
123 }
124 BPtr=MPtr; // Text block begins here
125 while((*MPtr!=0)&&(*MPtr!=_T('?'))&&(*MPtr!=_T('*')))
126 MPtr++; // Find the end of text block
127 while(1)
128 {
129 while((*SPtr!=0)&&(*SPtr!=*BPtr))
130 SPtr++;
131 if (_tcslen(SPtr)<((size_t)(MPtr-BPtr)) * sizeof(TCHAR))
132 return FALSE; // Length of remained text less than remaining pattern
133 if (!memcmp(BPtr,SPtr,(MPtr-BPtr) * sizeof(TCHAR)))
134 break;
135 SPtr++;
136 }
137 SPtr+=(MPtr-BPtr); // Increment SPtr because we alredy match current fragment
138 break;
139 default:
140 if (*MPtr==*SPtr)
141 {
142 SPtr++;
143 MPtr++;
144 }
145 else
146 return FALSE;
147 break;
148 }
149 }
150
151 return *SPtr==0 ? TRUE : FALSE;
152 }
153
154 BOOL LIBNETXMS_EXPORTABLE MatchString(const TCHAR *pattern,
155 const TCHAR *string,
156 BOOL matchCase)
157 {
158 if (matchCase)
159 return MatchStringEngine(pattern, string);
160 else
161 {
162 TCHAR *tp, *ts;
163 BOOL bResult;
164
165 tp = _tcsdup(pattern);
166 ts = _tcsdup(string);
167 _tcsupr(tp);
168 _tcsupr(ts);
169 bResult = MatchStringEngine(tp, ts);
170 free(tp);
171 free(ts);
172 return bResult;
173 }
174 }
175
176
177 //
178 // Strip whitespaces and tabs off the string
179 //
180
181 void LIBNETXMS_EXPORTABLE StrStrip(TCHAR *str)
182 {
183 int i;
184
185 for(i=0;(str[i]!=0)&&((str[i]==_T(' '))||(str[i]==_T('\t')));i++);
186 if (i>0)
187 memmove(str,&str[i],(_tcslen(&str[i])+1) * sizeof(TCHAR));
188 for(i=_tcslen(str)-1;(i>=0)&&((str[i]==_T(' '))||(str[i]==_T('\t')));i--);
189 str[i+1]=0;
190 }
191
192
193 //
194 // Add string to enumeration result set
195 //
196
197 void LIBNETXMS_EXPORTABLE NxAddResultString(NETXMS_VALUES_LIST *pList, TCHAR *pszString)
198 {
199 // FIXME
200 pList->ppStringList = (TCHAR **)realloc(pList->ppStringList, sizeof(TCHAR *) * (pList->dwNumStrings + 1));
201 pList->ppStringList[pList->dwNumStrings] = _tcsdup(pszString);
202 pList->dwNumStrings++;
203 }
204
205
206 //
207 // Get arguments for parameters like name(arg1,...)
208 // Returns FALSE on processing error
209 //
210
211 BOOL LIBNETXMS_EXPORTABLE NxGetParameterArg(TCHAR *param, int index, TCHAR *arg, int maxSize)
212 {
213 TCHAR *ptr1, *ptr2;
214 int state, currIndex, pos;
215 BOOL bResult = TRUE;
216
217 arg[0] = 0; // Default is empty string
218 ptr1 = _tcschr(param, _T('('));
219 if (ptr1 == NULL)
220 return TRUE; // No arguments at all
221 for(ptr2 = ptr1 + 1, currIndex = 1, state = 0, pos = 0; state != -1; ptr2++)
222 {
223 switch(state)
224 {
225 case 0: // Normal
226 switch(*ptr2)
227 {
228 case _T(')'):
229 if (currIndex == index)
230 arg[pos] = 0;
231 state = -1; // Finish processing
232 break;
233 case _T('"'):
234 state = 1; // String
235 break;
236 case _T('\''): // String, type 2
237 state = 2;
238 break;
239 case _T(','):
240 if (currIndex == index)
241 {
242 arg[pos] = 0;
243 state = -1;
244 }
245 else
246 {
247 currIndex++;
248 }
249 break;
250 case 0:
251 state = -1; // Finish processing
252 bResult = FALSE; // Set error flag
253 break;
254 default:
255 if ((currIndex == index) && (pos < maxSize - 1))
256 arg[pos++] = *ptr2;
257 }
258 break;
259 case 1: // String in ""
260 switch(*ptr2)
261 {
262 case _T('"'):
263 state = 0; // Normal
264 break;
265 case _T('\\'): // Escape
266 ptr2++;
267 if ((currIndex == index) && (pos < maxSize - 1))
268 arg[pos++] = *ptr2;
269 if (ptr2 == 0) // Unexpected EOL
270 {
271 bResult = FALSE;
272 state = -1;
273 }
274 break;
275 case 0:
276 state = -1; // Finish processing
277 bResult = FALSE; // Set error flag
278 break;
279 default:
280 if ((currIndex == index) && (pos < maxSize - 1))
281 arg[pos++] = *ptr2;
282 }
283 break;
284 case 2: // String in ''
285 switch(*ptr2)
286 {
287 case _T('\''):
288 state = 0; // Normal
289 break;
290 case _T('\\'): // Escape
291 ptr2++;
292 if ((currIndex == index) && (pos < maxSize - 1))
293 arg[pos++] = *ptr2;
294 if (ptr2 == 0) // Unexpected EOL
295 {
296 bResult = FALSE;
297 state = -1;
298 }
299 break;
300 case 0:
301 state = -1; // Finish processing
302 bResult = FALSE; // Set error flag
303 break;
304 default:
305 if ((currIndex == index) && (pos < maxSize - 1))
306 arg[pos++] = *ptr2;
307 }
308 break;
309 }
310 }
311
312 if (bResult)
313 StrStrip(arg);
314 return bResult;
315 }
316
317
318 //
319 // Get current time in milliseconds
320 // Based on timeval.h by Wu Yongwei
321 //
322
323 INT64 LIBNETXMS_EXPORTABLE GetCurrentTimeMs(void)
324 {
325 #ifdef _WIN32
326 FILETIME ft;
327 LARGE_INTEGER li;
328 __int64 t;
329
330 GetSystemTimeAsFileTime(&ft);
331 li.LowPart = ft.dwLowDateTime;
332 li.HighPart = ft.dwHighDateTime;
333 t = li.QuadPart; // In 100-nanosecond intervals
334 t -= EPOCHFILETIME; // Offset to the Epoch time
335 t /= 10000; // Convert to milliseconds
336 #else
337 struct timeval tv;
338 INT64 t;
339
340 gettimeofday(&tv, NULL);
341 t = (INT64)tv.tv_sec * 1000 + (INT64)(tv.tv_usec / 10000);
342 #endif
343
344 return t;
345 }
346
347
348 //
349 // Extract word from line. Extracted word will be placed in buffer.
350 // Returns pointer to the next word or to the null character if end
351 // of line reached.
352 //
353
354 TCHAR LIBNETXMS_EXPORTABLE *ExtractWord(TCHAR *line, TCHAR *buffer)
355 {
356 TCHAR *ptr,*bptr;
357
358 for(ptr=line;(*ptr==_T(' '))||(*ptr==_T('\t'));ptr++); // Skip initial spaces
359 // Copy word to buffer
360 for(bptr=buffer;(*ptr!=_T(' '))&&(*ptr!=_T('\t'))&&(*ptr!=0);ptr++,bptr++)
361 *bptr=*ptr;
362 *bptr=0;
363 return ptr;
364 }
365
366
367 //
368 // Get system error string by call to FormatMessage
369 // (Windows only)
370 //
371
372 #if defined(_WIN32)
373
374 TCHAR LIBNETXMS_EXPORTABLE *GetSystemErrorText(DWORD dwError, TCHAR *pszBuffer, int iBufSize)
375 {
376 TCHAR *msgBuf;
377
378 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
379 FORMAT_MESSAGE_FROM_SYSTEM |
380 FORMAT_MESSAGE_IGNORE_INSERTS,
381 NULL, dwError,
382 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
383 (LPTSTR)&msgBuf, 0, NULL) > 0)
384 {
385 msgBuf[_tcscspn(msgBuf, _T("\r\n"))] = 0;
386 _tcsncpy(pszBuffer, msgBuf, iBufSize);
387 LocalFree(msgBuf);
388 }
389 else
390 {
391 _stprintf(pszBuffer, _T("MSG 0x%08X - Unable to find message text"), dwError);
392 }
393 return pszBuffer;
394 }
395
396 #endif
397
398
399 //
400 // daemon() implementation for systems which doesn't have one
401 //
402
403 #if !(HAVE_DAEMON) && !defined(_NETWARE)
404
405 int LIBNETXMS_EXPORTABLE daemon(int nochdir, int noclose)
406 {
407 return 0;
408 }
409
410 #endif
411
412
413 //
414 // Check if given name is a valid object name
415 //
416
417 BOOL LIBNETXMS_EXPORTABLE IsValidObjectName(TCHAR *pszName)
418 {
419 static TCHAR szValidCharacters[] = _T("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_- @()./");
420 return (pszName[0] != 0) && (_tcsspn(pszName, szValidCharacters) == _tcslen(pszName));
421 }