Konfigurace Asterisku (10) - Výrazy a operátory

Jak jsme si ukázali v minulém dílu seriálu, dialplan Asterisku je svébytný (a svérázný) jazyk. V dnešním pokračování se zaměříme na operátory pro práci s čísly a logickými hodnotami. Ukážeme si také některé záludnosti a zvláštnosti dialplanu Asterisku.

Porovnávání

Asterisk nemá jiný typ proměnné než řetězec. Číslo je reprezentováno jako řetězec, který obsahuje jen číslice, tj. například "123". Algoritmus porovnávání dvou výrazů záleží na jejich typu a typ je dán obsahem porovnávaných proměnných (přesněji operandů). Neobsahují-li operandy jiné znaky než číslice, je provedeno numerické porovnávání, v opačném případě jsou operandy porovnány lexikograficky. Vezměme jednoduchý příklad:

exten => 999,1,Set(a=15)
exten => 999,n,Set(b=5)
exten => 999,n,Set(c=$[${a} > ${b}])
exten => 999,n,NoOp(${c})
exten => 999,n,Set(c=$[x${a} > x${b}])
exten => 999,n,NoOp(${c})

Při prvním porovnávání bude hodnota ${c} nastavena na "1", tj. výsledek porovnávání 15 > 5 je pravda. Operandy byly porovnány numericky. Při druhém porovnávání se mezi sebou porovnávají hodnoty "x15" a "x5". Asterisk je porovnává jako řetězce, tj. lexikograficky. Výsledkem je hodnota "0", tj. nepravda.

Operátory pro porovnávání jsou následující:

>
první operand je ostře větší než druhý
<
první operand je ostře menší než druhý
>=
první operand je větší nebo roven druhému
<=
první operand je menší nebo roven druhému
=
první operand je roven druhému
!=
první operand není roven druhému

 

Aritmetické operátory

Jsou-li operandy celá čísla, je možné použít aritmetické operátory. Zde je přehled binárních aritmetických operátorů:

+
součet
-
rozdíl
*
násobení
/
celočíselné dělení
%
zbytek po celočíselném dělení

 

Kromě binárních operátorů existuje také jeden unární operátor -, který mění znaménko nenulového operandu.

Objasníme chování Asterisku při použití aritmetického operátoru na nečíselné operandy, tj. například


exten => 999,1,Set(a=3f)
exten => 999,n,Set(b=5)
exten => 999,n,Set(c=$[${a} + ${b}])
exten => 999,n,NoOp(${c})
exten => 999,1,Set(a=3.0)
exten => 999,n,Set(c=$[${a} + ${b}])
exten => 999,n,NoOp(${c})

Asterisk na konzoli vypíše varování, že operand není číslo a při provádění aritmetické operace použije místo neplatného operandu nulu:

 

