[SCRIPT.DOC] -- Documentation for VTKermit's Script Facility -- 2 Feb 86 VTKermit's Script Facility is a small special-purpose programming language which is tied into the VTKermit VT100 terminal emulator. It enables a programmer to create a program which can control a communications session and act as an interface between the user and a remote host, as well as controlling any modem, network or other mechanism required to access a remote host. The most typical use of a script is to log a user into a remote computer over a dialup line, but many other uses are possible. Beyond the most typical uses of scripts are some useful features that can be provide greater customization possibilities. Scripts can ask a user questions, store the answers in variables, test those variables in simple ways, set other variables, take different actions depending on user or host input, send text to the host, wait for responses from the host or timeout waiting for one, sleep for brief periods, loop within a script, call and chain from script to script and create and write to disk files. This is far short of a general purpose programming language like FORTRAN or C, but is powerful nonetheless. There are two types of VTKermit scripts: script-files, which are standard ASCII text files with lines delimited by CR-LF, and script-macros, which are macros interpreted as scripts. Script-files are created with any ASCII text editor, while script-macros are created with the VTKermit DEFINE command. Script-files are executed with the SCRIPT-FILE command, and script-macros are executed with the DO-SCRIPT command. As with all macros, the maximum size of a script-macro is 255 characters. This means that any non-trivial script will have to be implemented as a separate ASCII file. Once a script has been created and the invoking SCRIPT-FILE command given, the Script Processor takes over control of your keyboard and you are thrown into Terminal Emulation mode. You will see the entire communications session take place on your screen, but any keyboard input you provide will be ignored unless the script is specifically prompting you for something. If you see that the script is not working for some reason, you can always type CONTROL-C to abort the script. You will be left in Terminal mode at the point that you typed CONTROL-C -- you can then take whatever action is required to continue or terminate the communications session, and press F5 (or ALT-F5) to leave Terminal mode. It sometimes takes a lot of tries to build a bulletproof script which will handle all typical circumstances properly (e.g. modem unplugged, phone unplugged, host not available, etc.), so CONTROL-C can be very helpful during script debugging. A script consists of script commands, labels, comments, line separators and whitespace. Every script command begins with a script verb, and most script commands take one or more arguments. Script verbs may be in upper, lower or mixed case. Script arguments are usually surrounded by delimiters, which can be almost any printable ASCII character you want. This makes it easy to include most ASCII characters in the script argument, since any character not used in the argument may act as the delimiter. Also, control characters may be invoked within delimited text by using up-arrow (carat) constructs, such as ^M for CR, ^J for LF or ^[ for ESCape. The sequence "^^", however, is converted to "^" to allow the up-arrow character to be included. To get the ASCII character control-uparrow you should type uparrow-tilde ("^~"). The control character conversion function ignores the case of its argument, so ^M and ^m will both invoke CR. Script labels, which are tags to be used in jumping around the script, are not enclosed in delimiters, since labels are not supposed to contain nonalphanumeric characters. Two printable characters are reserved within a script and may not be used as delimiters: exclamation point and semicolon. Exclamation is used as a comment-begin character, and semicolon is used as a line separator. Either of these characters may be used within a delimited argument. A script is primarily line-oriented: most script commands end at the end of the line they begin on. However, if a script verb takes a delimited argument, that argument may span multiple lines. Internally, CR-LF pairs in a delimited argument are treated as CR -- usually the right thing to do when sending text which spans multiple lines. The semicolon provides a mechanism for putting multiple script commands on the same line. At any point that a script command might be considered logically complete, you may insert a semicolon and continue with another script command on the same line. Similarly, an exclamation point inserted at a logical command end will cause the rest of the line to be treated as a comment. A semicolon within a comment does not terminate the comment -- comments are terminated only with CR. Scripts provide support for simple variables. Script variables always hold ASCII text which must not exceed 94 characters in length, and always have names which begin with a percent-sign. Each variable name can be as long as 31 characters (including the percent) and can contain dashes or underscores to inprove readability. There may be as many as 20 variables defined. After that limit, additional variables will not be created. Variables are set with any of the ASK, NASK or LET commands, and may be invoked in any delimited string simply by naming them and terminating them with a space which is treated as part of the variable name (i.e. ignored). Invoking an undefined variable will give a single percent-sign, so percent- signs may be easily included in delimited text by typing percent-percent-space (for example) where a percent is desired. Variables remain intact as long as script processing continues, so CALLed and CHAINed script may use the variables of the calling/chaining script, or may set new variables for use by the calling script. Leaving the script processor and returning later, however, will erase all variable definitions. Scripts can sleep (sit and do nothing) for periods of seconds or hundredths of seconds. The maximum quantity should be 150 or less -- either 2.5 minutes (150 seconds) or 1.5 seconds (150 hundredths of a second). Similarly, a timer can be set to abort a "wait" in which the script is waiting for host output. The timer can be up to 150 seconds or 150 hundredths of a second. Due to the way sleeps and timer are implemented, only one can be in effect at a time (that is, a SLEEP command will clobber any TIMER which is set). Verbs may be abbreviated to the shortest abbreviation which is still unique. To allow for the possibility of future versions of VTKermit which may have additional verbs, you should not overdo this. All verbs, variables and labels may be entered in upper, lower or mixed case. Internally, these are all treated as upper case. Delimited text, on the other hand, it not case-converted at all -- mixed case text is sent as mixed case. Whitespace (combinations of space and tab) are generally ignored between script verbs and arguments or between script commands. Appropriate use of whitespace can improve script readability. Blank lines are ignored, so these may also be used to improve readability. Scripts generally are composed of sequences of standard activities. Text can be sent to the host (out the serial port) with SEND or displayed on the screen with PRINT. The script can SLEEP for a period of time, or can block WAITing for some particular host output, optionally abortable when a TIMER expires. To avoid "race conditions" in which host output is returned before the script can WAIT for it, you can enable buffering of host output with a LISTEN command. You can jump from one script to another with CHAIN, or jump-and- return with CALL. Disk files may be created (or zeroed) with an OPEN command, written to with WRITE then closed with CLOSE. Finally, you can terminate the script by leaving to COMMAND-MODE or TERMINAL-MODE or quit the program entirely with EXIT-TO-DOS. Hitting end-of-file on the outermost (unCALLed) script will leave you in Terminal mode. There are currently 27 script commands, some of which are trivial variations on each other. All the commands are described here. Each command is described first in a general way, followed by the exact command format. For some commands, this will be followed by a discussion of any special details you may need to know to use the command, and an example of a typical use. In the descriptions below, the following definitions apply: [optional] An item in square braces is optional %variable A variable name, including the percent-sign, always terminated with a space, which is "eaten" (not used) delimited-text A delimiter, any amount of text, the delimiter again label A label to be jumped to number A number between 0 and 150 condition A condition code set by WAIT, or a comparison between a variable and a delimited string command Another VTKermit command, usually a GOTO or BACKTO = A literal equal-sign (=) NO-OP No-operation ... do nothing ASK ASK is used to get a value for a variable from the user. ASK will prompt the user by typing a text string to the screen (using the VT100 channel, so ESC sequences may be used) and will wait for text to be typed followed by Enter (CR). Any typed text will be echoed to the screen. ASK variable delimited-text ASK is often used prior to beginning a communications session so that required parameters will be established up-front. ASK %userid "What is your User-ID: " BACKTO BACKTO performs backward branching within a script file. BACKTO label BACKTO sets a pointer to the start of the file and then searches forwards just like a GOTO. Labels should be unique for best results. BACKTO Start CALL CALL sets a pointer in the current script and thens runs another script-file, optionally starting execution at a specified label. CALL delimited-text [label] The delimited-text is a full DOS 2.0 file specification which may contain a path name. The label is optional and, if used, will cause an implicit GOTO to the label once the script is started. If the specified script file is not found, this instruction is a NO-OP. CALL "c:\scripts\error.scr" No_modem CHAIN CHAIN leaves the current script and then runs another script, without returning, optionally starting execution at a label. CHAIN delimited-text [label] The delimited-text is a full file spec, as with CALL. The label is optional. If the specified script file is not found, this instruction is equivalent to a GOTO to the end of the current script. CHAIN "part2.scr" CLOSE CLOSE closes any file which was openned with the OPEN command. CLOSE If no file is open, this is a NO-OP. COMMAND-MODE The COMMAND-MODE command immediately terminates script processing and exits back to Command mode (or Menu mode if SET MODE MENU has been given). It will terminate any number of CALLs. COMMAND-MODE CR A synonym for SENDCR. See below. EXIT-TO-DOS The EXIT-TO-DOS command immediately terminates script processing and exits completely back to DOS. It will terminate any number of CALLs. EXIT-TO-DOS GOTO The GOTO command performs a forward jump through the current script file searching for a specific label. (Labels are always the first text on a line and end with a colon.) GOTO label If the specified label is not found, end-of-file will be hit and the current script will terminate. If the current script was CALLed, execution will then continue in the calling script. GOTO We_are_connected HSLEEP HSLEEP sleeps (does nothing) for a period of hundredths of seconds. HSLEEP number HSLEEP is useful for short delays of less than a second. Some modems, and probably some remote hosts, do not respond to text which is sent too quickly, but a delay of a full second may be more than is needed. HSLEEP allows for "micro-sleeps" of a fraction of a second. HSLEEP 50 ! Sleep for 1/2 second HTIMER HTIMER sets a very short timer to abort a WAIT. HTIMER number HTIMER might be useful when waiting for an event that will happen either very quickly or not at all, such as a response from a connected modem. HTIMER 150 IF The IF command has two forms, one of which is used to test a completion code of a WAIT, the other of which is used to compare a variable with a delimited string. IF condition command The first form is used following a WAIT command to determine what event terminated the WAIT. In this case, the "condition" will be a number between 1 and the number of waiting items (see WAIT for further discussion) or 255. Lower numbers indicate the matching waiting item, while 255 means "timeout". 255 will only occur if a TIMER had been set prior to entering the WAIT. The second form is used to test a variable to see if it begins with a certain string of characters. The format of the condition in this case is %variable = delimited-text Only "equality" can be tested for, and this test is actually for "abbreviation". Thus, "%system = /A/" will be true if %system is "A" or "ABCDEF", but false if %system is "B". When the tested condition is true, the command which follows will be executed: when false, the command will be skipped. The most useful command is usually GOTO or BACKTO, since these allow more than one command to be executed in response to the condition. IF 1 GOTO We_are_in or IF %modem = "H" GOTO HAYES LET The LET command sets a variable to a specified value. LET %variable = delimited-text This is often useful when several items should be set in unison. You might query the user for some selector (e.g. "Which system?") and then set several variables based on the user's response. Another use is when there might be several paths through front-end scripts leading to a final "worker" script in which some front-ends prompt the user for values (with ASK) and others just force those values with LET. LET %Phone_number = "555-1212" LISTEN Ordinarily, the script processor pays no attention to what is received from the remote host. When a WAIT command is executed, however, script processing halts until either some specified text is received from the host or a timeout occurs. Often the received text will be triggered in the host by something sent by the script. In this case, there may be circumstances in which the hosts response will come so fast that the WAIT command hasn't even been set up yet, in which case the WAIT will not see the host's text. The LISTEN command can be used to turn on "listening" to host output BEFORE the triggering text is sent, assuring that the host's response will be seen. Ordinarily, "listening" begins when the WAIT command is executed. LISTEN LWAIT LWAIT is a variant of the WAIT command that does not turn off listening when it finishes. It prevents the script processor from being "deaf" to host output, which would ordinarily happen between WAIT commands. It can be used to wait in succession for several host responses which may come all in a row. The format is identical to that of the WAIT command, which you should also see. LWAIT delimited-text [delimited-text ...] NASK NASK is a variant of ASK which does not echo user-typed text to the screen. This is most useful when prompting for passwords. NASK %variable delimited-text OPEN The OPEN command either creates or erases-and-opens the specified file. This must be performed prior to using the WRITE command. OPEN delimited-text The delimited-text is a DOS 2.0 file specification. If the file cannot be created or opened, this command is a NO-OP. PRINT PRINT sends its argument to the screen through the VT100 filter. That is, PRINT simulates the receipt of host-typed output, and all VT100 tricks which the host could use (bold, cursor positioning, line and screen clears, line-drawing graphics, etc.) are available. The delimited-text may contain CR-LF pairs, in which case the pair is reduced to CR and then expanded to CR-LF. This makes the text look right on the screen. As with all delimited-text, up-arrow prefixes may be used to "control-ize" the following characters, so "^[" will turn into ESCape. Also, variables may be invoked. PRINT delimited-text PRINT can also be used in a tricky way to control the program. By using the "enter-server" and "preload-command" escape sequences described in VT100.DOC, you can throw the program temporarily into Server mode or execute any VTKermit command you want. Note that the preloaded command is executed only when you leave Terminal mode, so the script will have to terminate in order to execute the command. PRINT /^[[H^[[J The screen is now clear./ PRINTCR PRINTCR is identical to PRINT except that a CR-LF is appended to the output. This is for convenience only. PRINTCR delimited-text SEND The SEND command sends text out the serial port. If the delimited-text spans multiple lines, then the CR-LF pairs which separate the lines will be sent as CR only. This is usually what is wanted when sending text to a remote host. If you want to send a true LF, you must code "^J" in the delimited-text. SEND delimited-text SEND is probably the most necessary script command and may be the most heavily used. SEND /AT D%type %phone ^m/ SENDBR SENDBR sends a break signal out the port. This is sometimes used to get the attention of a remote host or intermediate circuit switch. SENDBR SENDCR SENDCR is identical to SEND except that it appends a CR to the sent text. This is for convenience only. SENDCR delimited-text The CR command is a synonym for SENDCR, also only for convenience. SLEEP The SLEEP command puts the script processor into a "sleeping" state in which the keyboard is ignored and host output is directed to the screen but otherwise ignored. This is most useful when dealing with hosts or devices which lose input typed at the wrong time. The SLEEP command sleeps for a period numbered in seconds, while the HSLEEP command sleeps for a period numbered in hundredths of a second. SLEEP number The standard Hayes modem, for example, chokes on the sequence SEND /AT Q0^mAT DT %phone ^m/ but works with the sequence SEND /AT Q0^m/ ; SLEEP 1 ; SEND /AT DT %phone ^m/ in which the only difference is the delay between sent lines. TERMINAL-MODE The TERMINAL-MODE command throws you immediately into Terminal mode, terminating any number of CALLs. This is different from hitting end-of-file in a script if the script was CALLed, but is identical otherwise. TERMINAL-MODE TIMER The TIMER command sets a timer which will abort a later WAIT command if none of the desired sequences of host output is seen within the timeout period. This is very useful for determining if a modem is attached to a line, for example, since a null response can be timed out and action taken. The TIMER command sets a timer for some number of seconds, while the HTIMER command sets a timer for some number of hundredths of seconds. Note that TIMER is aborted by a SLEEP, so any desired SLEEPing should be done prior to hitting the TIMER command. TIMER number As with SLEEP, HSLEEP and HTIMER, number should be 150 or less. Also, a timer is not cleared at the conclusion of a WAIT unless the WAIT was ended by a timeout. Thus, one TIMER may affect more than one WAIT if the first WAIT is terminated by host output. A TIMER may be cleared with a TIMER 0 or SLEEP 0 command, or may be reset for the next WAIT. WAIT The WAIT command halts script processing until either one of several desired strings is received from the host or a certain amount of time has elapsed. WAIT can wait for any one of several strings from the remote host, but all "waiting" strings must be listed on the same line as the WAIT verb. There may be as many as 10 waiting items, each up to 31 characters long. WAIT delimited-text [delimited-text ...] WAIT is very useful for taking different courses of action depending on events seen while trying to dial up a remote host or log in. In combination with the IF command, this can be used for error-detection, error-recovery or simply choosing different courses of action. Ordinarily, only text received after the WAIT command had begun would be seen by the command. The LISTEN command, described earlier, may be used to pre-buffer the host's text for a later WAIT command. Also, the WAIT turns off listening when it terminates. The LWAIT command is a variant of WAIT which leaves listening in effect. WAIT /CONNECTED/ /NOT RESPONDING/ /UNKNOWN/ /ERROR/ WRITE The WRITE command works just like PRINT and SEND, but instead sends its output to a disk file which was opened with the OPEN command. In the context of VTKermit, this is most useful for building a self- installing script which will build a smaller script file for actual use. WRITE delimited-text For example, you may want to write a script to log any user into your system. You could write a completely general script which asked the user for his user ID every time it was run. However, it might be more convenient for the user if he could specify his user ID only once, then have it automatically used unless he "reinstalled" his script. A "master" script could prompt the user for a user ID and build a specific script to log that user in under that user ID every time. (The generated script should do the prompting for password, since the password may change often and probably shouldn't be stored on disk.) The combination of OPEN, WRITE and CLOSE may be used to have one script file write another which will then be used to log the user in on a daily basis. If any details asked by the generating script change, the script can be run again and another "worker" script generated. All feature available to other "delimited-texts" may be used here, so control-characters and variables may be freely included. To have the generated script include control-ized characters (e.g. to have "^m" appear in the generated script) you should code "^^" to have the master script generate a "^". Similarly, to have the generated script invoke its own variables, you should write percent- percent-space anywhere you need a percent in the generated script. Thus, WRITE "SEND /%% phone /" will write "SEND /%phone /" to the file, while WRITE "SEND /%phone /" will try to use a master-script variable named %phone. That is the complete set of script commands as of 2 February 1986. The remainder of this file presents some examples of the use of these commands. >> To test a Hayes Smartmodem 1200, or to see if one is there ... Print "^[[H^[[JTesting your Hayes Smartmodem 1200 ...^m" HSleep 50 ! Give DTR a chance to go high Send "^m" ; HSleep 50 ! First, wake up Hayes modem Listen ; Timer 3 ! See if we got it Send "AT Q0^m" ; Wait "OK" ! Did it go ready? HSleep 30 ! Short pauses help If 255 GoTo Not_responding ! Looks dead or missing ! The modem is here ... >> To see what type or Hayes modem we have, normal or advanced (has X4 and L1) Learn_type: HSleep 30 ! Give it a short rest Listen ; Timer 3 ! Make modem identify itself Send "ATI^m" ; Wait "123" "136" "OK" If 2 GoTo Advanced ! Use special codes on new model GoTo Normal ! Normal Hayes type >> To see if user wants Tone or Pulse dialing (T or P for Hayes modem) GType: Ask %Type /Type "T" for Tone dialing, "P" for Pulse: / If %Type = "t" Let %Type = "T" If %Type = "p" Let %Type = "P" If %Type = "T" GoTo Do_access If %Type = "P" GoTo Do_access Print "^g? Must be T or P^m" ; Backto GType >> Code to generate a script ... Print "^[[H^[[JGenerating script ...^m" Ask %phone "Phone number? " Open "worker.scr" ! Open the file for output Write ~TIMER 30 ; SEND "ATDT%Phone ^m" WAIT "CONNECT" "NO CARRIER" SLEEP 1 ; IF 1 GOTO GOT_IN PRINT "? Couldn't dial up host^^m" ; TERMINAL-MODE GOT_IN: PRINT "You are in^^m" ~ Close ! Close the new script file Print "^mScript file generation complete.^m" Ask %Ignore "Press ^[[4;7m[Enter]^[[m to return to the menu: " Print "^[[H^[[J" Command-Mode [End of SCRIPT.DOC]