|
Table of Contents | Intro | Quickstart | Phonebook | DP Viewer | Cmd. Line Ref. | Transferring Files BLAST Protocol | Xmodem | FTP | BLASTscript Topics | Connecting/Disconnecting Command Ref. | Reserved Variables | Autopoll | Error Messages | ASCII Char. Set |
Program Style
Scripts are composed in a text editor, such as Windows Notepad. A script does not need to adhere to a particular style or format, but some common coding conventions may be observed:
IF, ELSE, WHILE, or FILETRANSFER block to improve readability.LOG OPEN command, and a trace file is started with TRACE ON. The ECHO command can also provide additional feedback on the progress of a script and the status of the script interpreter.Common sources of errors include:
Especially frustrating are scripts that work correctly most of the time yet occasionally fail. In these cases, often there is a subtle timing issue that has been overlooked. For instance, time allowed to complete a lengthy process, such as a login, may be insufficient.
The Status of @STATUS
The result of many script operations is reported in the variable
@STATUS.
This reserved variable has a number of functions, such as indicating
whether an error occurred during the
CONNECT
command and identifying which member of a list of target strings
was detected by
TTRAP. Because
@STATUS
is affected by so many script operations, it may be necessary to
save the value of
@STATUS
in a "safe" variable if you need to refer to it later in your script.
The following commands set @STATUS.
CALL, CALLSUB, and GOSUB statements provide a flexible means of breaking scripts into modules.
The CALL Statement
The CALL statement causes BLAST to leave the script that is currently executing and begin executing a different one. Control returns to the original script when the RETURN command is executed by the called script. The RETURN command may include an exit code that sets the value of @STATUS in the calling program. For example, Testone.txt could call Testtwo.txt like this:
# testone.txt |
At this point, Testtwo.txt executes:
# testtwo.txt |
When Testone.txt continues, it can check the value of @STATUS, which holds the exit code from Testtwo.txt:
# testone.txt continues... |
GOSUB statement transfers control to a subroutine within the current script. The subroutine is a section of script that begins with the keyword SUB and ends with the RETURNSUB statement.
# testgsub.scr |
Like RETURN, the RETURNSUB statement can include an exit code that sets @STATUS.
Differences Between CALL and GOSUB
Though CALL and GOSUB perform similar functions in a script, there are important differences between these commands.
One difference is in the way labels are handled. The labels used in a subroutine must be unique not only within the subroutine itself, but throughout the entire file containing the subroutine. This warning does not apply to scripts that are called. Labels are understood to apply only within the file where they are found. Thus, several scripts could contain the label ".begin," and a master script that calls each one could have the same label without causing an error.
Another difference between calling a script and jumping to a subroutine involves execution time. Each time a CALL statement is encountered in a script, a fresh copy of the script is retrieved from disk and parsed. Thus, it may be inefficient to call a script frequently in a loop. The CALLSUB statement, discussed below, specifically addresses this problem.
CALLSUB Statement
Sometimes a combination of the features of CALL and GOSUB are required for a particular task. The CALLSUB command presents such a combination. A script that is called by CALLSUB is parsed only once; so there is no performance penalty if the script is executed frequently. In addition, the values of file-local variables are retained between invocations. In these respects, a script executed via CALLSUB resembles a subroutine invoked by GOSUB. On the other hand, the code executed by CALLSUB must reside in a separate file from the calling script, and duplicate script labels are allowed, just as in the CALL statement.
All parameters in a CALLSUB statement must be string constants. This means that the script specified in a CALLSUB statement cannot be represented by a variable.
CALL, CALLSUB, and GOSUB offer a range of choices for breaking a complex script into modules. The following guidelines may help in selecting the right approach:
GOSUB when the function is short and its purpose is confined to a particular script.CALL when compatibility with older versions of BLAST is important, when the name of the script is not known until execution begins, or when the script is constructed "on the fly" and then executed.CALLSUB when the function is complex, when it is itself composed of specialized subroutines, or if it has general utility.
CALLSUB "mainmenu.scr" # cannot use callsub here |
Making Decisions
It is necessary in most scripts to conditionally execute statements. BLASTscript provides two conditional commands: IF and WHILE. The IF command will test a condition and execute statements if the condition is true. The WHILE command tests a condition and continually repeats execution of statements until the condition is no longer true. For a guide to writing conditional statements, or test expressions, see IF, IF-ELSE.
It is important when setting up conditional operations to know whether the conditionals you are testing are string values or numeric values. Because string and numeric values use different operators, you will get unexpected results using the wrong operator.
String Operators
String operators are:
= is equal toNumeric Operators
< is less than
<= is less than or equal to
> is greater than
>= is greater than or equal to
!= is unequal to
EQ is equal toIF Statement
LT is less than
LE is less than or equal to
GT is greater than
GE is greater than or equal to
NE is unequal to
IF command tests a condition and executes a command if the condition is true.
Single Line IF Statement
In its simplest form, IF tests a condition and executes a single command if the condition is true:
if @STATUS tsend @PHONENO, CR |
This statement checks the value of @STATUS. If @STATUS has a nonzero value, the condition is true and the TSEND statement will be executed.
Alternatively, it is possible to check for specific values by using a string or numeric operator in the conditional. For example, the statement below will execute, if @STATUS is equal to zero. Note that the numeric operator "EQ" is used since @STATUS will be compared to a numeric value.
if @STATUS EQ 0 ttrap 60, "CONNECT" |
In the following statement, the display command will be executed if @USERID is set to the string "Bill." Note that the string operator "=" is used since @USERID is a string value.
if @USERID = "Bill" display "Hello, Bill" |
Multi-line IF - END Statement
The IF-END statement is a multi-line IF statement. It allows an entire block of code to be executed based on the condition of the IF statement:
if @STATUS = 1 |
In the above example, the statements between IF and END will only execute if @STATUS is equal to "1."
IF - ELSE Statement
The IF-ELSE statement allows multiple paths of execution. In an IF-ELSE block, one set of statements will be executed if the condition is true. Otherwise, another set of statements will be executed.
if @STATUS = 1 tsend @PHONENO, CR ttrap 30, "CONNECT" tsend CR ttrap 30, "ogin:" display "Failed to initialize the modem" offline |
In this example, as in the prior example, the statements between the IF and END will execute if @STATUS is equal to "1." Otherwise, the statements between ELSE and END will be executed.
WHILE Statement
The WHILE command tests a condition and executes a block of statements if the condition is true. When execution of the block is completed, the condition will be tested again. If the condition is still true, execution of the block will be repeated. Looping will continue until the condition is false.
In the example below, the WHILE block will execute until @counter is greater than ten. Note the use of the numeric operator "LE" since @counter is a numeric value.
let @counter = 0 let @counter = @counter + 1 display "counter is: ", @counter |
IF and WHILE statements. Evaluation is from left to right with no grouping of conditionals. For readability, you may use parentheses, but they will not change the meaning of the statement.
AND
Both conditions must be true for a statement to evaluate true when using AND. In the example below, the statements between IF and END will execute only if @STATUS and @DCD are both equal to 1.
if @STATUS EQ 1 and @DCD EQ 1 tsend "blast -h", CR ttrap 60, "otocol" |
OR
Only one condition must be true for a statement to evaluate true when using OR. In the example below, the statements between IF and END will execute if @COMMPORT is set to either "com1" or "com2."
if @COMMPORT = "com1" or @COMMPORT = "com2" set @BAUDRATE="19200" set @RTSCTS = "YES" |
NOT
The NOT operator reverses the sense of the conditional. In essence, using the NOT logical will cause the statement to be true, if the conditional is false. For example, the following statement will execute if @total is equal to 0:
if NOT @total display "status is 0" |
NULL
The NULL logical evaluates to true if a string variable is empty. By definition, a variable with a numeric value, even zero, is non-null. Thus, NULL is always false for variables assigned a numeric value. Any variable can be made null by setting it to a null string. The following statement will execute if @var is null ("").
if NULL @var display "@var is empty" |
EXIST
The EXIST logical tests for the existence of a file. If the file exists, the conditional is true. If the file does not exist, the conditional is false. The following statement will execute if C:\tmp\test exists.
if exist "C:\\tmp\\test" display "found test file" |
ISDIR
The ISDIR logical tests for the existence of a directory. If the directory exists,
the conditional is true. If the directory does not exist, the conditional is false. The following statement
will execute if C:\tmp\ exists.
if isdir "C:\\tmp\\" display "found C:\\tmp\\ directory" |
ISOPEN
The ISOPEN logical tests the existence of an open file handle. If the file handle is assigned to an open file, the conditional is true. If the file handle is not assigned to an open file, the conditional is false. The following WHILE loop will execute until an open file handle is found.
let @fh = 1 let @fh = @fh + 1 |
To Quote or Not to Quote
The BLASTscript language supports both quoted and unquoted strings. Unquoted strings are supported for compatibility with some older BLAST products. Because quoted strings are more flexible than unquoted strings, they should be used in all new scripts. The following discussion should help you understand the limitations of unquoted strings.
Unquoted strings are limited to printable characters and may not contain the space (" "), pound sign ("#"), or comma (",") characters. If you wish to create a string containing one of these characters, or any non-printable characters, you must enclose the string in quotes. The following statements containing unquoted strings are all legal.
set @done = yes |
The statements below containing unquoted strings are probably not going to work as intended. The strings in these statements should be enclosed in quotes:
display Sending files now |
Quoted strings may contain any character including non-printable characters. Non-printable characters and special characters are included in quoted strings via the use of escape sequences. An escape is of one or more characters preceded by a backslash "\" or a caret "^" character. The only special rule for quoted strings is that you must escape an escape character in order to use it in a quoted string. In other words, to have a backslash in a quoted string, you must use two backslashes "\\." For example, to send a file called "C:\tmp\sales," you must use the following send statement:
send "C:\\tmp\\sales" |
The following statements containing escape sequences are all legal.
display "Processing \"weekly-reports\" please wait" |
For more information on escape sequences, see String Constants under BLASTScript Command Reference.
Manipulating Text
A number of script commands are available for manipulating text files and text strings. The commands that work with text strings include:
STRCAT string1, string2, [, ...]--Add two or more strings to make a single, longer string. The longer string replaces string1.
STRLEN string1--Find the length of a string. @STATUS is set to the value of the length.STRINX string1, string2--Find the first occurrence of string2 in string1. @STATUS holds the position of the first character in string1 where a match is found.STRRINX string1, string2
--Find the last occurrence of string2 in string1.
@STATUS
holds the position of the first character of the last occurrence of string2 in string1.STRTRIM string1, position1, position2--Extract a substring of string1 beginning at position1 and ending at position2. After extracting the substring, the value of string1 is set to the substring.
# String demo |
@LISTDELIM. A string not containing any delimiter characters is a list consisting of one item; a null string is a list with zero items.
The list-handling commands
LISTCAT, LISTINX, LISTTRIM, LISTLEN, and LISTITEM operate on lists. The syntax and effect of these commands is similar to their string-handling counterparts. (LISTITEM is unique in that it has no string cousin.) For instance, the command LISTINX is used to determine if an item is in a list, just as STRINX determines if a string contains a given substring. Likewise, extracting a range of items from a list is performed by LISTTRIM, just as STRTRIM extracts a range of characters from a string. LISTITEM reads an item from a list without disturbing the list. Here is an example showing the list-handling commands:
# list demo |
It may be helpful to remember that a list is nothing more than a string, and string manipulations can be legally performed on a list:
# string-as-list demo |
Two script commands produce lists as output,
LISTFILES and FREADINISTRING. LISTFILES is a convenient way to access a directory listing in a script. FREADINISTRING can create lists of section names and key names from Windows initialization (.ini) files.Reading and Writing Text Files
FOPENA handle, name--Open a file for appending.
FOPENW handle, name--Open a new file for writing (deletes existing file).
FOPENR handle, name--Open a file for reading.
The commands listed above specify two pieces of information: the file name and a file handle. The file handle is an integer that other commands in the script will use to refer to the file for reading, writing, and closing.
@STATUS is set to the value "0" if the file is opened successfully.
The commands for reading, writing, and closing files are:
FREAD handle, variable--Read a line of text.
FWRITE handle, string [, string]--Write a line of text.
FCLOSE handle--Close the file.
When read and write operations are successful,
@STATUS is set to "0." If a script attempts to read past the end of a file, @STATUS is set to a nonzero value.
Here is an example that uses the file-handling commands:
# file demo |
[section_name1] |
[Capitals] |
Two script commands are available for manipulating .ini files:
FREADINISTRING--Read values from an .ini file.
FWRITEINISTRING--Write values to an .ini file.
For example, to read the value of the key "Iowa" from the section "Capitals" in the .ini file shown above, the following command could be used:
FREADINISTRING "Capitals", "Iowa", @capital, "C:\\Tmp\\geo.ini" |
where the name of the .ini file in this example is C:\Tmp\geo.ini. The name of the capital city, "Des Moines," will be copied to the variable
@capital.
Similarly, to write the value "Austin" for the key "Texas" in the Capitals section:
FWRITEINISTRING "Capitals", "Texas", "Austin", "C:\\Tmp\\geo.ini" |
FWRITEINISTRING creates new sections and key-value pairs automatically as needed.
FWRITEINISTRING includes a feature for obtaining a list of section names or a list of key names for a particular section of an .ini file. Manipulating Binary Data
For example, the same string manipulation commands work with buffers as well as strings.
STRLEN returns the size of a binary buffer; STRINX will match any arbitrary binary value (or buffer) within another buffer; STRCAT appends binary values to a buffer; and STRTRIM extracts sub-buffers from a larger one.
In some cases, however, it is necessary to distinguish text strings from binary buffers. In particular, the list-handling commands cannot be used with buffers because they require a special character to separate items. Because the item delimiter cannot appear as part of any item, lists cannot handle all ASCII values.
In addition, commands such as
DISPLAY and PUT are tailored for displaying text strings. Attempts to display a buffer will not cause an error, but all the characters may not appear in the Script View as expected. When the interpreter encounters an ASCII NUL (\x00) in a buffer, string processing stops.
Here is an example illustrating BLASTscript's handling of binary data.
# binary data demo |
FOPENAB handle, name--Open a file for appending.
FOPENWB handle, name--Open a new file for writing (deletes existing file).
FOPENRB handle, name--Open a file for reading.
The commands listed above specify two pieces of information: the file name and a file handle. The file handle is a positive integer that other commands in the script will use to refer to the file for reading, writing, and closing.
@STATUS is set to the value "0" if the file opens successfully.
The commands for reading, writing, and positioning with a file are:
FREADB handle, variable, length--Read a buffer of the given length.
FWRITEB handle, string, ...--Write a buffer.
FSEEK handle, { BEGIN | END | offset }--Change position with a file.
When read and write operations are successful,
@STATUS
is set to "0." If a script attempts to read past the end of a file,
@STATUS is set to a nonzero value.
FREADB differs from
FREAD in requiring the number of bytes to read from the
file. Reading does not stop automatically at the end of a line as it does with
FREAD.
FWRITEB differs from FWRITE in that it does not append line termination characters to the end of the buffer that is written.
The file positioning command,
FSEEK, is used to change position within a file. The BEGIN and END parameters move the pointer to the beginning or end of the file. BEGIN and END may be used with files opened for text-mode operation as well as binary-mode operation. With binary files but not text files, an offset (positive or negative) may be given to specify the number of bytes to move from the current position.
The same command,
FCLOSE, that closes text files also closes binary files.
Managing the Script View
Thoughtful screen displays help users gain a sense of being "in good hands." By informing users of the progress of a lengthy job, such as a file transfer, the user will relax and let the software do its job. But throwing too much text onto the screen at once, or neglecting the screen completely, can make users wonder instead if their session has gone haywire. BLASTscript provides a number of commands and reserved variables to control the Script View, so you can always present just the right amount of information to your users.
For some applications, you may wish to turn off regions of the Script View. The following reserved variables control particular regions of the display:@USERIF--Use top four lines of the view for status information.@SCRLREG--Use bottom of the view to display data. @USERIF to "OFF"), those lines are made available to the scrolling region. The operation of @USERIF is equivalent to the MENU command.
Two script commands permit you to display text in the status area:WRITE--Print a message.WERROR--Print a message and wait for the user to press the Enter key (but script will not pause if @ONERROR is set to "CONTINUE").
The most common way to display text in the scrolling region is with the DISPLAY statement. DISPLAY prints a string at the current cursor position and advances the cursor to the beginning of the next line.CURSOR and PUT:CURSOR row, column--Position the cursor at row (0-19 or 0-24) and column (0-79).PUT string--Print a string.CLEAR) and clearing text to the end of the current line (CLEOL).
# screen demo |
|
|
|
|---|---|---|
DISPLAY
|
|
|
PUT
|
|
|
WRITE
|
|
|
WERROR
|
|
|
LOG
|
|
|
Communicating with Other Programs
In some BLAST applications, the end user is not even aware that BLAST is operating in the system. BLAST provides a simple interface that lets other programs control BLAST, hiding the existence of BLAST completely from the user if necessary.
The command line can contain up to ten "arguments," or parameters, that pass information to a BLAST script. For example, consider the following BLAST command line:
blast -pMidwest -lChicago -sNightlyPoll.txt 12:05 kaufmann spode |
This command will start BLAST with the phonebook "Midwest," the listing "Chicago," and the script "NightlyPoll.txt." The remaining parameters on the command line are available to the script as follows:
@ARG0--Contains the string "12:05".@ARG1--Contains the string "kaufmann."@ARG2--Contains the string "spode." |
A program can also pass information to a script by writing a file that the script opens and reads. Alternatively, because scripts are simple text files, a sophisticated controlling application could write "on the fly" the script that BLAST will execute.
Controlling Other Programs from BLAST
LSYSTEM statement, which permits your script to execute a single command as you would type it on the MS-DOS command line. Second, the script can issue an LRUN command, which permits it to launch a Windows application. For example:
# lsystem-lrun demo |
With
LSYSTEM, script execution pauses until the command completes. With LRUN, script execution normally continues as soon as the program has started, but an optional timeout can be given that forces the interpreter to wait a specified number of seconds before continuing.
Storing User-Defined Scripts
We recommend storing your user-defined scripts in Userscripts\ rather than in Scripts\ because Userscripts\ is searched by CALL and CALLSUB before @SCRIPTDIR is searched.
|
Table of Contents | Intro | Quickstart | Phonebook | DP Viewer | Cmd. Line Ref. | Transferring Files BLAST Protocol | Xmodem | FTP | BLASTscript Topics | Connecting/Disconnecting Command Ref. | Reserved Variables | Autopoll | Error Messages | ASCII Char. Set |