2f50883f28fdbe3e7374cf3b966558912c0e856e
[public/netxms.git] / src / libnxsl / functions.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** NetXMS Scripting Language Interpreter
4 ** Copyright (C) 2005-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 General Public License as published by
8 ** the Free Software Foundation; either version 2 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 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: functions.cpp
21 **
22 **/
23
24 #include "libnxsl.h"
25 #include <math.h>
26
27
28 //
29 // Global data
30 //
31
32 const char *g_szTypeNames[] = { "null", "object", "string", "real", "int32",
33 "int64", "uint32", "uint64" };
34
35
36
37 //
38 // Type of value
39 //
40
41 int F_typeof(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
42 {
43 *ppResult = new NXSL_Value(g_szTypeNames[argv[0]->getDataType()]);
44 return 0;
45 }
46
47
48 //
49 // Class of an object
50 //
51
52 int F_classof(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
53 {
54 if (!argv[0]->isObject())
55 return NXSL_ERR_NOT_OBJECT;
56
57 *ppResult = new NXSL_Value(argv[0]->getValueAsObject()->getClass()->getName());
58 return 0;
59 }
60
61
62 //
63 // Absolute value
64 //
65
66 int F_abs(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
67 {
68 int nRet;
69
70 if (argv[0]->isNumeric())
71 {
72 if (argv[0]->isReal())
73 {
74 *ppResult = new NXSL_Value(fabs(argv[0]->getValueAsReal()));
75 }
76 else
77 {
78 *ppResult = new NXSL_Value(argv[0]);
79 if (!argv[0]->isUnsigned())
80 if ((*ppResult)->getValueAsInt64() < 0)
81 (*ppResult)->negate();
82 }
83 nRet = 0;
84 }
85 else
86 {
87 nRet = NXSL_ERR_NOT_NUMBER;
88 }
89 return nRet;
90 }
91
92
93 //
94 // Calculates x raised to the power of y
95 //
96
97 int F_pow(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
98 {
99 int nRet;
100
101 if ((argv[0]->isNumeric()) && (argv[1]->isNumeric()))
102 {
103 *ppResult = new NXSL_Value(pow(argv[0]->getValueAsReal(), argv[1]->getValueAsReal()));
104 nRet = 0;
105 }
106 else
107 {
108 nRet = NXSL_ERR_NOT_NUMBER;
109 }
110 return nRet;
111 }
112
113
114 //
115 // Calculates natural logarithm
116 //
117
118 int F_log(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
119 {
120 int nRet;
121
122 if (argv[0]->isNumeric())
123 {
124 *ppResult = new NXSL_Value(log(argv[0]->getValueAsReal()));
125 nRet = 0;
126 }
127 else
128 {
129 nRet = NXSL_ERR_NOT_NUMBER;
130 }
131 return nRet;
132 }
133
134
135 //
136 // Calculates common logarithm
137 //
138
139 int F_log10(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
140 {
141 int nRet;
142
143 if (argv[0]->isNumeric())
144 {
145 *ppResult = new NXSL_Value(log10(argv[0]->getValueAsReal()));
146 nRet = 0;
147 }
148 else
149 {
150 nRet = NXSL_ERR_NOT_NUMBER;
151 }
152 return nRet;
153 }
154
155
156 //
157 // Calculates x raised to the power of e
158 //
159
160 int F_exp(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
161 {
162 int nRet;
163
164 if (argv[0]->isNumeric())
165 {
166 *ppResult = new NXSL_Value(exp(argv[0]->getValueAsReal()));
167 nRet = 0;
168 }
169 else
170 {
171 nRet = NXSL_ERR_NOT_NUMBER;
172 }
173 return nRet;
174 }
175
176
177 //
178 // Convert string to uppercase
179 //
180
181 int F_upper(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
182 {
183 int nRet;
184 DWORD i, dwLen;
185 TCHAR *pStr;
186
187 if (argv[0]->isString())
188 {
189 *ppResult = new NXSL_Value(argv[0]);
190 pStr = (TCHAR *)(*ppResult)->getValueAsString(&dwLen);
191 for(i = 0; i < dwLen; i++, pStr++)
192 *pStr = toupper(*pStr);
193 nRet = 0;
194 }
195 else
196 {
197 nRet = NXSL_ERR_NOT_STRING;
198 }
199 return nRet;
200 }
201
202
203 //
204 // Convert string to lowercase
205 //
206
207 int F_lower(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
208 {
209 int nRet;
210 DWORD i, dwLen;
211 TCHAR *pStr;
212
213 if (argv[0]->isString())
214 {
215 *ppResult = new NXSL_Value(argv[0]);
216 pStr = (TCHAR *)(*ppResult)->getValueAsString(&dwLen);
217 for(i = 0; i < dwLen; i++, pStr++)
218 *pStr = tolower(*pStr);
219 nRet = 0;
220 }
221 else
222 {
223 nRet = NXSL_ERR_NOT_STRING;
224 }
225 return nRet;
226 }
227
228
229 //
230 // String length
231 //
232
233 int F_length(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
234 {
235 int nRet;
236 DWORD dwLen;
237
238 if (argv[0]->isString())
239 {
240 argv[0]->getValueAsString(&dwLen);
241 *ppResult = new NXSL_Value(dwLen);
242 nRet = 0;
243 }
244 else
245 {
246 nRet = NXSL_ERR_NOT_STRING;
247 }
248 return nRet;
249 }
250
251
252 //
253 // Minimal value from the list of values
254 //
255
256 int F_min(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
257 {
258 int i;
259 NXSL_Value *pCurr;
260
261 if (argc == 0)
262 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
263
264 pCurr = argv[0];
265 for(i = 1; i < argc; i++)
266 {
267 if (!argv[i]->isNumeric())
268 return NXSL_ERR_NOT_NUMBER;
269
270 if (argv[i]->LT(pCurr))
271 pCurr = argv[i];
272 }
273 *ppResult = new NXSL_Value(pCurr);
274 return 0;
275 }
276
277
278 //
279 // Maximal value from the list of values
280 //
281
282 int F_max(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
283 {
284 int i;
285 NXSL_Value *pCurr;
286
287 if (argc == 0)
288 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
289
290 pCurr = argv[0];
291 for(i = 0; i < argc; i++)
292 {
293 if (!argv[i]->isNumeric())
294 return NXSL_ERR_NOT_NUMBER;
295
296 if (argv[i]->GT(pCurr))
297 pCurr = argv[i];
298 }
299 *ppResult = new NXSL_Value(pCurr);
300 return 0;
301 }
302
303
304 //
305 // Check if IP address is within given range
306 //
307
308 int F_AddrInRange(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
309 {
310 int nRet;
311 DWORD dwAddr, dwStart, dwEnd;
312
313 if (argv[0]->isString() && argv[1]->isString() && argv[2]->isString())
314 {
315 dwAddr = ntohl(inet_addr(argv[0]->getValueAsCString()));
316 dwStart = ntohl(inet_addr(argv[1]->getValueAsCString()));
317 dwEnd = ntohl(inet_addr(argv[2]->getValueAsCString()));
318 *ppResult = new NXSL_Value((LONG)(((dwAddr >= dwStart) && (dwAddr <= dwEnd)) ? 1 : 0));
319 nRet = 0;
320 }
321 else
322 {
323 nRet = NXSL_ERR_NOT_STRING;
324 }
325 return nRet;
326 }
327
328
329 //
330 // Check if IP address is within given subnet
331 //
332
333 int F_AddrInSubnet(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
334 {
335 int nRet;
336 DWORD dwAddr, dwSubnet, dwMask;
337
338 if (argv[0]->isString() && argv[1]->isString() && argv[2]->isString())
339 {
340 dwAddr = ntohl(inet_addr(argv[0]->getValueAsCString()));
341 dwSubnet = ntohl(inet_addr(argv[1]->getValueAsCString()));
342 dwMask = ntohl(inet_addr(argv[2]->getValueAsCString()));
343 *ppResult = new NXSL_Value((LONG)(((dwAddr & dwMask) == dwSubnet) ? 1 : 0));
344 nRet = 0;
345 }
346 else
347 {
348 nRet = NXSL_ERR_NOT_STRING;
349 }
350 return nRet;
351 }
352
353
354 //
355 // Convert time_t into string
356 // PATCH: by Edgar Chupit
357 //
358
359 int F_strftime(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
360 {
361 TCHAR buffer[512];
362 time_t tTime;
363 struct tm *ptm;
364 BOOL bLocalTime;
365
366 if ((argc == 0) || (argc > 3))
367 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
368
369 if (!argv[0]->isString())
370 return NXSL_ERR_NOT_STRING;
371 if (argc > 1)
372 {
373 if (!argv[1]->isNumeric() && !argv[1]->isNull())
374 return NXSL_ERR_NOT_NUMBER;
375 tTime = (argv[1]->isNull()) ? time(NULL) : (time_t)argv[1]->getValueAsUInt64();
376
377 if (argc > 2)
378 {
379 if (!argv[2]->isInteger())
380 return NXSL_ERR_BAD_CONDITION;
381 bLocalTime = argv[2]->getValueAsInt32() ? TRUE : FALSE;
382 }
383 else
384 {
385 // No third argument, assume localtime
386 bLocalTime = TRUE;
387 }
388 }
389 else
390 {
391 // No second argument
392 tTime = time(NULL);
393 }
394
395 ptm = bLocalTime ? localtime(&tTime) : gmtime(&tTime);
396 _tcsftime(buffer, 512, argv[0]->getValueAsCString(), ptm);
397 *ppResult = new NXSL_Value(buffer);
398
399 return 0;
400 }
401
402
403 //
404 // Convert seconds since uptime to string
405 // PATCH: by Edgar Chupit
406 //
407
408 int F_SecondsToUptime(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
409 {
410 DWORD d, h, n;
411
412 if (!argv[0]->isNumeric())
413 return NXSL_ERR_NOT_NUMBER;
414
415 QWORD arg = argv[0]->getValueAsUInt64();
416
417 d = (DWORD)(arg / 86400);
418 arg -= d * 86400;
419 h = (DWORD)(arg / 3600);
420 arg -= h * 3600;
421 n = (DWORD)(arg / 60);
422 arg -= n * 60;
423 if (arg > 0)
424 n++;
425
426 char pResult[MAX_PATH];
427 pResult[0] = 0;
428
429 snprintf(pResult, MAX_PATH, "%u days, %2u:%02u", d, h, n);
430
431 *ppResult = new NXSL_Value(pResult);
432 return 0;
433 }
434
435
436 //
437 // Get current time
438 //
439
440 int F_time(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
441 {
442 *ppResult = new NXSL_Value((DWORD)time(NULL));
443 return 0;
444 }
445
446
447 //
448 // NXSL "TIME" class
449 //
450
451 class NXSL_TimeClass : public NXSL_Class
452 {
453 public:
454 NXSL_TimeClass();
455
456 virtual NXSL_Value *getAttr(NXSL_Object *pObject, const TCHAR *pszAttr);
457 virtual void onObjectDelete(NXSL_Object *object);
458 };
459
460
461 //
462 // Implementation of "TIME" class
463 //
464
465 NXSL_TimeClass::NXSL_TimeClass()
466 :NXSL_Class()
467 {
468 strcpy(m_szName, "TIME");
469 }
470
471 NXSL_Value *NXSL_TimeClass::getAttr(NXSL_Object *pObject, const TCHAR *pszAttr)
472 {
473 struct tm *st;
474 NXSL_Value *value;
475
476 st = (struct tm *)pObject->getData();
477 if (!strcmp(pszAttr, "sec") || !strcmp(pszAttr, "tm_sec"))
478 {
479 value = new NXSL_Value((LONG)st->tm_sec);
480 }
481 else if (!strcmp(pszAttr, "min") || !strcmp(pszAttr, "tm_min"))
482 {
483 value = new NXSL_Value((LONG)st->tm_min);
484 }
485 else if (!strcmp(pszAttr, "hour") || !strcmp(pszAttr, "tm_hour"))
486 {
487 value = new NXSL_Value((LONG)st->tm_hour);
488 }
489 else if (!strcmp(pszAttr, "mday") || !strcmp(pszAttr, "tm_mday"))
490 {
491 value = new NXSL_Value((LONG)st->tm_mday);
492 }
493 else if (!strcmp(pszAttr, "mon") || !strcmp(pszAttr, "tm_mon"))
494 {
495 value = new NXSL_Value((LONG)st->tm_mon);
496 }
497 else if (!strcmp(pszAttr, "year") || !strcmp(pszAttr, "tm_year"))
498 {
499 value = new NXSL_Value((LONG)(st->tm_year + 1900));
500 }
501 else if (!strcmp(pszAttr, "yday") || !strcmp(pszAttr, "tm_yday"))
502 {
503 value = new NXSL_Value((LONG)st->tm_yday);
504 }
505 else if (!strcmp(pszAttr, "wday") || !strcmp(pszAttr, "tm_wday"))
506 {
507 value = new NXSL_Value((LONG)st->tm_wday);
508 }
509 else if (!strcmp(pszAttr, "isdst") || !strcmp(pszAttr, "tm_isdst"))
510 {
511 value = new NXSL_Value((LONG)st->tm_isdst);
512 }
513 else
514 {
515 value = NULL; // Error
516 }
517 return value;
518 }
519
520 void NXSL_TimeClass::onObjectDelete(NXSL_Object *object)
521 {
522 safe_free(object->getData());
523 }
524
525
526 //
527 // NXSL "TIME" class object
528 //
529
530 static NXSL_TimeClass m_nxslTimeClass;
531
532
533 //
534 // Return parsed local time
535 //
536
537 int F_localtime(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
538 {
539 struct tm *p;
540 time_t t;
541
542 if (argc == 0)
543 {
544 t = time(NULL);
545 }
546 else if (argc == 1)
547 {
548 if (!argv[0]->isInteger())
549 return NXSL_ERR_NOT_INTEGER;
550
551 t = argv[0]->getValueAsUInt32();
552 }
553 else
554 {
555 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
556 }
557
558 p = localtime(&t);
559 *ppResult = new NXSL_Value(new NXSL_Object(&m_nxslTimeClass, nx_memdup(p, sizeof(struct tm))));
560 return 0;
561 }
562
563
564 //
565 // Return parsed UTC time
566 //
567
568 int F_gmtime(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
569 {
570 struct tm *p;
571 time_t t;
572
573 if (argc == 0)
574 {
575 t = time(NULL);
576 }
577 else if (argc == 1)
578 {
579 if (!argv[0]->isInteger())
580 return NXSL_ERR_NOT_INTEGER;
581
582 t = argv[0]->getValueAsUInt32();
583 }
584 else
585 {
586 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
587 }
588
589 p = gmtime(&t);
590 *ppResult = new NXSL_Value(new NXSL_Object(&m_nxslTimeClass, nx_memdup(p, sizeof(struct tm))));
591 return 0;
592 }
593
594
595 //
596 // Get substring of a string
597 // Possible usage:
598 // substr(string, start) - all characters from position 'start'
599 // substr(string, start, n) - n characters from position 'start'
600 // substr(string, NULL, n) - first n characters
601 //
602
603 int F_substr(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
604 {
605 int nStart, nCount;
606 const TCHAR *pBase;
607 DWORD dwLen;
608
609 if ((argc < 2) || (argc > 3))
610 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
611
612 if (!argv[0]->isString())
613 return NXSL_ERR_NOT_STRING;
614
615 if (argv[1]->isNull())
616 {
617 nStart = 0;
618 }
619 else if (argv[1]->isInteger())
620 {
621 nStart = argv[1]->getValueAsInt32();
622 if (nStart > 0)
623 nStart--;
624 else
625 nStart = 0;
626 }
627 else
628 {
629 return NXSL_ERR_NOT_INTEGER;
630 }
631
632 if (argc == 3)
633 {
634 if (!argv[2]->isInteger())
635 return NXSL_ERR_NOT_INTEGER;
636 nCount = argv[2]->getValueAsInt32();
637 if (nCount < 0)
638 nCount = 0;
639 }
640 else
641 {
642 nCount = -1;
643 }
644
645 pBase = argv[0]->getValueAsString(&dwLen);
646 if ((DWORD)nStart < dwLen)
647 {
648 pBase += nStart;
649 dwLen -= nStart;
650 if ((nCount == -1) || ((DWORD)nCount > dwLen))
651 {
652 nCount = dwLen;
653 }
654 *ppResult = new NXSL_Value(pBase, (DWORD)nCount);
655 }
656 else
657 {
658 *ppResult = new NXSL_Value("");
659 }
660
661 return 0;
662 }
663
664
665 //
666 // Convert decimal value to hexadecimal string
667 // d2x(value) -> hex value
668 // d2x(value, padding) -> hex value padded vith zeros
669 //
670
671 int F_d2x(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
672 {
673 TCHAR buffer[128], format[32];
674
675 if ((argc < 1) || (argc > 2))
676 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
677
678 if (!argv[0]->isInteger())
679 return NXSL_ERR_NOT_INTEGER;
680
681 if ((argc == 2) && (!argv[1]->isInteger()))
682 return NXSL_ERR_NOT_INTEGER;
683
684 if (argc == 1)
685 {
686 _tcscpy(format, _T("%X"));
687 }
688 else
689 {
690 _sntprintf(format, 32, _T("%%0%dX"), argv[1]->getValueAsInt32());
691 }
692 _sntprintf(buffer, 128, format, argv[0]->getValueAsUInt32());
693 *ppResult = new NXSL_Value(buffer);
694 return 0;
695 }
696
697
698 //
699 // left() - take leftmost part of a string and pad or truncate it as necessary
700 // Format: left(string, len, [pad])
701 //
702
703 int F_left(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
704 {
705 const TCHAR *str;
706 TCHAR *newStr, pad;
707 LONG newLen;
708 DWORD i, len;
709
710 if ((argc < 2) || (argc > 3))
711 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
712
713 if (!argv[1]->isInteger())
714 return NXSL_ERR_NOT_INTEGER;
715
716 if ((!argv[0]->isString()) ||
717 ((argc == 3) && (!argv[2]->isString())))
718 return NXSL_ERR_NOT_STRING;
719
720 if (argc == 3)
721 {
722 pad = *(argv[2]->getValueAsCString());
723 if (pad == 0)
724 pad = _T(' ');
725 }
726 else
727 {
728 pad = _T(' ');
729 }
730
731 newLen = argv[1]->getValueAsInt32();
732 if (newLen < 0)
733 newLen = 0;
734
735 str = argv[0]->getValueAsString(&len);
736 if (len > (DWORD)newLen)
737 len = (DWORD)newLen;
738 newStr = (TCHAR *)malloc(newLen * sizeof(TCHAR));
739 memcpy(newStr, str, len * sizeof(TCHAR));
740 for(i = len; i < (DWORD)newLen; i++)
741 newStr[i] = pad;
742 *ppResult = new NXSL_Value(newStr, newLen);
743 free(newStr);
744 return 0;
745 }
746
747
748 //
749 // right() - take rightmost part of a string and pad or truncate it as necessary
750 // Format: right(string, len, [pad])
751 //
752
753 int F_right(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
754 {
755 const TCHAR *str;
756 TCHAR *newStr, pad;
757 LONG newLen;
758 DWORD i, len, shift;
759
760 if ((argc < 2) || (argc > 3))
761 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
762
763 if (!argv[1]->isInteger())
764 return NXSL_ERR_NOT_INTEGER;
765
766 if ((!argv[0]->isString()) ||
767 ((argc == 3) && (!argv[2]->isString())))
768 return NXSL_ERR_NOT_STRING;
769
770 if (argc == 3)
771 {
772 pad = *(argv[2]->getValueAsCString());
773 if (pad == 0)
774 pad = _T(' ');
775 }
776 else
777 {
778 pad = _T(' ');
779 }
780
781 newLen = argv[1]->getValueAsInt32();
782 if (newLen < 0)
783 newLen = 0;
784
785 str = argv[0]->getValueAsString(&len);
786 if (len > (DWORD)newLen)
787 {
788 shift = len - (DWORD)newLen;
789 len = (DWORD)newLen;
790 }
791 else
792 {
793 shift = 0;
794 }
795 newStr = (TCHAR *)malloc(newLen * sizeof(TCHAR));
796 memcpy(&newStr[(DWORD)newLen - len], &str[shift], len * sizeof(TCHAR));
797 for(i = 0; i < (DWORD)newLen - len; i++)
798 newStr[i] = pad;
799 *ppResult = new NXSL_Value(newStr, newLen);
800 free(newStr);
801 return 0;
802 }
803
804
805 //
806 // Exit from script
807 //
808
809 int F_exit(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
810 {
811 if (argc > 1)
812 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
813
814 *ppResult = (argc == 0) ? new NXSL_Value((LONG)0) : new NXSL_Value(argv[0]);
815 return NXSL_STOP_SCRIPT_EXECUTION;
816 }
817
818
819 //
820 // Trim whitespace characters from the string
821 //
822
823 int F_trim(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
824 {
825 if (!argv[0]->isString())
826 return NXSL_ERR_NOT_STRING;
827
828 DWORD len;
829 const TCHAR *string = argv[0]->getValueAsString(&len);
830
831 int i;
832 for(i = 0; (i < (int)len) && (string[i] == _T(' ') || string[i] == _T('\t')); i++);
833 int startPos = i;
834 if (len > 0)
835 for(i = (int)len - 1; (i >= startPos) && (string[i] == _T(' ') || string[i] == _T('\t')); i--);
836
837 *ppResult = new NXSL_Value(&string[startPos], i - startPos + 1);
838 return 0;
839 }
840
841
842 //
843 // Trim trailing whitespace characters from the string
844 //
845
846 int F_rtrim(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
847 {
848 if (!argv[0]->isString())
849 return NXSL_ERR_NOT_STRING;
850
851 DWORD len;
852 const TCHAR *string = argv[0]->getValueAsString(&len);
853
854 int i;
855 for(i = (int)len - 1; (i >= 0) && (string[i] == _T(' ') || string[i] == _T('\t')); i--);
856
857 *ppResult = new NXSL_Value(string, i + 1);
858 return 0;
859 }
860
861
862 //
863 // Trim leading whitespace characters from the string
864 //
865
866 int F_ltrim(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
867 {
868 if (!argv[0]->isString())
869 return NXSL_ERR_NOT_STRING;
870
871 DWORD len;
872 const TCHAR *string = argv[0]->getValueAsString(&len);
873
874 int i;
875 for(i = 0; (i < (int)len) && (string[i] == _T(' ') || string[i] == _T('\t')); i++);
876
877 *ppResult = new NXSL_Value(&string[i], (int)len - i);
878 return 0;
879 }
880
881
882 //
883 // Trace
884 //
885
886 int F_trace(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
887 {
888 if (!argv[0]->isInteger())
889 return NXSL_ERR_NOT_INTEGER;
890
891 if (!argv[1]->isString())
892 return NXSL_ERR_NOT_STRING;
893
894 program->trace(argv[0]->getValueAsInt32(), argv[1]->getValueAsCString());
895 *ppResult = new NXSL_Value();
896 return 0;
897 }
898
899
900 //
901 // Common implementation for index and rindex functions
902 //
903
904 static int F_index_rindex(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program, bool reverse)
905 {
906 if ((argc != 2) && (argc != 3))
907 return NXSL_ERR_INVALID_ARGUMENT_COUNT;
908
909 if (!argv[0]->isString() || !argv[1]->isString())
910 return NXSL_ERR_NOT_STRING;
911
912 DWORD strLength, substrLength;
913 const TCHAR *str = argv[0]->getValueAsString(&strLength);
914 const TCHAR *substr = argv[1]->getValueAsString(&substrLength);
915
916 int start;
917 if (argc == 3)
918 {
919 if (!argv[2]->isInteger())
920 return NXSL_ERR_NOT_INTEGER;
921
922 start = argv[2]->getValueAsInt32();
923 if (start > 0)
924 {
925 start--;
926 if (reverse && (start > (int)strLength - (int)substrLength))
927 start = (int)strLength - (int)substrLength;
928 }
929 else
930 {
931 start = reverse ? (int)strLength - (int)substrLength : 0;
932 }
933 }
934 else
935 {
936 start = reverse ? (int)strLength - (int)substrLength : 0;
937 }
938
939 int index = 0; // 0 = not found
940 if ((substrLength < strLength) && (substrLength > 0))
941 {
942 if (reverse)
943 {
944 for(int i = start; i >= 0; i--)
945 {
946 if (!memcmp(&str[i], substr, substrLength * sizeof(TCHAR)))
947 {
948 index = i + 1;
949 break;
950 }
951 }
952 }
953 else
954 {
955 for(int i = start; i < (int)(strLength - substrLength); i++)
956 {
957 if (!memcmp(&str[i], substr, substrLength * sizeof(TCHAR)))
958 {
959 index = i + 1;
960 break;
961 }
962 }
963 }
964 }
965 else if ((substrLength == strLength) && (substrLength > 0))
966 {
967 index = !memcmp(str, substr, substrLength * sizeof(TCHAR)) ? 1 : 0;
968 }
969
970 *ppResult = new NXSL_Value((LONG)index);
971 return 0;
972 }
973
974
975 //
976 // index(string, substring, [position])
977 // Returns the position of the first occurrence of SUBSTRING in STRING at or after POSITION.
978 // If you don't specify POSITION, the search starts at the beginning of STRING. If SUBSTRING
979 // is not found, returns 0.
980 //
981
982 int F_index(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
983 {
984 return F_index_rindex(argc, argv, ppResult, program, false);
985 }
986
987
988 //
989 // rindex(string, substring, [position])
990 // Returns the position of the last occurrence of SUBSTRING in STRING at or before POSITION.
991 // If you don't specify POSITION, the search starts at the end of STRING. If SUBSTRING
992 // is not found, returns 0.
993 //
994
995 int F_rindex(int argc, NXSL_Value **argv, NXSL_Value **ppResult, NXSL_Program *program)
996 {
997 return F_index_rindex(argc, argv, ppResult, program, true);
998 }