-- Executing [999@internal:1] Set("SIP/novak-088ce210", "a="3f") in new stack
-- Executing [999@internal:2] Set("SIP/novak-088ce210", "b=5") in new stack
-- Executing [999@internal:3] NoOp("SIP/novak-088ce210", "5") in new stack
[Aug 14 16:12:48] WARNING[7745]: ast_expr2.y:698 op_plus: non-numeric argument
-- Executing [999@internal:4] Set("SIP/novak-088ce210", "c=5") in new stack
-- Executing [999@internal:5] NoOp("SIP/novak-088ce210", "5") in new stack
-- Executing [999@internal:6] Set("SIP/novak-088ce210", "a="3.0") in new stack
[Aug 14 16:12:48] WARNING[7745]: ast_expr2.y:926 op_rem: non-numeric argument
-- Executing [999@internal:7] Set("SIP/novak-088ce210", "c=5") in new stack
-- Executing [999@internal:8] NoOp("SIP/novak-088ce210", "5") in new stack

Zajímavé jsou operátory dělení / a modulo %, které nesmí mít jako druhý operand nulu.

exten => 999,1,Set(a=3)
exten => 999,n,Set(b=0)
exten => 999,n,Set(c=$[${a} / ${b}])
exten => 999,n,NoOp(${c})

-- Executing [999@internal:1] Set("SIP/novak-088ce210", "a=3") in new stack
-- Executing [999@internal:2] Set("SIP/novak-088ce210", "b=0") in new stack
[Aug 14 16:15:49] WARNING[7755]: ast_expr2.y:904 op_div: division by zero
-- Executing [999@internal:3] Set("SIP/novak-088ce210", "c=2147483647") in new stack
-- Executing [999@internal:4] NoOp("SIP/novak-088ce210", "2147483647") in new stack

Jak je vidět z příkladu, Asterisk vypíše varování a do výsledku nastaví hodnotu největšího 32-bitového integeru se znaménkem, tj. 2^31-1.

exten => 999,1,Set(a=3)
exten => 999,n,Set(c=$[- ${a}])
exten => 999,n,NoOp(${c})

V proměnné ${c} nakonec skončí hodnota -3.

Logické operátory

Podle voip-info.org znamená hodnota "" (prázdný řetězec), nebo "0" nepravdu (False), všechny ostatní hodnoty proměnných jsou pravda (True). Jak ale uvidíme dále, situace je trochu složitější.

Operátor | má význam logického operátoru nebo. Lze použít i několik takových operátorů za sebou, Asterisk pak dá celému takovému výrazu hodnotu prvního nenulového operandu. Příklady odhalí záludnosti:

exten => 999,n,Set(c=$[53 | 42])

V tomto případě je výsledek hodnota 53 (první nenulový operand).

exten => 999,n,Set(c=$[0 | 42])

V tomto případě je výsledek hodnota 42.

exten => 999,n,Set(c=$[0 | 00 | 42])

V tomto případě je výsledek hodnota 42, dvě nuly jsou číslo s hodnotou 0

exten => 999,n,Set(c=$[0 | 00 | 0])
exten => 999,n,Set(c=$[0 | 00 | 000])

V těchto případech jsou jsou výsledky 0 a 000. Pokud jsou všechny operandy nulové, Asterisk vrátí poslední z nich. Všimněte si, že druhá varianta vrátí řetězec s délkou tři. Výsledek se z výrazu přebírá v textové podobě.

exten => 999,n,Set(c=$["" | 45])

V tomto případě je výsledek "", Asterisk bere uvozovky jako řetězec se dvěma znaky. Pokusíme se ho obelstít za pomoci proměnné:

exten => 999,n,Set(a=)
exten => 999,n,Set(c=$[${a} | 45])

Při vyhodnocování druhého řádku dojde k chybě. Asterisk totiž provede textovou substituci a tak vznikne výraz $[ | 45], se kterým dál pracuje. Asterisk chybějící první operand vyhodnotí jako chybu.

Podobně jako operátor | funguje operátor & s významem logické spojky a. Je-li aspoň jeden z operandů nulový, je výsledek 0.

exten => 999,n,Set(c=$[00 & 000])

V tomto případě je výsledek jeden znak 0. Operátor & v případě nepravdivého výsledku nevrací hodnotu jednoho z operandů.

exten => 999,n,Set(c=$[ahoj & nazdar])

Jsou-li všechny operandy nenulové, použije se jako výsledek hodnota prvního z nich. V předchozích příkladech jsme používali čísla, ale pokud bychom místo nenulových čísel použili řetězce, Asterisk by je zpracoval úplně stejně. V tomto příkladu jsme provedli logické a na dva řetězce, výsledkem je první řetězec ahoj.

Posledním logickým operátorem je negace. Opět se ukazuje, že Asterisk není tak logický, jak by měl být.

exten => 999,n,Set(c=$[!5])

Je-li za vykřičníkem něco jiného než nula, je výsledek 0.

exten => 999,n,Set(c=$[!0])

Je-li za vykřičníkem 0 (nula), je výsledkem 1.

exten => 999,n,Set(c=$[!00])

Jsou-li za vykřičníkem dvě nuly, je výsledkem jednoduchá nula. Zdá se, že operátor negace považuje více nul za pravdu, narozdíl od obou ostatních logických operátorů.

Narozdil od O'Reillyho 600-strankove bichle popisujici Asterisk do posledniho detailu je tato serie strucna, ale vystihujici stravitelnym zpusobem vse podstatne pro bezne uziti doma ci v male firme. Skvele, dekuji!