AutoPatrol, Bureaucrats, Administrators
481
edits
m (Text replacement - "^" to "{{deprecated}}") |
|||
(17 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:NetXMS Scripting Language (NXSL)}} | {{deprecated}}{{DISPLAYTITLE:NetXMS Scripting Language (NXSL)}} | ||
{| style="border-spacing: 20px; border: 20px solid red;" | |||
| | |||
'''WARNING''': This page is no longer updated. Please visit '''[https://www.netxms.org/documentation/nxsl-latest/#_language_syntax Language syntax]''' for current version of the documentation. | |||
|} | |||
= NXSL Overview = | = NXSL Overview = | ||
In many parts of the system, fine tuning can be done by using NetXMS built-in scripting language called NXSL (stands for NetXMS Scripting Language). NXSL was designed specifically to be used as embedded scripting language within NetXMS, and because of this has some specific features and limitations. Most notable is very limited access to data outside script boundaries – for example, from NXSL script you cannot access files on server, nor call external programs, nor even access data of the node object other than script is running for without explicit permission. NXSL is interpreted language – scripts first compiled into internal representation (similar to byte code in Java), which than executed inside NXSL VM. | In many parts of the system, fine tuning can be done by using NetXMS built-in scripting language called NXSL (stands for NetXMS Scripting Language). NXSL was designed specifically to be used as embedded scripting language within NetXMS, and because of this has some specific features and limitations. Most notable is very limited access to data outside script boundaries – for example, from NXSL script you cannot access files on server, nor call external programs, nor even access data of the node object other than script is running for without explicit permission. NXSL is interpreted language – scripts first compiled into internal representation (similar to byte code in Java), which than executed inside NXSL VM. | ||
Line 32: | Line 42: | ||
Everything inside /* */ is considered a comment and will be ignored by interpreter. You can enclose comments, like below: | Everything inside /* */ is considered a comment and will be ignored by interpreter. You can enclose comments, like below: | ||
<syntaxhighlight> | <syntaxhighlight lang="c"> | ||
/* comment /* another comment */ still comment */ | /* comment /* another comment */ still comment */ | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Line 76: | Line 86: | ||
return is another built-in operator which exits the function and sets it's return value. | return is another built-in operator which exits the function and sets it's return value. | ||
= Script entry point = | |||
NXSL handles script entry in 2 ways:<br> | |||
* Explicit main() function | |||
* Implicit $main() fucntion | |||
If an explicitelly defined main() exists, it will be called. | |||
If an explicit main() doesnt exist, an implicit $main() fucntion will be created by the script interpreter and the script will enter at the $main() function.<br> | |||
The $main() fucntion is constructed from code that is not a part of any other functions. | |||
Line 105: | Line 126: | ||
Variables in NXSL behave the same way as variables in most popular programming languages (C, C++, etc.) do, but in NXSL you don't have to declare variables before you use them. | Variables in NXSL behave the same way as variables in most popular programming languages (C, C++, etc.) do, but in NXSL you don't have to declare variables before you use them. | ||
Scope of a variable can be either global (visible in any function in the script) or local (visible only in the function within which it was defined). Any variable is by default limited to the local function scope. Variable can be declared global using '''global''' operator. | |||
For example: | |||
<syntaxhighlight lang="c"> | |||
x = 1; | |||
myFunction(); | |||
sub myFunction() | |||
{ | |||
println "x=" . x; | |||
} | |||
</syntaxhighlight> | |||
This script will cause run time error "Error 5 in line 6: Invalid operation with NULL value", because variable '''x''' is local (in implicit main function) and is not visible in function '''myFunction'''. The following script will produce expected result (prints x=1): | |||
<syntaxhighlight lang="c"> | |||
global x = 1; | |||
myFunction(); | |||
sub myFunction() | |||
{ | |||
println "x=" . x; | |||
} | |||
</syntaxhighlight> | |||
= Functions = | = Functions = | ||
A function is a named code block that is generally intended to process specified input values into an output value, although this is not always the case. For example, the [[NXSL:trace|trace]] function takes variables and static text and prints the values into server log. Like many languages, NXSL provides for user-defined functions. These may be located anywhere in the main program or loaded in from other scripts via the use keywords. | |||
To define a function, you can use the following form: | |||
'''sub''' ''NAME'' '''(''' ''ARGUMENTS'' ''')''' '''BLOCK''' | |||
where ''NAME'' is any valid identifier, ''ARGUMENTS'' is optional list of argument names, and ''BLOCK'' is code block. | |||
To call a function you would use the following form: | |||
''NAME'' '''(''' ''LIST'' ''')''' | |||
where ''NAME'' is identifier used in function definition, and ''LIST'' is an optional list of expressions passed as function arguments. | |||
To give a quick example of a simple subroutine: | |||
<syntaxhighlight lang="c"> | |||
sub message() | |||
{ | |||
println "Hello!"; | |||
} | |||
</syntaxhighlight> | |||
== Function Arguments == | |||
The first argument you pass to the function is available within the function as $1, the second argument is $2, and so on. For example, this simple function adds two numbers and prints the result: | |||
<syntaxhighlight lang="c"> | |||
sub add() | |||
{ | |||
result = $1 + $2; | |||
println "The result was: " . result; | |||
} | |||
</syntaxhighlight> | |||
To call the subroutine and get a result: | |||
<syntaxhighlight lang="c"> | |||
add(1, 2); | |||
</syntaxhighlight> | |||
If you want named arguments, list of aliases for $1, $2, etc. can be provided in function declaration inside the brackets: | |||
<syntaxhighlight lang="c"> | |||
sub add(numberA, numberB) | |||
{ | |||
result = numberA + numberB; | |||
println "The result was: " . result; | |||
} | |||
</syntaxhighlight> | |||
If parameter was not provided at function call, value of appropriate variable will be '''null'''. | |||
== Return Values from a Function == | |||
You can return a value from a function using the '''return''' keyword: | |||
<syntaxhighlight lang="c"> | |||
sub pct(value, total) | |||
{ | |||
return value / total * 100.0; | |||
} | |||
</syntaxhighlight> | |||
When called, return immediately terminates the current function and returns the value to the caller. If you don't specify a value in '''return''' statement or function ends implicitly by reaching end of function's block, then the return value is '''null'''. | |||
= Arrays = | = Arrays = | ||
An array in NXSL is actually an ordered map. A map is a type that associates ''values'' to ''keys''. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays, | An array in NXSL is actually an ordered map. A map is a type that associates ''values'' to ''keys''. This type is optimized for several different uses; it can be treated as an array, list (vector), hash table (an implementation of a map), dictionary, collection, stack, queue, and probably more. As array values can be other arrays. | ||
A ''key'' must be a non-negative integer. When an array is created, its size is not specified and its map can have empty spots in it. For example, an array can have a element with a ''0'' key and an element with ''4'' key and no keys in-between. Attempting to access an array key which has not been defined is the same as accessing any other undefined variable: the result will be <tt>NULL</tt>. | |||
Array elements can be accessed using [''index''] operator. For example, to access element with index 3 of array ''a'' you should use | |||
<syntaxhighlight lang="c"> | |||
a[3]; | |||
</syntaxhighlight> | |||
== Array Initialization == | |||
New array can be created in two ways. First is to use '''array''' operator. <br> | |||
This statement will create empty array and assign reference to it to variable ''a''. | |||
<syntaxhighlight lang="c"> | |||
array a; | |||
</syntaxhighlight> | |||
You can then assign values to the array like this.<br> | |||
Please note arrays in NXSL are sparse, so you can have elements with nothing in between. | |||
<syntaxhighlight lang="c"> | |||
array a; | |||
a[1] = 1; | |||
a[2] = 2; | |||
a[260] = 260; | |||
println(a[1]); // will print 1 | |||
</syntaxhighlight> | |||
Second way is to use %( ) construct to create array already populated with values.<br> | |||
This statement will create array with four elements at positions 0, 1, 2, and 3, and assign reference to this array to variable ''a''. | |||
<syntaxhighlight lang="c"> | |||
// no need to use "array a;" here, since we are creating it dirrectly | |||
a = %(1, 2, 3, 4); | |||
println(a[0]); // will actually print 1, since 1 is the 0th member | |||
</syntaxhighlight> | |||
Array initialization can also be used directly in expressions, like this: | |||
<syntaxhighlight lang="c"> | |||
sub f() | |||
{ | |||
return %(2, "text", %(1, 2, 3)); | |||
} | |||
</syntaxhighlight> | |||
In this example function ''f'' returns array of 3 elements - number, text, and another array of 3 numeric elements. | |||
= Operators = | = Operators = | ||
Line 121: | Line 278: | ||
== Arithmetic Operators == | == Arithmetic Operators == | ||
{| class="wikitable" | |||
|- | |||
! Example !! Name !! Result | |||
|- | |- | ||
| -a || Negation || Opposite of ''a''. | |||
| | |||
| | |||
|- | |- | ||
| a + b || Addition || Sum of ''a'' and ''b''. | |||
| | |||
| | |||
|- | |- | ||
| a - b || Subtraction || Difference of ''a'' and ''b''. | |||
| | |||
| | |||
|- | |- | ||
| a * b || Multiplication || Product of ''a'' and ''b''. | |||
| | |||
| | |||
|- | |- | ||
| a / b || Division || Quotient of ''a'' and ''b''. | |||
| | |||
| | |||
|- | |- | ||
| a % b || Modulus || Remainder of ''a'' divided by ''b''. | |||
| | |||
| | |||
|} | |} | ||
The division operator ("/") returns a float value unless the two operands are integers (or strings that get converted to integers) and the numbers are evenly divisible, in which case an integer value will be returned. | The division operator ("/") returns a float value unless the two operands are integers (or strings that get converted to integers) and the numbers are evenly divisible, in which case an integer value will be returned. | ||
Line 170: | Line 305: | ||
== Bitwise Operators == | == Bitwise Operators == | ||
{| style="border-spacing:0;" | {| style="border-spacing:0;" | ||
Line 254: | Line 387: | ||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match | | style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match | ||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details. | | style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details. | ||
|- | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a match b | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b''. As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details. | |||
|- | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a imatch b | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Match (case insensitive) | |||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if ''a'' is matched to regular expression ''b'' (case insensitive). As a side effect, assigns values to special variables $1, $2, $3, etc. See ''Regular Expressions'' for details. | |||
|} | |} | ||
Line 308: | Line 451: | ||
|- | |- | ||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a || b | | style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| a <nowiki>||</nowiki> b | ||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Or | | style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:none;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| Or | ||
| style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if either ''a'' or ''b'' is <tt>TRUE</tt>. | | style="border-top:none;border-bottom:0.0007in solid #000000;border-left:0.0007in solid #000000;border-right:0.0007in solid #000000;padding-top:0.0236in;padding-bottom:0.0236in;padding-left:0.075in;padding-right:0.075in;"| <tt>TRUE</tt> if either ''a'' or ''b'' is <tt>TRUE</tt>. | ||
|} | |} | ||
== String Operators == | == String Operators == | ||
There are two string operators. The first is the concatenation operator ('.'), which returns the concatenation of its right and left arguments. The second is the concatenating assignment operator ('''.='''), which appends the argument on the right side to the argument on the left side. | There are two string operators. The first is the concatenation operator ('.'), which returns the concatenation of its right and left arguments. The second is the concatenating assignment operator ('''.='''), which appends the argument on the right side to the argument on the left side. | ||
= Control structures = | = Control structures = | ||
Line 355: | Line 498: | ||
== do-while == | == do-while == | ||
''do-while'' loops are very similar to ''while'' loops, except the truth expression is checked at the end of each iteration instead of in the beginning. The main difference from regular ''while'' loops is that the first iteration of a ''do-while'' loop is guaranteed to run (the truth expression is only checked at the end of the iteration), whereas it may not necessarily run with a regular ''while'' loop (the truth expression is checked at the beginning of each iteration, if it evaluates to FALSE right from the beginning, the loop execution would end immediately). | |||
== for == | == for == | ||
Line 380: | Line 523: | ||
== switch == | == switch == | ||
The ''switch'' statement is similar to a series of ''if'' statements on the same expression. In many occasions, you may want to compare the same variable (or expression) with many different values, and execute a different piece of code depending on which value it equals to. This is exactly what the ''switch'' statement is for. | The ''switch'' statement is similar to a series of ''if'' statements on the same expression. In many occasions, you may want to compare the same variable (or expression) with many different values, and execute a different piece of code depending on which value it equals to. This is exactly what the ''switch'' statement is for. | ||
Example: | |||
<syntaxhighlight lang="c"> | |||
switch (input) | |||
{ | |||
case "1": | |||
trace(0,"Input is 1"); | |||
break; | |||
case "2": | |||
trace(0,"Input is 2"); | |||
break; | |||
default: | |||
trace(0, "Input is unknown"); | |||
} | |||
</syntaxhighlight> | |||
Line 407: | Line 565: | ||
The last example of expressions is combined operator-assignment expressions. You already know that if you want to increment ''a'' by 1, you can simply write '''a''++' or '++''a'''. But what if you want to add more than one to it, for instance 3? In NXSL, adding 3 to the current value of ''a'' can be written '''a'' += 3'. This means exactly "take the value of ''a'', add 3 to it, and assign it back into ''a''". In addition to being shorter and clearer, this also results in faster execution. The value of '''a'' += 3', like the value of a regular assignment, is the assigned value. Notice that it is NOT 3, but the combined value of ''a'' plus 3 (this is the value that's assigned into ''a''). Any two-place operator can be used in this operator-assignment mode. | The last example of expressions is combined operator-assignment expressions. You already know that if you want to increment ''a'' by 1, you can simply write '''a''++' or '++''a'''. But what if you want to add more than one to it, for instance 3? In NXSL, adding 3 to the current value of ''a'' can be written '''a'' += 3'. This means exactly "take the value of ''a'', add 3 to it, and assign it back into ''a''". In addition to being shorter and clearer, this also results in faster execution. The value of '''a'' += 3', like the value of a regular assignment, is the assigned value. Notice that it is NOT 3, but the combined value of ''a'' plus 3 (this is the value that's assigned into ''a''). Any two-place operator can be used in this operator-assignment mode. | ||
== Short-circuit evaluation == | |||
[http://en.wikipedia.org/wiki/Short-circuit_evaluation Short-circuit evaluation] denotes the semantics of some Boolean operators in which the second argument is only executed or evaluated if the first argument does not suffice to determine the value of the expression: when the first argument of the AND function evaluates to false, the overall value must be false; and when the first argument of the OR function evaluates to true, the overall value must be true. NXSL uses short-circuit evaluation for && and || boolean operators. This feature permits two useful programming constructs. Firstly, if the first sub-expression checks whether an expensive computation is needed and the check evaluates to false, one can eliminate expensive computation in the second argument. Secondly, it permits a construct where the first expression guarantees a condition without which the second expression may cause a run-time error. Both are illustrated in the following example: | |||
<syntaxhighlight lang="c"> | |||
if ((x != null) && ((trim(x) == "abc") || (long_running_test(x))) | |||
do_something(); | |||
</syntaxhighlight> | |||
Without short-circuit evaluation, trim(x) would cause run-time error if x is null. Also, long running function will only be called if condition (trim(x) == "abc") will be false. | |||
[[Category:Scripting Guide]] |