Parser module is based on a scripting language T-Script which primary purpose is to generate text files. It can be useful for processing templates with some additional data retrieved from data sources like SQL databases or text files. In lmsd's module contents of scripts are stored in database, so they can be edited via LMS-UI. In the future parser should replace almost all lmsd modules.
Before compilation ensure that you have in your system packages bison (at least 1.875 version) and flex.
Parser has following options:
script
Contents of script. Default: empty.
Example: script = '{var=1}variable var={var}'
file
Location of output file. Default: empty.
Example: file = /tmp/parser.out
command
Shell command to execute after script compilation. Default: empty
Example: command = "sh /tmp/parser.out"
T-Script language syntax is based on other popular languages like C or JavaScript with little changes made to make writting templates simpler. Additional commands should be written inside { } parenthesis. Data outside curly brackets will be writed to output file (or ommited if file was not specified). All expressions, variables, commands, function names are case-sensitive.
Supported expressions:
Literal inside quotes.
"some literal"
Number.
1234
Value of variable "var".
var
N-th element of array "var".
var[n]
Subvariable "n" of variable "var".
var.n
Value of expression inside parenthesis.
( <expression> )
1 if value of expression is false, otherwise 0.
! <expression>
Evaluates to 1 if expression1 value equals expression2 value or 0 if not.
<expression1> == <expression2>
Evaluates to 1 if expression1 value doesn't equal expression2 value or 0 if it does.
<expression1> != <expression2>
Evaluates to 1 if expression1 value is less than expression2 value.
<expression1> < <expression2>
Evaluates to 1 if expression1 value is greater than expression2 value.
<expression1> > <expression2>
Evaluates to 1 if expression1 value or expression2 value are true.
<expression1> || <expression2>
Evaluates to 1 if expression1 value and expression2 value are true.
<expression1> && <expression2>
When both expression values have numeric type evaluates to result of arithmetic operation. In other situation treats expressions as strings and performs string concatenation.
<expression1> + <expression2>
Evaluates to result of arithmetic operation on two expression values.
<expression1> - <expression2> <expression1> * <expression2> <expression1> / <expression2> <expression1> % <expression2>
Evaluates to 1 if expression1 value match with regular expression2, else 0.
<expression1> =~ <expression2>
Comments:
C-style comment.
{/* this is a comment - it can be also multiline */}
Basic commands:
Assigns expression value to specified variable.
{<variable_name> = <expression>}
Executes command only if expression is true. Second form executes command1 if expression is true or command2 if expression is false.
{if ( <expression> }) <command> {/if} {if ( <expression> }) <commands1> {else} <commands2> {/if}
Text between command blocks is treated as a command so the following example is correct:
Some text {if (a==1)} a equals 1 {else} a doesn't equal 1 {/if}You can put backslash between command block and end of line to eat \n symbol and keep normal text flow. For example:
Some text {if (a==1)}\ a equals 1 {else}\ a doesn't equal 1 {/if}\
Executes first command1 as loop initialization command. Then executes commands and command2 while expression is true.
{for ( <command1> ; <expression> ; <command2> )} <commands> {/for}
Redirects script output to file. Data will be appended to file.
{file <file_name>} <commands> {/file}
Basic functions:
Converts numeric variable to string value.
{string(<variable_name>)}
Converts string variable to numeric value. For arrays returns number of items in array.
{number(<variable_name>)}
Extensions are tscript library supplements. That are functions and constants, wich can be used in scripts. Below are described extensions implemented in lmsd.
![]() | Functions have two calling forms: with brackets ({function(var)}) and without brackets ({function {var}}). |
Shell commands execution is possible with exec(). You can run many commands separated by semicolons in one function call.
Shell commands execution.
{exec <command>}
'String' consists basic functions for strings operations.
Deleting of whitespace signs from the beginning and the end of string.
{trim <string>}
SQL extension implements functions for database operations. Allows to run SQL commands.
SQL commands
{SELECT <the_rest_of_query>} {INSERT <the_rest_of_query>} {DELETE <the_rest_of_query>} {UPDATE <the_rest_of_query>} {CREATE <the_rest_of_query>} {DROP <the_rest_of_query>}
Returns SQL result rows count. Use it for non-select commands.
{rows(<sql>)}
Escapes a string for use within an SQL commands.
{escape(<string>)}
Extension closely connected with LMS. Makes possible to create scripts without of LMS's database structure knowledge. Contains predefined constants, which consists data from database. Query defined in program is executed when constant is used first time. Constants names are uppercase. Each constant is an array with rows indexed starting from zero, and each row consist subvariables accessible by name (lowercase).
CUSTOMERS - customers list:
id - customer ID |
lastname - customer lastname |
name - customer name |
status - status |
address - address |
zip - postal code |
city - city |
email - email address |
phone1, phone2, phone3 - phone numbers |
ten - tax exempt number |
ssn - security serial number |
info - additional informations |
message - warning contents |
warning - warning status (status of all customer's nodes summary) |
access - accessibility status (status of all customer's nodes summary) |
balance - customer's balance |
NODES - nodes list (and network devices addresses):
id - node ID |
owner - customer name and lastname |
ownerid - customer ID ('0' for devices) |
name - node (device's address) name |
access - status: connected/disconnected (1/0) |
warning - warnings status: enabled/disabled (1/0) |
netdev - device ID, to which is connected |
lastonline - last activity timestamp |
info - additional informations |
message - warning message contents |
mac - MAC address |
passwd - password |
ip - IP address |
ip_pub - public IP address |
linktype - connection type (0-cable, 1-air) |
NETWORKS - networks list:
id - network ID |
name - network name |
address - IP address |
mask - subnet mask (xxx.xxx.xxx.xxx) |
prefix - number of bits in mask |
size - network size (number of addresses) |
interface - interface name |
gateway - gateway address |
dns - primary DNS server |
dns2 - secondary DNS server |
wins - WINS server |
domain - domain name |
dhcpstart - start of DHCP range |
dhcpend - end of DHCP range |
In this extension are included two functions (with lowercase names) destined to IP addresses and subnet masks operations.
Returns number of bits in subnet mask.
mask2prefix(<mask>)
Change octal IP address to long number.
ip2long(<address>)
Change long number to IP address octal format (xxx.xxx.xxx.xxx).
long2ip(<number>)
Calculate broadcast address from specified IP address and mask (any mask format).
broadcast(<address/mask>)
Let's begin from simple script creating file /etc/hosts with list of computers (and devices) IPs and names list.
Example 6-1. Parser: Creating /etc/hosts file
{result = SELECT name, inet_ntoa(ipaddr) AS ip FROM nodes}\ 127.0.0.1 localhost {for (r=0; r<number(result); r++)}\ {result[r].name}\t{result[r].ip} {/for}\
How to create debtors list? It's easy with use of predefined constants.
Example 6-2. Parser: Debtors list
{for (r=0; r<number(CUSTOMERS); r++)}\ {if (CUSTOMERS[r].balance < 0)}\ {CUSTOMERS[r].lastname} {CUSTOMERS[r].name}\t{CUSTOMERS[r].balance} {/if}\ {/for}\
Next example is longer. Here we are using especially 'exec'. Script sends e-mails to customers with balance less than specified limit.
Example 6-3. Parser: Notify module replacement
{limit = 0} {month = exec date +%B} {year = exec date +%Y} {customers = SELECT customers.id AS id, email, pin, name, lastname, SUM((type * -2 +7) * cash.value) AS balance FROM customers LEFT JOIN cash ON customers.id = cash.customerid AND (cash.type = 3 OR cash.type = 4) WHERE deleted = 0 AND email!='' GROUP BY customers.id, name, lastname, email, pin HAVING SUM((type * -2 +7) * cash.value) < {limit}} {for(i=0; i<number(customers); i++)} {exec echo "NOTE: This message has been generated automatically. We kindly remind that you have debt on your internet service provide account for the amount of $ {customers[i].balance}. If you have already regulated your subscription fees for current month, that is {trim(month)} {trim(year)}, please just skip this message. If you think this message was sent to you in error, please contact our customer service representative. All information about payments could be also found at: http://bigpro.com/myAccount/ If you want to regulate your account status, please contact our accountant: Aldfert Rule phone: 0-509031337 e-mail: alde@staff.bigpro.com PS. Last 10 operations on your account has been attached below for your convenience. --------------+--------------+----------------------------- Date | Value | Comment --------------+--------------+-----------------------------" > /tmp/mail} {last10 = SELECT comment, time, CASE WHEN type=4 THEN value*-1 ELSE value END AS value FROM cash WHERE customerid = {customers[i].id} ORDER BY time DESC LIMIT 10} {for(j=0; j<number(last10); j++)} {exec echo "{last10[j].time}|\t{last10[j].value}|\t{last10[j].comment}" >> /tmp/mail} {/for} {exec mail -s "Liabilities information" -r lms@domain.tld {customers[i].email} < /tmp/mail} {/for}