Introduction to the RSX, P/OS, and RT Indirect Command File Processor - RX018 - T. R. Wyant E. I. DuPont de Nemours October 8, 1986 Housekeeping - Outline Housekeeping Outline Goal & Caveats Acknowledgment Background Canned Command Procedures Approaches to Processing Canned Command Procedures Invoking the ICP Contents of an ICP file Processing a Line of an ICP file Symbols What Are Symbols Logical Symbols Numeric Symbols String Symbols Symbol Substitution Determining the Characteristics of Symbols Manipulating Substrings Control Conditional Statements Labels Transfer of Control File I/O Basic File Operations Miscellaneous Capabilities Terminal I/O .ASKx Operation .ASKx Exception Handling Miscellaneous Input Output Modules Internal External External Environment What Kind of System Are You On? The Device Configuration Other Things About the System The Context of the ICP File Executing under Multiple CLIs Interfacing With Your Own Code Synchronizing With Tasks Debugging Aids Bibliography Housekeeping - Goal Help all listeners to make efficient use of the Indirect Command File Processor (ICP) under RSX, P/OS, and RT. Caveats The current releases of all the operating systems are assumed. However, this paper should be useful as far back as: RSX-11M V3.2 RSX-11M+ V1.0 P/OS V1.0 RT-11 V5.0 (FB and XM) Where there are differences between the Indirect Command File Processors of these systems (and I am aware of these differences) they are indicated. Command lines in examples are all for RSX MCR. I am not the final authority on the ICP in all its multifarious versions. Errors in research and transcription do occur. I apologize in advance for these, but assume no responsibility for their consequences. Housekeeping - Acknowledgment Allen A. Watson's paper, "Indirect Command Files for New RSX Users", presented at the Spring, 1983 DECUS US Symposium, was both an inspiration and a reference for this paper. Background - Canned Command Procedures Canned command procedures are useful to: Group frequently-issued Command Line Interpreter (CLI) commands in a file. Reduce typing. Drastically reduce typos (and the effects thereof). Save time (and aggravation). Create user-friendly or custom interfaces to complex commands (eg: BRU). Background - Approaches to Processing Canned Command Procedures Integrate into I/O mechanism: Creates a "batch"-like environment: Input to programs is in-line to the command procedure; Programs think they're running interactively in most cases, and provided you get all the input right in the command procedure. Drawbacks: Advanced features can require a lot of code where there isn't room for much. Examples: VMS - DCL command procedures; RT-11 Indirect Command Facility. Implement in separate task: Not "batch"-like: In-line input not allowed; Tasks need own indirect command facility - or interface ; Distinguishes between logic and Command Line Interpreter (CLI) commands. Examples: RSX Indirect Command File Processor; P/OS Indirect Command File Processor; RT Indirect Control File Processor. Our subject is the (RSX + P/OS + RT) Indirect Command/Control File Processor. This will hereafter be referred to as the ICP. Background - Invoking the ICP To feed a command file to the ICP: (RSX) >@filename (Default filetype is .CMD) (P/OS) $ @filename (Default filetype is .CMD) (RT) . SET KMON IND . @filename (Default filetype is .COM) or . IND @filename (Default filetype is .COM) In all cases the input is to a CLI prompt. "@filename" in response to some other prompt has nothing to do with the ICP. For example, PIP>@filename feeds the file to PIP's own command processor. Background - Contents of an ICP file Each line of an ICP file is: An "external" comment: Begins with ";" Is displayed when encountered (unless .ENABLE QUIET is in effect) Has no other effect An "internal" comment: Begins with ".;" Is not displayed when encountered Has no other effect An ICP directive: Begins with "." Is interpreted and executed by the ICP Most of this paper deals with these A CLI command: Is any line that doesn't meet the above criteria Is issued as a command to the current CLI, as though you typed it. If the current CLI can't handle it, that's your problem, not ICP's. Background - Processing a line of an ICP file A record (line) in an ICP file is processed in the following steps: Read it; Perform symbol substitution (if enabled); Decide what category it falls in. If it's an ICP directive: Parse the first "word"; Load the overlay that processes it (overlaid versions); Complete parsing; Execute; Why am I telling you this? Because: Symbol substitution occurs very early in the processing of a line. Many "LISP"-ish behaviors of the ICP are based on this. Many versions of the ICP are overlaid, so grouping like operations together can improve performance. Running an overlaid ICP off a floppy disk can require a good deal of patience. Symbols - What are Symbols? They are named data stores used by the ICP. They are not accessible outside the ICP (though the ICP can make their VALUES available). Their names are 1-6 RAD50 characters (excluding "."), and MUST contain at least one non-numeric character. Note: Certain releases of the ICP have had trouble with embedded dollar signs, or with symbol names that begin with a numeric character. Also note: There are certain predefined Special Symbols, which are named according to the same convention, but have their names enclosed in "<>". These do not conflict with ordinary names. They come in three flavors: Logical (True of False); Numeric (16-bit integer values); String (0 to 132 bytes). They can be assigned values: By computation within the ICP; By querying the user; In special cases, by reference or on entry to the ICP. Their values can be tested. They are normally local to the command file in which they were created. Note: If you .ENABLE GLOBAL, symbols whose name begins with a "$" are available for the life of the ICP run. Symbols - Logical Symbols Take on the values TRUE or FALSE. Can be assigned values by: .SETT symbol (sets it TRUE); .SETF symbol (sets it FALSE); .SETL symbol expression (sets it to value of expr.). Logical expressions consist of logical symbols (or the Special Logical Symbols or ), connected by the following operators: ! (logical OR); & (logical AND); (RSX,P/OS) # (logical NOT); (RT) ^ (logical NOT). Expressions are evaluated left to right, without regard for usual precedence of operators. Operations may be grouped with parentheses. Values can be tested by .IFT, .IFF, or .IF directive. These directives are discussed under "Control". Can take on values entered from your terminal, using the .ASK directive. This directive is discussed under "Terminal I/O". Substitution yields "T" for TRUE, or "F" for FALSE. Substitution is discussed later in this section. Symbols - Numeric Symbols Take on 16-bit integer values. These are unsigned. (RSX,P/OS) - They can be treated as signed values if you .ENABLE OVERFLOW (RT) - They are always unsigned. Can be assigned values by: .SETN symbol expression (sets it to value of expr.); .INC symbol (adds 1 to it); .DEC symbol (Subtracts 1 from it); (RT) .SETT [mask] symbol (Sets the masked bits); (RT) .SETF [mask] symbol (Clears the masked bits). Numeric expressions consist of numeric symbols or constants, connected by the following operators: + (addition); - (subtraction); * (multiplication); / (integer division); ! (bitwise logical OR); & (bitwise logical AND); (RSX,P/OS) # (bitwise logical NOT); (RT) ^ (bitwise logical NOT). Expressions are evaluated left to right, without regard for usual precedence of operators. Operations may be grouped with parentheses. Numeric constants are octal unless you append a decimal point, or unless you: (RSX,P/OS) .ENABLE DECIMAL (RT) .DISABLE OCTAL Values can be tested by the .IF directive. This directive is discussed under "Control". Can take on values entered from your terminal, using the .ASKN directive. This directive is discussed under "Terminal I/O". The default radix of a symbol is decimal, unless the expression that computed its value consisted only of octal symbols and constants. This default radix can be changed by: .SETO symbol (default radix to octal); .SETD symbol (default radix to decimal). Substitution yields the value of the symbol, in the current default radix of the symbol. Substitution is discussed later in this section. Symbols - String Symbols Take on the value of a 0-132 byte string. Can be assigned values by: .SETS symbol expression (sets it to value of expr.) If you .DISABLE LOWERCASE, the string is uppercased before being assigned to the symbol. String expressions consist of string symbols, substrings, or constants, connected by the following operator: + (concatenation). Expressions are evaluated left to right. Operations may NOT be grouped with parentheses, but then with only one operator, why would you need to? A string constant is constructed as follows: "this is a string constant" (RSX,P/OS) #this is a string constant, too# The quoting character may not appear in the constant under any of the systems. Substrings can be extracted by the construction: symbol[start:end] which represents the bytes between the start and end positions, inclusive. Any valid numeric expression can be used for "start" and "end". Also, "*" can be used, representing the last character in the string. Values can be tested by the .IF directive. This directive is discussed under "Control". Can take on values entered from your terminal, using the .ASKS directive. This directive is discussed under "Terminal I/O". Substitution yields the bytes in the string. Substitution is discussed later in this section. Symbols - Symbol Substitution Occurs only when enabled by .ENABLE SUBSTITUTION. Under P/OS and RT, substitution is enabled by default. Under RSX, it is disabled by default. Is called for by enclosing a symbol name in apostrophes. If you attempt substitution on an undefined symbol, an error occurs. Substitution in an ICP file line occurs BEFORE the line is parsed. Therefore it can occur anywhere in a line, and in any kind of line. Under RSX and P/OS, you can get format control by following the symbol name (within apostrophes) by a percent sign ("%") and one or more of the following: D (substitute the decimal value); O (substitute the octal value); Rn (right justify in "n" byte field); Ln (left justify in "n" byte field); Z (fill field with leading zeros); S (signed value); C (do blank compression); X (substitute RAD50 string for number); V (substitute value for first byte, or a byte for value). Examples (all of which assume .ENABLE SUBSTITUTION): Assembling and task building an arbitrary module: .ASKS MODULE What module shall I assemble MAC 'MODULE'='MODULE' TKB @'MODULE'BLD Effects: You are prompted for the name of a module; That module is assembled and taskbuilt. Inserting control characters: .SETN NJUNK 33 .SETS ESCAPE "'NJUNK%V'" Effect: String Symbol ESCAPE now contains an escape character. Using format control to set the size of a field: .SETN NJUNK 1 PIP FILE.'NJUNK%R3Z'/LI Effect: A directory listing of file FILE.001 is produced. Symbols - Determining the Characteristics of Symbols Finding out whether a symbol exists: .IFDF symbol (satisfied if symbol defined); .IFNDF symbol (satisfied if symbol not defined). Note: the line .IFDF symbol ;'symbol' will result in an error if the symbol is undefined. The substitution is attempted BEFORE the line is parsed. Characteristics of a symbol: .TEST symbol (Causes the following Special Symbol values to be set:) = 0 if the symbol is a Logical Symbol, = 2 if the symbol is a Numeric Symbol, = 4 if the symbol is a String Symbol; = if octal (numeric and string only); = Length of string (string symbols only); = if (uppercase) alphanumeric (string symbols only); = if a number (string symbols only); = if a RAD50 string (string only). Symbols - Manipulating Substrings Finding substrings of a string: .TEST string1 string2 (returns the following Special Symbol value:) = position of first occurrence of string2 in string1, or 0 if it doesn't occur. Note: the strings may be either string constants or string symbols. Also note: Extracting substrings based on character position was discussed under String Symbols. Substrings based on character locations: .PARSE string1 string2 symbol1 symbol2 ... (Takes string2 as a list of separators, and picks string1 apart. symbol1 gets everything up to the first separator, and so on.) If there are more symbols than separator characters in string2, the last separator character gets reused. If all separators do not occur IN ORDER in string1, symbols corresponding to the missing separators come back with the null string. Example: .PARSE "[,]" JUNK1 GROUP MEMBER JUNK2 sets JUNK1 and JUNK2 null, GROUP to your current UIC group, and MEMBER to your current UIC member. JUNK1, JUNK2, GROUP, and MEMBER are all string symbols. Control - Conditional Statements .IFx statement: Syntax: .IFx condition statement The "statement" (directive, CLI command, or whatever) is executed ONLY if the condition is satisfied. Flavors: Syntax Condition satisfied if ------------------- ---------------------- .IFT symbol logical symbol is true .IFF symbol logical symbol is false .IFDF symbol symbol is defined .IFNDF symbol symbol is not defined .IFLOA driver driver is loaded .IFNLOA driver driver is not loaded .IF symbol rel expr relation is satisfied (RSX,P/OS) .IFINS task task is installed (RSX,P/OS) .IFNINS task task is not installed (RSX,P/OS) .IFACT task task is active (RSX,P/OS) .IFNACT task task is not active (RT) .IFT [mask] symbol numeric symbol has any (RT) masked bits set (RT) .IFF [mask] symbol numeric symbol has any (RT) masked bits clear Valid relations in a .IF directive: Satisfied if value of Syntax symbol is ------------------- ---------------------- = or EQ equal to expression <> or NE not equal to expression > or GT greater than expression < or LT less than expression >= or GE greater than or equal to expression <= or LE less than or equal to expression The expression must be of the same type as the symbol. Tests can be connected using: .OR - satisfied if either condition is met. Syntax: .IFx condition .OR .IFx condition .AND - satisfied if both conditions are met. Syntax: .IFx condition .AND .IFx condition Parentheses after the first .IFx to group tests. Syntax: .IFx .AND (.IFx .OR .IFx) Control - Labels Are used to identify locations as targets of .GOTO or .GOSUB directives. Are formed in the same way as symbol names but do not conflict with them. Must occur (at least) once in the same command file as all .GOTOs or .GOSUBs that refer to them, or you get an error. Need not be unique - but you can get "strange" results if they're not. Come in two flavors: Standard labels: Defined by the syntax: .label: (more stuff on same line) Are found by scanning the command file forward from the .GOTO or .GOSUB to the end of the file and then (if the file is on disk) rewinding and scanning forward to the .GOTO or .GOSUB directive; Substitution does not occur when scanning for labels. Direct-access labels: Defined by the syntax .label: with nothing else on the same line; Location is cached, and loaded directly when referenced by a .GOTO or .GOSUB directive; If cache fills, earliest defined label is dropped (ie: it reverts to being a standard label); Obviously, there are no direct-access labels if the command file is not on disk. Control - Transfer of Control "Standard" GO TO syntax: .GOTO label Unconditionally transfers control to the given label. The given label must occur in the same command procedure as the .GOTO that refers to it. "Computed" GO TO syntax: No explicit support for this. Can be implemented using symbol substitution and smart choice of labels, as in: .ENABLE SUBSTITUTION .SETN OPTION 0 .QUERY: .ASKS FILE Which file .ASKN [0:2:OPTION] OPTION Which option .GOTO OPT'OPTION' .OPT0: .EXIT .OPT1: PIP 'FILE'/LI .GOTO QUERY .OPT2: PIP 'FILE'/SP .GOTO QUERY "Assigned" GO TO syntax: No explicit support for this. Can be implemented using symbol substitution and smart choice of labels, as in: .ENABLE SUBSTITUTION .SETS ASSIGN "LABEL1" . . . .GOTO 'ASSIGN' . . . .LABEL1: File I/O - Basic File Operations Syntax for input directives: .OPENR filename (Open existing file for input.) .READ symbol (Read the next record into the String Symbol. If the end of the file is encountered, Special Symbol is set , and the symbol's value is untouched.) .CLOSE (Close the file.) Syntax for output directives: .OPEN filename (Open new file for output.) or .OPENA filename (Open existing file for append, or new file for output.) .DATA text (Writes one record containing the given text to the file.) or .ENABLE DATA (Causes all subsequent lines in the commend procedure to be written to the file, down to the corresponding .DISABLE DATA. Note: Labels in a data block are recognized during a label search. This is a restriction.) followed by .DISABLE DATA (Turns off the writing of data to the file. Note: Some ICPs don't recognize unless left justified in the record.) .CLOSE (Closes the output file.) or (RT) .PURGE (Same as .CLOSE, unless the file was opened with .OPEN - then the file is deleted.) File I/O - Miscellaneous Capabilities Multiple files: All file I/O directives will take an optional File Number after the directive, but before any arguments. For example: .OPEN #1 KANGA.ROO .DATA #2 This data is written to File 2. The File Number is a hash mark ("#") and a number from 0-3. #0 is the same as omitting the file number. You can, of course, generate the number by symbol substitution: .DATA #'FILENO' This data is written to some .DATA #'FILENO' file, but which one is not .DATA #'FILENO' determined until the ICP is .DATA #'FILENO' run. Determining file attributes (RSX only): Special Symbol is loaded with the first 7 words of the FCS file descriptor block for the most recently .OPENed file (as a string of decimal numbers, separated by commas). This includes such useful info as how big the file is, what its largest record is, and more. Terminal I/O - .ASKx Operation .ASKx is used to prompt for and validate symbol values. .ASKx always returns either a valid value or some specific exception condition. Validation failure causes reprompting automatically. By default, entry of ^Z causes the ICP to exit. Syntax: .ASK [def:tmo] symbol prompt (Logical); .ASKN [lo:hi:def:tmo] symbol prompt (Numeric); .ASKS [lo:hi:def:tmo] symbol prompt (String), Where: lo = lowest valid value (.ASKN) or lowest acceptable length (.ASKS) ; hi = highest valid value (.ASKN) or highest acceptable length (.ASKS); def = default value; tmo = timeout on question: (RT) This requires a system clock, and a (RT) .ENABLE TIMEOUT (RSX, P/OS) This can be disabled with a (RSX, P/OS) .DISABLE TIMEOUT All parameters are optional - except that "lo" and "hi" must be either both specified or both omitted. Trailing colons in parameter block can be omitted. If all parameters are omitted, the square brackets can be, too. If the default answer is taken, comes back TRUE. If the timeout expires, comes back TRUE. You can get uppercase conversion on a .ASKS by: .DISABLE LOWERCASE Terminal I/O - .ASKx Exception Handling You don't get exceptions returned unless you .ENABLE them. .ENABLE ESCAPE Causes the escape character to be valid for any .ASKx directive (and its synonym ) come back TRUE Generally used to break out of the normal logic sequence .DISABLE CONTROL-Z (RSX, P/OS only) Allows ^Z to be trapped by your command procedure comes back TRUE Used to break out of normal logic sequence, or with SET /SLAVE=TI: to create captive command procedures The manual specifies that the default answer is returned for exceptions. Not all versions of ICP support this. Terminal I/O - Miscellaneous Input You can also .OPENR a terminal. This is the only way to do I/O to a terminal other than TI: (RSX, P/OS) or TT: (RT). Terminal I/O - Output By default: Each .ASKx displays: (RSX) >* prompt [parameters]: (P/OS) $ * prompt [parameters]: (RT) * prompt [parameters]: "External" comments display: (RSX) >; comment text (P/OS) $ ; comment text (RT) ; comment text CLI commands are displayed as: (RSX) >Command (P/OS) $ Command (RT) . Command You can disable the extra stuff by: (RSX,P/OS) .DISABLE DISPLAY (RT) .DISABLE PREFIX,SUFFIX If you do this: Each .ASKx displays: prompt "External" comments display: comment text CLI commands are displayed as: Command You can get rid of "External" comments and CLI commands completely by: .ENABLE QUIET You can also (of course) .OPEN a terminal for output. Modules - Internal Modules internal to the current command file can be created by using the .GOSUB - .RETURN construction. Module entry syntax: .GOSUB label arguments Argument passing: The arguments are available in the reserved String Symbol COMMAN. This contains a literal copy of anything on the .GOSUB command line after the label. Module exit syntax: .RETURN (returns to the first line after the .GOSUB directive.) Example: .ENABLE SUBSTITUTION .GOSUB STORE Arthur Dent .GOSUB STORE 6*9=42 .EXIT .STORE: ; The argument string is "'COMMAN'". .RETURN This displays (under RSX): >; The argument string is "Arthur Dent". >; The argument string is "6*9=42". >@ Modules - External Other command files can be called just as though from the CLI prompt. Module entry syntax: @file arguments Argument passing: The following reserved String Symbols are loaded: COMMAN - Contains entire command line, uppercased and with blank compression. P0-P9 - Loaded as though by: .PARSE COMMAN " " P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 Module exit syntax: .EXIT status (return to the calling command file) or .STOP (terminate the ICP) "status" is a 16-bit value, returned to the calling procedure in Special Symbol , or to the parent task (if any). If omitted, it defaults to 1. The end of a command file is equivalent to a .EXIT directive. You can pass results back to the caller in global symbols, or in Special Symbol by: .SETS results Under RSX and P/OS, you can also chain between command files: .CHAIN file The only parameter passing is by global symbols, or by using .CHAIN file/LO which causes all local symbols to be preserved in the new command file. External Environment - What Kind of System Are You On? Finding out what system you are running under: A reference to Special Symbol returns (in octal): 0 = RSX-11D; 1 = RSX-11M; 2 = RSX-11S (nice trick!); 3 = IAS; 4 = RSTS (for expansion?); 5 = AME, or VAX-11 RSX; 6 = RSX-11M+; 7 = RT-11 SJ; 10 = RT-11 FB (or RTEM-11); 11 = P/OS. A reference to Special Symbol returns a string describing the system type. This is a new feature in RSX, and may or may not be in P/OS or RT. A reference to Special Symbol returns a string describing the system version number. This is a new feature in RSX, and may or may not be in P/OS or RT. Finding out the system name: The system name is stored in Special Symbol (RSX,P/OS) (RT) By default, this is the name given at SYSGEN. However (at least under RSX) if you are running DECnet, it will contain your DECnet Node Name. External Environment - The Device Configuration Finding a driver: .IFLOA driver (satisfied if driver loaded); .IFNLOA driver (satisfied if driver not loaded). Finding a device: .TESTDEVICE name returns, in Special Symbol , the string "phys,n1,n2,n3,n4,flags" where: Phys is the physical name of the device; (RSX,P/OS) n1 thru n4 are octal numbers, and represent (RSX,P/OS) U.CW1 thru U.CW4 for the given device; (RT) n1 is a decimal number (with trailing dot) (RT) which gives the size of the device; (RT) n2 through n4 are zero. Flags are various device status indicators: Driver status: LOD, driver is loaded; UNL, driver is not loaded. Device status: ONL, device is online; OFL, device is offline; (RT) UNK, device status is unknown. Mount status: MTD, device is mounted; NMT, device is not mounted. Mount type: (RSX,P/OS) FOR, device is mounted foreign; (RSX,P/OS) NFO, device is not mounted foreign. "Publicity": (RSX,P/OS) PUB, device is set public; (RSX,P/OS) NPU, device is not set public. Allocation: (RSX,P/OS) NAL, device is not allocated; (RSX,P/OS) ALU, device is allocated to this terminal; (RSX,P/OS) ALO, device is allocated to another terminal. Note: some versions of the ICP get confused whether to return ALO or ALU. Attachment: (RSX,P/OS) NAT, device not attached; (RSX,P/OS) ATU, device attached by this copy of the ICP; (RSX,P/OS) ATT, device attached by another task. If the device is not in the system, returns "NSD," no such device in this system. External Environment - Other Things About the System Finding out what volume is on a drive (RT ONLY): .VOL symbol device (loads volume label in symbol). Finding out what time it is: , when referenced, returns the system date;