license headers in libnetxms changed to LGPL
[public/netxms.git] / src / libnetxms / string.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Foundation Library
4 ** Copyright (C) 2003-2010 Victor Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published
8 ** by the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: string.cpp
21 **
22 **/
23
24 #include "libnetxms.h"
25
26
27 //
28 // Static members
29 //
30
31 const int String::npos = -1;
32
33
34 //
35 // Constructors
36 //
37
38 String::String()
39 {
40 m_dwBufSize = 1;
41 m_pszBuffer = NULL;
42 }
43
44 String::String(const String &src)
45 {
46 m_dwBufSize = src.m_dwBufSize;
47 m_pszBuffer = (src.m_pszBuffer != NULL) ? (TCHAR *)nx_memdup(src.m_pszBuffer, src.m_dwBufSize * sizeof(TCHAR)) : NULL;
48 }
49
50 String::String(const TCHAR *init)
51 {
52 m_dwBufSize = (DWORD)_tcslen(init) + 1;
53 m_pszBuffer = _tcsdup(init);
54 }
55
56
57 //
58 // Destructor
59 //
60
61 String::~String()
62 {
63 safe_free(m_pszBuffer);
64 }
65
66
67 //
68 // Operator =
69 //
70
71 const String& String::operator =(const TCHAR *pszStr)
72 {
73 safe_free(m_pszBuffer);
74 m_pszBuffer = _tcsdup(CHECK_NULL_EX(pszStr));
75 m_dwBufSize = (DWORD)_tcslen(CHECK_NULL_EX(pszStr)) + 1;
76 return *this;
77 }
78
79 const String& String::operator =(const String &src)
80 {
81 safe_free(m_pszBuffer);
82 m_dwBufSize = src.m_dwBufSize;
83 m_pszBuffer = (src.m_pszBuffer != NULL) ? (TCHAR *)nx_memdup(src.m_pszBuffer, src.m_dwBufSize * sizeof(TCHAR)) : NULL;
84 return *this;
85 }
86
87
88 //
89 // Operator +=
90 //
91
92 const String& String::operator +=(const TCHAR *pszStr)
93 {
94 DWORD dwLen;
95
96 if (pszStr != NULL)
97 {
98 dwLen = (DWORD)_tcslen(pszStr);
99 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwLen) * sizeof(TCHAR));
100 _tcscpy(&m_pszBuffer[m_dwBufSize - 1], pszStr);
101 m_dwBufSize += dwLen;
102 }
103 return *this;
104 }
105
106
107 //
108 // Add formatted string to the end of buffer
109 //
110
111 void String::addFormattedString(const TCHAR *format, ...)
112 {
113 va_list args;
114
115 va_start(args, format);
116 addFormattedStringV(format, args);
117 va_end(args);
118 }
119
120 void String::addFormattedStringV(const TCHAR *format, va_list args)
121 {
122 int len;
123 TCHAR *buffer;
124
125 #ifdef UNICODE
126
127 #if HAVE_VASWPRINTF
128 vaswprintf(&buffer, format, args);
129 #elif HAVE_VSCWPRINTF && HAVE_DECL_VA_COPY
130 va_list argsCopy;
131 va_copy(argsCopy, args);
132
133 len = (int)vscwprintf(format, args) + 1;
134 buffer = (WCHAR *)malloc(len * sizeof(WCHAR));
135
136 vsnwprintf(buffer, len, format, argsCopy);
137 va_end(argsCopy);
138 #else
139 // No way to determine required buffer size, guess
140 len = wcslen(format) + CharCount(format, L'%') * 1000 + 1;
141 buffer = (WCHAR *)malloc(len * sizeof(WCHAR));
142
143 vsnwprintf(buffer, len, format, args);
144 #endif
145
146 #else /* UNICODE */
147
148 #if HAVE_VASPRINTF && !defined(_IPSO)
149 vasprintf(&buffer, format, args);
150 #elif HAVE_VSCPRINTF && HAVE_DECL_VA_COPY
151 va_list argsCopy;
152 va_copy(argsCopy, args);
153
154 len = (int)vscprintf(format, args) + 1;
155 buffer = (char *)malloc(len);
156
157 vsnprintf(buffer, len, format, argsCopy);
158 va_end(argsCopy);
159 #elif SNPRINTF_RETURNS_REQUIRED_SIZE && HAVE_DECL_VA_COPY
160 va_list argsCopy;
161 va_copy(argsCopy, args);
162
163 len = (int)snprintf(NULL, 0, format, args) + 1;
164 buffer = (char *)malloc(len);
165
166 vsnprintf(buffer, len, format, argsCopy);
167 va_end(argsCopy);
168 #else
169 // No way to determine required buffer size, guess
170 len = strlen(format) + NumChars(format, '%') * 1000 + 1;
171 buffer = (char *)malloc(len);
172
173 vsnprintf(buffer, len, format, args);
174 #endif
175
176 #endif /* UNICODE */
177
178 *this += buffer;
179 free(buffer);
180 }
181
182
183 //
184 // Add string to the end of buffer
185 //
186
187 void String::addString(const TCHAR *pStr, DWORD dwSize)
188 {
189 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
190 memcpy(&m_pszBuffer[m_dwBufSize - 1], pStr, dwSize * sizeof(TCHAR));
191 m_dwBufSize += dwSize;
192 m_pszBuffer[m_dwBufSize - 1] = 0;
193 }
194
195
196 //
197 // Add multibyte string to the end of buffer
198 //
199
200 void String::addMultiByteString(const char *pStr, DWORD dwSize, int nCodePage)
201 {
202 #ifdef UNICODE
203 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
204 MultiByteToWideChar(nCodePage, (nCodePage == CP_UTF8) ? 0 : MB_PRECOMPOSED, pStr, dwSize, &m_pszBuffer[m_dwBufSize - 1], dwSize);
205 m_dwBufSize += dwSize;
206 m_pszBuffer[m_dwBufSize - 1] = 0;
207 #else
208 addString(pStr, dwSize);
209 #endif
210 }
211
212
213 //
214 // Add widechar string to the end of buffer
215 //
216
217 void String::addWideCharString(const WCHAR *pStr, DWORD dwSize)
218 {
219 #ifdef UNICODE
220 addString(pStr, dwSize);
221 #else
222 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwSize) * sizeof(TCHAR));
223 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK | WC_DEFAULTCHAR, pStr, dwSize, &m_pszBuffer[m_dwBufSize - 1], dwSize, NULL, NULL);
224 m_dwBufSize += dwSize;
225 m_pszBuffer[m_dwBufSize - 1] = 0;
226 #endif
227 }
228
229
230 //
231 // Escape given character
232 //
233
234 void String::escapeCharacter(int ch, int esc)
235 {
236 int nCount;
237 DWORD i;
238
239 if (m_pszBuffer == NULL)
240 return;
241
242 nCount = NumChars(m_pszBuffer, ch);
243 if (nCount == 0)
244 return;
245
246 m_dwBufSize += nCount;
247 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, m_dwBufSize * sizeof(TCHAR));
248 for(i = 0; m_pszBuffer[i] != 0; i++)
249 {
250 if (m_pszBuffer[i] == ch)
251 {
252 memmove(&m_pszBuffer[i + 1], &m_pszBuffer[i], (m_dwBufSize - i - 1) * sizeof(TCHAR));
253 m_pszBuffer[i] = esc;
254 i++;
255 }
256 }
257 }
258
259
260 //
261 // Set dynamically allocated string as a new buffer
262 //
263
264 void String::setBuffer(TCHAR *pszBuffer)
265 {
266 safe_free(m_pszBuffer);
267 m_pszBuffer = pszBuffer;
268 m_dwBufSize = (m_pszBuffer != NULL) ? (DWORD)_tcslen(m_pszBuffer) + 1 : 1;
269 }
270
271
272 //
273 // Translate given substring
274 //
275
276 void String::translate(const TCHAR *pszSrc, const TCHAR *pszDst)
277 {
278 DWORD i, dwLenSrc, dwLenDst, dwDelta;
279
280 if (m_pszBuffer == NULL)
281 return;
282
283 dwLenSrc = (DWORD)_tcslen(pszSrc);
284 dwLenDst = (DWORD)_tcslen(pszDst);
285
286 if (m_dwBufSize <= dwLenSrc)
287 return;
288
289 for(i = 0; i < m_dwBufSize - dwLenSrc; i++)
290 {
291 if (!memcmp(pszSrc, &m_pszBuffer[i], dwLenSrc * sizeof(TCHAR)))
292 {
293 if (dwLenSrc == dwLenDst)
294 {
295 memcpy(&m_pszBuffer[i], pszDst, dwLenDst * sizeof(TCHAR));
296 i += dwLenDst - 1;
297 }
298 else if (dwLenSrc > dwLenDst)
299 {
300 memcpy(&m_pszBuffer[i], pszDst, dwLenDst * sizeof(TCHAR));
301 i += dwLenDst;
302 dwDelta = dwLenSrc - dwLenDst;
303 m_dwBufSize -= dwDelta;
304 memmove(&m_pszBuffer[i], &m_pszBuffer[i + dwDelta], (m_dwBufSize - i) * sizeof(TCHAR));
305 i--;
306 }
307 else
308 {
309 dwDelta = dwLenDst - dwLenSrc;
310 m_pszBuffer = (TCHAR *)realloc(m_pszBuffer, (m_dwBufSize + dwDelta) * sizeof(TCHAR));
311 memmove(&m_pszBuffer[i + dwLenDst], &m_pszBuffer[i + dwLenSrc], (m_dwBufSize - i - dwLenSrc) * sizeof(TCHAR));
312 m_dwBufSize += dwDelta;
313 memcpy(&m_pszBuffer[i], pszDst, dwLenDst * sizeof(TCHAR));
314 i += dwLenDst - 1;
315 }
316 }
317 }
318 }
319
320
321 //
322 // Extract substring into buffer
323 //
324
325 TCHAR *String::subStr(int nStart, int nLen, TCHAR *pszBuffer)
326 {
327 int nCount;
328 TCHAR *pszOut;
329
330 if ((nStart < (int)m_dwBufSize - 1) && (nStart >= 0))
331 {
332 if (nLen == -1)
333 {
334 nCount = (int)m_dwBufSize - nStart - 1;
335 }
336 else
337 {
338 nCount = min(nLen, (int)m_dwBufSize - nStart - 1);
339 }
340 pszOut = (pszBuffer != NULL) ? pszBuffer : (TCHAR *)malloc((nCount + 1) * sizeof(TCHAR));
341 memcpy(pszOut, &m_pszBuffer[nStart], nCount * sizeof(TCHAR));
342 pszOut[nCount] = 0;
343 }
344 else
345 {
346 pszOut = (pszBuffer != NULL) ? pszBuffer : (TCHAR *)malloc(sizeof(TCHAR));
347 *pszOut = 0;
348 }
349 return pszOut;
350 }
351
352
353 //
354 // Find substring in a string
355 //
356
357 int String::find(const TCHAR *pszStr, int nStart)
358 {
359 TCHAR *p;
360
361 if ((nStart >= (int)m_dwBufSize - 1) || (nStart < 0))
362 return npos;
363
364 p = _tcsstr(&m_pszBuffer[nStart], pszStr);
365 return (p != NULL) ? (int)(((char *)p - (char *)m_pszBuffer) / sizeof(TCHAR)) : npos;
366 }
367
368
369 //
370 // Strip leading and trailing spaces, tabs, newlines
371 //
372
373 void String::trim()
374 {
375 if (m_pszBuffer != NULL)
376 {
377 Trim(m_pszBuffer);
378 m_dwBufSize = (DWORD)_tcslen(m_pszBuffer) + 1;
379 }
380 }
381
382
383 //
384 // Shring string by removing trailing characters
385 //
386
387 void String::shrink(int chars)
388 {
389 if (m_dwBufSize > 1)
390 {
391 m_dwBufSize -= min(m_dwBufSize - 1, (DWORD)chars);
392 if (m_pszBuffer != NULL)
393 m_pszBuffer[m_dwBufSize - 1] = 0;
394 }
395 }