Luca Bariani
LucaBariani@Ferrara.Linux.it
May 2003
GNU Bayonne is a script driven telephony application server. As such, it has it's own scripting language built by class extension from the GNU ccScript interpreter.
The main characteristics of the ccScript scripting language are described in the document: GNU Bayonne Script Programming Guide; this document gives a lot of examples to show how programming Bayonne using ccScript.
Every example of this document is tested in the indicated environment (Bayonne version, ccScript version, ...) and the output reported after the source.
This document will never be complete: there are always new examples to add (by adding new feature og changing it).
Every example of this document has been tested with Ccscript and/or Bayonne version's as reported in the Testing environment line. To run example example.scr and get the output example.out as reported here follow this steps:
ccscript example.scr
bayonne_start -x -driver dummy
bayonne_control start 0 example
bayonne_control compile
.
bayonne -x --driver dummy
bayonne --control start 0 example
bayonne --control compile
.
The Dummy driver simulates IVR hardware behavior using a normal sound card and a keyboard, so it's possible to run Bayonne without the specific IVR hardware; it's very useful to make a testing/developing environment or to try Bayonne itself.
Using Dummy driver is very simple:
So a phone call simulation is very easy:
Every Bayonne script program must end with the exit instruction, so everything is closed in the right mode. Without the exit instruction, a Bayonne script has an infinite loop. With Ccscript only (without Bayonne) a script can end without the exit instruction without any error. The first two examples are equal, but have different testing environment, so they have completely different output and behavior.
slog "No exit at the end: with ccscript no problem"
luca-noexit1: 1 steps compiled luca-noexit1: No exit at the end: with ccscript no problem exiting..
The output is three lines only, the first is the compile report, the last is for exit and the second is the real output of the script.
slog "No exit at the end: infinite loop"
dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy(0): luca-noexit2: No exit at the end: infinite loop dummy0: hangup...
The output is an infinite loop, to end this we must press `H' and terminate the call.
The basic use of Ccscript variables needs the set instruction (assignment, concatenation); to delete a variable value there is the clear instruction. The instruction slog is very useful for logging out messages.
A basic variable is defined with the set instruction; an undefined variable is like an empty one.
slog %variable # empty value set %variable "luca" # new value slog %variable # prints "luca" clear %variable # empty again slog %variable # no output exit # NB: always an exit at end
luca-set1: 6 steps compiled luca-set1: luca-set1: luca luca-set1: exiting...
The second line is empty because the variable is undefined, the forth line is empty because variable has been cleared.
The set instruction is used in assignment, but in some cases for this purpose the symbol `=' can be used. Using multiple values with set instruction we got string concatenation.
set %var1 "Luca" # string assignment slog %var1 # prints "Luca" set %var2 "10" # numeric assignment slog %var2 # prints "10" %var3 = 100 # alternative numeric assignment slog %var3 # prints "100" %var4 = "Luke" # WRONG: only numbers slog %var4 # prints "0" and not the "Luke" set %var5="Bariani" # both "set" and "=" slog %var5 set %concat1 %var1 %var2 %var3 # string concatenation slog %concat1 # prints "Luca10100" set %concat2 %var1, " ", %var5 # string concatenation with a costant # using comma or not is indifferent slog %concat2 # prints "Luca Bariani" slog %var1 " " %var5 # slog string concatenation # prints "Luca Bariani" again exit # NB: always an exit at the end
luca-set2: 16 steps compiled luca-set2: Luca luca-set2: 10 luca-set2: 100 luca-set2: 0 luca-set2: Bariani luca-set2: Luca10100 luca-set2: Luca Bariani luca-set2: Luca Bariani exiting...
The instructions set.min and set.max allow variable assignment/definition getting the minimum/maximum value from the specified list. The instruction swap allows setting two variables to each other's value.
set %var1=1 # numeric value set %var2=10 # numeric value set %var3=100 # numeric value slog "var1="%var1 ", var2=" %var2 ",var3=" %var3 set.min %min %var1 %var2 %var3 # set to the lesser value set.max %max %var1 %var2 %var3 # set to the greater values slog "min: " %min " max: " %max swap %var1 %var3 # variable exchange slog "var1="%var1 ", var2=" %var2 ",var3=" %var3 exit # NB: always an exit at the end
luca-set3: 10 steps compiled luca-set3: var1=1, var2=10,var3=100 luca-set3: min: 1 max: 100 luca-set3: var1=100, var2=10,var3=1 exiting...
The instructions inc and dec perform the basic numeric operations.
set %var1=10 # numeric value set %var2=10 # numeric value inc %var1 # single increment dec %var2 # single decrement slog "var1=" %var1 ", var2="%var2 inc %var1 4 # arbitrary increment: sum dec %var2 4 # arbitrary decrement: difference slog "var1=" %var1 ", var2="%var2 inc %var1 %var2 # increment with no costants slog "var1=" %var1 ", var2="%var2 exit # NB: always an exit at the end
luca-inc: 11 steps compiled luca-inc: var1=11, var2=9 luca-inc: var1=15, var2=5 luca-inc: var1=20, var2=5 exiting..
A Ccscript package provides new commands and properties to your script. These new features are defined in external modules. To import a package and use its functions there is the command/directive use, so use mypack imports the package mypack.
The trim instruction normalizes a string to a specific length. Normalization can be based on specific offset: start, middle, end. If no offset is specified the default is start. Offset indexing begins with 0, as is the case in Python and Perl.
use digits set %var "1234567890" # a generic variable trim.start %var 6 # leave the first 6 digits slog "var: " %var set %var "1234567890" trim.end %var 6 # leave the last 6 digits slog "var: " %var set %var "1234567890" trim.2 %var 6 # leave the first 6 digits after # the second digit slog "var: " %var set %var "1234567890" trim.start %var 10 # leave the first 10 digits: %var # is inaltered slog "var: " %var exit # NB: always an exit at the end
luca-digits1: 14 steps compiled luca-digits1: var: 123456 luca-digits1: var: 567890 luca-digits1: var: 345678 luca-digits1: var: 1234567890 exiting...
# vim: set ts=8 sw=8: use digits set %var "1234567890" slog "Original string: " %var trim.start %var 7 slog "First 7 digits: " %var trim.end %var 5 slog "Last 5 digits: " %var trim.1 %var 2 slog "2 digits, offset 1: " %var trim.start %var 4 # var unaltered as it's only 2 digits long slog "First 4 digits: " %var trim %var 1 # default offset is start slog "First digit: " %var slog "" set %var "abnormally" slog "Works with letters also: " slog %var trim.start %var 8 slog %var trim.end %var 6 slog %var trim.1 %var 2 slog %var trim %var 1 slog %var exit
jim-digits1: 26 steps compiled jim-digits1: Original string: 1234567890 jim-digits1: First 7 digits: 1234567 jim-digits1: Last 5 digits: 34567 jim-digits1: 2 digits, offset 1: 45 jim-digits1: First 4 digits: 45 jim-digits1: First digit: 4 jim-digits1: jim-digits1: Works with letters also: jim-digits1: abnormally jim-digits1: abnormal jim-digits1: normal jim-digits1: or jim-digits1: o exiting...
The chop instruction cuts digits from a specific offset: start, middle, end. Chop is the inverse of trim. Where trim saves the specified part of the string, chop deletes it.
use digits set %var "1234567890" # a generic variable chop.start %var 6 # cuts the first 6 digits slog "var: " %var set %var "1234567890" chop.end %var 6 # cuts the last 6 digits slog "var: " %var set %var "1234567890" chop.2 %var 6 # cuts the first 6 digits after # the second digit slog "var: " %var set %var "1234567890" chop.10 %var 10 # cuts digits after the tenth digit: %var # is inaltered slog "var: " %var exit # NB: always an exit at the end
luca-digits2: 14 steps compiled luca-digits2: var: 7890 luca-digits2: var: 1234 luca-digits2: var: 1290 luca-digits2: var: 1234567890 exiting...
The delete instruction deletes a specific digit if present in the specified position.
use digits set %var "abcdefg" # a generic variable delete.start %var "a" # if the first digit is "a" deletes it slog "var: " %var set %var "abcdefg" delete.3 %var "d" # if the fourth digit (the first digit is # the number 0) is "d" deletes it slog "var: " %var set %var "abcdefg" delete.0 %var "a" # delete.0 is equal to delete.start slog "var: " %var set %var "abcdefg" delete.2 %var "e" # the 3rd digit in not "e", nothing happens slog "var: " %var set %var "abcdefg" delete.end %var "g" # if the last digit is "g" deletes it slog "var: " %var exit # NB: always an exit at the end
luca-digits3: 17 steps compiled luca-digits3: var: bcdefg luca-digits3: var: abcefg luca-digits3: var: bcdefg luca-digits3: var: abcdefg luca-digits3: var: abcdef exiting...
# vim: set ts=8 sw=8: use digits set %var "abnormally" slog "Original string: " %var delete.start %var "ab" slog "delete.start ab: " %var delete.end %var "ly" slog "delete.end ly: " %var delete.2 %var "rm" slog "delete.2 rm: " %var exit
jim-digits3: 10 steps compiled jim-digits3: Original string: abnormally jim-digits3: delete.start ab: normally jim-digits3: delete.end ly: normal jim-digits3: delete.2 rm: noal exiting...
The insert instruction inserts a digit in a specific offset. Insert did not accept the end keyword until ccscript 2.5.2.
use digits set %var "123456" # a generic variable insert.start %var "a" # insert "a" at the beginning of %var slog "var: " %var set %var "123456" insert.3 %var "AA" # insert after the fourth digit # (the first digit is the number 0) slog "var: " %var set %var "123456" insert.0 %var "a" # insert.0 is equal to insert.start slog "var: " %var exit # NB: always an exit at the end
luca-digits4: 11 steps compiled luca-digits4: var: a123456 luca-digits4: var: 123AA456 luca-digits4: var: a123456 exiting...
# vim: set ts=8 sw=8: use digits set %var "noal" slog "Original string: " %var insert.2 %var "rm" slog "Insert.2 rm: " %var insert.start %var "ab" slog "insert.start ab: " %var insert.end %var "ly" slog "insert.end ly: " %var exit
jim-digits4: 10 steps compiled jim-digits4: Original string: noal jim-digits4: Insert.2 rm: normal jim-digits4: insert.start ab: abnormal jim-digits4: insert.end ly: lyabnormal exiting...
The prefix instruction inserts a digit in at a beginning of a string, but only if it's not already present. Using an offset or the end keyword leaves the string unchanged.
use digits set %var "123456" # a generic variable prefix.start %var "a" # insert "a" at the beginning of # %var because $var starts with 1 slog "var: " %var set %var "123456" prefix.0 %var "a" # insert.0 is equal to insert.start slog "var: " %var set %var "123456" prefix.start %var "1" # doesn't insert "1" at the beginning # of %var because $var already # starts with 1 slog "var: " %var exit # NB: always an exit at the end
luca-digits5: 11 steps compiled luca-digits5: var: a123456 luca-digits5: var: a123456 luca-digits5: var: 123456 exiting...
# vim: set ts=8 sw=8: use digits set %var "normal" slog "Original string: " %var prefix.start %var "no" slog "prefix.start 'no': " %var prefix.start %var "ab" slog "prefix.start 'ab': " %var prefix.end %var "ly" slog "prefix.end 'ly' does nothing: " %var prefix.4 %var "licious" slog "Nor does prefix.4: " %var exit
jim-digits5: 12 steps compiled jim-digits5: Original string: normal jim-digits5: prefix.start 'no': normal jim-digits5: prefix.start 'ab': abnormal jim-digits5: prefix.end 'ly' does nothing: lyabnormal jim-digits5: Nor does prefix.4: lyabnormal exiting...
The replace instruction replace a character with different string, at the specific offset.
use digits set %var "abcdefg" # a generic variable replace.start %var "a" "A" # if the first digit is "a" # replaces it slog "var: " %var set %var "abcdefg" replace.3 %var "d" "D" # if the fourth digit (the first digit # is the number 0) is "d" replaces it slog "var: " %var set %var "abcdefg" replace.0 %var "a" "A" # replace.0 is equal to replace.start slog "var: " %var set %var "abcdefg" replace.2 %var "e" "E" # the 3rd digit in not "e" # nothing happens slog "var: " %var set %var "abcdefg" replace.end %var "g" "G" # if the last digit is "g" # replaces it slog "var: " %var exit # NB: always an exit at the end
luca-digits6: 17 steps compiled luca-digits6: var: Abcdefg luca-digits6: var: abcDefg luca-digits6: var: Abcdefg luca-digits6: var: abcdefg luca-digits6: var: abcdefG exiting...
# vim: set ts=8 sw=8: use digits set %var "abnormally" slog "Original string: " %var replace.2 %var "normal" "ysmal" slog "Updated string: " %var exit
jim-digits6: 6 steps compiled jim-digits6: Original string: abnormally jim-digits6: Updated string: abysmally exiting...
Replacing a character with another string:
use digits set %var "abcdefg" # a generic variable replace.start %var "a" "AB" # if the first digit is "a" # replaces it with AB slog "var: " %var set %var "abcdefg" replace.end %var "g" "GH" # if the last digit is "g" # replaces it with GH slog "var: " %var exit # NB: always an exit at the end
luca-digits7: 8 steps compiled luca-digits7: var: ABbcdefg luca-digits7: var: abcdefGH exiting...
# vim: set ts=8 sw=8: use random random.seed 6 # same numbers each time we run repeat 5 random.9 %var # 1 <= %var <= 9 slog %var loop slog " " random.seed 6 # Restart RNG repeat 5 random.9 %var # Same numbers as above slog %var loop slog " " random.9 seed=6 %var1 %var2 %var3 %var4 %var5 # Same numbers, once again slog %var1 ", " %var2 ", " %var3 ", " %var4 ", " %var5 exit
jim-random1: 16 steps compiled jim-random1: 2 jim-random1: 9 jim-random1: 8 jim-random1: 4 jim-random1: 1 jim-random1: jim-random1: 2 jim-random1: 9 jim-random1: 8 jim-random1: 4 jim-random1: 1 jim-random1: jim-random1: 2, 9, 8, 4, 1 exiting...
There are several modifiers for the random number stream.
# vim: set ts=8 sw=8: use random repeat 20 random.6 count=2 %var1 # Simulate throwing 2 dice slog %var1 loop slog " " repeat 20 random.6 count=2 reroll=4 %var1 # Simulate throwing 2 dice slog %var1 loop exit
jim-random2: 11 steps compiled jim-random2: 8 jim-random2: 5 jim-random2: 7 jim-random2: 5 jim-random2: 4 jim-random2: 10 jim-random2: 6 jim-random2: 6 jim-random2: 11 jim-random2: 6 jim-random2: 7 jim-random2: 8 jim-random2: 6 jim-random2: 6 jim-random2: 2 jim-random2: 11 jim-random2: 8 jim-random2: 6 jim-random2: 6 jim-random2: 5 jim-random2: jim-random2: 6 jim-random2: 10 jim-random2: 7 jim-random2: 5 jim-random2: 6 jim-random2: 12 jim-random2: 11 jim-random2: 9 jim-random2: 6 jim-random2: 8 jim-random2: 6 jim-random2: 10 jim-random2: 12 jim-random2: 7 jim-random2: 6 jim-random2: 6 jim-random2: 8 jim-random2: 5 jim-random2: 5 jim-random2: 6 exiting...
Notice the way min and max are defined. As can be seen in the following example, careless use weights the RNG stream to the minimum/maximum, which is probably not what is wanted. Use a range and an offset to get a true set of random numbers in a given range.
# vim: set ts=8 sw=8: use random random.seed 300 random.4 seed=0 offset=4 %var1 %var2 %var3 %var4 %var5 \ %var6 %var7 %var8 %var9 %var10 %var11 %var12 \ %var13 %var14 %var15 %var16 %var17 %var18 \ %var19 %var20 slog "Evenly distributed: " slog %var1 ", " %var2 ", " %var3 ", " %var4 ", " \ %var5 ", " %var6 ", " %var7 ", " %var8 ", " \ %var9 ", " %var10 ", "%var11 ", " %var12 ", " \ %var13 ", " %var14 ", " %var15 ", " %var16 \ ", " %var17 ", " %var18 ", " %var19 ", " %var20 random.10 seed=0 min=5 max=8 %var1 %var2 %var3 %var4 \ %var5 %var6 %var7 %var8 %var9 %var10 %var11 \ %var12 %var13 %var14 %var15 %var16 %var17 \ %var18 %var19 %var20 slog "Weighted at 5 and 8:" slog %var1 ", " %var2 ", " %var3 ", " %var4 ", " \ %var5 ", " %var6 ", " %var7 ", " %var8 ", " \ %var9 ", " %var10 ", "%var11 ", " %var12 ", " \ %var13 ", " %var14 ", " %var15 ", " %var16 \ ", " %var17 ", " %var18 ", " %var19 ", " %var20 random.4 seed=0 offset=4 %var1 %var2 %var3 %var4 %var5 \ %var6 %var7 %var8 %var9 %var10 %var11 %var12 \ %var13 %var14 %var15 %var16 %var17 %var18 \ %var19 %var20 exit
jim-random3: 10 steps compiled jim-random3: Evenly distributed: jim-random3: 8, 6, 8, 8, 8, 5, 6, 8, 6, 7, 6, 7, 6, 7, 8, 8, 7, 7, 5, 7 jim-random3: Weighted at 5 and 8: jim-random3: 8, 5, 8, 8, 8, 5, 5, 8, 5, 6, 5, 7, 5, 6, 8, 8, 7, 8, 5, 7 exiting...
use sort sequence 5 %seq post %seq 3 5 2 1 4 # five values in random order dup %seq %seqUp # sequenze duplication dup %seq %seqDown # sort %seqUp # normal sort sort.reverse %seqDown # reverse sort slog "original: " %seq " up: " %seqUp " down: " %seqDown slog "original: " %seq " up: " %seqUp " down: " %seqDown slog "original: " %seq " up: " %seqUp " down: " %seqDown slog "original: " %seq " up: " %seqUp " down: " %seqDown slog "original: " %seq " up: " %seqUp " down: " %seqDown exit # NB: always an exit at end
luca-sort1: 13 steps compiled luca-sort1: original: 3 up: 1 down: 5 luca-sort1: original: 5 up: 2 down: 4 luca-sort1: original: 2 up: 3 down: 3 luca-sort1: original: 1 up: 4 down: 2 luca-sort1: original: 4 up: 5 down: 1 exiting...
use sort set %list "2,5,3,4,1" dup %list %listUp # list duplication dup %list %listDown # sort %listUp # normal sort sort.reverse %listDown # reverse sort slog "original: "%list slog "up ordered: "%listUp slog "down ordered: "%listDown exit # NB: always an exit at end
luca-sort2: 10 steps compiled luca-sort2: original: 2,5,3,4,1 luca-sort2: up ordered: 1,2,3,4,5 luca-sort2: down ordered: 5,4,3,2,1 exiting...
Ccscript allows some complex data structures and some specific and automatic operations on them.
Ccscript allows time and date manipulation with particular data structures. For definition and assignment there are instructions set.time and set.date. These data structures support basic operation like inc and dec which results are always valid time or date values.
use date set.date %date "20031225" # a date dup %date %minus1 # date copy dup %date %minus30 dup %date %add1 dup %date %add10 slog "date (mouth/day/year): "%date dec.date %minus1 # date - 1 day dec.date %minus30 30 # date - 30 days inc.date %add1 # date + 1 day inc.date %add10 10 # date + 10 days slog "one day before "%minus1 slog "30 days before "%minus30 slog "one day after "%add1 slog "10 days after "%add10 exit # NB: always an exit at the end
luca-date: 16 steps compiled luca-date: date (mouth/day/year): 12/25/2003 luca-date: one day before 12/24/2003 luca-date: 30 days before 11/25/2003 luca-date: one day after 12/26/2003 luca-date: 10 days after 01/04/2004 exiting...
use time set.time %time "115700" # a time dup %time %minus1 dup %time %minus70 dup %time %minus4000 dup %time %add1 dup %time %add70 dup %time %add4000 slog "time (HH:MM:SS): "%time dec.time %minus1 slog "one second before: " %minus1 dec.time %minus70 70 slog "70 seconds before: " %minus70 dec.time %minus4000 4000 slog "4000 seconds before: " %minus4000 inc.time %add1 slog "one second after: " %add1 inc.time %add70 70 slog "70 seconds after: " %add70 inc.time %add4000 4000 slog "4000 seconds after: " %add4000 exit # NB: always an exit at the end
luca-time: 22 steps compiled luca-time: time (HH:MM:SS): 11:57:00 luca-time: one second before: 11:56:59 luca-time: 70 seconds before: 11:55:50 luca-time: 4000 seconds before: 10:50:20 luca-time: one second after: 11:57:01 luca-time: 70 seconds after: 11:58:10 luca-time: 4000 seconds after: 13:03:40 exiting...
A counter data structure is a variable which is incremented at every use.
counter %count # counter definition slog "counter " %count # prints count and increments it slog "counter " %count # prints count and increments it slog "counter " %count # prints count and increments it exit # NB: always an exit at the end
luca-count: 5 steps compiled luca-count: counter 1 luca-count: counter 2 luca-count: counter 3 exiting...
The stack and fifo are dynamic structures (FIFO = First In First Out, Stack = LIFO = Last In First Out); they store values with post instruction and release them at every use, a value can be deleted with remove. Of course using post and remove don't release a value from structure.
stack 3 %stck # stack declaration post %stck 1 # insert a value, stck = 1 post %stck 2 # insert a value, stck = 2 1 post %stck 3 # insert a value, stck = 3 2 1 slog "stck " %stck # prints the stack value and remove it, stck = 2 1 slog "stck " %stck # prints the stack value and remove it, stck = 1 slog "stck " %stck # prints the stack value and remove it, stck = slog "stck " %stck # prints an empty value: the stack is empty post %stck 1 2 3 # multiple post, stck = 3 2 1 slog "stck " %stck # prints the stack value and remove it, stck = 2 1 slog "stck " %stck # prints the stack value and remove it, stck = 1 slog "stck " %stck # prints the stack value and remove it, stck = post %stck 1 2 3 4 # too many elements: the stack has size 3 # the fourth value is ignored slog "stck " %stck # prints 3 and not 4, stck = 2 1 slog "stck " %stck # prints the stack value and remove it, stck = 1 slog "stck " %stck # prints the stack value and remove it, stck = slog "stck " %stck # prints an empty value: the stack is empty post %stck 1,2,3 # post: with or without commas remove %stck 2 # remove a value from stack, stck = 3 1 remove %stck 10 # does nothing: value not present into the stack slog "stck " %stck # prints the stack value and remove it, stck = 1 slog "stck " %stck # prints the stack value and remove it, stck = slog "stck " %stck # prints an empty value: the stack is empty exit # NB: always an exit at the end
luca-stack: 24 steps compiled luca-stack: stck 3 luca-stack: stck 2 luca-stack: stck 1 luca-stack: stck luca-stack: stck 3 luca-stack: stck 2 luca-stack: stck 1 luca-stack: stck 3 luca-stack: stck 2 luca-stack: stck 1 luca-stack: stck luca-stack: stck 3 luca-stack: stck 1 luca-stack: stck exiting...
FIXME fifo bug FIXME
fifo 3 %fifo # fifo declaration post %fifo 1 # insert a value, fifo = 1 post %fifo 2 # insert a value, fifo = 1 2 post %fifo 3 # insert a value, fifo = 1 2 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = 2 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = slog "fifo " %fifo # prints an empty value: the fifo is empty post %fifo 1 2 3 # multiple post, fifo = 1 2 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = 2 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = post %fifo 1 2 3 4 # too many elements: the fifo has size 3 # the fourth value is ignored slog "fifo " %fifo # prints 1, fifo = 2 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = slog "fifo " %fifo # prints an empty value: the fifo is empty post %fifo 1,2,3 # post: with or without commas remove %fifo 2 # remove a value from fifo, fifo = 1 3 remove %fifo 10 # does nothing: value not present into the fifo slog "fifo " %fifo # prints the fifo value and remove it, fifo = 3 slog "fifo " %fifo # prints the fifo value and remove it, fifo = slog "fifo " %fifo # prints an empty value: the fifo is empty exit # NB: always an exit at the end
luca-fifo: 24 steps compiled luca-fifo: fifo 1 luca-fifo: fifo 2 luca-fifo: fifo luca-fifo: fifo luca-fifo: fifo 1 luca-fifo: fifo 2 luca-fifo: fifo luca-fifo: fifo 1 luca-fifo: fifo 2 luca-fifo: fifo luca-fifo: fifo luca-fifo: fifo 1 luca-fifo: fifo luca-fifo: fifo exiting...
The sequence structure is also dynamic, but doesn't remove a value after using it: when the last element is used, the next referenced is the first again. So from a not empty sequence is always possible getting values. With instructions post and remove is possible to add/remove values to/from sequence.
sequence 3 %seq # sequence declaration post %seq 1 # insert a value, seq = 1 post %seq 2 3 # insert two values, seq = 1 2 3 slog "seq " %seq # prints the sequence value 1 slog "seq " %seq # prints the sequence value 2 slog "seq " %seq # prints the sequence value 3 slog "seq " %seq # prints the first value again: 1 remove %seq 2 # remove a value from sequence remove %seq 10 # does nothing: value not present # into the sequence slog "seq " %seq # prints the sequence value 3 slog "seq " %seq # prints the sequence value 1 slog "seq " %seq # prints the sequence value 3 sequence 3 %seq2 # another sequence post %seq2 1 2 3 4 # too many elements: sequenze has size 3 # the fourth element is ignered slog "seq2 " %seq2 # prints the sequence value 1 slog "seq2 " %seq2 # prints the sequence value 2 slog "seq2 " %seq2 # prints the sequence value 3 slog "seq2 " %seq2 # prints the sequence value 1 not 4 exit # NB: always an exit at the end
luca-sequence: 19 steps compiled luca-sequence: seq 1 luca-sequence: seq 2 luca-sequence: seq 3 luca-sequence: seq 1 luca-sequence: seq 3 luca-sequence: seq 1 luca-sequence: seq 3 luca-sequence: seq2 1 luca-sequence: seq2 2 luca-sequence: seq2 3 luca-sequence: seq2 1 exiting...
Ccscript array are not dynamic, but have a finite and fixed size. Arrays support three different notation (with array %vett):
array 3 %vett # array declaration set %vett.1 10 # setting values set %vett.2 20 set %vett.3 30 # basic notation slog "vett.1 " %vett.1 slog "vett.2 " %vett.2 slog "vett.3 " %vett.3 # index notation: useful for loops set %vett.index 1 slog "element with index " %vett.index ": "%vett set %vett.index 2 slog "element with index " %vett.index ": "%vett set %vett.index 3 slog "element with index " %vett.index ": "%vett # hash notation: still useful for loops set %tmp 1 slog "vett#%tmp: " %vett#%tmp set %tmp 2 slog "vett#%tmp: " %vett#%tmp set %tmp 3 slog "vett#%tmp: " %vett#%tmp exit # NB: always an exit at the end
luca-array: 20 steps compiled luca-array: vett.1 10 luca-array: vett.2 20 luca-array: vett.3 30 luca-array: element with index 1: 10 luca-array: element with index 2: 20 luca-array: element with index 3: 30 luca-array: vett#%tmp: 10 luca-array: vett#%tmp: 20 luca-array: vett#%tmp: 30 exiting...
A list is a set of variables separated by a token (the default token is `,' and is stored in %script.token). To access the element there is the %list.n notation.
set %list1 "a,b,c,d,e" slog "list1: " %list1 slog "list1 second element: " %list1.2 # direct access set %list2 "f-g-h-i-l" slog "list2: " %list2 slog "list2 second element (token ,): " %list2.2 # empty value set %script.token "-" # changes the token symbol slog "list2 second element (token -): " %list2.2 # right value exit # NB: always an exit at end
luca-list: 9 steps compiled luca-list: list1: a,b,c,d,e luca-list: list1 second element: b luca-list: list2: f-g-h-i-l luca-list: list2 second element (token ,): luca-list: list2 second element (token -): g exiting...
The fifth line has no value because the token `-' is unrecognized, in the sixth one the output is right because %script.token changed to `-'.
In the package string (use string) there are some useful functions for lists. To create a list from several variables there is the instruction string.pack, so in the following examples lists are also called packed strings.
use string string.pack %pack1 1 2 3 # basic definition slog %pack1 string.pack %pack2 token=- 1 2 3 # use "-" instead of dafault = "," slog %pack2 string.pack %pack3 size=3 1 2 3 # with size=3 not enough space for slog %pack3 # all values string.pack %pack4 prefix="start" suffix="end" 1 2 3 # defines a starting and ending values slog %pack4 string.pack %pack5 size=20 fill="FILL" 1 2 3 # add as many values "FILL" as possible slog %pack5 string.pack %pack6 size=22 fill="FILL" 1 2 3 # add as many values "FILL" as possible # the last "FILL" value i trunced by size slog %pack6 exit # NB: always an exit at end
luca-pack1: 14 steps compiled luca-pack1: 1,2,3 luca-pack1: 1-2-3 luca-pack1: 1,2 luca-pack1: start,1,2,3,end luca-pack1: 1,2,3,FILL,FILL,FILL luca-pack1: 1,2,3,FILL,FILL,FILL,F exiting...
In the output line there are the results of the different kind of list creation.
The string.pack instruction allows appending, while string.repack and string.clear allow list redefine and list clear respectively.
use string string.pack %pack 1 2 3 # basic definition slog %pack string.pack %pack 4 5 6 # basic appending slog %pack string.repack token='-' %pack 7 8 9 # basic redefine slog %pack string.clear %pack # clear the string slog %pack exit # NB: always an exit at end
luca-pack2: 10 steps compiled luca-pack2: 1,2,3 luca-pack2: 1,2,3,4,5,6 luca-pack2: 7-8-9 luca-pack2: exiting...
With string.unpack instruction is possible to extract values from a list, while with string.cut values are removed from list too.
use string string.pack %pack1 10 20 30 # basic definition string.pack token=- %pack2 40 50 60 slog %pack1 " " %pack2 # gets 3 values from pack and places into variables string.unpack %pack1 %v1 %v2 %v3 slog "v1:"%v1 " v2:" %v2 " v3:" %v3 # gets value from pack starting by the second, the first # value is the number 1 string.unpack offset=2 %pack1 %v4 %v5 slog "v4:"%v4 " v5:" %v5 # this doesn't work: the token is not the default string.unpack %pack2 %v4 %v5 %v6 slog "v4: "%v4 " v5:" %v5 " v6:" %v6 # this work: the token is defined string.unpack token=- %pack2 %v1 %v2 %v3 slog "v1:"%v1 " v2:" %v2 " v3:" %v3 # gets 3 values from pack, places into variables # and remove them string.cut %pack1 %v1 %v2 %v3 # now %pack1 is empty slog "v1:"%v1 " v2:" %v2 " v3:" %v3 " pack1: " %pack1 # get and remove the second value from %pack2 string.cut token=- offset=2 %pack2 %v5 slog "v5:"%v5 " pack2: " %pack2 exit # NB: always an exit at end
luca-pack3: 17 steps compiled luca-pack3: 10,20,30 40-50-60 luca-pack3: v1:10 v2:20 v3:30 luca-pack3: v4:20 v5:30 luca-pack3: v4: 40-50-60 v5:30 v6: luca-pack3: v1:40 v2:50 v3:60 luca-pack3: v1:30 v2:20 v3:10 pack1: luca-pack3: v5:50 pack2: 40-60 exiting...
The instruction dup allows the duplication of a data structure.
sequence 5 %seq post %seq 1 2 3 4 # five values in random order dup %seq %seq2 # sequenze duplication stack 5 %stck post %stck 1 2 3 4 # five values in random order dup %stck %stck2 # sequenze duplication slog "original seq: " %seq " original stack: " %stck slog "seq:" %seq " seq2:" %seq2 " stck:" %stck " stck2:" %stck2 slog "seq:" %seq " seq2:" %seq2 " stck:" %stck " stck2:" %stck2 slog "seq:" %seq " seq2:" %seq2 " stck:" %stck " stck2:" %stck2 slog "seq:" %seq " seq2:" %seq2 " stck:" %stck " stck2:" %stck2 exit # NB: always an exit at end
luca-dup: 12 steps compiled luca-dup: original seq: 1 original stack: 4 luca-dup: seq:2 seq2:1 stck:3 stck2:4 luca-dup: seq:3 seq2:2 stck:2 stck2:3 luca-dup: seq:4 seq2:3 stck:1 stck2:2 luca-dup: seq:1 seq2:4 stck: stck2:1 exiting...
A Ccscript property is basically a function applied to a variable using the dot notation %var.property; this property function can return an internal value, like the maximun size of dynamic structure, or something else. Many property are defined into external package, so there's the need to import them (use package).
The type and size property get the basic information about data structures or variables.
use date use time use string set %v1 10 set %v2 text set.date %v3 20031225 set.time %v4 115700 slog "number v1,val: "%v1 " type: " %v1.type ", size:" %v1.size slog "string v2,val: "%v2 " type: " %v2.type ", size:" %v2.size slog "date v3,val: "%v3 " type: " %v3.type ", size:" %v3.size slog "time v4,val: "%v4 " type: " %v4.type ", size:" %v4.size sequence 3 %v5 fifo 4 %v6 stack 5 %v7 array 6 %v8 string.pack %v9 1 2 3 counter %v10 slog "sequence v5 type: " %v5.type ", size: " %v5.size slog "fifo v6 type: " %v6.type ", size: " %v6.size slog "stack v7 type: " %v7.type ", size: " %v7.size slog "array v8 type: " %v8.type ", size: " %v8.size slog "pack v9 type: " %v9.type ", size: " %v9.size slog "counter v10 type: " %v10.type " size: " %v10.size exit # NB: always an exit at end
luca-typesize: 24 steps compiled luca-typesize: number v1,val: 10 type: string, size:64 luca-typesize: string v2,val: text type: string, size:64 luca-typesize: date v3,val: 12/25/2003 type: string, size:10 luca-typesize: time v4,val: 11:57:00 type: string, size:8 luca-typesize: sequence v5 type: sequence, size: 62 luca-typesize: fifo v6 type: fifo, size: 61 luca-typesize: stack v7 type: stack, size: 60 luca-typesize: array v8 type: luca-typesize: pack v9 type: string, size: 64 luca-typesize: counter v10 type: counter size: 11 exiting...
In the date package there are some useful properties to get year, month, day values or day name.
FIXME (monthof) FIXME
use date set.date %dayDate "20031225" # Chrismas 2003 slog "dayDate: " %dayDate slog %dayDate.date " " %dayDate.monthof " " %dayDate.weekday slog %dayDate.year " " %dayDate.month " " %dayDate.day set %dayStr "20031225" # Chrismas 2003 slog "dayStr: " %dayStr slog %dayStr.date " " %dayStr.monthof " " %dayStr.weekday slog %dayStr.year " " %dayStr.month " " %dayStr.day exit # NB: always an exit at the end
luca-dateProp: 12 steps compiled luca-dateProp: dayDate 12/25/2003 luca-dateProp: string 10 10 luca-dateProp: 20031225 20031225 thursday luca-dateProp: 2003 12 25 luca-dateProp: dayStr 20031225 luca-dateProp: string 8 64 luca-dateProp: 20031225 20031225 thursday luca-dateProp: 2003 12 25 exiting...
use time set.time %nowTime "115740" # a time slog "nowTime " %nowTime slog %nowTime.time slog %nowTime.hour " " %nowTime.minute " " %nowTime.second set %nowStr "125740" # a time slog "nowStr " %nowStr slog %nowStr.hour " " %nowStr.minute " " %nowStr.second exit # NB: always an exit at the end
luca-timeProp: 9 steps compiled luca-timeProp: nowTime 11:57:40 luca-timeProp: 115740 luca-timeProp: 11 57 40 luca-timeProp: nowStr 125740 luca-timeProp: 12 57 40 exiting...
use string set %var "abcd" # a generic variable slog "uppecase: " %var.upper set %var "ABCD" slog "lowercase: " %var.lower set %var "abcd" slog "capitalize: " %var.capitalize set %var " abcd " # with spaces slog "with spaces:-" %var "-" slog "without spaces:-" %var.trim "-" exit # NB: always an exit at the end
luca-stringProp: 11 steps compiled luca-stringProp: uppecase: ABCD luca-stringProp: lowercase: abcd luca-stringProp: capitalize: Abcd luca-stringProp: with spaces:- abcd - luca-stringProp: without spaces:-abcd- exiting...
use digits set %str "ccscript" set %list %str.each slog "list of digits: " %list exit # NB: always an exit at end
luca-each: 5 steps compiled luca-each: list of digits: c,c,s,c,r,i,p,t exiting...
In this section there are examples for basic loops, conditional structures and conditional loops.
To loop n times there are the following instructions:
counter %count repeat 3 # loop without index or condition slog "counter: " %count loop # closes the loop exit # NB: always an exit at the end
luca-repeat: 5 steps compiled luca-repeat: counter: 1 luca-repeat: counter: 2 luca-repeat: counter: 3 exiting...
for %index 1 2 3 4 a b string # any value slog "index: " %index loop # closes the loop exit # NB: always an exit at the end
luca-for: 4 steps compiled luca-for: index: 1 luca-for: index: 2 luca-for: index: 3 luca-for: index: 4 luca-for: index: a luca-for: index: b luca-for: index: string exiting...
use string # to use packed string foreach %index "1,2,3,4,a,b,string" # any value slog "index: " %index loop # closes the loop string.pack %pack 5 6 7 c d "any value" slog "with packed string: " %pack foreach %index %pack slog "index: " %index loop # closes the loop exit # NB: always an exit at the end
luca-foreach: 10 steps compiled luca-foreach: index: 1 luca-foreach: index: 2 luca-foreach: index: 3 luca-foreach: index: 4 luca-foreach: index: a luca-foreach: index: b luca-foreach: index: string luca-foreach: with packed string: 5,6,7,c,d,any value luca-foreach: index: 5 luca-foreach: index: 6 luca-foreach: index: 7 luca-foreach: index: c luca-foreach: index: d luca-foreach: index: any value exiting...
Ccscript conditions are of two types: numerical ones and string ones.
The numerical conditions are:
The next two examples have the same output.
for %index 1 2 3 4 # any value slog "index " %index if %index -eq 1 then slog "index equals 1" if %index -ne 1 then slog "index not equals 1" if %index -lt 3 then slog "index less than 3" if %index -le 3 then slog "index less equal 3" if %index -ge 2 then slog "index greater equal 2" if %index -gt 2 then slog "index greater than 2" loop # closes the loop exit # NB: always an exit at the end
luca-cond1: 16 steps compiled luca-cond1: index 1 luca-cond1: index equals 1 luca-cond1: index less than 3 luca-cond1: index less equal 3 luca-cond1: index 2 luca-cond1: index not equals 1 luca-cond1: index less than 3 luca-cond1: index less equal 3 luca-cond1: index greater equal 2 luca-cond1: index 3 luca-cond1: index not equals 1 luca-cond1: index less equal 3 luca-cond1: index greater equal 2 luca-cond1: index greater than 2 luca-cond1: index 4 luca-cond1: index not equals 1 luca-cond1: index greater equal 2 luca-cond1: index greater than 2 exiting...
for %index 1 2 3 4 # any value slog "index " %index if %index = 1 then slog "index equals 1" if %index <> 1 then slog "index not equals 1" if %index < 3 then slog "index less than 3" if %index <= 3 then slog "index less equal 3" if %index >= 2 then slog "index greater equal 2" if %index > 2 then slog "index greater than 2" loop # closes the loop exit # NB: always an exit at the end
luca-cond2: 16 steps compiled luca-cond2: index 1 luca-cond2: index equals 1 luca-cond2: index less than 3 luca-cond2: index less equal 3 luca-cond2: index 2 luca-cond2: index not equals 1 luca-cond2: index less than 3 luca-cond2: index less equal 3 luca-cond2: index greater equal 2 luca-cond2: index 3 luca-cond2: index not equals 1 luca-cond2: index less equal 3 luca-cond2: index greater equal 2 luca-cond2: index greater than 2 luca-cond2: index 4 luca-cond2: index not equals 1 luca-cond2: index greater equal 2 luca-cond2: index greater than 2 exiting..
The string conditions are:
The next two examples have the same output.
for %index a aa bb cc # any value slog "index " %index if %index .eq. a then slog "index equals a" if %index .ne. a then slog "index not equals a" if %index $< aab then slog "index is a prefix of aab" if %index $> cbb then slog "index is a suffix of cbb" loop # closes the loop exit # NB: always an exit at the end
luca-cond3: 12 steps compiled luca-cond3: index a luca-cond3: index equals a luca-cond3: index is a prefix of aab luca-cond3: index aa luca-cond3: index not equals a luca-cond3: index is a prefix of aab luca-cond3: index bb luca-cond3: index not equals a luca-cond3: index is a suffix of cbb luca-cond3: index cc luca-cond3: index not equals a exiting...
for %index a aa bb cc # any value slog "index " %index if %index == a then slog "index equals a" if %index != a then slog "index not equals a" if %index $+ aab then slog "index is a prefix of aab" if %index $- cbb then slog "index is a suffix of cbb" loop # closes the loop exit # NB: always an exit at the end
luca-cond4: 12 steps compiled luca-cond4: index a luca-cond4: index equals a luca-cond4: index not equals a luca-cond4: index is a prefix of aab luca-cond4: index aa luca-cond4: index not equals a luca-cond4: index is a prefix of aab luca-cond4: index bb luca-cond4: index not equals a luca-cond4: index is a suffix of cbb luca-cond4: index cc luca-cond4: index not equals a exiting...
For strings Ccscript allows a case sensitive condition:
for %index aa AA "aa bb" "bb aa" "AA bb" "b aa b" "b aaa" slog "index " %index if aa $ %index then slog "index contains aa" loop # closes the loop exit # NB: always an exit at the end
luca-cond5: 6 steps compiled luca-cond5: index aa luca-cond5: index contains aa luca-cond5: index AA luca-cond5: index aa bb luca-cond5: index contains aa luca-cond5: index bb aa luca-cond5: index contains aa luca-cond5: index AA bb luca-cond5: index b aa b luca-cond5: index contains aa luca-cond5: index b aaa luca-cond5: index contains aa exiting...
Two or more conditions can be composed using the operators and and or.
for %index 1 2 3 4 # any value slog "index " %index if %index -eq 1 or %index -eq 3 then slog "index is odd" if %index -gt 1 and %index -lt 4 then slog "index is 2 or 3" loop # closes the loop exit # NB: always an exit at the end
luca-cond6: 8 steps compiled luca-cond6: index 1 luca-cond6: index is odd luca-cond6: index 2 luca-cond6: index is 2 or 3 luca-cond6: index 3 luca-cond6: index is odd luca-cond6: index is 2 or 3 luca-cond6: index 4
Ccscript has two conditional structures:
for %index 1 2 3 4 # any value if %index -eq 4 then slog "index is 4" # single line statement if %index -eq 1 or %index -eq 3 then # in this block as many statement as we wish slog "index " %index slog "index is odd" else slog "index " %index slog "index is even" endif loop # closes the loop exit # NB: always an exit at the end
luca-if: 13 steps compiled luca-if: index 1 luca-if: index is odd luca-if: index 2 luca-if: index is even luca-if: index 3 luca-if: index is odd luca-if: index is 4 luca-if: index 4 luca-if: index is even exiting....
In the following example there is a case with mutual exclusive condition:
for %index 0 1 2 3 4 # any value case %index -eq 1 or %index -eq 3 slog "index " %index slog "index is odd" case %index -eq 2 or %index -eq 4 slog "index " %index slog "index is even" otherwise slog "index " %index " is null" endcase loop # closes the loop exit # NB: always an exit at the end
e1: 12 steps compiled luca-case1: index 0 is null luca-case1: index 1 luca-case1: index is odd luca-case1: index 2 luca-case1: index is even luca-case1: index 3 luca-case1: index is odd luca-case1: index 4 luca-case1: index is even exiting...
In the following example there is a case without mutual exclusive condition:
for %index 0 1 2 3 4 # any value slog "index " %index case %index -eq 1 or %index -eq 4 slog "index is a square" case %index -eq 1 or %index -eq 3 slog "index is odd" case %index -eq 2 or %index -eq 4 slog "index is even" endcase loop # closes the loop exit # NB: always an exit at the end
luca-case2: 11 steps compiled luca-case2: index 0 luca-case2: index 1 luca-case2: index is a square luca-case2: index 2 luca-case2: index is even luca-case2: index 3 luca-case2: index is odd luca-case2: index 4 luca-case2: index is a square exiting...
By output it's possible to see that in the case structure when one condition is true all other condition are ignored.
To make loop with initial and/or end conditions Ccscript has do loop structure:
The loop instruction supports conditions with commands for, foreach and repear, but in these cases is often used without condition.
set %index 0 do %index -lt 4 # condition before loop slog "index: " %index inc %index loop # closes the loop do %index -lt 4 # can be never execuded slog "index: " %index inc %index loop # closes the loop exit # NB: always an exit at the end
luca-doloop1: 10 steps compiled luca-doloop1: index: 0 luca-doloop1: index: 1 luca-doloop1: index: 2 luca-doloop1: index: 3 exiting...
set %index 0 do # no condition before loop slog "index: " %index inc %index loop %index -lt 4 # condition after loop do # always execuded at least once slog "index: " %index inc %index loop %index -lt 4 # condition aftere loop exit # NB: always an exit at the end
luca-doloop2: 10 steps compiled luca-doloop2: index: 0 luca-doloop2: index: 1 luca-doloop2: index: 2 luca-doloop2: index: 3 luca-doloop2: index: 4 exiting...
set %index1 0 set %index2 10 do %index1 -lt 5 # condition before loop slog "index1: " %index1 " index2: " %index2 inc %index1 dec %index2 loop %index2 -gt 5 # condition after loop exit # NB: always an exit at the end
luca-doloop3: 8 steps compiled luca-doloop3: index1: 0 index2: 10 luca-doloop3: index1: 1 index2: 9 luca-doloop3: index1: 2 index2: 8 luca-doloop3: index1: 3 index2: 7 luca-doloop3: index1: 4 index2: 6 exiting...
Every Ccscript loop behavior can be forced with two instruction:
for %index 1 2 3 4 5 # any value slog "before break and continue index: " %index if %index -eq 2 then slog "continue match" continue # continue with no condition endif if %index -eq 3 then slog "break match" break # break with no condition endif slog "after break and continue index: " %index loop # closes the loop slog "Second loop" for %index 1 2 3 4 5 # any value slog "before break and continue index: " %index continue %index -eq 2 # continue with a condition break %index -eq 3 # break with a condition slog "after break and continue index: " %index loop # closes the loop exit # NB: always an exit at the end
luca-breakcontinue: 22 steps compiled luca-breakcontinue: before break and continue index: 1 luca-breakcontinue: after break and continue index: 1 luca-breakcontinue: before break and continue index: 2 luca-breakcontinue: continue match luca-breakcontinue: before break and continue index: 3 luca-breakcontinue: break match luca-breakcontinue: Second loop luca-breakcontinue: before break and continue index: 1 luca-breakcontinue: after break and continue index: 1 luca-breakcontinue: before break and continue index: 2 luca-breakcontinue: before break and continue index: 3 exiting...
From output it's important to note that:
Ccscript supports two kind of labels, one defined with label instruction, the other defined with ::label syntax.
set %index 0 label lab1 # label definition slog "after lab1" label lab2 # label definition slog "after lab2" label lab3 # label definition slog "after lab3" slog "" # empty line inc %index # counts the loop if %index -eq 1 then skip lab1 if %index -eq 2 then skip lab2 if %index -eq 3 then skip lab3 exit # NB: always an exit at the end
luca-labelskip: 16 steps compiled luca-labelskip: after lab1 luca-labelskip: after lab2 luca-labelskip: after lab3 luca-labelskip: luca-labelskip: after lab1 luca-labelskip: after lab2 luca-labelskip: after lab3 luca-labelskip: luca-labelskip: after lab2 luca-labelskip: after lab3 luca-labelskip: luca-labelskip: after lab3 luca-labelskip: exiting...
The output shows this kind of loop.
set %index 0 goto ::lab1 ::lab1 # label definition slog "after lab1" goto ::lab2 ::lab2 # label definition slog "after lab2" goto ::lab3 ::lab3 # label definition slog "after lab3" goto ::common ::common slog "" inc %index if %index -eq 1 then goto ::lab1 if %index -eq 2 then goto ::lab2 if %index -eq 3 then goto ::lab3 exit # NB: always an exit at the end
luca-labelgoto: 2 steps compiled luca-labelgoto::lab1: 2 steps compiled luca-labelgoto::lab2: 2 steps compiled luca-labelgoto::lab3: 2 steps compiled luca-labelgoto::common: 9 steps compiled luca-labelgoto::lab1: after lab1 luca-labelgoto::lab2: after lab2 luca-labelgoto::lab3: after lab3 luca-labelgoto::common: luca-labelgoto::lab1: after lab1 luca-labelgoto::lab2: after lab2 luca-labelgoto::lab3: after lab3 luca-labelgoto::common: luca-labelgoto::lab2: after lab2 luca-labelgoto::lab3: after lab3 luca-labelgoto::common: luca-labelgoto::lab3: after lab3 luca-labelgoto::common: exiting...
The output shows again a kind of loop.
The goto instruction supports variable assignment too.
set %index 0 set %string first goto ::lab1 ::lab1 # label definition slog "after lab1" goto ::lab2 ::lab2 # label definition slog "after lab2" goto ::lab3 ::lab3 # label definition slog "after lab3" goto ::common ::common slog "string: " %string inc %index if %index -eq 1 then goto ::lab1 %string="second" if %index -eq 2 then goto ::lab2 %string="third" if %index -eq 3 then goto ::lab3 %string="fourth" exit # NB: always an exit at the end
luca-labelgoto2: 3 steps compiled luca-labelgoto2::lab1: 2 steps compiled luca-labelgoto2::lab2: 2 steps compiled luca-labelgoto2::lab3: 2 steps compiled luca-labelgoto2::common: 9 steps compiled luca-labelgoto2::lab1: after lab1 luca-labelgoto2::lab2: after lab2 luca-labelgoto2::lab3: after lab3 luca-labelgoto2::common: string: first luca-labelgoto2::lab1: after lab1 luca-labelgoto2::lab2: after lab2 luca-labelgoto2::lab3: after lab3 luca-labelgoto2::common: string: second luca-labelgoto2::lab2: after lab2 luca-labelgoto2::lab3: after lab3 luca-labelgoto2::common: string: third luca-labelgoto2::lab3: after lab3 luca-labelgoto2::common: string: fourth exiting...
The if structure support implicit goto ::label statement.
set %index 0 goto ::lab1 ::lab1 # label definition slog "after lab1" goto ::lab2 ::lab2 # label definition slog "after lab2" goto ::lab3 ::lab3 # label definition slog "after lab3" goto ::common ::common inc %index if %index -eq 1 ::lab1 if %index -eq 2 ::lab2 if %index -eq 3 ::lab3 exit # NB: always an exit at the end
luca-labelif::lab1: 2 steps compiled luca-labelif::lab2: 2 steps compiled luca-labelif::lab3: 2 steps compiled luca-labelif::common: 5 steps compiled luca-labelif::lab1: after lab1 luca-labelif::lab2: after lab2 luca-labelif::lab3: after lab3 luca-labelif::lab1: after lab1 luca-labelif::lab2: after lab2 luca-labelif::lab3: after lab3 luca-labelif::lab2: after lab2 luca-labelif::lab3: after lab3 luca-labelif::lab3: after lab3 exiting...
From output it's possible to that there is a goto behavior without a got statement.
The basic structure is the following (where only global params are used):
counter count # counter is global call ::routine call ::routine call ::routine slog "local: " %local # empty value: it's local... exit # NB: always an exit at the end ::routine set %local %count # local to subroutine slog "counter: " %local return
luca-gosub: 6 steps compiled luca-gosub::routine: 3 steps compiled luca-gosub::routine: counter: 1 luca-gosub::routine: counter: 2 luca-gosub::routine: counter: 3 luca-gosub: local: exiting...
To use returning value in the return statement:
counter count # counter is global call ::routine slog "ret value: " %ret " localvar: " %localvar # %localvar is empty call ::routine slog "ret value: " %ret " localvar: " %localvar # %localvar is empty call ::routine slog "ret value: " %ret " localvar: " %localvar # %localvar is empty exit # NB: always an exit at the end ::routine set %localvar %count # local to subroutine return %ret=%localvar
luca-gosub2: 8 steps compiled luca-gosub2::routine: 2 steps compiled luca-gosub2: ret value: 1 localvar: luca-gosub2: ret value: 2 localvar: luca-gosub2: ret value: 3 localvar: exiting...
To use local params:
call ::routine %par=1 slog "value of par:" %par # empty value call ::routine %par=2 slog "value of par:" %par # empty value call ::routine %par=3 slog "value of par:" %par # empty value exit # NB: always an exit at the end ::routine set %local %par # local to subroutine slog "local: " %local return
luca-gosub3: 7 steps compiled luca-gosub3::routine: 3 steps compiled luca-gosub3::routine: local: 1 luca-gosub3: value of par: luca-gosub3::routine: local: 2 luca-gosub3: value of par: luca-gosub3::routine: local: 3 luca-gosub3: value of par: exiting...
set %global "global from main" gosub ::routine slog "global : " %global slog "local.var : " %localvar # empty slog "global.var : " %global.var # with a value exit # NB: always an exit at the end ::routine # local scope variable set %localvar "local variable from routine" # global scope variable set %global.var "global variable from routine" slog "global : " %global slog "local.var : " %localvar slog "global.var : " %global.var return
luca-scope: 6 steps compiled luca-scope::routine: 6 steps compiled luca-scope::routine: global : global from main luca-scope::routine: local.var : local variable from routine luca-scope::routine: global.var : global variable from routine luca-scope: global : global from main luca-scope: local.var : luca-scope: global.var : global variable from routine exiting...
Variable defined within a subroutine is in local scope, so out of the subroutine scope the variable is undefined.
Ccscript is event driven scripting language. An event is something that happens out of the normal processing flow. When an event happens, the corresponding event handler, if present, is called.
repeat 3 slog "pause 5 second: hangup to exit" sleep 5 loop # closes the loop slog "after loop: exit" exit # NB: always an exit at the end ^hangup slog "hangup event: exit" exit
without giving a Hangup dummy(0): luca-hangup: pause 5 second: hangup to exit dummy(0): luca-hangup: pause 5 second: hangup to exit dummy(0): luca-hangup: pause 5 second: hangup to exit dummy(0): luca-hangup: after loop: exit giving a HangUp dummy(0): luca-hangup: pause 5 second: hangup to exit dummy(0): luca-hangup: pause 5 second: hangup to exit dummy0: hangup... dummy(0): luca-hangup: hangup event: exit
With Dummy driver to generate a hangup event is necessary to hit `H' key.
The dtmf event notifies when a key is pressed (every key from phone keyboard):
do sleep 5 loop # closes the loop slog "after loop: exit" exit # NB: always an exit at the end ^dtmf slog "dtmf received" goto luca-input-dtmf # loops to start ^hangup slog "hangup event: exit" exit
dummy0: digit 1... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 2... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 3... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 4... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 5... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 6... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 7... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 8... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 9... dummy(0): luca-input-dtmf: dtmf received dummy0: digit 0... dummy(0): luca-input-dtmf: dtmf received dummy0: digit #... dummy(0): luca-input-dtmf: dtmf received dummy0: digit *... dummy(0): luca-input-dtmf: dtmf received dummy0: hangup... dummy(0): luca-input-dtmf: hangup event: exit
To get this output press all the phone keys, then hangup.
To notify for specific input tone there are events 0...9, pound, star (for input 0...9, `#', `*' respectively).
do sleep 5 loop # closes the loop slog "after loop: exit" exit # NB: always an exit at the end ^0 slog "tone 0 received" goto luca-input-single # loops to start ^1 slog "tone 1 received" goto luca-input-single # loops to start ^2 slog "tone 2 received" goto luca-input-single # loops to start ^3 slog "tone 3 received" goto luca-input-single # loops to start ^4 slog "tone 4 received" goto luca-input-single # loops to start ^5 slog "tone 5 received" goto luca-input-single # loops to start ^6 slog "tone 6 received" goto luca-input-single # loops to start ^7 slog "tone 7 received" goto luca-input-single # loops to start ^8 slog "tone 8 received" goto luca-input-single # loops to start ^9 slog "tone 9 received" goto luca-input-single # loops to start ^pound slog "tone # received" goto luca-input-single # loops to start ^star slog "tone * received" goto luca-input-single # loops to start ^hangup slog "hangup event: exit" exit
dummy0: digit 1... dummy(0): luca-input-single: tone 1 received dummy0: digit 2... dummy(0): luca-input-single: tone 2 received dummy0: digit 3... dummy(0): luca-input-single: tone 3 received dummy0: digit 4... dummy(0): luca-input-single: tone 4 received dummy0: digit 5... dummy(0): luca-input-single: tone 5 received dummy0: digit 6... dummy(0): luca-input-single: tone 6 received dummy0: digit 7... dummy(0): luca-input-single: tone 7 received dummy0: digit 8... dummy(0): luca-input-single: tone 8 received dummy0: digit 9... dummy(0): luca-input-single: tone 9 received dummy0: digit 0... dummy(0): luca-input-single: tone 0 received dummy0: digit *... dummy(0): luca-input-single: tone * received dummy0: digit #... dummy(0): luca-input-single: tone # received dummy0: hangup... dummy(0): luca-input-single: hangup event: exit
To get this output press all the phone keys, then hangup.
repeat 3 slog "pause 3 second: press 1 or hangup" sleep 3 loop # closes the loop slog "after first loop" goto ::loop2 ^1 slog "tone 1 received" goto ::loop2 ^hangup slog "hangup event: exit" exit ::loop2 repeat 3 slog "pause 3 second: press 2 or hangup" sleep 3 loop # closes the loop slog "after second loop" exit # NB: always an exit at the end ^2 slog "tone 2 received" exit ^hangup slog "hangup event: exit" exit
dummy(0): luca-eventScope: pause 3 second: press 1 or hangup dummy0: digit 2... dummy(0): luca-eventScope: pause 3 second: press 1 or hangup dummy0: digit 1... dummy(0): luca-eventScope: tone 1 received dummy(0): luca-eventScope::loop2: pause 3 second: press 2 or hangup dummy0: digit 1... dummy(0): luca-eventScope::loop2: pause 3 second: press 2 or hangup dummy0: digit 2... dummy(0): luca-eventScope::loop2: tone 2 received
In this example output is important to note that:
^2
or ^dtmf
are present);
^1
is present);
^1
is not present);
^2
is present).
A ^timeout
event occours when timed operation timed out; there are examples in the next sections:
Bayonne lets program an event timeout from calling time or current time, the called event is ^time
. To set the timeout:
sync.exit sec
and sync.start sec
: the ^time
is called after sec seconds from the calling start.
sync.current sec
: the ^time
is called after sec seconds from the current time.
^time
event is non handled by script, sync.start and sync.current do nothing, sync.exit instead calls ^hangup
event (if ^hangup
is missig the script exits).
Here how to use sync.exit sec
and ^time
:
slog "timeout in 3 seconds from " %session.starttime sync.exit 3 sleep 5 slog "normal exit" exit # NB: always an exit at the end ^time slog %session.time " timeout reached: exit" exit
dummy(0): luca-event_time1: timeout in 3 seconds from 170705 dummy(0): luca-event_time1: 170708 timeout reached: exit
Here with sync.exit sec
only, without ^time
:
slog "timeout in 3 seconds from " %session.starttime sync.exit 3 sleep 4 slog "normal exit" exit # NB: always an exit at the end ^hangup slog "hangup signal received" exit
dummy(0): luca-event_time2: timeout in 3 seconds from 170925 dummy(0): luca-event_time2: hangup signal received
By output it's possible to see that the ^hangup
is called because ^time
is missing.
slog "timeout in 3 seconds from " %session.starttime sync.start 3 sleep 5 slog "normal exit" exit # NB: always an exit at the end ^time slog %session.time " timeout reached: exit" exit
dummy(0): luca-event_time3: timeout in 3 seconds from 185122 dummy(0): luca-event_time3: 185125 timeout reached: exit
Here with sync.start sec
only, without ^time
:
slog "timeout in 3 seconds from " %session.starttime sync.start 3 sleep 4 slog "normal exit" exit # NB: always an exit at the end ^hangup slog "hangup signal received" exit
dummy(0): luca-event_time4: timeout in 3 seconds from 185208 dummy(0): luca-event_time4: normal exit
By output it's possible to see that the ^hangup
isn't called by ^time
miss.
At last sync.current sec
and ^time
:
slog "start time " %session.starttime sleep 2 slog "timeout 2 seconds from now: " %session.time sync.current 2 sleep 4 slog "normal exit" exit # NB: always an exit at the end ^time slog %session.time " timeout reached: exit" exit
dummy(0): luca-event_time5: start time 171011 dummy(0): luca-event_time5: timeout 2 seconds from now: 171014 dummy(0): luca-event_time5: 171016 timeout reached: exit
Bayonne uses the event ^event
to interprocess signal notification. See subections 13.2 for the examples.
To perform telephone output Bayonne uses the following instructions:
Audio files must have a particular format and characteristics. Supported formats are '.au' and '.wav'; the audio file must be 8 bit, 8 Khz, mono (these characteristics are due to phone standards).
play audio
: Bayonne plays /usr/share/aapromps/VOICE/audio.au;
play dir:audio
: Bayonne plays /usr/share/aapromps/dir/audio.au;
play dir::audio
: Bayonne plays /home/bayonne/apps/dir/VOICE/audio.au;
play prefix=/dir audio
: Bayonne plays /dir/audio.au;
play audio
: Bayonne plays /usr/local/share/bayonne/VOICE/audio.au;
play dir:audio
: Bayonne plays /usr/local/share/bayonne/sys/dir/audio.au;
play dir::audio
: Bayonne plays /home/bayonne/dir/VOICE/audio.au;
play prefix=/dir audio
: Bayonne plays /dir/audio.au;
For Bayonne 1.0.x:
set %session.voice VOICE play audio # use the default extension play audio.au # specific the extension play audio.wav # not the default extension play dir:audio # path changes play dir::audio play prefix=/dir audio exit # NB: always an exit at end
/usr/share/aaprompts/VOICE/audio.au: cannot open /usr/share/aaprompts/VOICE/audio.au: cannot open /usr/share/aaprompts/VOICE/audio.wav: cannot open /usr/share/aaprompts/VOICE/dir:audio.au: cannot open /home/bayonne/apps/dir/VOICE/audio.au: cannot open /dir/audio: cannot open
For bayonne 1.2.x:
set %session.voice VOICE play audio # use the default extension play audio.au # specific the extension play audio.wav # not the default extension play dir:audio # path changes play dir::audio play prefix=/dir audio exit # NB: always an exit at end
/usr/local/share/bayonne/VOICE/audio.au: cannot open /usr/local/share/bayonne/VOICE/audio.au: cannot open /usr/local/share/bayonne/VOICE/audio.wav: cannot open /usr/local/share/bayonne/sys/dir/audio.au: cannot open /home/bayonne/dir/VOICE/audio.au: cannot open /dir/audio: cannot open
The speak command can play audio file like play:
For Bayonne 1.0.x:
set %session.voice VOICE speak audio # use the default extension speak audio.au # specific the extension speak audio.wav # not the default extension speak dir:audio # path changes speak dir::audio speak prefix=/dir audio exit # NB: always an exit at end
/usr/share/aaprompts/VOICE/audio.au: cannot open /usr/share/aaprompts/VOICE/audio.au: cannot open /usr/share/aaprompts/VOICE/audio.wav: cannot open /usr/share/aaprompts/VOICE/dir:audio.au: cannot open /home/bayonne/apps/dir/VOICE/audio.au: cannot open /usr/share/aaprompts/VOICE/audio.au: cannot open
For bayonne 1.2.x:
set %session.voice VOICE speak audio # use the default extension speak audio.au # specific the extension speak audio.wav # not the default extension speak dir:audio # path changes speak dir::audio speak prefix=/dir audio exit # NB: always an exit at end
/usr/local/share/bayonne/VOICE/audio.au: cannot open /usr/local/share/bayonne/VOICE/audio.au: cannot open /usr/local/share/bayonne/VOICE/audio.wav: cannot open /usr/local/share/bayonne/sys/dir/audio.au: cannot open /home/bayonne/dir/VOICE/audio.au: cannot open /usr/local/share/bayonne/VOICE/audio.au: cannot open
But doesn't support `prefix' directive (as you can see from the last output line).
To play audio file play is better than speak, The speak command is used to compose vocal phrases.
The speak supports a lot of directives (&directive):
For Bayonne 1.0.x:
set %session.voice VOICE set %var1 123 set %var2 "string" slog %var1 " " %var2 speak %var1 speak &number %var1 speak &spell %var1 speak %var2 speak &spell %var2 exit # NB: always an exit at end
dummy(0): luca-speak2: 123 string /usr/share/aaprompts/VOICE/123.au: cannot open /usr/share/aaprompts/VOICE/1.au: cannot open /usr/share/aaprompts/VOICE/1.au: cannot open /usr/share/aaprompts/VOICE/string.au: cannot open /usr/share/aaprompts/VOICE/s.au: cannot open
For Bayonne 1.2.x:
set %session.voice VOICE set %var1 123 set %var2 "string" slog %var1 " " %var2 speak %var1 speak &number %var1 speak &spell %var1 speak %var2 speak &spell %var2 exit # NB: always an exit at end
/usr/local/share/bayonne/VOICE/123.au: cannot open /usr/local/share/bayonne/VOICE/1.au: cannot open /usr/local/share/bayonne/VOICE/1.au: cannot open /usr/local/share/bayonne/VOICE/string.au: cannot open /usr/local/share/bayonne/VOICE/s.au: cannot open
By the output it's possible to see that:
Bayonne handles two types of input: audio/voice and keyboard digits. The first one is got with record command, the second one is got with collect command (keyboard digits can be read using events too).
The record command receives audio/voice input and stores it in a file, the audio file created has the same type and format of audio files used by the play command.
The record command has the format: record audio length term
with:
record prefix=/path audio length term
.
For Bayonne 1.0.x:
slog "before record: * to end" record audio1 5 "*" # /var/bayonne/audio1.au slog "after first record" slog "before record: # to end" record prefix=/tmp audio2 5 "#" # /tmp/audio2.au slog "after second record" exit # NB: always an exit at the end
dummy(0): luca-record: before record: * to end dummy0: digit *... dummy(0): luca-record: after first record dummy(0): luca-record: before record: # to end dummy0: digit #... dummy(0): luca-record: after second record
For Bayonne 1.2.x:
slog "before record: * to end" record audio1 5 "*" # /var/lib/bayonne/audio1.au slog "after first record" slog "before record: # to end" record prefix=/tmp audio2 5 "#" # /tmp/audio2.au slog "after second record" exit # NB: always an exit at the end
dummy(0): luca-record: before record: * to end dummy0: digit *... dummy(0): luca-record: after first record dummy(0): luca-record: before record: # to end dummy0: digit #... dummy(0): luca-record: after second record
The two recordings end by pressing term keys. You can see the files were created in the appropriate directories.
Changing term keys and specifying audio format:
slog "before record: 1 or 2 to end" record audio1.au 5 "12" # 1.0.x: /var/bayonne/audio1.au # 1.2.x: /var/lib/bayonne/audio1.au slog "after first record" slog "before record: 3 or 4 to end" record prefix=/tmp audio2.wav 5 "34" # /tmp/audio2.wav slog "after second record" exit # NB: always an exit at the end
dummy(0): luca-record2: before record: 1 or 2 to end dummy0: digit 1... dummy(0): luca-record2: after first record dummy(0): luca-record2: before record: 3 or 4 to end dummy0: digit 4... dummy(0): luca-record2: after second record
The result is very like the previous one.
The collect instruction reads input from phone keyboard. The collect command has the form collect count timeout term ignore
with:
slog "before collect: * end, # ignored" collect 10 15 "*" "#" slog "after collect: digits " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect1: before collect: * end, # ignored dummy0: digit 1... dummy0: digit 2... dummy0: digit #... dummy0: digit 3... dummy0: digit 4... dummy0: digit 5... dummy0: digit #... dummy0: digit 6... dummy0: digit 7... dummy0: digit *... dummy(0): luca-collect1: after collect: digits 1234567
By the output it's to see that all pressed digits are stored in %session.digits but not # ignored and * used for term.
Every digits can be ignored or used to term:
slog "before collect: # end, 3,4 ignored" collect 10 15 "#" "34" slog "after collect: digits " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect2: before collect: # end, 3,4 ignored dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy0: digit 5... dummy0: digit 6... dummy0: digit *... dummy0: digit #... dummy(0): luca-collect2: after collect: digits 1256*
After "count" digits pressed the collect ends:
slog "before collect: max 10 digits" collect 10 15 "*" "#" slog "after collect: digits " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect3: before collect: max 10 digits dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy0: digit 5... dummy0: digit 6... dummy0: digit 7... dummy0: digit 8... dummy0: digit 9... dummy0: digit 0... dummy(0): luca-collect3: after collect: digits 1234567890
From the output you can see that the term digit is not pressed.
Waiting "timeout" seconds between two digits the collect ends:
slog "before collect: max pause interdigit 5 secs" collect 10 5 "*" "#" slog "after collect: digits " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect4: before collect: max pause interdigit 5 secs dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy(0): luca-collect4: after collect: digits 1234
From the output you can see that the term digit is not pressed and the maximum number of digits is not reached.
Using two or more collect, digits in %session.digits are appended and digits of the first collect are counted in the second collect too.
slog "first collect" collect 5 10 "#" "*" slog "after collect: digits " %session.digits slog "second collect" collect 8 10 "#" "*" slog "after collect: digits (append) " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect5: first collect dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy0: digit #... dummy(0): luca-collect5: after collect: digits 1234 dummy(0): luca-collect5: second collect dummy0: digit 9... dummy0: digit 8... dummy0: digit 7... dummy0: digit 6... dummy(0): luca-collect5: after collect: digits (append) 12349876
The instruction cleardigits clears %session.digits (like clear %session.digits
) and let using more collect without problems or digits appending:
slog "first collect" collect 5 10 "#" "*" slog "after collect: digits " %session.digits cleardigits slog "digits cleared" slog "second collect" collect 8 10 "#" "*" slog "after collect: digits " %session.digits exit # NB: always an exit at the end
dummy(0): luca-collect6: first collect dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy0: digit 5... dummy(0): luca-collect6: after collect: digits 12345 dummy(0): luca-collect6: digits cleared dummy(0): luca-collect6: second collect dummy0: digit 8... dummy0: digit 7... dummy0: digit 6... dummy0: digit 5... dummy0: digit 4... dummy0: digit 3... dummy0: digit 2... dummy0: digit 1... dummy(0): luca-collect6: after collect: digits 87654321
When the collect's timeout occours, then the ^timeout
event is generated (it can be handled or not).
slog "start collect on time: " %session.time collect 2 4 "*" "#" slog "end collect" exit # NB: always an exit at the end ^timeout slog "timeout on time: " %session.time exit
dummy(0): luca-timeout-collect: start collect on time: 182508 dummy(0): luca-timeout-collect: timeout on time: 182512
This output is obtained without pressing any phone key.
goto ::start ::start goto ::start # infinite loop ^pound slog "digits " %session.digits exit # NB: always an exit at the end ^dtmf goto ::start
dummy0: digit 1... dummy0: digit 2... dummy0: digit 3... dummy0: digit 4... dummy0: digit *... dummy0: digit #... dummy(0): luca-input-event::start: digits 1234*#
The output is very like collect behavior with # term digit (but in this case the # digit is stored in %session.digits).
The TGI module lets Bayonne to interact with external languages like Perl and Python.
The TGI call is made using libexec command in the form:
libexec timeout outscript %param
with
^timeout
event occours);
The default path for external script to be invoked is /usr/libexec/bayonne (Bayonne 1.0.x) or /usr/local/libexec/bayonne (Bayonne 1.2.x).
To exchange data with perl scripts, TGI has two instructions:
A basic perl script is the follow:
#!/usr/bin/perl # use lib '/usr/libexec/bayonne/'; # 1.0.x use lib '/usr/local/libexec/bayonne/'; # 1.2.x use TGI; $fatt1 = $TGI::QUERY{'var1'}; $fatt2 = $TGI::QUERY{'var2'}; $result = $fatt1*$fatt2; # any operation TGI::set("res",$result); exitTo use this perl script:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 10 luca-tgiperl1.pl %var1 %var2 slog.info %res exit # NB: always an exit at the end
dummy(0): luca-tgiperl1: 8 7 tgi: cmd=luca-tgiperl1.pl query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 14160 fifo: cmd=SET&0&res&56 fifo: cmd=exit 0 0 dummy(0): luca-tgiperl1: 56
The variables %var1 and %var2 are passed to perl that return %res value.
In this second perl script variables are uppercase too:
#!/usr/bin/perl # use lib '/usr/libexec/bayonne/'; # 1.0.x use lib '/usr/local/libexec/bayonne/'; # 1.2.x use TGI; $fatt1 = $TGI::QUERY{'Var1'}; $fatt2 = $TGI::QUERY{'Var2'}; $var3 = $TGI::QUERY{'var3'}; $result = $fatt1*$fatt2; # any operation TGI::set("Res",$result); TGI::set("Res2",$var3); TGI::set("result",$result); TGI::set("result2",$var3); exitThe Bayonne becomes:
set %Var1 8 set %Var2 7 set %var3 10 slog.info %Var1 " " %Var2 " " %var3 libexec 20 luca-tgiperl2.pl %Var1 %Var2 %var3 slog.info "Res: "%Res slog.info "Res2: "%Res2 slog.info "result: "%result slog.info "result2: "%result2 exit # NB: always an exit at the end
dummy(0): luca-tgiperl2: 8 7 10 tgi: cmd=luca-tgiperl2.pl query=Var1=8&Var2=7&var3=10 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 14183 fifo: cmd=SET&0&Res&0 fifo: cmd=SET&0&Res2&10 fifo: cmd=SET&0&result&0 fifo: cmd=SET&0&result2&10 fifo: cmd=exit 0 0 dummy(0): luca-tgiperl2: Res: 0 dummy(0): luca-tgiperl2: Res2: 10 dummy(0): luca-tgiperl2: result: 0 dummy(0): luca-tgiperl2: result2: 10
It's possible to see that:
A perl script can need several seconds to compute its operation:
#!/usr/bin/perl # use lib '/usr/libexec/bayonne/'; # 1.0.x use lib '/usr/local/libexec/bayonne/'; # 1.2.x use TGI; $fatt1 = $TGI::QUERY{'var1'}; $fatt2 = $TGI::QUERY{'var2'}; sleep(10); $result = $fatt1*$fatt2; # any operation TGI::set("result",$result); exitThe libexec command has a timeout, if timeout is greater than perl script execution time, the results are imported (and printed) correctly:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 20 luca-tgiperl3.pl %var1 %var2 slog.info %result exit # NB: always an exit at the end
dummy(0): luca-tgiperl3: 8 7 tgi: cmd=luca-tgiperl3.pl query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 14193 fifo: cmd=SET&0&result&56 fifo: cmd=exit 0 0 dummy(0): luca-tgiperl3: 56
If timeout is lesser than perl script execution time, the results aren't imported (and printed) correctly:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 5 luca-tgiperl3.pl %var1 %var2 slog.info "result: "%result exit # NB: always an exit at the end
dummy(0): luca-tgiperl4: 8 7 tgi: cmd=luca-tgiperl3.pl query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 14211 fifo: cmd=SET&0&result&56 dummy(0): luca-tgiperl4: result:
From output it's possible to see that the %result value is undefined because the perl script doesn't end before timeout.
The tgi call can generate a ^timeout
event:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 slog "tgi call on time: " %session.time libexec 5 luca-tgiperl3.pl %var1 %var2 slog.info "result: "%result exit # NB: always an exit at the end ^timeout slog "tgi timeout, time: " %session.time exit
dummy(0): luca-timeout-tgi: 8 7 dummy(0): luca-timeout-tgi: tgi call on time: 220052 dummy(0): luca-timeout-tgi: timeout time: 220057
To exchange data with python scripts, TGI has two instructions:
A basic perl script is the follow (the python script must be executable with chmod +x python_script.py):
#!/usr/bin/env python import sys #sys.path.insert(0,'/usr/local/libexec/bayonne') # Bayonne 1.0.x sys.path.insert(0,'/usr/local/libexec/bayonne') # bayonne 1.2.x import TGI v1 = int(TGI.QUERY['var1']) v2 = int( TGI.QUERY['var2']) result = v1+v2 TGI.set('res',result)To use this perl script:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 10 luca-tgipython1.py %var1 %var2 slog.info %res exit # NB: always an exit at the end
dummy(0): luca-tgipython1: 8 7 tgi: cmd=luca-tgipython1.py query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 2949 tgi: exec /usr/local/libexec/bayonne/luca-tgipython1.py fifo: cmd=SET&0&res&15 fifo: cmd=exit 0 0 dummy(0): luca-tgipython1: 15
The variables %var1 and %var2 are passed to python that return %res value.
In this second python script variables are uppercase too:
#!/usr/bin/env python import sys #sys.path.insert(0,'/usr/local/libexec/bayonne') # Bayonne 1.0.x sys.path.insert(0,'/usr/local/libexec/bayonne') # bayonne 1.2.x import TGI v1 = int(TGI.QUERY['var1']) v2 = int( TGI.QUERY['var2']) result = v1+v2 TGI.set('Res',result) TGI.set('result',result)The Bayonne becomes:
set %Var1 8 set %Var2 7 slog.info %Var1 " " %var2 libexec 20 luca-tgipython2.py %Var1 %var2 slog.info "Res: "%Res slog.info "result: "%result exit # NB: always an exit at the end
dummy(0): luca-tgipython2: 8 7 tgi: cmd=luca-tgipython2.py query=Var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 3041 tgi: exec /usr/local/libexec/bayonne/luca-tgipython2.py fifo: cmd=SET&0&Res&15 fifo: cmd=SET&0&result&15 fifo: cmd=exit 0 0 dummy(0): luca-tgipython2: Res: 15 dummy(0): luca-tgipython2: result: 15
It's possible to see that:
A python script can need several seconds to compute its operation:
#!/usr/bin/env python import sys import time #sys.path.insert(0,'/usr/local/libexec/bayonne') # Bayonne 1.0.x sys.path.insert(0,'/usr/local/libexec/bayonne') # bayonne 1.2.x import TGI v1 = int(TGI.QUERY['var1']) v2 = int( TGI.QUERY['var2']) time.sleep(10) result = v1+v2 TGI.set('res',result)The libexec command has a timeout, if timeout is greater than python script execution time, the results are imported (and printed) correctly:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 20 luca-tgipython3.py %var1 %var2 slog.info %res exit # NB: always an exit at the end
dummy(0): luca-tgipython3: 8 7 tgi: cmd=luca-tgipython3.py query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 3149 tgi: exec /usr/local/libexec/bayonne/luca-tgipython3.py fifo: cmd=SET&0&res&15 fifo: cmd=exit 0 0 dummy(0): luca-tgipython3: 15
If timeout is lesser than python script execution time, the results aren't imported (and printed) correctly:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 libexec 5 luca-tgipython3.py %var1 %var2 slog.info "res: "%res exit # NB: always an exit at the end
dummy(0): luca-tgipython4: 8 7 tgi: cmd=luca-tgipython3.py query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 3179 tgi: exec /usr/local/libexec/bayonne/luca-tgipython3.py fifo: cmd=exit 0 0 dummy(0): luca-tgipython4: res:
From output it's possible to see that the %res value is undefined because the python script doesn't end before timeout.
The tgi call can generate a ^timeout
event:
set %var1 8 set %var2 7 slog.info %var1 " " %var2 slog "tgi call on time: " %session.time libexec 5 luca-tgipython3.py %var1 %var2 slog.info "res: "%res exit # NB: always an exit at the end ^timeout slog "tgi timeout, time: " %session.time exit
dummy(0): luca-timeout-tgi-python: 8 7 dummy(0): luca-timeout-tgi-python: tgi call on time: 223818 tgi: cmd=luca-tgipython3.py query=var1=8&var2=7 digits= clid=UNKNOWN dnid=UNKNOWN fifo: cmd=wait 0 3222 tgi: exec /usr/local/libexec/bayonne/luca-tgipython3.py fifo: cmd=exit 0 0 dummy(0): luca-timeout-tgi-python: tgi timeout, time: 223823
Bayonne runs many threads/processes at the same time; one process can start, send signals, send data or join to another one. Unfortunaly, multiprocessing/multithreading cannot be used with dummy driver because it supports only one precess per time. For these examples I used a 4-port IVR card which driver supports 4 threads/processes at the same time.The following examples have at least two source file and one output file only.
The start command lanches a new thread/process. In the %session.parent global variables is stored the session id of the parent process that starts the new one.
With
start.trunk trnk scrpt
Bayonne starts the script scrpt.scr on the trunk trnk if available (if the trunk is busy nothing happens).
slog "father: start, id: " %session.id sleep 1 # any operation start.trunk 1 luca-start1b # starts child on trunk 1 sleep 1 # any operation slog "father: stop" exit # NB: always an exit at the end
slog "child: start, id: " %session.id slog "child: father id: " %session.parent sleep 1 # any operation slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-start1a: father: start, id: luca-000-1060947537 bayonne: dx(1): luca-start1b(1): child: start, id: luca-001-1060947539 bayonne: dx(1): luca-start1b(1): child: father id: luca-000-1060947537 bayonne: dx(0): luca-start1a: father: stop bayonne: dx(1): luca-start1b(1): child: exit
With start.offset offst scrpt
Bayonne starts the script scrpt.scr on the offst trunk next to the currently used (is exist and is available).
slog "father: start with id: " %session.id sleep 1 # any operation start.offset 2 luca-start2b # starts child 2 trunks over sleep 1 # any operation slog "father: stop" exit # NB: always an exit at the end
slog "child: start with id: " %session.id slog "child: father session-id: " %session.parent sleep 1 # any operation slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-start2a: father: start with id: luca-000-1060950161 bayonne: dx(2): luca-start2b(2): child: start with id: luca-002-1060950162 bayonne: dx(2): luca-start2b(2): child: father session-id: luca-000-1060950161 bayonne: dx(0): luca-start2a: father: stop bayonne: dx(2): luca-start2b(2): child: exit
With start.group grp scrpt
Bayonne starts the script scrpt.scr on a trunk of the grp group (if one is available). Trunks groups are defined in the bayonne-conf configuration file. For this examples I use the follow definition:
[outgoing-trunks] trunks = 2,3
slog "father: start with id: " %session.id sleep 1 # any operation start.group outgoing luca-start3b # starts child on the # outgoing group sleep 1 # any operation start.group outgoing luca-start3b # starts child on the # outgoing group sleep 1 # any operation slog "father: stop" exit # NB: always an exit at the end
slog "child: start with id: " %session.id slog "child: father session-id: " %session.parent sleep 1 # any operation slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-start3a: father: start with id: luca-000-1060950823 bayonne: dx(3): luca-start3b(3): child: start with id: luca-003-1060950825 bayonne: dx(3): luca-start3b(3): child: father session-id: luca-000-1060950823 bayonne: dx(2): luca-start3b(2): child: start with id: luca-002-1060950826 bayonne: dx(2): luca-start3b(2): child: father session-id: luca-000-1060950823 bayonne: dx(3): luca-start3b(3): child: exit bayonne: dx(0): luca-start3a: father: stop bayonne: dx(2): luca-start3b(2): child: exit
With start ... scrpt %var1 %var2...
Bayonne starts the script scrpt.scr with variables %var1, %var2, ...initialized to the parent values.
slog "father: start with id: " %session.id sleep 1 # any operation set %any_parameter "any value" start.group outgoing luca-start4b %any_parameter # starts child passing a parameter sleep 1 # any operation slog "father: stop" exit # NB: always an exit at the end
slog "child: start with id: " %session.id slog "parameter received: " %any_parameter sleep 1 # any operation slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-start4a: father: start with id: luca-000-1060952900 bayonne: dx(3): luca-start4b(3): child: start with id: luca-003-1060952901 bayonne: dx(3): luca-start4b(3): parameter received: any value bayonne: dx(0): luca-start4a: father: stop bayonne: dx(3): luca-start4b(3): child: exit
When a child thread/process exits, a ^child
event is notified to the parent (this event can be handled or not).
slog "father: start with id: " %session.id sleep 1 # any operation start.group outgoing luca-start5b # starts child sleep 5 # any operation slog "father: stop" exit # NB: always an exit at the end ^child slog "child terminated" exit
slog "child: start with id: " %session.id sleep 1 # any operation slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-start5a: father: start with id: luca-000-1060968662 bayonne: dx(3): luca-start5b(3): child: start with id: luca-003-1060968663 bayonne: dx(3): luca-start5b(3): parameter received: bayonne: dx(3): luca-start5b(3): child: exit bayonne: dx(0): luca-start5a: child terminated
Bayonne use signals to send notification and data from one thread/process to another.
With send call-id
the thread/process sends a signal to the thread/process call-id, the receiver can use the signal handling the event ^event
; the receiver can recognize the sender by the global variable %session.eventsenderid and the signal text by the global variable %session.eventsendermsg.
slog "father: start with id: " %session.id sleep 1 # any operation start.group outgoing luca-send1b # starts child slog "start sleep" sleep 10 slog "sleep end" slog "father: stop" exit # NB: always an exit at the end ^event slog "event received from: " %session.eventsenderid slog "message received: " %session.eventsendermsg slog "father: stop from event" exit
slog "child: start with id: " %session.id sleep 1 # any operation send %session.parent # no message sent, only event slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-send1a: father: start with id: luca-000-1060960344 bayonne: dx(0): luca-send1a: start sleep bayonne: dx(3): luca-send1b(3): child: start with id: luca-003-1060960345 bayonne: dx(0): luca-send1a: event received from: luca-003-1060960345 bayonne: dx(3): luca-send1b(3): child: exit bayonne: dx(0): luca-send1a: message received: bayonne: dx(0): luca-send1a: father: stop from event
With send.message call-id msg
the thread/process sends a signal and the message msg to the thread/process call-id, the receiver can use the signal handling the event ^event
; the receiver can recognize the sender by the global variable %session.eventsenderid and the signal text by the global variable %session.eventsendermsg.
slog "father: start with id: " %session.id sleep 1 # any operation start.group outgoing luca-send2b # starts child slog "start sleep" sleep 10 slog "sleep end" slog "father: stop" exit # NB: always an exit at the end ^event slog "event received from: " %session.eventsenderid slog "message received: " %session.eventsendermsg slog "father: stop from event" exit
slog "child: start with id: " %session.id sleep 1 # any operation send.message %session.parent message=any_message slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-send2a: father: start with id: luca-000-1060961174 bayonne: dx(0): luca-send2a: start sleep bayonne: dx(3): luca-send2b(3): child: start with id: luca-003-1060961175 bayonne: dx(0): luca-send2a: event received from: luca-003-1060961175 bayonne: dx(3): luca-send2b(3): child: exit bayonne: dx(0): luca-send2a: message received: any_message bayonne: dx(0): luca-send2a: father: stop from event
With send.copy call-id %var
the thread/process copies the local value of %var to the receiver call-id.
slog "father: start with id: " %session.id sleep 1 # any operation start.group outgoing luca-send3b # starts child set %dummy 0 slog "before sleep: " %dummy sleep 5 slog "after sleep: " %dummy slog "father: stop" exit # NB: always an exit at the end
slog "child: start with id: " %session.id sleep 1 # any operation set %dummy 10 send.copy %session.parent %dummy slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-send3a: father: start with id: luca-000-1060963066 bayonne: dx(0): luca-send3a: before sleep: 0 bayonne: dx(3): luca-send3b(3): child: start with id: luca-003-1060963068 bayonne: dx(3): luca-send3b(3): child: exit bayonne: dx(0): luca-send3a: after sleep: 10 bayonne: dx(0): luca-send3a: father: stop
With send.post call-id %strct value
the thread/process adds the value %value to the data structure %strct of the receiver call-id.
slog "father: start with id: " %session.id stack 3 %stck # empty stack start.group outgoing luca-send4b # starts child sleep 3 # the stack is filled by child slog "stack " %stck slog "stack " %stck slog "stack " %stck slog "father: stop" exit # NB: always an exit at the end
slog "child: start with id: " %session.id sleep 1 # any operation send.post %session.parent %stck 1 %stck 2 send.post %session.parent %stck 3 slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-send4a: father: start with id: luca-000-1060972221 bayonne: dx(3): luca-send4b(3): child: start with id: luca-003-1060972222 bayonne: dx(3): luca-send4b(3): child: exit bayonne: dx(0): luca-send4a: stack 3 bayonne: dx(0): luca-send4a: stack 2 bayonne: dx(0): luca-send4a: stack 1 bayonne: dx(0): luca-send4a: father: stop
With send.digits call-id digits
the thread/process adds digits to %session.digits global variable of the receiver call-id; for the receiver these digits are like the normal input.
slog "father: start with id: " %session.id cleardigits start.group outgoing luca-send5b # starts child collect 5 3 * # slog "digits collect: " %session.digits cleardigits slog "pause...." sleep 5 slog "father: stop" exit # NB: always an exit at the end ^dtmf slog "digits reveiced: " %session.digits slog "father: stop after digits" exit # NB: always an exit at the end
slog "child: start with id: " %session.id send.digits %session.parent "123" # first digits sleep 4 send.digits %session.parent "456" #second digits slog "child: exit" exit # NB: always an exit at the end
bayonne: dx(0): luca-send5a: father: start with id: luca-000-1060967273 bayonne: dx(3): luca-send5b(3): child: start with id: luca-003-1060967274 bayonne: dx(0): luca-send5a: digits collect: 123 bayonne: dx(0): luca-send5a: pause.... bayonne: dx(0): luca-send5a: digits reveiced: 4 bayonne: dx(3): luca-send5b(3): child: exit bayonne: dx(0): luca-send5a: father: stop after digits
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts
This document was generated using the LaTeX2HTML translator Version 2002 (1.62)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -nosubdir -split 0 examples.tex
The translation was initiated by Luca on 2003-08-24