SAIL-COMND Interface ==================== Andrew R. Lowry and David S. Millman Columbia University Center for Computing Activities User Services Group 15 June 1979 Table of Contents i Table of Contents Preface 1 1. The Jsys 3 1.1 General Information 3 1.2 How It Works 3 1.2.1 Information Needed By COMND 3 1.2.2 The Parsing Process 5 1.2.3 The Command Line 7 1.2.4 The Control/H Feature 8 1.2.5 Multiple Function Calls 9 2. The Interface 11 2.1 General Rules 11 2.1.1 Loading the Routines 11 2.1.2 Naming Conventions 11 2.1.3 Handling Error and Reparse Conditions 12 2.1.3.1 Cm!Err and Cm!Reparse Flags 12 2.1.3.2 Cm!Retry - An Alternative Error 13 Recovery Mechanism 2.1.3.3 The Built-in Error Handler 14 2.1.4 The Atom Buffer 15 2.1.5 Command Files 16 2.1.6 Common Parameters 17 2.2 Specifics 19 2.2.1 The Cm!Act Procedure 19 2.2.2 The Cm!Cfm Procedure 19 2.2.3 The Cm!Cma Procedure 20 2.2.4 The Cm!Dev Procedure 21 2.2.5 The Cm!Dir Procedure 21 2.2.6 The Cm!Fil Procedure 22 2.2.7 The Cm!Fld Procedure 24 2.2.8 The Cm!Flt Procedure 25 2.2.9 The Cm!Getatm Procedure 25 2.2.10 The Cm!Ifi Procedure 25 2.2.11 The Cm!Ini Procedure 26 2.2.12 The Cm!Key Procedure 27 2.2.13 The Cm!Nod Procedure 29 2.2.14 The Cm!Noi Procedure 29 2.2.15 The Cm!Num Procedure 30 2.2.16 The Cm!Nux Procedure 30 2.2.17 The Cm!Ofi Procedure 31 2.2.18 The Cm!Qst Procedure 31 2.2.19 The Cm!Retry Procedure 32 2.2.20 The Cm!Size Procedure 33 2.2.21 The Cm!Swi Procedure 33 2.2.22 The Cm!Tad Procedure 34 2.2.23 The Cm!Take Procedure 35 2.2.24 The Cm!Tbuild Procedure 36 2.2.25 The Cm!Tok Procedure 38 2.2.26 The Cm!Txt Procedure 38 2.2.27 The Cm!Uqs Procedure 39 2.2.28 The Cm!Usr Procedure 39 ii SAIL-COMND Interface 2.3 Multiple FDBs 40 3. Examples 43 3.1 Example 1 - Nothing Fancy 43 3.1.1 SAIL Code 43 3.1.2 Remarks 47 3.2 Example 2 - The Ctrl/H Feature And Switches 48 3.2.1 SAIL Code 49 3.2.2 Remarks 53 A. Standard Break Tables 55 Index 59 Preface 1 PREFACE This document describes a package of SAIL procedures designed to make the TOPS-20 COMND jsys easily available to the SAIL programmer. All functions of COMND are included, including provisions for up to ten alternate functions in a single call. Two features of COMND which are not implemented are the following: A reparse dispatch address may not be specified in word 0 of the command state block, and the cm!tbuild procedure for constructing TBLUK lookup tables from string arrays does not make provision for declaring strings as abbreviations for other strings in the array (see the discussion of the CM%ABR bit in the description of the CMKEY function call in the Monitor Calls Reference Manual). The document is in three parts. The first part describes the COMND jsys itself in moderate detail. The second part describes the SAIL-COMND interface routines and how to use them. The third part gives some brief examples of the use of the interface routines. Many thanks go to Frank da Cruz, Chris Ryland and Norman Kincl of the CUCCA Systems Group, and to Ted Markowitz, Ken Rossman, Harry Yudenfriend and Jeffrey Slavitz of the CUCCA User Services Group for their technical assistance and numerous suggestions. Also thanks to any others who used the preliminary versions of the package during its development, for bearing with the many bugs and misfeatures and for any contributions which they have made. 2 SAIL-COMND Interface The Jsys 3 1. THE JSYS 1.1 General Information Every user of the DECsystem-20 quickly becomes familiar with the workings of the COMND jsys, although he may not be aware of his education. The COMND jsys is the thing that figures out what he means when he abbreviates his commands to the EXEC and finishes up his commands for him when he types an escape character. It is also what types guide words in parentheses telling him what he must type next, and it is the thing that will untiringly answer his question marks with lists of alternatives for him to choose from. In short, it is one of the things that makes learning and typing in commands to the EXEC as easy as it is. Hence its name -- COMND. 1.2 How It Works Using the COMND jsys mainly consists of the following: you tell it what you're looking for, and it tells you what it finds. All the complexities have to do with how this communication takes place. A great deal of this is common to all the calls you can give to COMND, but some of it depends on exactly what you're asking COMND to look for. 1.2.1 Information Needed By COMND All the information which you must supply to COMND may be broken down basically into two sets, the Command State Block (CSB) and the Function Descriptor Block (FDB). 4 SAIL-COMND Interface The CSB is ten words (storage locations) long and contains information about what has been typed so far, how much more can be typed without overflowing the space that has been set aside to store it, and where COMND can find other information that it needs. Most of this information must be supplied only once by the program using COMND, and from that point on COMND will update the information as it goes. Exact information on the contents of the CSB is not necessary for the SAIL programmer who wants to use COMND, but for those interested, it can be found in the DECsystem-20 Monitor Calls Reference Manual. The FDB is four words long and contains information which is more specific to the type of call which is being made than is the information in the CSB. It is here that COMND finds out what type of information it should be looking for -- file name, time of day, one out of a list of possible keywords, or any other of the 24 different items it knows how to look for. Also in the FDB it finds pointers to a help string and a default string which the controlling program supplies. The help string is what will be typed if the user types a question mark, and the default string is what COMND will fill in if the user types an escape character. Finally, COMND finds several indicators in the FDB telling it how to process the request -- things like whether or not to convert lower case input into upper case, whether or not to accept indirect file specifications, etc. The SAIL programmer who wishes to use the COMND The Jsys 5 interface need not worry at this point how the information is stored in the FDB and the CSB. He will simply supply the information as parameters to the package routines, and they will take over from there. Those who are interested, however, are referred to the DECsystem-20 Monitor Calls Reference Guide. The only thing left to do after the CSB and FDB have been properly filled in is to tell COMND where they are and let it go do its work. 1.2.2 The Parsing Process When COMND is invoked, it starts accepting characters from (usually) the job's controlling terminal. It keeps taking characters until the user types what is called an "action" chatacter. Action characters include question mark, escape, ctrl/f and carriage return, and they are called action characters because COMND won't start doing what it is supposed to do until one of them is typed. Once an action character is encountered, COMND will determine whether or not the user has finished typing what he was supposed to type, and if so, will return control to the calling program. This can be done in any of three possible states. If COMND was able to interpret what was typed, and decided that it was an appropriate response, then it returns normally with the data that it received stored somewhere where the program can easily retrieve it. 6 SAIL-COMND Interface If COMND was unable to understand what was typed in the context of what it was told it was looking for, then it will return with an error indicator set so that the program will know that something went wrong. The third possibility is best shown by example. Suppose a program desires to obtain from the user first a file name, then a time of day. This will involve two calls to COMND. When the first call is executed, suppose the user (call him Fred) types in FOO.BAR as his file name. COMND accepts this as a valid file name and returns normally to the calling program, which then executes COMND again, this time asking for a time of day. At this point, Fred decides that he really didn't want to use FOO.BAR, but wanted FOO.BAZ instead. So he deletes back to the R and types in a Z, and then he goes ahead and types in a time of day as required. Now it looks like trouble ... COMND has already told the program that Fred wanted FOO.BAR, and now it needs some way to let the program know that he changed his mind. In COMND jargon, we say that a "reparse" is needed. COMND sets a flag to let the program know what has happened, and now the program must start right from the beginning and reissue all the calls that it made to COMND for the current command line (this rather vague term will be firmed up shortly). Thus it redoes the call to get a file name, and COMND fills in FOO.BAZ this time, and then it continues with the time of day call just like before. If there had been other calls on this command line before the The Jsys 7 file name, they too would have to be reissued in the same order as they originally were called. This may seem rather complicated, but with SAIL's block structure and its NEXT and CONTINUE statements it all becomes fairly simple, as will be demonstrated in Part III of this document. 1.2.3 The Command Line The term "command line" was used a few times in the preceeding paragraph, and although it may have a fairly intuitive meaning, it also has a very strict meaning in the context of the COMND jsys, which will be explained now and should be kept in mind when trying to understand the reparse mechanism. One of the calls that can be made to COMND is called "CMINI" (each different call has its own slightly mnemonic name). The CM signifies that it has something to do with COMND, and the INI stands for "INItialize". This call, unlike the rest of the calls, accepts no input from the terminal. It is used to set up initial values in the CSB and to type out the command line prompt. The end of this prompt is the farthest back that a user may delete when using the program. A "command line", then, consists of all responses to COMND calls made between successive CMINI's. For a reparse, the program reissues COMND calls starting with the one after the CMINI call that initiated the command line. The CMINI call should not be reissued. That would be done if an error were detected and the entire command line had to be 8 SAIL-COMND Interface restarted. The difference is that when CMINI is done, COMND forgets everything that was previously contained in the buffer. This is appropriate for a complete restart after an error, but not for merely backing up on a reparse. 1.2.4 The Control/H Feature It was explained in the previous section that when a parsing error occurs during a call to COMND, a flag will be set and the calling program should reissue all the COMND calls for the current command line, including the CMINI. When that is done, the user may retype all of the information that he previously typed correctly, and then finish the command line. Often, however, this will mean that the user will have to retype quite a bit of correct information. This may be avoided by using the cm!retry procedure as described above, but there is a safer way of going about things. If the program leaves the CSB in the correct state, then the user will have the option of typing a contro/h (backspace) character as the very first character after the new prompt, which will cause the previous contents of the command line to automatically be retyped up to but not including the erroneous field. All this can be perfectly transparent to the calling program; although there is a way for the program to find out that a ctrl/h was typed, it may ignore this information and issue its calls exactly as if the user were typing everything in again by hand. To find out how to adopt the ctrl/h feature in your The Jsys 9 SAIL programs, see the description of the cm!ini procedure (section 2.2.11, page 26). 1.2.5 Multiple Function Calls The only topic left to cover in Part I is concept of multiple function calls. This refers to giving COMND more than one alternative to look for. For instance, it may be equally acceptable at a particular point in a command line for the user to type either a date, or simply a decimal integer, specifying possiblly a number of days from the current date. It would be advantageous for COMND to know about the alternatives and not have to return an error if the second alternative were chosen. To accomplish this, it is possible to have several FDB'S all linked together in a chain. The first one contains a pointer to the second, which contains a pointer to the third, etc. Then if COMND can't make sense of what is typed in the context of the first FDB, it goes on and tries the next FDB, and so on right down the line until it gets to an FDB that does not point to another one. At that point, if none of the FDB's succeeded, an error condition is finally signalled and COMND returns. If one of the FDB's does fit, then not only is the normal data returned, but also the location of the succeeding FDB so that the program will be able to determine what ultimately happened. The same procedures apply to multiple FDB's as to single ones in regard to reparsing, error restarts, etc. Remember that when using multiple FDB's only one input item 10 SAIL-COMND Interface is parsed, not several. The multiple nature comes from the fact that COMND is given several choices as to how it should attempt to interpret that item. Note that when using multiple FDB's, only one CSB is used. This fact underlines the main difference between the natures of information stored in the two blocks, the CSB being fairly call-independent, while almost all of the information in the FDB depends on exactly what call is being made. This concludes Part I of this document. At this point you should have an idea of what is involved in getting the COMND jsys to do your work for you. You are not prepared to go out and use COMND in your assembler programs (unless you have done some reading in other sources), but you should have enough understanding now to be able to follow Part II, which goes into the details of using COMND from SAIL programs. The Interface 11 2. THE INTERFACE The information in this part describes the use of the SAIL-COMND interface. This interface allows the programmer to implement the COMND jsys in his programs in the form of a set of SAIL procedure calls. The information which must be stored in the CSB and FDB is passed in the form of procedure parameters, and the procedures take care of storing them in their final form. This part is broken up into three sections, the first describing conventions and procedures common to all COMND calls using the interface. The second section describes each call in detail, indicating what information must be supplied and what is returned. The third section gives an overview of how to implement multiple FDB's using the interface. 2.1 General Rules 2.1.1 Loading the Routines To include the interface as part of a SAIL program, the programmer should use the statement, REQUIRE "SAI:COMND.HDR" SOURCE!FILE; somewhere within his declarations. This will cause all the necessary declarations to be made and will instruct the loader as to where to find the compiled procedures. 2.1.2 Naming Conventions All of the procedures, arrays, variables, etc. in the 12 SAIL-COMND Interface COMND interface package with which the SAIL programmer need concern himself have names beginning with either "cm!" or "cm#". Those beginning with "cm#" have to do specifically with using multiple FDB's, whereas those beginning with "cm!" either have nothing to do with multiple FDB's or are equally applicable to multiple and single FDB's. The vast majority of the "cm!"-type procedures actually perform a call to COMND. These are named according to the particular call they perform. Thus the procedure cm!key performs the CMKEY function call, and the procedure cm!act performs the CMACT function call. The rest of the cm! procedures are used to set up arrays, etc. needed by other procedures. Thus cm!tbuild will construct a table in the necessary format for cm!key and cm!swi from a string array of keywords. In contrast, only one of the "cm#"-type procedures actually executes a call to COMND. That procedure is called cm#call. Most of the rest of the cm# procedures set up their own particular FDB'S and link them into the chain. Thus the cm#key procedure sets up and links in an FDB which when used will cause the CMKEY function to be performed. Once several FDB's have been set up, the cm#call procedure is used to set things moving. 2.1.3 Handling Error and Reparse Conditions 2.1.3.1 Cm!Err and Cm!Reparse Flags When a field is unparsable (the user types in something The Interface 13 that doesn't make sense), the variable cm!err will be set to the TOPS-20 error code indicating the error. Otherwise, cm!err will be zero upon return. If a reparse is required, the variable cm!reparse will be set to true. Otherwise it will be false. Thus by testing these two variables after each call, the program can always determine what it must do next -- go on and parse the next field, reissue all parse requests following the last cm!ini, or reissue all parse requests including the cm!ini. This will be shown in Part III. 2.1.3.2 Cm!Retry - An Alternative Error Recovery Mechanism In Part I it was explained that when a field is unparsable (cm!err would be non-zero when using the interface), the program must start all over right from the prompt. This is not the only alternative, however, when using the SAIL-COMND interface. The procedure cm!retry takes one string parameter and acts as follows: First it prints its argument followed by a carriage return - linefeed, then it retypes the entire command line up to but not including the unparsable field. The program should then reissue the call only for that field. It need not back up all the way to the beginning, and the user need not retype all the things he typed correctly in the command line. This was not mentioned in Part I since it is not a feature of the COMND jsys. It is accomplished by playing with the CSB in such a way as to fool COMND into thinking that everything has been redone as it should be. 14 SAIL-COMND Interface 2.1.3.3 The Built-in Error Handler There is an error handler built into the interface which will trap all errors occurring during execution of the COMND jsys and will act according to the values of two variables which may be set by the program. Errors are divided into two basic types: major errors and minor errors. Major errors include all those errors which, if not trapped, would cause an illegal instruction interrupt and stop the program dead. This category includes such things as command line overflow (the user types in more than can be held in the command line buffer), an invalid CSB or FDB, etc. Minor errors are all other errors which may occur. This would include things such as failing to confirm a command line with a carriage return when required, typing a word that does not match anything in a list of acceptable keywords, etc. The error handler handles minor and major errors in different ways. If a minor error occurs, the error handler will look at the value of the variable cm!minor. If that value is true, then the TOPS-20 error message corresponding to the error is printed. If it is false, nothing is printed. In either case, control is returned to the program with the appropriate TOPS-20 error code in the cm!err variable. If a major error occurs, the error handler inspects the value of the variable cm!major. If that value is true, the appropriate TOPS-20 error message is printed and the program The Interface 15 halts. Otherwise, nothing is printed, the TOPS-20 error code is placed in the variable cm!err, and the variable cm!fatal is set to true. Then control is returned to the program. Until the program explicitly changes them, cm!minor and cm!major will both be true. 2.1.4 The Atom Buffer Many of the procedures in the interface return values other than the user's input as a string. The cm!usr procedure, for instance, returns a TOPS-20 user number, rather than the user name as typed in by the person running the program. When using these procedures, however, it is often required to obtain the input string itself. In this case the cm!getatm procedure is useful. When accepting input from the keyboard, COMND stores the user's input as typed for each field in what is called the "atom buffer" (thus the name cm!getatm). Only one field's worth of input is stored in the atom buffer at a time. Thus, if a program makes a call to COMND to first get an output file name, then a quoted string, the atom buffer will evolve as follows: Before the initial CMINI call, the contents of the atom buffer will be unpredictable. Between CMINI and the CMOFI call (the call to get an output file specification), the atom buffer will be empty. After the CMOFI call, the atom buffer will contain the file specification as typed by the user, even though the cm!ofi procedure returns a SAIL channel number. After the CMQST 16 SAIL-COMND Interface call (the call to get a string delimited by double quotes), the atom buffer will contain the string typed by the user, not including the quotes. The cm!getatm procedure always returns the current contents of the atom buffer in the form of a SAIL string. Remember that the input for a particular field is available only until the next COMND call (any call) is made. 2.1.5 Command Files Often it is desirable for COMND to accept its input from somewhere other than the keyboard. This idea is most familiar to most users in the form of the LOGIN.CMD and COMAND.CMD files that the EXEC can take commands from, and in terms of the EXEC's TAKE command. The cm!take procedure may be used to achieve this effect. After a call to cm!take, all following input to COMND is gotten from the file specified, until the end of that file is reached. At that point, the file is closed, the cm!eof variable is set to true, and the previous source of input is resumed. There are two ways of handling errors that occur while input is coming from a command file. 1. Automatically abort the file and resume taking input from the previous source. In this case, the cm!abort variable is set to true, and a message is printed saying that the file is being aborted if the values of cm!minor and cm!major allow it. 2. Print error messages according to the values of cm!minor and cm!major and continue to take commands from the command file. Both of these options are available with the cm!take The Interface 17 procedure. 2.1.6 Common Parameters Many of the procedures in the interface have almost identical parameters. Those that are common to a very large number of the procedures will be described now. In the descriptions of the particular procedures these parameters will not be rediscussed. help a string which will be printed if the user types a question mark as his response. The COMND jsys also has its own standard help messages, one for each different call. These are listed in the Monitor Calls Reference Manual. The standard help message will follow the supplied help message when both are printed. When using multiple FDB's, the help message for each FDB will be printed on a new line, with the word "or" separating help messages. If this parameter is unspecified, it will default to a null string. def a string which will be used as the default response to this call. If the user types an escape character, and what he has typed so far matches this string, then it will be filled in automatically for him. If this parameter is unspecified, it will default to a null string. When using multiple FDB's, only one default string may be specified, so this parameter is included in the cm#call procedure, and left out of all the other cm# procedures. sup$help a boolean value (true or false). If this parameter is true, then the standard help message will not be typed, whether or not the help parameter is null. If unspecified, sup$help defaults to false. raise$input a boolean value. If this parameter is true, then the user's input will be converted to upper case before it is analyzed. While this may not seem to make any difference in many of the function calls, since they do not return strings (e.g. cm!usr returns a TOPS-20 user number), it may be necessary for a program to look in the atom buffer (via the cm!getatm procedure), in which the 18 SAIL-COMND Interface conversion would be visible. If the parameter is not specified it defaults to a value of false. no$indirect a boolean value. If this parameter is false, then the user will be able to respond to this field with something of the form "@filename", causing the contents of the file whose name is filename to be used to complete the field. If no$indirect is true, this will not be allowed, and a minor error will result if such an attempt is made. If the parameter is not specified it will default to a value of false. wake$always It was mentioned in Part I that when COMND is accepting input from the terminal, it won't start looking at it until an action character is typed. This is not always true, however. If the wake$always parameter is true, then COMND will wake up whenever it senses that the field has been completed. Thus it will wake up on such characters a spaces, commas, etc. One use for this comes when it is required to obtain a password from a user. The command line would be parsed with wake$always true on every call, and then as soon as the field before the password has been completed, the program would turn off terminal echoing so that the password would not show up on the terminal as it was typed. If wake$always were false in this case, COMND may not even begin parsing the password field until after it has been typed in, and then it would probably be too late to turn off echoing. If wake$always is not specified it will default to a value of false. Brchars This is a string of characters on which the current field is to be broken. That is, if any of these characters is encountered while parsing this field, the field will be considered terminated. These characters do not become action characters. If the string is null, the standard break table will be used for the field. Different field types (i.e. COMND functions) have different standard break tables, and only a few of them use break tables at all. Of those few, only about half have user-changeable break tables. The standard break tables will be described along with the descriptions of the cm!-type procedures for the corresponding COMND functions. There is also a convenient table showing the standard break tables for The Interface 19 all COMND functions that use them in Appendix 1. 2.2 Specifics This section looks at all the cm! - type procedures in the interface in detail. The discussions appear in alphabetical order, and each description is introduced by a reproduction of the procedure definition header. Note that those parameters which were discussed in the preceding section will be included in the procedure headers, but otherwise will not be mentioned in the descriptions in this section. 2.2.1 The Cm!Act Procedure string procedure cm!act (string help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false)); The cm!act procedure performs the CMACT (ACT = ACcounT) function call of the COMND jsys. It is used to parse an account name string. The string, up to but not including the first non-alphanumeric character typed is returned as the value of the function. No verification of the account name is done, so a minor error cannot occur in this procedure. There is no standard help message for the CMACT call, so if the help parameter is null, no help message will be printed when the user types a question mark. 2.2.2 The Cm!Cfm Procedure procedure cm!cfm (string help(null); 20 SAIL-COMND Interface boolean sup$help(false)); The cm!cfm procedure performs the CMCFM (CFM = ConFirM) function call of the COMND jsys. The only valid user input for this call is a carriage return. It is generally good practice to make this the last call of every command line. This gives the user a chance to correct mistakes in the command line before any action is taken. The standard help message for the CMCFM function call is "CONFIRM WITH CARRIAGE RETURN". Note that several of the common parameters are not included in this procedure, simply because they do not make sense here. 2.2.3 The Cm!Cma Procedure procedure cm!cma (string help(null); boolean sup$help(false)); The cm!cma procedure performs the CMCMA (CMA = CoMmA) function call of the COMND jsys. The only valid user input for this call is a comma. This procedure would be used, for instance, when a list of input file names is needed. The program would keep calling first the cm!ifi procedure (see below), then the cm!cma procedure until cm!cma fails, at which point the user did not type a comma, so the program should try other possibilities, such as cm!cfm (above). The standard help message for the CMCMA function call is "COMMA". Note that, as with the cm!cfm procedure, several of the common parameters are not included in this procedure, because they do not make sense here. The Interface 21 2.2.4 The Cm!Dev Procedure integer procedure cm!dev (string help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false); string brchars(null)); The cm!dev procedure performs the CMDEV (DEV = DEVice) function call of the COMND jsys. It is used for parsing a device name. This could be a physical device name or a logical name. The procedure returns the device designator corresponding to the device name input. The standard help message for the CMDEV call is "DEVICE NAME". The standard break table for CMDEV is as follows: ASCII Codes Description 0 - 37 All Control Characters 40 - 54 Space Through Comma 56 - 57 Dot and Slash 72 - 76 Colon Through Pound Sign (#) 100 Atsign (@) 133 - 136 Open Bracket Through Up-Arrow 140 Apostrophe 173 - 177 Close Bracket Through Tilde 2.2.5 The Cm!Dir Procedure integer procedure cm!dir (string help(null),def(null); boolean sup$help(false), allow$wild(false), raise$input(false), no$indirect(false), wake$always(false), parse$only(false)); The cm!dir procedure performs the CMDIR (DIR = DIRectory) function call of the COMND jsys. It is used for parsing a directory name (with angle brackets - <>). The procedure returns the 36-bit directory number corresponding to the directory named by the user's input. If the allow$wild 22 SAIL-COMND Interface parameter is true, wildcard characters ("*" and "%") will be allowed as part of the directory name. Otherwise they will cause a minor error. If parse$only is true, then the field will be parsed, but if the input does not match an existing directory no minor error will occur. The directory number can be translated into a directory name string using SAIL's DIRST built-in function. The standard help message for the CMDIR function call is "DIRECTORY NAME". 2.2.6 The Cm!Fil Procedure integer procedure cm!fil (string help(null),def(null); integer flag$gen('440004000000); string device(null), directory(null), name(null), extension(null), protection(null), account(null); integer jfn(0); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false)); The cm!fil procedure performs the CMFIL (FIL = FILe) function call of the COMND jsys. It is used to parse an arbitrary file specification (i.e. where neither cm!ifi nor cm!ofi is quite right). This call uses the GTJFN jsys to process the file specification, and so there many new parameters for this procedure which are used to fill in the GTJFN Argument Block. To find the details of the contents of this block, see the Monitor Calls Reference Manual. The new parameters are as follows: flag$gen The integer passed for this parmeter will be placed into word 0 (.GJGEN) of the GTJFN argument block. It contains various flags in the left half, and a default generation The Interface 23 number in the right half. See the Monitor Calls Reference Manual for details on the contents of this word. If the flag$gen parameter is not specified, it will default to octal 440004000000, and cm!fil will behave like cm!ofi. device A pointer to the string supplied for this parameter will be placed in word 2 (.GJDEV) of the GTJFN Argument Block. The string will become the default for the device field of thef file specification. If no string is specified, the default device will be the currently connected structure. directory A pointer to the string supplied for this parameter will be placed in word 3 (.GJDIR) of the GTJFN Argument Block. The string will become the default for the directory field of the file specification. If no string is passed, the default directory will be the currently connected directory. name A pointer to the string supplied for this parameter will be placed in word 4 (.GJNAM) of the GTJFN Argument Block. The string will become the default for the name field of the file specification. If no string is passed, there will be no default name field. extension A pointer to the string supplied for this parameter will be placed in word 5 (.GJEXT) of the GTJFN Argument Block. The string will become the default for the extension field of the file specification. If no string is passed the default extension will be null. protection A pointer to the string supplied for this parameter will be stored in word 6 (.GJPRO) of the GTJFN Argument Block. The string will become the default for the protection field of the file specification. If no string is passed the default protection will be whatever is specified in the directory, or the protection of the next lower generation. account A pointer to the string passed for this parameter will be placed in word 7 (.GJACT) of the GTJFN Argument Block. The string will become the default account for the file specification. If no string is specified the default account will be the LOGIN account set for the user. jfn The integer passed for this parameter will be placed in word 10 (.GJJFN) of the GTJFN 24 SAIL-COMND Interface Argument Block. The system will attempt to assign this number as the jfn for the file specification obtained in the call. If you specify this parameter, make sure you set bits 9 and 10 (GJ%JFN) in flag$gen appropriately. See the Monitor Calls Reference Manual to find out the possible bit patterns. If this parameter is not specified it will be given the value zero. Note that any fields present in the def parameter will take precedence over any defaults passed in the parameters listed above. The cm!fil procedure will return a SAIL channel number for the file that is obtained. The channel will not be open. Use the OPENF built-in SAIL function to open the file. The standard help message for CMFIL is "OUTPUT FILESPEC" if bits 0 and 2 (GJ%FOU and GJ%OLD) are both on in flag$gen. Otherwise it is "INPUT FILESPEC". 2.2.7 The Cm!Fld Procedure string procedure cm!fld (string help(null),def(null); boolean raise$input(false), no$indirect(false), wake$always(false); string brchars(null)); The cm!fld procedure performs the CMFLD (FLD = FieLD) function call of the COMND jsys. This procedure is used when none of the other procedures seem to fit the required application. The user's input, as delimited by the first non-alphanumeric character, is returned as the value of the function. The delimiting character is not part of the string returned. There is no standard help message for the CMFLD function call. The Interface 25 The standard break table for CMFLD is as follows: ASCII Codes Description 0 - 37 All Control Characters 40 - 54 Space Through Comma 56 - 57 Dot and Slash 72 - 77 Colon Through Question Mark 100 Atsign (@) 133 - 140 Open Bracket Through Accent Grave 173 - 177 Close Bracket Through Tilde 2.2.8 The Cm!Flt Procedure real procedure cm!flt (string help(null),def(null); boolean sup$help(false), no$indirect(false), wake$always(false)); The cm!flt procedure performs the CMFLT (FLT = FLoaT) function call of the COMND jsys. This procedure is used to parse a real number. The number is returned as the value of the function. There is no raise$input parameter, since alphabetic characters are invalid for this field anyway. The standard help message for the CMFLT function call is "NUMBER". 2.2.9 The Cm!Getatm Procedure string procedure cm!getatm; The cm!getatm returns the current contents of the atom buffer (see discussion in Part II, Section 1 above). The procedure does not call the COMND jsys or alter the state of any related storage areas (in particular the atom buffer is unchanged). 2.2.10 The Cm!Ifi Procedure integer procedure cm!ifi (string help(null),def(null); boolean sup$help(false), raise$input(false), 26 SAIL-COMND Interface no$indirect(false), wake$always(false)); The cm!ifi procedure performs the CMIFI (IFI = Input FIle) function call of the COMND jsys. It is used for parsing the name of a file to be used for input (i.e., the file must exist). The procedure returns a SAIL channel number as its value (so the calling program need not use SAIL's SETCHAN built-in function). The file is not opened by cm!ifi. To open the file for reading, the calling program would use SAIL's OPENF built-in procedure using the channel number returned by cm!ifi. The standard help string for the CMIFI function call is "INPUT FILESPEC". 2.2.11 The Cm!Ini Procedure boolean procedure cm!ini (string prompt; boolean newcomm(true)); The cm!ini procedure performs the CMINI (INI = INItialize) function of the COMND jsys. It is always the first call that should be made when starting to parse a new command line. When called it will initialize the CSB and the various buffers used to hold the user's input, and will issue the command line prompt. This prompt is supplied via the prompt parameter to the procedure. The end of this prompt marks the farthest back that the user will be allowed to delete when using COMND. The cm!ini procedure causes no input to be read from the keyboard, unlike all the rest of the COMND function calls. And of course, there is no standard help message. The newcomm parameter determines whether or not the The Interface 27 ctrl/h feature will be available in this command line (see section 1.2.4, page 8). If this call to cm!ini is being made because a parsing error was just encountered in a command line, then it would probably be desirable to activate the ctrl/h feature. In this case, specify a value of false for the newcomm parameter. If this is the beginning of a new command line, or if for some other reason the ctrl/h feature should not be activated, specify a value of true for the newcomm parameter. If the ctrl/h feature is activated and the user actually does use the feature to retype a portion of the command line, then the cm!ini will return a value of false. Otherwise it will return a value of true. Note that this value, like any value returned by a SAIL procedure, may be ignored, and the newcomm parameter is an optional parameter defaulting to true, so the ctrl/h feature is upward compatible with previous versions of the interface which did not provide for the feature. An example using the ctrl/h feature is included in Part III. 2.2.12 The Cm!Key Procedure integer procedure cm!key (integer array table; string help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false); string brchars(null)); 28 SAIL-COMND Interface The cm!key procedure performs the CMKEY (KEY = KEYword) function call of the COMND jsys. It is used when the user must type one out of a list of possible keywords. The keywords are originally stored in a string array, one keyword per array element. The array is then submitted to the cm!tbuild procedure (below) which converts it into a TBLUK lookup table (see the description of the TBLUK jsys in the Monitor Calls Reference Manual for details on the format of this table), which is stored in an integer array. This array is then supplied to cm!key as the table parameter. If the user's input matches one of the valid keywords, then the index of that keyword in the original string array is returned as the value of the function. Otherwise a minor error will occur, and a zero will be returned. Note to wizards: If you are planning to build your own TBLUK lookup tables, take note! The right half of the table entry for each keyword should contain the integer that you want returned by COMND if that keyword is selected. The cm!tbuild procedure stores the original string array indices in these half-words. The standard help message for the CMKEY function call is "ONE OF THE FOLLOWING", followed by an alphabetical list of all the keywords which could still possibly match what the user has typed in so far. If there are no possible matches, the message "KEYWORD (NO DEFINED KEYWORDS MATCH THIS INPUT)" is typed. The standard break table for CMKEY is: ASCII Codes Description 0 - 37 All Control Characters 40 - 54 Space Through Comma 56 - 57 Dot and Slash The Interface 29 72 - 77 Colon Through Question Mark 100 Atsign (@) 133 - 140 Open Bracket Through Accent Grave 173 - 177 Close Bracket Through Tilde 2.2.13 The Cm!Nod Procedure string procedure cm!nod (string help(null),def(null); boolean sup$help(false), no$indirect(false), wake$always(false)); The cm!nod procedure performs the CMNOD (NOD = NODe) function call of the COMND jsys. This procedure is used to parse a network node name, which consists of from 1 to 6 characters followed by two colons. The node name (without the colons) is returned as the value of the procedure. Lowercase characters are always converted to upper case (hence no raise$input parameter). Note that a successful return does not guarantee the existence of the node - only that the field was typed in the correct syntax. The standard help message for CMNOD is "NODE NAME". 2.2.14 The Cm!Noi Procedure procedure cm!noi (string noise); The cm!noi procedure performs the CMNOI (NOI = NOIse word) function call of the COMND jsys. It is used to display a string which will guide the user by telling him what should be input for the next field, or by qualifying what he typed in the last field. If the user terminates a field with an ESCAPE character, and the next procedure executed is cm!noi, then the noise string supplied as a parameter will be output surrounded by parentheses (the parentheses should not be 30 SAIL-COMND Interface included as part of the parameter passed to cm!noi). If he terminates the field with a non-action character, then he has the option of either typing the guide word himself, or ignoring it altogether. It will not be typed for him. The only minor error that can occur here will result if the user attempts to type in the noise word by himself, but gets it wrong. There is no standard help message (or nonstandard, for that matter) for the CMNOI function call. 2.2.15 The Cm!Num Procedure integer procedure cm!num (string help(null),def(null); boolean sup$help(false); integer radix(10); boolean no$indirect(false), wake$always(false)); The cm!num procedure performs the CMNUM (NUM = NUMber) function call of the COMND jsys. It is used for parsing an integer number. The radix parameter specifies in what base the number is to be interpreted, and must be between 2 and 10 inclusive. The number typed is returned as the value of the procedure. There is no raise$input parameter, since, as in cm!flt, no alphabetic characters are valid anyway. The standard help message is "DECIMAL NUMBER" if radix is 10, "OCTAL NUMBER" if radix is 8, and "A NUMBER IN BASE nn" if radix (nn) is anything else. The radix parameter defaults to 10 if it is left unspecified. 2.2.16 The Cm!Nux Procedure integer procedure cm!nux (string help(null),def(null); boolean sup$help(false); integer radix(10); boolean no$indirect(false), The Interface 31 wake$always(false)); The cm!nux procedure performs the CMNUX (NUX = NUmber, sort of) function call of the COMND jsys. This procedure is used to parse an integer number field, as in cm!num, the only difference being that cm!nux will terminate on the first non-numeric character, without giving a minor error, even if that character is not one of the valid terminators for cm!num. The number is returned as the value of the procedure. The radix parameter is as in cm!num. The standard help message for CMNUX is the same as for CMNUM. 2.2.17 The Cm!Ofi Procedure integer procedure cm!ofi (string help(null),def(null); boolean sup$help(false), rase$input(false), no$indirect(false), wake$always(false)); The cm!ofi procedure performs the CMOFI (OFI = Output FIle) function call of the COMND jsys. It is almost identical to cm!ifi (above), but the user's input is this time expected to specify an output file. Thus, it is not necessary that the file exist already, and if it does exist, then the default generation number will be one higher than the highest existing generation number for the file. Like cm!ifi, cm!ofi returns a SAIL channel number, not just a JFN. To open the file for output, use SAIL's OPENF built-in procedure. The standard help message for the CMOFI function call is "OUTPUT FILESPEC". 2.2.18 The Cm!Qst Procedure string procedure cm!qst 32 SAIL-COMND Interface (string help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false)); The cm!qst procedure performs the CMQST (QST = Quoted STring) function call of the COMND jsys. It is used to parse a string of text surrounded by double quotes. The string is returned without the quotes. This function is useful for obtaining strings which may include action characters, since these characters lose their significance after the opening quote in cm!qst. If a quote is desired in the string, the user must type two consecutive quotes. A carriage return is an illegal character inside the string. The standard help message for CMQST is "QUOTED STRING". 2.2.19 The Cm!Retry Procedure procedure cm!retry (string errmsg); The cm!retry may be used as an alternative to reparsing the entire command line when an invalid response is given by the user to a field. Instead, upon detecting a non-zero cm!err, the program calls cm!retry with an appropriate error message as a parameter, and then it reissues the COMND call just for the field in which the error occurred. When cm!retry is called, it first prints its argument, then it patches up the CSB to make COMND think everything up to that field has already been reparsed. This procedure should be used with caution, since it plays with the CSB in such a way that, if the COMND jsys internals were changed in a later monitor release, cm!retry could fall flat on its face. The Interface 33 2.2.20 The Cm!Size Procedure integer procedure cm!size (string array strarr); This procedure computes and returns the number of storage words necessary to build a TBLUK lookup table containing the strings in strarr (see cm!tbuild below). This number could be used as a dimensioning bound on an integer array which will be used to hold the table. The lower bound on the integer array should be zero. 2.2.21 The Cm!Swi Procedure integer procedure cm!swi (integer array table; string help(null),def(null); bollean sup$help(false), raise$input(false), no$indirect(false), wake$always(false); string brchars(null); The cm!swi procedure performs the CMSWI (SWI = SWItch) function call of the COMND jsys. It operates almost identically with the cm!key procedure. The main difference is that a switch should start with a slash ("/") when typed in by the user. A minor error occurs here if that is not the case. Slashes should not, however, be included in the strings making up the TBLUK lookup table. Their presence is assumed. As in the cm!key procedure, the table parameter may be prepared by using the cm!tbuild procedure (below). Wizards should read the "Note to Wizards" in the description of the cm!key procedure above. Often a switch will be terminated by a colon, usually indicating that some value is to follow. When this occurs, the variable cm!colon will be set to true by the cm!swi procedure. Colons may be included 34 SAIL-COMND Interface in the strings making up the TBLUK lookup table, in which case they will be included whenever the user uses recognition to finish typing the switch name. The standard help message is "ONE OF THE FOLLOWING", followed by an alphabetical list of those switches which still may be matched by what has been typed so far. If no switch can possibly be matched, the message "KEYWORD (NO DEFINED KEYWORDS MATCH THIS INPUT)" is typed. The standard break table for CMSWI is as follows: ASCII Codes Description 0 - 37 All Control Characters 40 - 54 Space Through Comma 56 - 57 Dot and Slash 72 - 77 Colon Through Question Mark 100 Atsign (@) 133 - 140 Open Bracket Through Accent Grave 173 - 177 Close Bracket Through Tilde 2.2.22 The Cm!Tad Procedure integer procedure cm!tad (string help(null),def(null); boolean sup$help(false), date(true),time(true), no$convert(false), raise$input(false), no$indirect(false), wake$always(false)); The cm!tad procedure performs the CMTAD (TAD = Time And Date) function call of the COMND jsys. This procedure is used to parse a time and/or a date. If the date parameter is true, a date will be parsed. If time is true a time will be parsed. Both default to true. If no$convert is false (the default) then the date/time is returned in internal format (see the Monitor Calls Reference Manual). Otherwise a zero is returned, and the date and time information are The Interface 35 stored in integer array cm!datime (dimensioned [2:4] so as to agree with accumulator assignments in the IDTNC monitor call return) as follows: Element Contents cm!datime[2] Year in Left Half Month (0=Jan) in Right Half cm!datime[3] Day of Month (0=1st Day) in Left Half Day of Week (0=Mon) in Right Half cm!datime[4] Flag Bits in Left Half Seconds Since Midnight in Right Half The flag bits returned in the left half of cm!datime[4] are as follows: Bit Number Meaning (if bit is on) 0 A Time Zone was input 1 Daylight Savings Time was input 2 A Time Zone was input 3 A Julian Day Format was input 12-17 Time Zone, if one was specified, or the Local Time Zone The standard help message for CMTAD is "DATE" if date was true, "TIME" if time was true, and "DATE AND TIME" if both were true. 2.2.23 The Cm!Take Procedure procedure cm!take (integer ichan, ochan(nulio); boolean errpop(true)); The cm!take procedure facilitates the redirection of input and output during operation of COMND to other files. It gets its name from its functional similarity to the EXEC's TAKE command. The ichan parameter holds a channel number associated with the file to be used for input. This file should not be open (i.e., it should be the result of a call to one of GTJFN, GTJFNL, cm!ifi, cm!ofi, cm!fil, or some other procedure that returns a channel number without opening the file on that channel). The ochan parameter 36 SAIL-COMND Interface holds a channel number associated with the file to be used for output. By output we mean everything the user normally sees at his keyboard other than normal input echoing (i.e. noise words, editing characters, help messages, etc.). This file also should not be open. The cm!take procedure will push the old JFNs on a stack and make those passed for ichan and ochan the ones to be used in COMND calls from that point on. When the file associated with ichan runs out, the old JFNs are automatically popped back into use, and the cm!eof variable is set to true. The errpop parameter controls what action is taken when an error (other than end-of-file) occurs while using the new JFNs. If errpop is true, then upon encountering such an error, the old JFNs are immediately popped back and if cm!minor and cm!major allow it, an error message is printed. Also the cm!abort variable is set to true. If errpop is false, then the JFNs are popped only for end-of-file, and error messages will be printed as usual according to the values of cm!minor and cm!major. 2.2.24 The Cm!Tbuild Procedure integer procedure cm!tbuild (string array keys; reference integer array table); The cm!tbuild procedure converts a string array of keywords into a TBLUK lookup table for use by the cm!key and cm!swi procedures (see the description of the TBLUK jsys in the Monitor Calls Reference Manual for details on the internals of a TBLUK lookup table). The keywords are passed by way of The Interface 37 the keys array, and the table is stored in the table array. If enough room was available in table to store the entire lookup table, a 0 is returned by cm!tbuild. Otherwise, a -1 is returned, and chances are the lookup table is in an unacceptable format for cm!key and cm!swi. One convenient way to insure that enough room will be available is by using the cm!size procedure (above). The keys parameter is a string array of keywords which are to be inserted into the table, and need not be alphabetized. cm!tbuild will not insert duplicate entries twice, and if two elements of keys are identical it will place the index of the last duplicate entry found in the cm!err variable. Each string in keys may be prefixed by either or both of two punctuation characters. If a "%" character appears within the first two characters of a string the CM%INV (INV = INVisible) bit will be turned on for the corresponding entry in the lookup table. The effect of this is that the keyword will not appear in the standard help message of the CMKEY or CMSWI function calls. In this way it is essentially "invisible" to the user. If a "#" character appears within the first two characters of a string in the keys array, the CM%NOR (NOR = igNORe) bit will be turned on in the corresponding lookup table entry. Its effect is such that the corresponding keyword will be "invisible" as above, but it will also not be recognized, even if an exact match is typed by the user. Thus the keyword is effectively "ignored" by cm!key and cm!swi. This is useful when you wish to rule out an abbreviation. For instance, if you wish the user to be required to type at 38 SAIL-COMND Interface least "MINIM" as an abbreviation for "MINIMAL", you could include the string "#MINI" as one of the strings in the keys array, and the desired result would be achieved. Note that the cm!tbuild procedure does not include a facility for setting the CM%ABR (ABR = ABbReviation) bit in a lookup table entry. For information on what this bit does, see the description of the CMKEY function call of the COMND jsys in the Monitor Calls Reference Guide. It is possible for wizards to set this bit themselves, but they should read the description of the TBLUK jsys in the Monitor Calls Reference Guide, as well as the "Note to Wizards" in the description of the cm!key procedure above. 2.2.25 The Cm!Tok Procedure boolean procedure cm!tok (string token, help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false)); The cm!tok procedure performs the CMTOK (TOK = TOKen) function call of the COMND jsys. This procedure is used to test whether or not the string passed for the token parameter matches the characters that appear next in the input buffer. The procedure returns true if the string matches, false otherwise. There is no standard help message for CMTOK. 2.2.26 The Cm!Txt Procedure string procedure cm!txt (string help(null),def(null); boolean sup$help(false), raise$input(false), The Interface 39 no$indirect(false), wake$always(false); string brchars(null)); The cm!txt procedure performs the CMTXT (TXT = TeXT) function call of the COMND jsys. It returns all text typed by the user up to but not including the next carriage return. The standard help message for the CMTXT function call is "TEXT STRING". The standard break table for CMTXT is as follows: ASCII Codes Description 12 Linefeed 15 Carriage Return 2.2.27 The Cm!Uqs Procedure string procedure cm!uqs (string brchars; string help(null),def(null); boolean raise$input(false), no$indirect(false), wake$always(false)); The cm!uqs procedure performs the CMUQS (UQS = UnQuoted String) function call of the COMND jsys. This procedure is used for parsing a string field with arbitrary break characters. The procedure will return all characters typed up to, but not including the first break character typed. Note that all action characters lose their special meaning unless they are included in the brchars string. There is no standard help message for CMUQS. 2.2.28 The Cm!Usr Procedure integer procedure cm!usr (string help(null),def(null); boolean sup$help(false), raise$input(false), no$indirect(false), wake$always(false), 40 SAIL-COMND Interface parse$only(false)); The cm!usr procedure performs the CMUSR (USR = USeR) function call of the COMND jsys. It is almost identical to the cm!dir procedure, except that user names are not surrounded by angle brackets ("<>") as are directory names. Also, there is no allow$wild parameter, since wildcards do not make sense with user names. A user number is returned by the procedure, which may be tranlated into a user name string via SAIL's DIRST built-in procedure. The standard help message for the CMUSR function call is "USER NAME". 2.3 Multiple FDBs It was mentioned in Part I of this document that it is possible to give COMND several alternatives from which to choose in a single call. This section of the document describes the implementation and use of this feature in the SAIL-COMND interface package. Room is set aside for building a chain of up to ten FDB's to be used in a call to COMND. These FDB's are set up by using procedures which parallel those just described in Section 2. Each of the cm! procedures which actually calls the COMND jsys into action (all but cm!getatm, cm!retry, cm!size, cm!take and cm!tbuild) has a companion procedure whose name starts with "cm#" instead of "cm!" (thus cm!key becomes cm#key, etc.). These cm# procedures are called in exactly the same way as the corresponding cm! procedures, except that all def, raise$input, no$indirect and wake$always parameters are left off. Each procedure returns The Interface 41 an integer: 0 if there was room in the multiple FDB block to set up the new FDB, and -1 otherwise (10 FDB's max). The FDB's are linked together in the order in which the procedures are called. Thus if the program calls first cm#key, then cm#usr, then cm#tad, COMND will try first to match a keyword, then a user name, then a time and date. COMND will stop as soon as one of the FDB's caused a success. If none of them succeeds, cm!err will be set to the error code appropriate to the last FDB tried. Before starting to set up the FDB's, however, the program should issue a call to the cm#reset procedure (no arguments, no value returned), which initializes the multiple FDB block. After all the FDB's have been set up, the program issues a call to the cm#call procedure, whose procedure definition header is as follows: integer procedure cm#call (string def(null); boolean raise$input(false), no$indirect(false), wake$always(false)); Here the parameters are the same as they were in the cm! procedures, but they apply to all the FDB's taken as a whole. The cm#call procedure returns an integer which indicates which FDB was successful, according to the order in which the FDB's were set up (1 is the first). The result of the parsing will always be a string, an integer, or a real number. Upon completion of the cm#call procedure, this result will be found in one of three variables corresponding 42 SAIL-COMND Interface to these types: cm#str (for strings), cm#int (for integers), or cm#real (for real numbers). It is up to the calling program to determine (via the integer returned by cm#call) where to look for the response. Thus if a CMKEY function call succeeds the program should look in the cm#int variable. If a CMQST function call succeeds, the program should look in the cm#str variable. Examples 43 3. EXAMPLES 3.1 Example 1 - Nothing Fancy This example does nothing fancy, but then, many real applications are that way. The example is a routine that could be used to perform the parsing for the TERMINAL command of the EXEC. The routine would be called by the main parsing routine when the keyword "terminal" is parsed. This routine should return upon a reparse or error condition, or upon a completed command. Note that the code for actually performing the various tasks is not included here, but it is indicated by the various block names where such code should go. 3.1.1 SAIL Code ******************** Start of Example 1 ******************** ! Set up the keyword and noise word tables to be used; Preload!With "flag","formfeed","immediate","indicate","lowercase", "raise","tabs","page","halfduplex","line-halfduplex", "fullduplex","length","speed","width","help","no","type", "33","35","37","bantam","concept-100","datamedia-1520", "execuport","glass-tty","la30","la36","perkin-elmer-1100", "system-default","terminet","ti","ti733","vt05","vt50", "vt52"; String Array ModeKeys[1:35]; ! Keywords to select mode; Preload!With "0","50","75","110","134","150","200","300","600","1200", "1800","2400","4800","9600"; String Array SpeedKeys[1:14]; ! Allowable Terminal Speeds; Preload!With "flag","formfeed","immediate","indicate","lowercase", "raise","tabs","page"; String Array NoKeys[1:8]; ! Allowable Keywords after ! "no" keyword; Preload!With "33","35","37","bantam","concept-100","datamedia-1520", 44 SAIL-COMND Interface "execuport","glass-tty","la30","la36","perkin-elmer-1100", "system-default","terminet","ti","ti733","vt05","vt50", "vt52"; String Array TypeKeys[18:35]; ! Possible keywords after; ! 'type' keyword (indices ; ! chosen to match ModeKeys); Preload!With "upper case output","exists on terminal","echo mode", "formfeed","exists on terminal","terminal input", "exist on terminal","mode","mode for terminal", "mode for terminal","mode for terminal","of page is", "of input","of line is"; String Array Noises[1:14]; ! Noise words for ModeKeys ! and NoKeys; Procedure Ter!Comm; Begin "Parse a 'Terminal' command line" ! Miscellaneous declarations; Integer ModeNo, ISpeed, OSpeed, PLen, PWid; Integer TOption, TType; Boolean ModeOn; ! False if a 'no ...' command; Boolean NoLen; ! True if no len was specified; ! on a 'terminal page' command; ! Declarations for keyword tables; Integer Array ModeTab[0:cm!size(ModeKeys)]; Integer Array SpeedTab[0:cm!size(SpeedKeys)]; Integer Array NoTab[0:cm!size(NoKeys)]; Integer Array TypeTab[0:cm!size(TypeKeys)]; ! Build the TBLUK Lookup Tables; cm!tbuild(ModeKeys,ModeTab); cm!tbuild(SpeedKeys,SpeedTab); cm!tbuild(NoKeys,NoTab); cm!tbuild(TypeKeys,TypeTab); cm!noi("mode is"); ! Noise word for 'terminal' command; If cm!err or cm!reparse then return; ModeOn := true; ! Until we get a 'no' command; ModeNo := cm!key(ModeTab); ! Get the desired mode; If cm!err or cm!reparse then return; ! First 14 modes require noise word next; If Modeno leq 14 then Begin "Noise" cm!noi(Noises[ModeNo]); If cm!err or cm!reparse then return; End "Noise"; ! Now treat any that require more fields; Case ModeNo of Begin "Extra Parsing" Examples 45 [8] Begin "Page Mode" ! Possible next field for page length; ! Turn off minor error messages in case ! length is not given; cm!minor := false; PLen := cm!num ("Carriage return or page length",null,true); ! Now turn minor error messages back on; cm!minor := true; If cm!reparse then return; ! Signal whether or not page was specified -; ! if it wasn't we'll try a cm!cfm later on; NoLen := cm!err; End "Page Mode"; [12]Begin "Length Mode" ! We get a page length next; PLen := cm!num ("Length of page in decimal",null,true); If cm!err or cm!reparse then return; End "Length Mode"; [13]Begin "Speed Mode" ! We get an input speed first; ISpeed := cm!key(SpeedTab); If cm!err or cm!reparse then return; ! Now a noise word; cm!noi("and output"); If cm!err or cm!reparse then return; ! Now get an output speed; ! Default is same as input speed; OSpeed := cm!key (SpeedTab,null,SpeedKeys[ISpeed]); If cm!err or cm!reparse then return; End "Speed Mode"; [14]Begin "Width Mode" ! We get a page width; PWid := cm!num ("Terminal line width in decimal",null,true); If cm!err or cm!reparse then return; End "Width Mode"; [16]Begin "No ... Mode" ! Find out what he doesn't want; ModeNo := cm!key(NoTab); If cm!err or cm!reparse then return; ! Put out a noise word; cm!noi(Noises[ModeNo]); If cm!err or cm!reparse then return; 46 SAIL-COMND Interface ! Reset flag to indicate 'no'; ModeOn := false; End "No ... Mode"; [17]Begin "Type Mode"; ! We get either a type number or name; ! Use multiple FDBs to parse this field; ! Default is 'system-default'; cm#reset; ! Clear the multiple FDBs; cm#key(TypeTab); cm#num("Terminal type",true); TOption := cm#call("system-default"); If cm!err or cm!reparse then return; ! If user typed one of the strings in; ! TypeKeys, then pretend that the user; ! never even typed the word 'type'; If TOption = 1 then ModeNo := cm#int ! Otherwise, set the TType variable; Else TType := cm#int; End "Type Mode"; Else ! Do nothing more for other modes; End "Extra Parsing"; ! Now the command line is almost complete - only; ! thing left to do is confirm; cm!cfm; If cm!err or cm!reparse then return; ! We have an acceptable command line - now implement it; Case ModeNo of Begin "Execute the command" [1] Begin "flag" ! Code to set flag mode goes here; End "flag"; [2] Begin "formfeed" ! Code to set formfeed mode goes here; End "formfeed"; . . . [35]Begin "vt52" ! Code to set terminal vt52 goes here; End "vt52" End "Execute the command"; Examples 47 ! We are all finished - now return successfully; Return; End "Parse a 'Terminal' command line"; ********************* End of Example 1 ********************* 3.1.2 Remarks 1. The keyword tables are built every time the Ter!Comm procedure is called. This is quite wasteful, and in most applications the keyword tables will all be built in an outside block only once, and will never need to be rebuilt. There are two prevalent ways of doing this: - The keyword table array may be declared with fixed bounds in the programs outer block. In this case, the cm!size procedure will not be used as it was in the example. The advantage of this method is that the array is static and can be declared in the same block as the string array containing the keywords. The disadvantage is that the fixed bounds may have to be altered if a new keyword needs to be added to the table. - The string arrays for the tables may be declared in the program's outer block, and the table arrays may be declared in an inner block, using the cm!size procedure to calculate upper array bounds. The advantage is that it is very easy to add a new keyword to the table. The disadvantages are the extra time required for computing the bound and allocating the array, and the extra level of nesting that will probably result. 2. All the parsing was done prior to the execution of the command. An alternative method would be to execute each command as soon as it is determined (e.g. in the above example, we could have included a cm!cfm and the code for setting page mode within the "Page Mode" block, etc.). The disadvantage of this is that it makes the parsing process more difficult to follow. Sometimes, however, this method is unavoidable where the results of some action taken on one field can change some parsing parameters of a following field. 3. In this example reparse and error conditions were treated identically. This is because the cm!ini and the first field of the line were both taken 48 SAIL-COMND Interface care of by the calling routine, so the action for either condition would have to start there. The calling routine can easily check the values of cm!err and cm!reparse immediately following the call to Ter!Comm. 4. The Case statement almost always accompanies the use of cm!key or cm#key, and often will go along with any multiple FDB uses. 5. Although in this example all the keywords were in preloaded arrays whose contents were never changed, this need not be the case. Keyword arrays may change in any way desired, and tables rebuilt from them. Do not forget to rebuild the table arrays, however; the changes will not show up in the COMND calls that use the tables until they are. 6. It is easy to finish reading part II with the impression that the routines in the interface are very complicated and difficult to use, since they all seem to have so many parameters. This is a false impression, however, as this example and those that follow demonstrate. The reason is that almost all the parameters used in the interface routines are optional parameters that are rarely specified. 7. A complete program that uses the Ter!Comm procedure and merely reports what it finds exists as sai:tercom.sai and sai:tercom.exe. 3.2 Example 2 - The Ctrl/H Feature And Switches In this example we see how to go about using the ctrl/h feature (see section 1.2.4, page 8) of COMND in SAIL programs. Also, a technique is given for parsing a list of similar objects separated by commas. The command line is one that might be used for a crude mail sending program. There are two commands: exit and send. The exit command causes the program to halt. The send command takes as its second field an input file name where a message is stored, and then a list of switches. Examples 49 Possible switches are /to, /cc, and /subject. The /to and /cc switches both take as arguments a list of userids separated by commas. The /subject switch takes a quoted string as an argument. The switches may be intermingled as desired, and any switch may be used more than once. If the /subject switch is used more than once, the old subject string is discarded. If the /to or /cc switch is used more than once, the new list is tacked onto the old list. 3.2.1 SAIL Code ******************** Start of Example 2 ******************** Begin "Compost" require "sai:comnd.hdr" source!file; require "{}{}" delimiters; define ! = {comment}; ! "Compost" stands for "Computer Post Office"; ! Declare keyword arrays; Preload!With "send", "exit"; String Array Commands[1:2]; Preload!With "to:","cc:","subject:"; String Array Switches[1:3]; ! Now descend into another block so we can dynamically; ! allocate the table arrays; Begin "Main Level" ! Declare the table arrays; Integer Array Comm!Tab[0:cm!size(commands)]; Integer Array Swit!Tab[0:cm!size(switches)]; ! Declare a record class to hold linked lists of; ! message recipients, along with list head pointers; Record!Class Recips(Integer Userid; Record!Pointer(Recips) Next); Record!Pointer(Recips) To!List, Cc!List; ! Integer to hold channel number for message file; Integer Channel; ! String to hold subject of message; String Subject; ! Boolean determines whether or not ctrl/h feature is ! activated on each call to cm!ini (activated if false); 50 SAIL-COMND Interface Boolean Ctrl!H!Off; ! Other miscellaneous variables; Integer Comm!No, Swit!No, Option, Userid; Record!Pointer(Recips) Temp; ! Build the lookup tables; cm!tbuild(Commands,Comm!Tab); cm!tbuild(Switches,Swit!Tab); ! Initialize Ctrl!H!Off to deactivate ctrl/h feature; Ctrl!H!Off := true; ! A useful definition; Define Check = {If cm!err then continue "outer loop"; If cm!reparse then continue "inner loop"}; ! Now go parse the command line; While true do Begin "outer loop" ! Issue the prompt and set up the command line; cm!ini("Compost> ", Ctrl!H!Off); ! Set Ctrl!H!Off so that ctrl/h feature will be; ! activated if we come here again due to an error.; ! If we return from a successful command line, the; ! variable should be reset before we get here; Ctrl!H!Off := false; While true do Begin "inner loop" ! Release any currently unopened JFN. It is; ! the result of an error after the JFN; ! has already been obtained; Start!code "release" hrroi 1,-1; Rljfn; Haltf; End "release"; ! Clear the recipients lists; To!List := Cc!List := Null!Record; ! Get a command; Comm!No := cm!key(Comm!Tab); Check; ! Checks for error and reparse; ! Halt on 'exit' command; If Comm!No = 2 then Begin "exit" cm!cfm; Check; Examples 51 While true do Start!code Haltf End; End "exit"; ! Otherwise, 'send' command - guide word next; cm!noi("message file"); Check; ! Now get an input file specification; Channel := cm!ifi; Check; ! Now parse any switches; ! May also get a carriage return, so use ; ! multiple FDB's; While true do Begin "Parse Switch" ! Use multiple FDBs for either carriage; ! return or a switch; ! Reset the multiple FDB chain; cm#reset; ! Now build the a new chain; cm#swi(Swit!Tab); cm#cfm; ! Get next field; Option := cm#call; Check; ! If cm#cfm then we're through; If Option = 2 then Done "inner loop"; ! If no colon after switch, get another one; If not cm!colon then continue "Parse Switch"; ! Otherwise, process the switch; Swit!No := cm#int; While true do Begin "Process Switch" Case Swit!No of Begin "Pick a Switch" [1] [2] Begin "Get userid list" ! Now we need a userid list; While true do Begin "Get a userid" ! Get one userid; Userid := cm!usr; Check; ! Allocate a record to hold new userid; Temp := New!Record(Recips); Recips:Userid[Temp] := Userid; 52 SAIL-COMND Interface ! Tack it onto the appropriate list; If Swit!No = 1 then Begin "New to" Recips:Next[Temp] := To!List; To!List := Temp; End "New to"; If Swit!No = 2 then Begin "New cc" Recips:Next[Temp] := Cc!List; Cc!List := Temp; End "New cc"; ! Now get a comma, a new switch,; ! or a carriage return; cm#reset; cm#cma; cm#swi(Swit!Tab); cm#cfm; Option := cm#call; Check; ! if cm#cfm was used, we're done; If Option = 3 then done "inner loop"; ! if cm#cma was used, get another userid; If Option = 1 then continue "Get a userid"; ! if cm#swi without colon, ignore switch; If not cm!colon then continue "Parse Switch"; ! Otherwise, process the switch; Swit!No := cm#int; Continue "Process Switch"; End "Get a userid"; End "Get userid list"; [3] Begin "Get subject string" ! Use cm!qst to get quoted string; Subject := cm!qst("Subject of message"); Check; ! Now get next switch; Continue "Parse Switch"; End "Get subject string" End "Pick a Switch"; End "Process Switch"; End "Parse Switch"; End "inner loop"; ! When we get here, we have successfully parsed a line; ! Deactivate ctrl/h feature for next time around; Examples 53 Ctrl!H!Off := true; ! Now process the request; Begin "Process Request" ! Code for processing the request goes here; End "Process Request"; ! Now we're ready for another line; End "outer loop"; End "Main Level"; End "Compost" ********************* End of Example 2 ********************* 3.2.2 Remarks 1. The most important part of this example, other than demonstrating the ctrl/h feature, the use of switches, and the accumulation of a list of similar items, is the demonstration of a very widespread style of writing a command line parser using the interface. The general format goes something like this: 2. While true do Begin "A" cm!ini( ... ); While true do Begin "B" . . . cm!xxx( ... ); if cm!err then continue "A"; if cm!reparse then continue "B"; . . . cm!cfm; if cm!err then continue "A"; if cm!reparse then continue "B"; Done "B"; . . . End "B"; . . ! Process the command line; 54 SAIL-COMND Interface . End "A"; With this format the command line will be repeated immediately after it is processed. An alternative is to move everything between 'End "B";' and 'End "A";' outside of the "A" block and change the 'Done "B";' to 'Done "A";'. This would be preferable if the command line is not to be repeated after the current contents are processed. 3. Parsing a list of similar objects (userids, in the above example) can be very difficult, and the form of the code will not always resemble the code in Example 2 very closely. The example is meant to give a general idea of what is involved in a concrete framework. 4. In this example the table arrays were built using the second suggestion of remark number one in Example 1. 5. As can be seen, nesting can get quite deep in a parsing routine that uses the interface. In Example 2, indenting of new levels had to be decreased from two spaces (the author's normal style) to one space, just to fit the code within the page boundaries. 6. A complete program which interprets the command line of this example and merely reports what it found exists as sai:compos.sai and sai:compos.exe. Standard Break Tables 55 A. STANDARD BREAK TABLES Following is a chart of the complete ASCII character set, with twelve columns indicating which characters are in the standard break tables for each of the twelve COMND functions that use them. Starred (*) columns indicate that the break tables are user-changeable, and the interface procedures corresponding to those functions include a brchars parameter. | | C O M N D F u n c t i o n | ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C | Code |phic | M | M | M | M | M | M | M | M | M | M | M | M | (Dec)| | A | D | D | F | F | I | K | O | S | T | U | U | | | C | E | I | I | L | F | E | F | W | X | Q | S | | | T | V | R | L | D | I | Y | I | I | T | S | R | | | | * | | | * | | * | | * | * | * | | ------------------------------------------------------------ 0 | ^@ | X | X | X | X | X | X | X | X | X | | | X | 1 | ^A | X | X | X | X | X | X | X | X | X | | | X | 2 | ^B | X | X | X | X | X | X | X | X | X | | | X | 3 | ^C | X | X | X | X | X | X | X | X | X | | | X | 4 | ^D | X | X | X | X | X | X | X | X | X | | | X | 5 | ^E | X | X | X | X | X | X | X | X | X | | | X | 6 | ^F | X | X | X | X | X | X | X | X | X | | | X | 7 | ^G | X | X | X | X | X | X | X | X | X | | | X | 8 | ^H | X | X | X | X | X | X | X | X | X | | | X | 9 | ^I | X | X | X | X | X | X | X | X | X | | | X | 10 | ^J | X | X | X | X | X | X | X | X | X | X | | X | 11 | ^K | X | X | X | X | X | X | X | X | X | | | X | 12 | ^L | X | X | X | X | X | X | X | X | X | | | X | 13 | ^M | X | X | X | X | X | X | X | X | X | X | | X | 14 | ^N | X | X | X | X | X | X | X | X | X | | | X | 15 | ^O | X | X | X | X | X | X | X | X | X | | | X | 16 | ^P | X | X | X | X | X | X | X | X | X | | | X | 17 | ^Q | X | X | X | X | X | X | X | X | X | | | X | 18 | ^R | X | X | X | X | X | X | X | X | X | | | X | 19 | ^S | X | X | X | X | X | X | X | X | X | | | X | 20 | ^T | X | X | X | X | X | X | X | X | X | | | X | 21 | ^U | X | X | X | X | X | X | X | X | X | | | X | 22 | ^V | X | X | X | X | X | X | X | X | X | | | X | 23 | ^W | X | X | X | X | X | X | X | X | X | | | X | 24 | ^X | X | X | X | X | X | X | X | X | X | | | X | 25 | ^Y | X | X | X | X | X | X | X | X | X | | | X | 26 | ^Z | X | X | X | X | X | X | X | X | X | | | X | 27 | ESC | X | X | X | X | X | X | X | X | X | | | X | 28 | ^\ | X | X | X | X | X | X | X | X | X | | | X | 29 | ^] | X | X | X | X | X | X | X | X | X | | | X | 30 | ^^ | X | X | X | X | X | X | X | X | X | | | X | 31 | ^_ | X | X | X | X | X | X | X | X | X | | | X | 56 SAIL-COMND Interface | | C O M N D F u n c t i o n | ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C | Code |phic | M | M | M | M | M | M | M | M | M | M | M | M | (Dec)| | A | D | D | F | F | I | K | O | S | T | U | U | | | C | E | I | I | L | F | E | F | W | X | Q | S | | | T | V | R | L | D | I | Y | I | I | T | S | R | | | | * | | | * | | * | | * | * | * | | ------------------------------------------------------------ 32 |space| X | X | X | X | X | X | X | X | X | | | X | 33 | ! | X | X | X | X | X | X | X | X | X | | | X | 34 | " | X | X | X | X | X | X | X | X | X | | | X | 35 | # | X | X | X | X | X | X | X | X | X | | | X | 36 | $ | X | | | | X | | X | | X | | | X | 37 | % | | X | | | X | | X | | X | | | | 38 | & | X | X | X | X | X | X | X | X | X | | | X | 39 | ' | X | X | X | X | X | X | X | X | X | | | X | 40 | ( | X | X | X | X | X | X | X | X | X | | | X | 41 | ) | X | X | X | X | X | X | X | X | X | | | X | 42 | * | | X | | | X | | X | | X | | | | 43 | + | X | X | X | X | X | X | X | X | X | | | X | 44 | , | X | X | X | X | X | X | X | X | X | | | X | 45 | - | | | | | | | | | | | | | 46 | . | | X | | | X | | X | | X | | | | 47 | / | X | X | X | X | X | X | X | X | X | | | X | 48 | 0 | | | | | | | | | | | | | 49 | 1 | | | | | | | | | | | | | 50 | 2 | | | | | | | | | | | | | 51 | 3 | | | | | | | | | | | | | 52 | 4 | | | | | | | | | | | | | 53 | 5 | | | | | | | | | | | | | 54 | 6 | | | | | | | | | | | | | 55 | 7 | | | | | | | | | | | | | 56 | 8 | | | | | | | | | | | | | 57 | 9 | | | | | | | | | | | | | 58 | : | X | X | | | X | | X | | X | | | X | 59 | ; | X | X | | | X | | X | | X | | | X | 60 | < | X | X | | | X | | X | | X | | | X | 61 | = | X | X | X | X | X | X | X | X | X | | | X | 62 | > | X | X | | | X | | X | | X | | | X | 63 | ? | X | X | X | X | X | X | X | X | X | | | X | 64 | @ | X | X | X | X | X | X | X | X | X | | | X | 65 | A | | | | | | | | | | | | | 66 | B | | | | | | | | | | | | | 67 | C | | | | | | | | | | | | | 68 | D | | | | | | | | | | | | | 69 | E | | | | | | | | | | | | | 70 | F | | | | | | | | | | | | | 71 | G | | | | | | | | | | | | | 72 | H | | | | | | | | | | | | | 73 | I | | | | | | | | | | | | | 74 | J | | | | | | | | | | | | | 75 | K | | | | | | | | | | | | | 76 | L | | | | | | | | | | | | | 77 | M | | | | | | | | | | | | | 78 | N | | | | | | | | | | | | | 79 | O | | | | | | | | | | | | | Standard Break Tables 57 | | C O M N D F u n c t i o n | ASCII|Gra- | C | C | C | C | C | C | C | C | C | C | C | C | Code |phic | M | M | M | M | M | M | M | M | M | M | M | M | (Dec)| | A | D | D | F | F | I | K | O | S | T | U | U | | | C | E | I | I | L | F | E | F | W | X | Q | S | | | T | V | R | L | D | I | Y | I | I | T | S | R | | | | * | | | * | | * | | * | * | * | | ------------------------------------------------------------ 80 | P | | | | | | | | | | | | | 81 | Q | | | | | | | | | | | | | 82 | R | | | | | | | | | | | | | 83 | S | | | | | | | | | | | | | 84 | T | | | | | | | | | | | | | 85 | U | | | | | | | | | | | | | 86 | V | | | | | | | | | | | | | 87 | W | | | | | | | | | | | | | 88 | X | | | | | | | | | | | | | 89 | Y | | | | | | | | | | | | | 90 | Z | | | | | | | | | | | | | 91 | [ | X | X | | | X | | X | | X | | | X | 92 | \ | X | X | X | X | X | X | X | X | X | | | X | 93 | ] | X | X | | | X | | X | | X | | | X | 94 | ^ | X | X | X | X | X | X | X | X | X | | | X | 95 | _ | X | | X | X | X | X | X | X | X | | | X | 96 | ` | X | X | X | X | X | X | X | X | X | | | X | 97 | a | | | | | | | | | | | | | 98 | b | | | | | | | | | | | | | 99 | c | | | | | | | | | | | | | 100 | d | | | | | | | | | | | | | 101 | e | | | | | | | | | | | | | 102 | f | | | | | | | | | | | | | 103 | g | | | | | | | | | | | | | 104 | h | | | | | | | | | | | | | 105 | i | | | | | | | | | | | | | 106 | j | | | | | | | | | | | | | 107 | k | | | | | | | | | | | | | 108 | l | | | | | | | | | | | | | 109 | m | | | | | | | | | | | | | 110 | n | | | | | | | | | | | | | 111 | o | | | | | | | | | | | | | 112 | p | | | | | | | | | | | | | 113 | q | | | | | | | | | | | | | 114 | r | | | | | | | | | | | | | 115 | s | | | | | | | | | | | | | 116 | t | | | | | | | | | | | | | 117 | u | | | | | | | | | | | | | 118 | v | | | | | | | | | | | | | 119 | w | | | | | | | | | | | | | 120 | x | | | | | | | | | | | | | 121 | y | | | | | | | | | | | | | 122 | z | | | | | | | | | | | | | 123 | { | X | X | X | X | X | X | X | X | X | | | X | 124 | | | X | X | X | X | X | X | X | X | X | | | X | 125 | } | X | X | X | X | X | X | X | X | X | | | X | 126 | ~ | X | X | X | X | X | X | X | X | X | | | X | 127 | DEL | X | X | X | X | X | X | X | X | X | | | X | 58 SAIL-COMND Interface Index 59 INDEX Account Name Fields 19 Account Parameter 23 Acknowledgements 1 Action Characters 5, 32, 39 Extending 18 Allow$Wild Parameter 21 Arbitrary Fields 24 Atom Buffer 15, 25 Backspace 8 Brchars Parameter 18 Break Characters 18 Standard 18, 54 Building TBLUK Lookup Tables 36, 47 Carriage Return 5, 32 CASE Statement In SAIL 48 Changing Contents of TBLUK Lookup Tables 48 Cm! - Procedures 12 Cm!Act 19 Cm!Cfm 19 Cm!Cma 20 Cm!Dev 21 Cm!Dir 21 Cm!Fil 22 Cm!Fld 24 Cm!Flt 25 Cm!Getatm 15, 25 Cm!Ifi 25 Cm!Ini 26 Cm!Key 27 Cm!Nod 29 Cm!Noi 29 Cm!Num 30 Cm!Nux 30 Cm!Ofi 31 Cm!Qst 31 Cm!Retry 13, 32 Cm!Size 33 Cm!Swi 33 Cm!Tad 34 Cm!Take 16, 35 Cm!Tbuild 36 Cm!Tok 38 Cm!Txt 38 Cm!Uqs 39 Cm!Usr 39 Cm!Abort Variable 16, 36 Cm!Act Procedure 19 Cm!Cfm Procedure 19 Example of Use 46, 50 Cm!Cma Procedure 20 Cm!Colon Variable 33 60 SAIL-COMND Interface Example of Use 51, 52 Cm!Datime Array 34 Cm!Dev Procedure 21 Cm!Dir Procedure 21 Cm!Eof Variable 16, 36 Cm!Err Variable 12, 14, 15 Example of Use 44, 45, 46 Cm!Fatal Variable 15 Cm!Fil Procedure 22 Cm!Fld Procedure 24 Cm!Flt Procedure 25 Cm!Getatm Procedure 15, 25 Cm!Ifi Procedure 25 Example of Use 51 Cm!Ini Procedure 26 Example of Use 50 Cm!Key Procedure 27 Example of Use 44, 45, 50 Cm!Major Variable 14 Cm!Minor Variable 14 Example of Use 45 Cm!Nod Procedure 29 Cm!Noi Procedure 29 Example of Use 44, 45, 51 Cm!Num Procedure 30 Example of Use 45 Cm!Nux Procedure 30 Cm!Ofi Procedure 31 Cm!Qst Procedure 31 Example of Use 52 Cm!Reparse Variable 13 Example of Use 44, 45, 46 Cm!Retry Procedure 13, 32 Caution 32 Cm!Size Procedure 33 Example of Use 44, 49 Cm!Swi Procedure 33 Cm!Tad Procedure 34 Cm!Take Procedure 16, 35 Cm!Tbuild Procedure 36 Example of Use 44, 50 Cm!Tok Procedure 38 Cm!Txt Procedure 38 Cm!Uqs Procedure 39 Cm!Usr Procedure 39 Example of Use 51 Cm# - Procedures 12, 40 Cm#Call 12, 41 Cm#Reset 41 (All Others) 40 Cm#Call Procedure 12, 41 Example of Use 46, 51, 52, 51, 52 Cm#Int Variable 41 Example of Use 46, 51, 52, 46 Cm#Real Variable 41 Cm#Reset Procedure 41 Index 61 Example of Use 46, 51, 52 Cm#Str Variable 41 Example of Use 51, 52 Colon 33 COMAND.CMD File 16 Comma Fields 20 Command Files 35 Command Line 7 Terminating 20 Command Line Prompt 7, 26 Command State Block 3 COMND Functions CMACT 19 CMCFM 20 CMCMA 20 CMDEV 21 CMDIR 21 CMFIL 22 CMFLD 24 CMFLT 25 CMIFI 26 CMINI 7, 26 CMKEY 27 CMNOD 29 CMNOI 29 CMNUM 30 CMNUX 31 CMOFI 31 CMQST 32 CMSWI 33 CMTAD 34 CMTOK 38 CMTXT 39 CMUQS 39 CMUSR 40 COMND.HDR File 11 COMPOS Sample Program 54 Confirmation Fields 19 Control/T Character 5 CSB 3 Ctrl/H Character 8 Date Fields 34 Date Parameter 34 Def Parameter 17 Default String 4, 17 And Multiple FDBs 17 Device Name Fields 21 Device Parameter 23 Directory Name Fields 21 Directory Parameter 23 DIRST Built-in SAIL Function 22, 40 Errmsg Parameter 32 Error Handler 14 And Major Errors 14 62 SAIL-COMND Interface And Minor Errors 14 Errpop Parameter 36 Escape Character 5, 17, 29 EXEC 3, 16, 35, 43 Extension Parameter 23 FDB 3, 4 FDB Chain 9, 40 File Name Fields 22, 25, 31 Flag$Gen Parameter 22 Fred 6 Function Descriptor Block 3, 4 GTJFN Argument Block 22 Word 0 (.GJGEN) 22 GJ%FOU Bit 24 GJ%JFN Bits 24 GJ%OLD Bit 24 Word 2 (.GJDEV) 23 Word 3 (.GJDIR) 23 Word 4 (.GJNAM) 23 Word 5 (.GJEXT) 23 Word 6 (.GJPRO) 23 Word 7 (.GJACT) 23 Word 10 (.GJJFN) 23 GTJFN Built-in SAIL Function 35 GTJFN Jsys 22 GTJFNL Built-in SAIL Function 35 Guide Words 29 Help Message 4, 17 And Multiple FDBs 17 Standard 17 Help Parameter 17 Ichan Parameter 35 IDTNC jsys 35 Ignored Keywords 37 Illegal Instruction Interrupts 14 Indirect Files 18 Initializing The CSB 26 Input File Fields 25 Integer Fields 30 Internal Date/Time Format 34 Invisible Keywords 37 Jfn Parameter 23 Keys Parameter 36 Keyword Abbreviations 1, 38 Keyword Fields 27 LOGIN.CMD File 16 Major Errors 14 Minor Errors 14 Index 63 Multiple Function Calls 9 Example of Use 46, 51, 52 Name Parameter 23 Newcomm Parameter 26 No$Convert Parameter 34 No$Indirect Parameter 18 Node Name Fields 29 Noise Parameter 29 Noise Words 29 Number Bases 30 Numeric Fields 25, 30 Obtaining Passwords 18 Ochan Parameter 35 Optional Parameters 48 Output File Fields 31 Parse$Only Parameter 22 Parsing Errors 5, 7, 12 And Cm!Retry 13, 32 In Command Files 16 With Multiple FDBs 9 Procedure Parameters Account 23 Allow$Wild 21 Brchars 18 Date 34 Def 17 Device 23 Directory 23 Errmsg 32 Errpop 36 Extension 23 Flag$Gen 22 Help 17 Ichan 35 Jfn 23 Keys 36 Name 23 Newcomm 26 No$Convert 34 No$Indirect 18 Noise 29 Ochan 35 Parse$Only 22 Prompt 26 Protection 23 Radix 30, 31 Raise$Input 17 Strarr 33 Sup$Help 17 Table 28, 33, 36 Time 34 Token 38 Wake$Always 18 64 SAIL-COMND Interface Prompt Parameter 26 Protection Parameter 23 Punctuation In TBLUK Lookup Tables 37 Question Mark 5, 17 Quoted String Fields 31 Radix Parameter 30, 31 Raise$Input Parameter 17 Real Number Fields 25 Reparse 6, 7, 13 Reparse Dispatch Address 1 REQUIRE Statement 11 Slash 33 Standard Break Characters 18, 55 CMDEV 21 CMFLD 24 CMKEY 28 CMSWI 34 CMTXT 39 Standard Help Message 17 CMACT 19 CMCFM 20 CMCMA 20 CMDEV 21 CMDIR 22 CMFIL 24 CMFLD 24 CMFLT 25 CMIFI 26 CMINI 26 CMKEY 28 CMNOD 29 CMNOI 30 CMNUM 30 CMNUX 31 CMOFI 31 CMQST 32 CMSWI 34 CMTAD 35 CMTOK 38 CMTXT 39 CMUQS 39 CMUSR 40 Suppressing 17 Strarr Parameter 33 Sup$Help Parameter 17 Switch Fields 33 Switches 33 Table Parameter 28, 33, 36 TAKE Command 16, 35 TBLUK Jsys 28 TBLUK Lookup Table 28 Abbreviated Entries 1, 38 Index 65 Building 36, 47 Changing Contents 48 Computing Size With Cm!Size 33 Ignored Entries 37 Invisible Entries 37 Special Punctuation 37 TERCOM Sample Program 48 TERMINAL command 43 Terminating Command Lines 20 Text Fields 38 Time And Date Fields 34 Time Fields 34 Time Parameter 34 Token Fields 38 Token Parameter 38 Turning Off Echoing 18 Unimplemented Features 1 Unquoted String Fields 39 Upper Case Conversion 17 User Name Fields 39 Variables Cm!Abort 16, 36 Cm!Colon 33 Cm!Datime (Array) 34 Cm!Eof 16, 36 Cm!Err 12, 14, 15 Cm!Fatal 15 Cm!Major 14 Cm!Minor 14 Cm!Reparse 13 Cm#Int 41 Cm#Real 41 Cm#Str 41 Wake$Always Parameter 18 Wildcard Characters 21 Wizard Note 28