Page 2 1 HOUSEKEEPING 1.1 Abstract This paper presents a compendium of advanced techniques for using the RSX Indirect Command Processor (ICP). These include the use of command procedure libraries, arrays and other structured data types, binary file I/O, screen handling both with and without FMS, error control, command line processing, and multiple precision arithmetic. This paper is aimed at an audience that is familiar with the RSX ICP, though "Introduction to the RSX Indirect Command File Processor" (RX009) should give sufficient background. Weird Tricks with the RSX Indirect Command Processor 1.2 Caveats The current releases of RSX are assumed. The techniques presented here may or may not work under previous versions of RSX, or under IAS, P/OS, or RT. Since the things covered in this paper are "off the beaten - RX015 - track", they are more likely than usual to be affected by bugs or other differences between releases of the ICP. The examples cited all work under RSX-11M+ V4.1. I will mention bugs where I am aware of their existence. I am not the final authority on the ICP in all its Thomas R. Wyant, III multifarious versions. Errors in research and transcription do E. I. DuPont de Nemours occur. I apologize in advance for these, but assume no Richmond, Virginia responsibility for their consequences. The examples are all from working command procedures, which Anthony E. Levan will be submitted to the Fall, 1990 RSX/IAS SIG tape. Some Systems Research Laboratories reformatting has been necessary to make the ICP code fit on the Dayton, Ohio page properly. I have tried to preserve the functionality, but I have no way to test the example code out of context. 1.3 Acknowlegement December 10, 1990 Allen A. Watson's paper, "Nifty Things to Do with RSX Indirect Command Files", presented at the Spring, 1983 DECUS US Symposium, was both an inspiration and a reference for this paper. 2 COMMAND PROCEDURE LIBRARIES It can be desirable to break a very large command procedure Page 3 Page 4 into separate modules. These will be easier to keep track of if they are kept in a Command Procedure Library. Examples include: .TESTFILE library/LB:module LB:[1,2]INDSYS.CLB This returns the value of 1 in Special Numeric Symbol LB:[200,200]SYSGEN.CLB if the library file exists and the module is in it. However, LB:[137,10]NETGEN.CLB some of the ICP releases involved (including at least M+ V2.1C) have a bug: will be 1 if the library file exists, regardless of whether the desired module is in it. A Command Procedure Library is just a Universal Library (as documented in the LBR manual), created as follows: >LBR library.CLB/CR::::UNI:CMD 3 STRUCTURED DATA TYPES Once the command procedure library is created, modules can be Although the ICP has explicit support only for simple inserted and removed just as they are for a macro or object variables, there are a number of ways in which arrays and other library. structured data types may be built. All of these are based on building symbol names at execution time, using substitution on Modules in a Command Procedure Library can be executed other symbols. An assortment of techniques is presented here. without extracting them from the library by: >@library/LB:module 3.1 Using A String Symbol As An Array Where: Small arrays can be stored in a String Symbol and extracted o "library" is the name of your command file library, by forming a substring. In order to do this, with default file type ".CLB". If you omit this, the current library is assumed if the command is issued o All elements in the array must be the same size. from inside a library, otherwise "module".CMD is used. The latter functionality is useful when debugging. o The total size of all elements in the array must not exceed the maximum size of a String Symbol (132 bytes). o "module" is the name of the module in the library to be executed. If you omit this, the module ".MAIN." is o The location of each element in the string must be executed. manually calculated from the INDEX of the desired element and the SIZE of the elements, as follows: If you do not specify the /LB switch when invoking a .SETN START (INDEX-1)*SIZE+1 Command Procedure, the ICP checks the attributes of the file to .SETN END START+SIZE-1 determine whether it is a Command Procedure Library. So, you can call your Command Procedure Library "library.CMD", and execute module .MAIN. by: This works best with arrays where the element is one byte >@library long, as the index can be used directly as both the start and the end of the substring. You can store things other than Command Procedures in a Command Procedure Library. For instance, you could store the sources for a software package there, and have the .MAIN. 3.1.1 Example (from PRN.CMD) - module extract the sources and build the package. PRN.CMD is a utility designed to print a file on an Under all releases of the ICP that support command LA-series printer connected to the printer port of a VT100- or procedure libraries, you can (officially) use the .TESTFILE VT200-series terminal. directive to test for the presence of a module in a Command Procedure Library or other universal library by: Page 5 Page 6 The horizontal pitch on an LA50 is set by an escape decremented) and clamped to a desired range. The key can sequence of the form "[w". The following array also be used to amplify the action of an arrow key; this is done translates any desired integer pitch from 1 through 16 to the by adding (or subtracting) a number greater than one, which is nearest equivalent escape sequence argument: dependent on what arrow key was used. .SETS S$PCHR "5555568800224444" All of this is accomplished by setting up String Symbols named after the six keys of interest. The escape sequence parser delivers control for all six keys to the same piece of When the desired horizontal pitch is determined (and stored code, which .PARSEs the aforementioned String Symbols and plugs in Numeric Symbol N$HPIT), the escape sequence required to set the derived attributes into its subsequent operations. the printer to that horizontal pitch is built using the String Expression: The following attributes turn out to be needed: ESCAPE+"["+S$PCHR[N$HPIT:N$HPIT]+"w" o The name of the Numeric Symbol updated by the key; o The amplification factor to apply if is in effect; 3.2 Using A String Symbol As An Attribute List o The sign of the operation on the Numeric Symbol modified by this key (+ or -); As a variant on arrays, a String Symbol can be used to store a list of attributes to be associated with the name of the o The limit beyond which the Numeric Symbol may not go; string symbol, or a portion thereof. These attributes can be tested for in place using the .TEST directive, or extracted o The type of test to make against this limit (eg: "<", using the .PARSE directive. In order to set up an attribute ">", ...). list: The String Symbols defining the keys are assembled from the o The attributes are listed in the String Symbol's value, concatenation of the appropriate attribute values, separated by punctuated by a unique character. commas: o Attributes may be subdivided by using another unique .SETS ARROWA "N$FLD,8,-,0.,<" character, to any level desired. .SETS ARROWB "N$FLD,8,+,N$FMAX,>" .SETS ARROWC "N$CVAL,10,+,N$CMAX,>" .SETS ARROWD "N$CVAL,10,-,N$CMIN,<" If the primary use of the attribute list is to search using .SETS ARROW5 "N$SCR,8,-,0.,<" .TEST, it may be helpful to start the list off with a .SETS ARROW6 "N$SCR,8,+,N$SMAX,>" punctuating character. However, there is a special case if the attributes are all one byte long, and the only purpose of the These define (in order) the up, down, right, and left arrows, list is to use it with the .TEST directive: the punctuation may and the Previous and Next Screen keys. be omitted. The following code is then used to execute all six keys (recognition of the keys is discussed later under "Screen Handling Without FMS"): 3.2.1 Example (from PRN.CMD) - .SETS KEY ARROW'CHAR' PRN.CMD is a utility designed to print a file on an .PARSE KEY "," AXS FAC SGN LIM TST LA-series printer connected to the printer port of a VT100- or .IFT GOLD .SETN ESCA0 ESCA0*'FAC'. VT200-series terminal. .SETN 'AXS' 'AXS''SGN'ESCA0 .IF 'AXS' 'TST' 'LIM' .SETN 'AXS' 'LIM' The command interface to PRN is screen driven. The arrow keys and (on the LK201 keyboard) the "Previous Screen" and "Next This code is entered with: Screen" keys have different functions, but are implemented in basically the same way: a counter is incremented (or Page 7 Page 8 o CHAR containing the last character of the escape o The naming convention must give rise to a unique symbol sequence that defines the key struck; this is forced to name for each element in an array. This is usually a "5" or "6" for the Previous and Next Screen keys, which problem only for multi-dimensional arrays, where the are named by a different convention than the arrow use of "%Rn" format control can be helpful. keys; o Symbol substitution can not be done on an arbitrary o ESCA0 containing the numeric value of the first array element. The value of that array element must be argument in the escape sequence; this is forced to 1 assigned to another, "constant-named" symbol, which is for the Previous and Next Screen keys; used instead in the desired substitution. o GOLD set to if the key was the last key struck; otherwise it is false. If (for example) the down arrow key is struck, the code is 3.3.1 Example (from UPS.CMD) - entered with CHAR = "B", ESCA0 = 1, and GOLD = . After substitution, this gives: UPS.CMD is a command procedure to send a number of files (up to 15) to another person or persons over DECmail-11. A .SETS KEY ARROWB screen is displayed, with spaces for the user to enter the .PARSE KEY "," AXS FAC SGN LIM TST addressees, the subject matter, and the names of the files to .IFT GOLD .SETN ESCA0 ESCA0*8. send. All the files desired are built into a single temporary .SETN N$FLD N$FLD+ESCA0 file, which is sent in batch mode. .IF N$FLD > N$FMAX .SETN N$FLD N$FMAX The file names are stored in an array of symbols, named This has the effect of moving the cursor forward 1 field on the S$FNnn, where "nn" is a two digit number from 00 through 14. screen (or eight fields if the key is in effect). All the file name fields on the screen are processed by the same code, which subtracts two from the field number to get the "nn" used to construct the name of the array element (subroutine ASKE is discussed under "Screen Handling Without FMS"). The file 3.3 Using Groups Of Symbols As An Array processing code follows: An array of arbitrary size can be constructed by using a .; Prompt for the name of the next group of symbols with similar names. The names of symbols in .; file. this group consist of a constant part (which can be thought of as the array name) and a variable part (which can be thought of .SETN N$ROW N$FLD+6. as the array subscript). The symbols in the array need not be .SETN N$FILE N$FLD-2. the same type, and only those elements that are actually used .SETS S$FILE S$FL'N$FILE%DR2Z' need to be defined. An array can have more than one dimension, .GOSUB ASKE 40;'N$ROW%D';10\'S$FILE' provided the naming convention for the elements is chosen .IFT .GOTO EXIT appropriately. .; Convert the file name to Array elements are referred to by using symbol substitution .; uppercase. to construct the name of the element's symbol out of the array name and the symbol(s) used to index the array. Arrays can be .DISABLE LOWERCASE indexed by symbols of any type. .SETS TEXT "'TEXT%C'" .ENABLE LOWERCASE The formation of arrays in this manner is subject to the following restrictions: .; If the file name is null, go .; process the associated escape o The naming convention used to map array elements onto .; sequence, if any. symbol names must never result in a symbol name more than six characters long. .IF TEXT = "" .GOTO ESCPSI .; Check for existence of the file, Page 9 Page 10 .; and get the full file name. 3.4.1 Example (from CRASHDUMP.CMD) - .SETS S$ERR "File 'TEXT' not found." CRASHDUMP.CMD is a crash dump analyzer suitable for sites .TESTFILE 'TEXT' where the procedure for generating the crash dump analysis .IF <> 1 .GOTO INPERR varies from system to system. This procedure accepts the name of the crashed system as input, and runs the appropriate .; Store the file name in its slot in analysis. .; the array. This command file contains a table that lists, for each .SETS S$FL'N$FILE%DR2Z' system, some help text, the name of the crash dump analyzer to use, the memory size, the crash device, the starting block on .; Redisplay the fully qualified file the crash device, and the name of the executive symbol table. .; name. This information is stored in a symbol named after the system, thus: .SETS TEXT "40;'N$ROW%D';10" .GOSUB PLOTF 'TEXT'\'' .SETS FENNY "PDP-11/84;;256;DU;;" .SETS MARVIN "PDP-11/03;CDA42;28;DY;;" .; Go handle the associated escape .SETS ZAPHOD "PDP-11/74;;1024;DR;;" .; sequence, if any. All other symbols used in this command procedure contain .SETS S$ERR "" embedded dollar signs, so any alphanumeric symbol name is likely .GOTO ESCPSI to be of interest. The reserved symbols COMMAN and P0 through P9 can be excluded by explicitly testing for them. When this command file is executed, it can simply prompt for the system name, insure that the entry is a valid symbol 3.4 Content-addressable Memory name (and is in fact the name of an existing symbol), and extract the information needed from symbol: This is really just an extension of the concept of using a group of symbol names as an array. There is no logical reason .DISABLE LOWERCASE why you can't use a String Symbol as an array subscript, .ASKS [0:6] S$SYS What system name provided the contents of the symbol give rise to a valid symbol .ENABLE LOWERCASE name. The same consideration applies to allowing the array name .IFF .GOTO SYSERR to shrink to zero bytes. What you have left is a system where .IFNDF 'S$SYS' .GOTO SYSERR the entire symbol table is an array, and the symbol names are .PARSE 'S$SYS' ";" ....... chosen to describe the information stored in the symbol. You should be aware that: o The String Symbol that contains the information to be looked up had better be validated first to be sure its 3.5 Searching A (Very) Sparse Array contents represent a legal symbol name. One of the disadvantages of using sparsely populated arrays o You must check for existence of the symbol before you is the inefficiency of weeding out nonexistent elements when use it, as a random symbol name is probably NOT defined iterating over the entire array. A better alternative may be to in the symbol table. iterate over the entire symbol table, searching for elements of the array. o Since it is probably not desirable to literally use the whole symbol table, a subset can be selected (eg: all DEC has provided Special String Symbol , which can symbols with alphanumeric names), and symbols used be used to search the symbol table. Each time this symbol is otherwise in the command procedure can be selected to referred to, it returns the name of the next symbol in the fall outside this subset (eg: names with embedded Symbol Table. The search is initialized by: dollar signs). .SETS "" Page 11 Page 12 .SETS S$SYS The end if the symbol table is indicated when returns a null string. .; If there is none, done. If you intend to use this technique, you should make note .IF S$SYS = "" .GOTO SYSASK of the following points: .; If not alphanumeric, skip. o You must refer to only once in each iteration, or you will skip symbols. A useful way to do this is: .TEST S$SYS .IFF .GOTO SYSHLL .SETS SYMNAM .; If not a String Symbol, skip o The documentation of contains warnings about .TEST 'S$SYS' its availability for general use. My experience is .IF <> 4 .GOTO SYSHLL that you might have to fiddle a bit to get it to work. See .; If it is COMMAN or P0-P9, skip LB:[1,2]INDSYS/LB:INDDMP .TEST S$NOGO ",'S$SYS'," .IF > 0 .GOTO SYSHLL for an example. I recommend against defining any new symbols inside the iteration loop. .; If it is a legal system name, .; pick it apart and display .; the identifying text; .PARSE 'S$SYS' ";" S$HELP S$JUNK 3.5.1 Example (from CRASHDUMP.CMD) - ; 'S$SYS%L6' - 'S$HELP' CRASHDUMP.CMD is a crash dump analyzer suitable for sites .; Go get the next Symbol: where the procedure for generating the crash dump analysis varies from system to system. This procedure accepts the name .GOTO SYSHLL of the crashed system as input, and runs the appropriate analysis. If the user input (obtained in the previous example) does not represent a valid system name, the symbol table is scanned, 4 BINARY FILE I/O and a list of all valid system names is produced. This is accomplished by the following code: I/O on files containing binary data can be done with the ICP, by converting the bytes in the file record to numeric .SYSERR:.; values, and then assembling the byte values in ways appropriate ; to the field in which they occur. The ICP can not process ; System "'S$SYS'" is invalid. records more than 132 bytes long, but otherwise any sequential .SYSHLP:.; file can be read. Files opened for output will have variable ; length records with "list" carriage control. RMSDES can be used ; Valid system names are: to create sequential files with other attributes, which can then .SETS "" be opened by the ICP for appending data. .; loop through Symbol Table: The binary data is interpreted by using symbol substitution with %V format control to convert the bytes in the record to .SYSHLL: their numeric values. These bytes are then assembled in an appropriate manner to yield the data in the record. .; Get next Symbol name. Page 13 Page 14 4.1 Example (from SYMDMP.CMD) 5.1 Screen Handling With FMS SYMDMP.CMD is a command file that reads a .OBJ or .STB The RSX-11M+ ICP comes with an interface to FMS-11. You file, and displays the types and values of the symbols it finds can use this interface to generate a form-driven application. there. Demonstration of the FMS capability of the ICP is provided by: The decoding of a binary byte is relatively @LB:[1,2]INDSYS.CLB/LB:FMSDEM straightforward: .SETS S$B0 S$REC[5:5] In order to create your own FMS-11 driven command .SETN O$FLG 'S$B0%V'&377 procedure: This extracts byte 5 of the record and stores its value in the o Forms must be designed and inserted in a form library, Numeric Symbol O$FLG. just as for any FMS application. This implies the need for an FMS license. Binary words are processed by extracting two consecutive binary bytes, and combining them in the correct order: o The .FORM directive is used to display forms and gather input. .SETS S$B0 S$REC[1:1] .SETS S$B1 S$REC[2:2] o You can use .IFENABLED FMS to determine if FMS support .SETN O$B0 'S$B0%V'&377 is available. .SETN O$B1 'S$B1%V'&377 .SETN O$W O$B1*400+O$B0 o Special Numeric Symbol will contain the status code for the previous FMS operation. You can also (if This extracts the binary word starting at byte 1 of the record, necessary) use .IFDF to determine whether and stores it in Numeric Symbol O$W. .IFENABLED FMS will produce a syntax error. RAD-50 words are processed in the same manner as binary words, and then converted to ASCII using %X format control: .SETS S$B0 S$REC[1:1] 5.2 Screen Handling Without FMS .SETS S$B1 S$REC[2:2] .SETN O$B0 'S$B0%V'&377 If you don't own RSX-11M+ and FMS-11, you can write your .SETN O$B1 'S$B1%V'&377 own screen handler for the ICP. This is not a trivial .SETN O$W O$B1*400+O$B0 undertaking, and several points must be observed to get your .SETS S$SYM "'O$W%X'" screen handler to work: .SETS S$B0 S$REC[3:3] .SETS S$B1 S$REC[4:4] o The ICP will have to do all input through the .ASKS .SETN O$B0 'S$B0%V'&377 directive. The prompt sequence of the .ASKS directive .SETN O$B1 'S$B1%V'&377 is used to position the cursor for input. .SETN O$W O$B1*400+O$B0 .SETS S$SYM "'S$SYM''O$W%X'" o The ICP must be conditioned to accept escape sequences by issuing the This extracts the six RAD-50 characters stored in bytes one through four of the record, and converts them to ASCII in String .ENABLE ESCAPE-SEQUENCE Symbol S$SYM. directive. o The terminal driver must be conditioned to recognize 5 SCREEN HANDLING escape sequences and pass them to the ICP by issuing the MCR command SET /ESCSEQ=TI: Page 15 Page 16 If you want to get really sophisticated, you can or its DCL equivalent. SET /NOECHO=TI: o You must issue the and have the ICP take care of displaying the characters on the .DISABLE DISPLAY screen. ICP directive to prevent unwanted characters from being displayed on the screen by the .ASKS directive. 5.2.1 Example (from PRN.CMD) - o The ICP must parse the escape sequence off the end of the .ASKS input string, and interpret it. PRN.CMD is a utility designed to print a file on an LA-series printer connected to the printer port of a VT100- or VT200-series terminal. In addition to the above, there are several points which are not absolutely essential, but which are highly recommended Both the ICP and the terminal driver must be initialized to to improve the performance and maintainability of your screen handle the escape sequences involved with screen input: handler: .ENABLE SUBSTITUTION o You should issue the .DISABLE DISPLAY .DISABLE DETACH .DISABLE DETACH .ENABLE ESCAPE-SEQUENCE ICP directive, so that input from additional keystrokes 'MCR'SET /LOWER=TI: will not be lost if you type faster than the ICP can 'MCR'SET /ESCSEQ=TI: process your input. Note that if you do this, programs 'MCR'SET /BUF=TI:132. run by the ICP may not have access to your terminal. o Constant escape sequences (eg: home cursor, clear Next, a selection of control characters suitable for ASCII screen, setup sequences) should be assigned to terminals is defined: appropriately named String Symbols on initialization. This enhances portability, and makes it easier to .SETN NJUNK 16 ! Shift out handle multiple terminal types. .SETS SO "'NJUNK%V'" .SETN NJUNK 17 ! Shift in. o Variable escape sequences (eg: cursor postioning) .SETS SI "'NJUNK%V'" should be generated in .GOSUB modules, for the same .SETN NJUNK 33 ! Escape reasons. .SETS ESCAPE "'NJUNK%V'" .SETN NJUNK 217 ! Single shift 3 o Literal escape sequences should not be embedded in the .SETS SS3 "'NJUNK%V'" command file. If you violate this rule, you may not be .SETN NJUNK 233 ! Ctrl Seq Init able to TYPE the procedure on your terminal. .SETS CSI "'NJUNK%V'" o Input should also be done in a .GOSUB module, so that the escape sequence can be easily parsed off the rest After symbols have been defined for the individual control of the input. characters, control sequences to perform specific functions can be built. The following are suitable for ANSI terminals: o Avoid leaving the cursor on the last line of the screen. If you cannot avoid this, repaint the screen .SETS HOME ESCAPE+"[H" !Home cursr after the inevitable scroll-up. .SETS CLEAR ESCAPE+"[J" !Clr screen .SETS CLRLIN ESCAPE+"[K"!Clear line .SETS BOLD ESCAPE+"[1m" !Bold video .SETS REV ESCAPE+"[7m" !Revers vid .SETS NML ESCAPE+"[m" !Normal vid Page 17 Page 18 .SETS BOTTOM ESCAPE+"[24;1H" .SETS ESCSEQ "" .DISABLE LOWERCASE .ASKS [::FLDTXT] TEXT 'FLDTMP' Last, a control sequence is defined to initialize the .ENABLE LOWERCASE terminal to the desired state. The following initializes a DEC VT100 or VT200 series terminal by homing the cursor and clearing .; Select the processor for the next the screen, loading the normal ASCII character set into G0 and .; field. the graphics character set into G1, and selecting G0: .SETS S$ERR "" .SETS INIT HOME+CLEAR+ESCAPE+"(B" .INC N$FLD .SETS INIT INIT+ESCAPE+")0"+SI .SETS S$GOTO "DISPAT" .IFT .RETURN Now that the constant control sequences are taken care of, .; Strip the terminating escape we need a subroutine to prompt for the current field. The .; sequence from the field. example given below is entered by: .TEST TEXT ESCAPE .GOSUB ASKE size;line;column\text .IF = 0 .TEST TEXT CSI .IF = 0 .TEST TEXT SS3 This positions the cursor at the given line and column, and .IF = 0 .GOTO ASKX displays the given text in a reverse video field of width .SETS ESCSEQ TEXT[:*] 'size'. The .ASKS directive is used to get the response. The .SETS TEXT TEXT[1:-1] text part of the response is returned in String Symbol TEXT, and .ASKX:.; the escape sequence in String Symbol ESCSEQ. If TEXT is null, it is loaded with the input text string. Finally, the user's .; If there was no text entered, input is redisplayed (in upper case) in the field. The code to .; supply the default. do all this is: .IF TEXT = "" .SETS TEXT FLDTXT .ASKE: .; Redisplay the field. .; Separate the command into its .; components. .TEST TEXT .SETN PAD 'FLDSIZ'.- .PARSE COMMAN ";" FLDSIZ COMMAN .SETS FLDTMP BLANKS[1:PAD] .PARSE COMMAN "\" COMMAN FLDTXT .SETS FLDTMP REV+TEXT+FLDTMP .SETS FLDTMP COMMAN+FLDTMP+BOTTOM .; Call on POSITN to build the escape .SETS FLDTMP FLDTMP+NML+CLRLIN+HOME .; sequence that positions the ;'FLDTMP' .; cursor. .RETURN .GOSUB POSITN 'COMMAN%C' The above subroutine relies on subroutine POSITN to .; Build the prompt string for the generate the escape sequence to position the cursor. The .; field. calling sequence for POSITN is .TEST FLDTXT .GOSUB POSITN line;column .SETN PAD 'FLDSIZ'.- .SETS FLDTMP BLANKS[1:PAD] and the escape sequence is returned in String Symbol COMMAN. .SETS FLDTMP REV+FLDTXT+FLDTMP The following is suitable for an ANSI compatible terminal: .SETS FLDTMP COMMAN+FLDTMP+COMMAN .POSITN: .; Get the input from the field. .SETS COMMAN "'COMMAN%C'" .SETS COMMAN ESCAPE+"["+COMMAN+"H" Page 19 Page 20 .RETURN .SETS ESCTYP "ESC" .GOTO ESCPSR Once the text part of each field has been processed, the .; First character is , or escape sequence that terminated it (if any) must be handled. This is done by a finite state machine, where each character of .INI217:.; the escape sequence is dispatched for processing based on what it is and the current state of the system. In the example, the .; First was and second is name of the current state is stored in String Symbol ESCTYP, and .; "O"; set state: each character is handled by executing a .GOTO to a label composed of the state name and the ASCII code for the character .ESC117:.; (in octal). The example parses ANSI escape sequences, composed .SETS ESCTYP "SS3" of an introductory sequence ( or or ), some .GOTO ESCPSR arguments (decimal numbers separated by semicolons), and a terminating character. The sequences "[" and "O" are .; Got nnn~ = one of the "F" recognized as alternates for and , respectively: .; keys. Dispatch appropriately. .; Initialize the escape sequence .CSI176:.; .; parser: .GOTO FKY'ESCA0%D' .ESCPSI: .; Got P = PF1 - use it as .SETS ESCTYP "INI" ! Parser "state" .; shift key: .SETN ESCAMX 0. ! Arguments .SETN ESCA0 0. ! First argument .SS3120:.; .SETN N$FLD N$OFLD .; Main parser loop: .SETT GOLD .GOTO ESCPSI .; Strip off the next character (if .; any), convert it to a number, and .; do a "computed" GO TO based on .; current parser state and character .; code: 6 ERROR CONTROL .ESCPSR: It can be useful to attempt an operation even though it may .IF ESCSEQ = "" .GOTO 'S$GOTO' produce an error in the ICP. Although the ICP can not be set to .SETS CHAR ESCSEQ[1:1] ignore such errors, it can be set to dispatch them to the label .SETS ESCSEQ ESCSEQ[2:*] of your choice for handling. .SETN CVALUE 'CHAR%V' .ONERR ESCPSE To cause errors to be trapped to your error handler, issue .GOTO 'ESCTYP''CVALUE' the ICP directive: .; Any unrecognized characters end .ONERR label .; up here. The next error encountered will cause control to be transferred .ESCPSE:.; to the given label. .SETN N$FLD N$OFLD .SETF GOLD Errors are divided into numbered classes, as described in .GOTO 'S$GOTO' the ICP documentation. You can set bits in Special Numeric Symbol to determine which classes are trapped to your .; First character = ; set error handler. Untrapped errors will cause the ICP to abort. .; state: By default, only Class 1 errors are trapped. On entry to the error handler, Special Numeric Symbol contains the .INI33:.; Error Class Number of the error encountered. The .ONERR Page 21 Page 22 directive must be reasserted after each error trapped. .SETN CVALUE 'CHAR%V' .ONERR ESCPSE The Error Classes are pretty broad (there are only two), .GOTO 'ESCTYP''CVALUE' and don't tell you very much about what actually caused the fault. If you are expecting more than one source of error, you .; Any unrecognized characters end will need to build your own logic to distinguish between them. .; up here. The manual says you should not resume processing after .ESCPSE:.; trapping a Class 2 Error, as the state of the ICP is .SETN N$FLD N$OFLD indeterminate. I have found that it works in some cases, but .SETF GOLD recommend trying each case out before you build an application .GOTO 'S$GOTO' around it. 6.1 Example (from PRN.CMD) 7 PARSING AN MCR- OR DCL-LIKE SYNTAX PRN.CMD is a utility designed to print a file on an Command Files can be invoked in much the same way as a CLI LA-series printer connected to the printer port of a VT100- or command, and the parameters passed are available to the Command VT200-series terminal. File in String Symbols P0-P9. Parsing these parameters normally takes place in two phases: This example follows on from the one in the previous topic. The escape sequence parser may receive an escape sequence that o Parsing the file specification(s); it is not equipped to handle. It would be nice to recover from the ICP error that results. A trap for this is set in the o Parsing the switches and options. .ONERR directive just before the main parser loop dispatches the character. If the character turns out to be unrecognized, the You need to design a command syntax that is both clear and escape sequence processing is aborted and reinitiated from that easily parsed. Either MCR or DCL can serve as a model. point. This will probably result in more aborts until the buffer is empty, or until an , , or is You get a "nicer" parser if you can process all the file encountered. The code here also appeared in the previous specifications in one loop, with an inner loop for the switches. example: This way, all the work can be done in one place. .; Initialize the escape sequence You may wish to check for a null command line, and get the .; parser: information you need through .ASKx directives. .ESCPSI: If the syntax for switches is properly defined, your switch .SETS ESCTYP "INI" ! Parser "state" parser code will be completely generic - that is, you can add .SETN ESCAMX 0. ! Arguments switches without modifying the parser. This is done by: .SETN ESCA0 0. ! First argument o Defining a consistent symbol name convention for .; Main parser loop: storing switch settings. In the example, "V$xx" is used, where "xx" represents the switch name, and the .; Strip off the next character (if Symbol Type of V$xx determines how the switch is .; any), convert it to a number, and processed. .; do a "computed" GO TO based on .; current parser state and character o Defining a consistent and restricted switch syntax. In .; code: the example, no switch may have more than one argument. .ESCPSR: .IF ESCSEQ = "" .GOTO 'S$GOTO' .SETS CHAR ESCSEQ[1:1] .SETS ESCSEQ ESCSEQ[2:*] Page 23 Page 24 7.1 Example (from SYMDMP.CMD) .PARSE S$FIL "/" S$FIL S$SWIT .PARSE S$OUT "/" S$OUT S$JUNK SYMDMP.CMD is a command file that reads a .OBJ or .STB .SETS S$SWIT "/"+S$SWIT+"/"+S$JUNK file, and displays the types and values of the symbols it finds there. Once the actual switches have been isolated, it is simple The command syntax for SYMDMP (which also has an to loop through the list of them, checking existence and interactive mode) is validating: >@SYMDMP outfile=infile/switches .SWITLP: .IF S$SWIT = "" .GOTO PROCES in MCR syntax, or .; Peel the next switch off, and >@SYMDMP infile/switches outfile .; get its arguments: in DCL syntax. The legal switches are: .PARSE S$SWIT "/" S$SWX S$SWIT .PARSE S$SWX ":" S$SWX S$SWP /BR - insert page breaks in the output file .; Figure out whether it is asserted .; or negated: /SP - submit the output file to the print spooler .SETT L$ASRT .IF S$SWX = "" .GOTO SWITLP Switches may appear on either the input or the output file. .IF S$DSH = S$SWX[1:1] .GOTO SWITNM .IF S$NO <> S$SWX[1:2] .GOTO SWITAS The first part of the parsing process is to define all .SETS S$SWX S$SWX[2:*] switches and their defaults, and separate the actual switch .SWITNM:.; specifications from the rest of the command: .SETS S$SWX S$SWX[2:*] .SETF L$ASRT .; Define and initialize the .SWITAS:.; .; command switches: .SETS S$SWX S$SWX[1:2] .SETF V$SP ! /SP (spool) .; See if this switch has a .SETT V$BR ! /BR (page break) .; corresponding V$sw symbol: .; Determine processing mode .TEST S$SWX .; (interactive or command line): .IFF .GOTO SWIBAD .IFNDF V$'S$SWX' .GOTO SWIBAD .IF P1 = "" .GOTO PROMPT .; Dispatch the rest based on the .; Get the file specs, from either .; symbol type: .; MCR or DCL syntax: .TEST V$'S$SWX' .IF P2 <> "" .GOTO SWIEXT .GOTO SWIT'' .PARSE P1 "=" S$OUT S$FIL .IF S$FIL <> "" .GOTO SWIEXT .; Logical symbol. Set its value to .SETS S$FIL S$OUT .; the switch polarity: .SETS S$OUT "" .SWIT0:.; .; Peel the switches off the file .IF S$SWP <> "" .GOTO SWINPR .; specifications: .SETL V$'S$SWX' L$ASRT .GOTO SWITLP .SWIEXT:.; Page 25 Page 26 .; Numeric symbol. Set its value to Utility. It prompts the user for how the operation is to be .; the switch parameter: done, and constructs a BRU command (along with the necessary device allocations, mounts, dismounts, CON commands, and so on) .SWIT2:.; based on the user's input and the current state of the system. .IFF L$ASRT .GOTO SWINNG .TEST S$SWP One of the options available to the user is to initialize .IFF .GOTO SWIIVP the output disk in a manner different than the input disk. For .SETN V$'S$SWX' 'S$SWP' this option, it was desired to use the same algorithm to .GOTO SWITLP calculate initial and maximum index file size as is used by the INITIALIZE command. The maximum index file size depends on the .; String symbol. Set its value to volume size, and the calculation must be done in double .; the switch parameter: precision. .SWIT4:.; The following subroutine will add two 32 bit numbers, each .IFF L$ASRT .GOTO SWINNG stored in a pair of Numeric Symbols named by the convention .SETS V$'S$SWX' S$SWP "xxxxxn" where "xxxxx" is the double precision "variable" name .GOTO SWITLP passed to the subroutine, and "n" is 0 or 1. The calling sequence is: .GOSUB VADD variable variable 8 MULTIPLE PRECISION ARITHMETIC The sum is returned in the left-hand variable. The code to do this is: The ICP is capable of doing arithmetic on 16-bit signed or unsigned integer values. Occasionally, this is not sufficient. .VADD: Normally, access to the carry bit is necessary for extended precision, and this is not available in the ICP. However, if .; Extract the variable names from the operations are performed eight bits at a time, the ninth bit .; the argument list. can be used as the carry bit in addition and subtraction. Since the product of two eight bit numbers is never more than sixteen .SETS COMMAN "'COMMAN%C'" bits, multiplication can also be done eight bits at a time, .PARSE COMMAN " " ST$A ST$B summing the cross products at the end. Division has to be done by the shift and subtract method, and is the slowest of the four .SETN OT$B0 'ST$B'0 conventional operations. .SETN OT$B1 'ST$B'1 Obviously, a 32 bit result can not be stored in a 16-bit .; Separate the first addend into its Numeric Symbol. However, a pair of symbols will do nicely. I .; constituent bytes. recommend the use of a two-element array, created as described earlier under "Using Groups of Symbols as an Array". .SETN OT$A0 'ST$A'0&377 Alternatively (or in addition), the values can be converted to .SETN OT$A1 'ST$A'0/400&377 decimal and stored in a String Symbol. .SETN OT$A2 'ST$A'1&377 .SETN OT$A3 'ST$A'1/400&377 To isolate the low-order byte of one of the operands, it suffices to perform a bitwise logical AND with the value 377 .; Separate the second addend into (octal). The high byte is obtained by dividing by 400 (octal). .; its constituent bytes. Assembling the resultant bytes into a word is the reverse of these steps. .SETN OT$B3 OT$B1/400&377 .SETN OT$B2 OT$B1&377 .SETN OT$B1 OT$B0/400&377 .SETN OT$B0 OT$B0&377 8.1 Example (from BRU.CMD) .; Add the corresponding bytes of the BRU.CMD is a preprocessor for BRU, the Backup and Restore .; two addends, with carry. Page 27 Page 28 that is not in the manual. .SETN OT$C0 OT$A0+OT$B0 .SETN OT$C1 OT$A1+OT$B1 RSX LB:[1,2]INDSYS.CLB .SETN OT$C1 OT$C1+(OT$C0/400&377) Sample command routines. .SETN OT$C2 OT$A2+OT$B2 .SETN OT$C2 OT$C2+(OT$C1/400&377) RSX-11M/M-PLUS RMS-11 Utilities .SETN OT$C3 OT$A3+OT$B3 The reference for RMSDES. .SETN OT$C3 OT$C3+(OT$C2/400&377) RSX-11M/M-Plus Task Builder Manual .; Strip out the carry bits. Documents object file layout. .SETN OT$C0 OT$C0&377 RSX-11M/M-PLUS Indirect Command .SETN OT$C1 OT$C1&377 Processor Manual .SETN OT$C2 OT$C2&377 The primary reference for the ICP .SETN OT$C3 OT$C3&377 under RSX. .; Reconstitute the sum. RSX-11 Utilities Manual Reference for the librarian .SETN 'ST$A'0 OT$C1*400+OT$C0 task (LBR). .SETN 'ST$A'1 OT$C3*400+OT$C2 RSX-11M-PLUS Guide to Writing an .RETURN I/O Driver Reference for the UCB data structures. VT220 Programmer Pocket Guide 9 BIBLIOGRAPHY Documents escape sequences for VT2xx terminals. "Nifty Things to Do with RSX Indirect Command Files" Allen A. Watson RSX/IAS SIG Symposium Handout Spring 1983 DECUS US Symposium "Nifty Things to Do with RSX Indirect Command Files" Allen A. Watson The DEC Professional March 1984 "RSX 11 System Management, A Beginner's Perspective" Arnold S. De Larisch Several examples of Indirect command files. LA50 Printer Programmer Reference Manual Documents printer escape sequences. RSX LB:[1,2]ICP.HLP On-line help file for ICP. Contains some information