Weird Tricks with the RSX Indirect Command Processor - RX015 - T. R. Wyant E. I. DuPont de Nemours A. E. Levan System Research Laboratories December 10, 1990 Housekeeping Outline Housekeeping Command Procedure Libraries Structured Data Types Binary File I/O Screen Handling Error Control Parsing an MCR- or DCL-like syntax Multiple Precision Arithmetic Bibliography Housekeeping (1.1) Goal The goal of this presentation is to exhibit some of the more advanced, exotic, and otherwise weird things that can be done with the RSX Indirect Command Processor (ICP), and to stimulate more ideas in the same vein. This presentation is aimed at an audience that is familiar with the RSX ICP, though attendance of "Introduction to the RSX, P/OS, and RT Indirect Command File Processor" (RX009) should give sufficient background. These slides and all command files cited as examples will be distributed on the FALL, 1990 RSX/IAS SIG tape. (1.2) Caveats The current releases of all the operating systems are assumed. The examples cited all work under RSX-11M+ V3.0 C. 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. (1.3) Acknowledgment 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.0) Command Procedure Libraries A command procedure made up of many modules can be kept in a universal library. To create the library: LBR library.CLB/CR::::UNI:CMD To execute a module @library/LB:module To execute module .MAIN.: @library/LB - or - @library.CLB To call another module on the same library as the caller: @/LB:module You can store things other than command procedures in a command procedure library. Readily available examples: LB:[1,2]INDSYS.CLB LB:[200,200]SYSGEN.CLB LB:[137,10]NETGEN.CLB Structured Data Types (3.1) Using a String Symbol as an Array Small arrays can be stored in a String Symbol and extracted by forming a substring. All elements in the array must be the same size. The total size of all elements in the array must not exceed the maximum size of a String Symbol. The start and end of each element in the string must be manually calculated from the INDEX of the desired element and the SIZE of the elements, as follows: .SETN START (INDEX-1)*SIZE+1 .SETN END START+SIZE-1 This works best with arrays where the element is one byte long, as the index can be used directly as both the start and the end of the substring. Structured Data Types Using a String Symbol as an Array (continued) (3.1.1) Example (from PRN.CMD) 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. The user selects the desired horizontal pitch, which is stored in Numeric Symbol N$HPIT The mapping of horizontal pitch to escape sequence argument is stored in String Symbol S$PCHR: .SETS S$PCHR "5555568800224444" The escape sequence is built by: .SETS S$HDR ESCAPE+"["+S$PCHR[N$HPIT:N$HPIT]+"w" Structured Data Types (3.2) Using a String Symbol as an Attribute List A String Symbol can be used to store a list of attributes to be associated with the name of the string symbol, or a portion thereof. The attributes are listed in the string symbol's value, punctuated by a unique character. Attributes may be subdivided by using another unique character. Attributes can be checked using the 2-argument .TEST directive. It may help to start the list with a punctuating character if you intend to do this. Attributes can be extracted using the .PARSE directive. Structured Data Types Using a String Symbol as an Attribute List (continued) (3.2.1) Example (from PRN.CMD) 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. The arrow keys and the previous and next screen keys perform different functions, but all operate by incrementing or decrementing a Numeric Symbol and clamping the result to a limit. The particulars are defined as follows: .; Define parameters used in processing the arrow keys: .; These are defined by: .; .SETS ARROWx "axis,fac,sign,limit,test" .; where: .; x = last character of escape sequence; .; axis = name of symbol to update; .; fac = factor to apply if PF1 in effect; .; sign = direction of travel along axis; .; limit = limiting value on the axis; .; test = type of test to make against limit. .SETS ARROWA "N$FLD,8,-,0.,<" ! A = Up arrow. .SETS ARROWB "N$FLD,8,+,N$FMAX,>" ! B = Down arrow. .SETS ARROWC "N$CVAL,10,+,N$CMAX,>" ! C = Right arrow. .SETS ARROWD "N$CVAL,10,-,N$CMIN,<" ! D = Left arrow. .SETS ARROW5 "N$SCR,8,-,0.,<" ! Fake for "Prev Screen" .SETS ARROW6 "N$SCR,8,+,N$SMAX,>" ! Fake for "Next Screen" These are executed by: .PARSE ARROW'CHAR' "," AXIS FAC SIGN LIMIT TEST .IF ESCA0 = 0 .SETN ESCA0 1. ! Force param. .IFT GOLD .SETN ESCA0 ESCA0*'FAC'. ! Apply PF1. .SETN 'AXIS' 'AXIS''SIGN'ESCA0 ! Set new loc. .IF 'AXIS' 'TEST' 'LIMIT' .SETN 'AXIS' 'LIMIT' .SETF GOLD ! Clear shift key. .GOTO ESCPSR ! Get next character. Structured Data Types (3.3) Using Groups of Symbols as an Array An array of arbitrary size can be constructed by using a group of symbols with similar names. A symbol is defined for each accessible element in the array. These need not be the same type. Only those elements that are actually used need be defined. Arrays can be sparsely populated, or have ragged rows. The names of the individual symbols consist of a constant part (which can be thought of as the name of the array) and a variable part (which can be thought of as the index into the array). Array elements are referred to by using symbol substitution to construct the element's symbol name out of the array name and the element index(es). Substitution can not be done on an arbitrary array element. The method chosen for encoding the index(es) in the array element's symbol name must give rise to legal and unique symbol names for each element in the array. Use of %RnZ format control can be helpful when using Numeric Symbols as array indices. Structured Data Types Using Groups of Symbols as an Array (continued) (3.3.1) Example (from UPS.CMD) UPS.CMD is a command procedure to automate the transmission of a number of files over DECmail-11. The names of the files are originally stored in String Symbol S$FILE, so the .TESTFILE directive can be used to check for existence. The number of files entered is counted in Numeric Symbol N$FILE. The file name is stored in element N$FILE of array S$FL by: .SETS S$FL'N$FILE%DR2Z' S$FILE When required, the file name is extracted from the array by: .SETS S$FILE S$FL'N$FILE%DR2Z' Structured Data Types (3.4) Content-addressable Memory In this scheme, the entire symbol name is chosen to reflect the content of the symbol. For example, information about a DECnet node can be stored in a symbol named after that node. In effect, this is using the entire symbol table as an array. The string symbol that contains the symbol name to be looked up had better be validated first to be sure it contains a legal symbol name. You must check for existence of the symbol before you use it, as a random symbol name is probably NOT defined in the symbol table. Structured Data Types Content-addressable Memory (continued) (3.4.1) Example (from CRASHDUMP.CMD) CRASHDUMP.CMD is a crash dump analyzer preprocessor, that generates a CDA run appropriate to the system being analyzed, based on the system name. .; The supported systems must be defined via: .; .SETS sysnam "cdanal;memsiz;crdev;blk;stbnam;hlptxt" .; Where: .; sysnam is the name of the system to which the .; information pertains; .; cdanal is the name of the crash dump analyzer task .; file - the defaults are: .; device ---- LB: .; directory - .; name ------ CDA .; type ------ .TSK .; memsiz is the memory size for the system; .; crdev is a list of legal crash devices (separated by .; commas); .; blk is the block on which the crash dump starts; .; stbnam is the STB file name - the defaults are: .; device ---- LB: .; directory - .; name ------ RSX11M .; type ------ .STB .; hlptxt is identifying text for the system. .; .SETS FENNY "CDAFSL;256;DR;2;;PDP 11/84" .SETS MARVIN "CDA41;28;DX,DY;1;[1,64];PDP 11/03" .SETS ZAPHOD "CDAFSL;512;DR;2;;PDP 11/74" .; .; Get the system being dumped. .; .SYSASK: ; .DISABLE LOWERCASE .ASKS [0:6:] S$SYS What system is crashdump for .ENABLE LOWERCASE .IFT .GOTO SYSHLP .IFF .GOTO SYSERR .TEST S$NOGO ",'S$SYS'," .IF > 0 .GOTO SYSERR .IFDF 'S$SYS' .GOTO SYSOK Structured Data Types (3.5) Searching a (Very) Sparse Array It may be faster to iterate over the entire symbol table than over the elements of a very sparse array. Each time the Special String Symbol is referred to, it returns the name of the next symbol in the Symbol Table. To initialize the iteration, you must: .SETS "" You must refer to only once in each iteration, or you will skip symbols. A useful way to do this is: .SETS SYMNAM I recommend against defining any new symbols inside the iteration loop. The documentation of contains warnings about its availability for general use. My experience is that you might have to fiddle a bit to get it to work. For an example of in action, see: LB:[1,2]INDSYS/LB:SYMDMP Structured Data Types Searching a (Very) Sparse Array (continued) (3.5.1) Example (from CRASHDUMP.CMD) CRASHDUMP.CMD is a crash dump analyzer preprocessor, that generates a CDA run appropriate to the system being analyzed, based on the system name. ; Valid system names are: .SETS "" .; Now, loop through the Symbol Table: .SYSHLL: .; Get the next Symbol name; if none, we are done: .SETS S$SYS .IF S$SYS = "" .GOTO SYSASK .; If it is not alphanumeric, we do not want it: .TEST S$SYS .IFF .GOTO SYSHLL .; If it is not a String Symbol, we do not want it: .TEST 'S$SYS' .IF <> 4 .GOTO SYSHLL .; If it is COMMAN or P0-P9, we do not want it: .TEST S$NOGO ",'S$SYS'," .IF > 0 .GOTO SYSHLL .; It it a legal system name; pick it apart and display .; the identifying text; .PARSE 'S$SYS' ";" S$CDA S$MEM S$CDL S$CBK S$STB S$HELP ; 'S$SYS%L6' - 'S$HELP' .; Go get the next Symbol: .GOTO SYSHLL (4.0) Binary File I/O I/O on files containing binary data can be done with the ICP, by converting the bytes to numeric values, and then assembling the byte values in ways appropriate to the field in which they occur. Any sequential file can be opened for read or append access. Files opened for output will have variable length records, with "list" carriage control. Use substitution with %V format control to convert bytes to their numeric values. If you wish to write a file with "unusual" attributes (fixed length records, no spanned blocks, etc.) you can invoke RMSDES to create an empty file, with the desired attributes, and then open it for append access. Binary File I/O (4.1) Example (from SYMDMP.CMD) SYMDMP.CMD is a command file that reads a .OBJ or .STB file, and displays the symbols it finds there. Example of extracting a binary byte (from byte 5 of the record) and storing its value in Numeric Symbol O$FLG: .SETS S$B0 S$REC[5:5] .SETN O$FLG 'S$B0%V'&377 Example of extracting a binary word (found in bytes 1 and 2 of the record) and storing its value in Numeric Symbol O$W: .SETS S$B0 S$REC[1:1] .SETS S$B1 S$REC[2:2] .SETN O$W ('S$B1%V'&377)*400+('S$B0%V'&377) Example of extracting 6 characters (stored in RAD-50 in bytes 1 through 4 of the record) and storing them in String Symbol S$SYM: .SETS S$B0 S$REC[1:1] .SETS S$B1 S$REC[2:2] .SETN O$W ('S$B1%V'&377)*400+('S$B0%V'&377) .SETS S$SYM "'O$W%X'" .SETS S$B0 S$REC[3:3] .SETS S$B1 S$REC[4:4] .SETN O$W ('S$B1%V'&377)*400+('S$B0%V'&377) .SETS S$SYM "'S$SYM''O$W%X'" Screen Handling (5.1) Screen Handling With FMS The RSX-11M+ ICP comes with an interface to FMS-11. Forms must be designed and inserted in a form library, just as for any FMS application. The .FORM directive is used to display forms and gather input. You can use .IFENABLED FMS to determine if FMS support is available. You can get a demonstration of the FMS capability of the ICP by: @LB:[1,2]INDSYS.CLB/LB:FMSDEM Screen Handling (5.2) Screen Handling Without FMS If you don't own RSX-11M+ and FMS-11, you can write your own screen handler for the ICP. The ICP must do all input through the .ASKS directive. The terminal must be conditioned so that escape sequences generated by the function keys are passed at the end of an input string: MCR>SET /ESCSEQ=TI: The ICP must be conditioned so that escape sequences generated by the function keys are accepted at the end of an input string: .ENABLE ESCAPE-SEQUENCE The prompt sequence of the .ASKS is used to position the cursor for input. Unwanted characters are supressed by: .DISABLE DISPLAY The ICP must parse the function key escape sequence off the end of the .ASKS input string, and interpret it. Screen Handling (5.2) Screen Handling Without FMS (continued) You should enable use of the type-ahead buffer: .DISABLE DETACH Literal escape sequences should not be embedded in the command file. Constant escape sequences (eg: home cursor, clear screen, setup sequences) should be assigned to appropriately named string symbols on initialization. Variable escape sequences (eg: cursor postioning) should be generated in .GOSUB modules. Input should also be done in a .GOSUB module, so that the escape sequence can be easily parsed off the rest of the input. Avoid leaving the cursor on the last line of the screen. If you must, repaint the screen after the inevitable scroll-up. You can SET /NOECHO=TI:, and have the ICP take care of displaying the characters on the screen. Screen Handling Screen Handling Without FMS (continued) (5.2.1) Example (from PRN.CMD) 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. .; Required ICP initialization: .ENABLE SUBSTITUTION .DISABLE DISPLAY .DISABLE DETACH .ENABLE CONTROL-Z .ENABLE ESCAPE-SEQUENCE .ENABLE OVERFLOW .; Required TT: driver initialization .ENABLE QUIET 'MCR'SET /FORMFEED=TI: 'MCR'SET /LOWER=TI: 'MCR'SET /ESCSEQ=TI: 'MCR'SET /BUF=TI:132. .DISABLE QUIET .; Useful symbol definitions (for ASCII terminals): .SETN NJUNK 33 ! Define ESCAPE to be .SETS ESCAPE "'NJUNK%V'" ! an character .SETN NJUNK 217 ! Define SS3 to be an .SETS SS3 "'NJUNK%V'" ! (="O") .SETN NJUNK 233 ! Define CSI to be a .SETS CSI "'NJUNK%V'" ! (="[") .; Useful symbol definitions (for ANSI terminals): .SETS HOME ESCAPE+"[H" ! HOME homes cursor .SETS CLEAR ESCAPE+"[J" ! CLEAR clears screen .SETS CLRLIN ESCAPE+"[K" ! Clear line. .SETS BOLD ESCAPE+"[1m" ! Bold video. .SETS REV ESCAPE+"[7m" ! Reverse video .SETS NML ESCAPE+"[m" ! Normal screen attrib. .SETS BOTTOM ESCAPE+"[24;1H" .; The following initializes a DEC VT100 or VT200 series .; terminal by homing and clearing the screen, loading the .; normal ASCII character set into G0 and the graphics .; character set into G1, and selecting G0. .SETS INIT HOME+CLEAR+ESCAPE+"(B"+ESCAPE+")0"+SI+NML Screen Handling Screen Handling Without FMS (continued) (5.2.1) Example (from SCRED.CMD) (continued) And, some useful subroutines: .; .; .GOSUB ASKE size;line;column\fldtxt .; .; Positions the cursor at the given line and column, .; displays "fldtxt" in a reverse video field, .; and issues a .ASKS. On return, .; TEXT contains the text part of the answer; .; ESCSEQ contains the escape sequence; .; contains the location of the escape .; character. .; .ASKE: .PARSE COMMAN ";" FLDSIZ COMMAN .PARSE COMMAN "\" COMMAN FLDTXT .GOSUB POSITN 'COMMAN%C' .TEST FLDTXT .SETS FLDTMP FLDTXT+BLANKS[+1:'FLDSIZ'.] .SETS ESCSEQ "" .INC N$FLD .DISABLE LOWERCASE .ASKS [::FLDTXT] TEXT 'COMMAN''REV''FLDTMP''COMMAN' .ENABLE LOWERCASE .SETS S$ERR "" .SETS S$GOTO "DISPAT" .IFT .RETURN .TEST TEXT ESCAPE .IF = 0 .TEST TEXT CSI .IF = 0 .TEST TEXT SS3 .IF <> 0 .SETS ESCSEQ TEXT[:*] .IF <> 0 .SETS TEXT TEXT[1:-1] .IF TEXT = "" .SETS TEXT FLDTXT .TEST TEXT .SETS FLDTMP TEXT+BLANKS[+1:'FLDSIZ'.] ;'COMMAN''REV''FLDTMP''BOTTOM''NML''CLRLIN''HOME' .RETURN .; .; .GOSUB POSITN line;column .; .; returns the escape sequence in COMMAN. .; .; The following is suitable for an ANSI terminal. .; .POSITN: .SETS COMMAN ESCAPE+"["+"'COMMAN%C'"+"H" .RETURN Screen Handling Screen Handling Without FMS (continued) (5.2.1) Example (from SCRED.CMD) (continued) .; Initialize the escape sequence parser: .ESCPSI: .SETS ESCTYP "INI" ! Set parser "state". .SETN ESCAMX 0. ! Set number of arguments. .SETN ESCA0 0. ! Clear the first argument. .; Main parser loop: .; 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: .ESCPSR: .IF ESCSEQ = "" .GOTO 'S$GOTO' ! If done, get more. .SETS CHAR ESCSEQ[1:1] ! Get first character, .SETS ESCSEQ ESCSEQ[2:*] ! remove from buffer. .SETN CVALUE 'CHAR%V' ! Get its value. .ONERR ESCPSE ! Trap unexpected chars. .GOTO 'ESCTYP''CVALUE' ! Handle this character. . . . .; First character = ; set state: .INI33: .SETS ESCTYP "ESC" ! Go to escape "state". .GOTO ESCPSR ! Get next character. .; First character is , or .INI217:.; .; First was and second is "O"; set state: .ESC117:.SETS ESCTYP "SS3" ! Go to SS3 "state". .GOTO ESCPSR ! Get next character. .; Got P = PF1 - use it as shift key: .SS3120:.SETN N$FLD N$OFLD .SETT GOLD ! Set shift flag. .GOTO ESCPSI ! Get next escape seq. (6.0) Error Control It can be useful to perform an operation even though it may produce an error in the ICP. The ICP can be set to dispatch errors to the label of your choice for handling, using: .ONERR label The .ONERR directive must be reasserted after each error trapped. Errors are divided into numbered classes, as described in the ICP documentation. You can set bits in Special Numeric Symbol to determine which classes are trapped. On entry to your error handler, Special Numeric Symbol contains the Error Class Number of the error encountered. The Error Classes are pretty broad (there are only two). If you are expecting more than one source of error, you will need to build your own logic to distinguish between them. The manual says you should not resume processing after trapping a Class 2 Error. I have found that it works in some cases, but recommend trying each case out before you build an application around it. Error Control (6.1) Example (from PRN.CMD) 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. .; Main parser loop: .; 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: .ESCPSR: .IF ESCSEQ = "" .GOTO 'S$GOTO' ! If done, get more. .SETS CHAR ESCSEQ[1:1] ! Get first character, .SETS ESCSEQ ESCSEQ[2:*] ! remove from buffer. .SETN CVALUE 'CHAR%V' ! Get its value. .ONERR ESCPSE ! Trap unexpected chars. .GOTO 'ESCTYP''CVALUE' ! Handle this character. .; Any unrecognised characters end up here. .ESCPSE:.SETN N$FLD N$OFLD ! Error. Recover field, .SETF GOLD ! Turn off gold key, .GOTO 'S$GOTO' ! Go do whatever. (7.0) Parsing an MCR- or DCL-like Syntax Command Files can be invoked in much the same way as a CLI command. The parameters passed are available to the Command File in string symbols P0-P9. Parsing these parameters normally takes place in two phases: Parsing the file specification(s); Parsing the switches and options. You need to design a command syntax that is both clear and easily parsed. Either MCR or DCL can serve as a model. You get a "nicer" parser if you can process all the file specifications in one loop, with an inner loop for the switches. You should specifically check for a null command line, and get the information you need through .ASKx directives. If the syntax for switches is properly defined, your switch parser code will be completely generic. This is done by: Defining a consistent symbol name convention for storing switch settings; Defining a consistent and restricted argument syntax. Parsing an MCR- or DCL-like Syntax (7.1) Example (from SYMDMP.CMD) .; PHASE 1 - Parsing the file specification(s): .; Define and initialize the command switches: .SETF V$SP ! Define /SP (spool) and assume false. .SETT V$BR ! Define /BR (page break), assume true. .; Determine processing mode (interactive or command line): .IF P1 = "" .GOTO PROMPT .; Get the file specs, from either MCR or DCL syntax: .IF P2 <> "" .GOTO SWIEXT .PARSE P1 "=" S$OUT S$FIL .IF S$FIL <> "" .GOTO SWIEXT .SETS S$FIL S$OUT .SETS S$OUT "" .; Peel the switches off the file specifications: .SWIEXT:.PARSE S$FIL "/" S$FIL S$SWIT .PARSE S$OUT "/" S$OUT S$JUNK .SETS S$SWIT "/"+S$SWIT+"/"+S$JUNK Parsing an MCR- or DCL-like Syntax (7.1) Example (from SYMDMP.CMD) (continued) .; PHASE 2 - Parsing the switches and options: .SWITLP: .IF S$SWIT = "" .GOTO PROCES .; Peel the next switch off, and get its arguments: .PARSE S$SWIT "/" S$SWX S$SWIT .PARSE S$SWX ":" S$SWX S$SWP .; Figure out whether it is asserted or negated: .SETT L$ASRT .IF S$SWX = "" .GOTO SWITLP .IF S$DASH = S$SWX[1:1] .GOTO SWITNM .IF S$NO <> S$SWX[1:2] .GOTO SWITAS .SETS S$SWX S$SWX[2:*] .SWITNM:.SETS S$SWX S$SWX[2:*] .SETF L$ASRT .SWITAS:.SETS S$SWX S$SWX[1:2] .; See if this switch has a corresponding V$sw symbol: .TEST S$SWX .IFF .GOTO SWIBAD .IFNDF V$'S$SWX' .GOTO SWIBAD .; Dispatch the rest based on the symbol type: .TEST V$'S$SWX' .GOTO SWIT'' .; Logical symbol. Set its value to switch polarity: .SWIT0: .IF S$SWP <> "" .GOTO SWINPR .SETL V$'S$SWX' L$ASRT .GOTO SWITLP .; Numeric symbol. Set its value to switch parameter: .SWIT2: .IFF L$ASRT .GOTO SWINNG .TEST S$SWP .IFF .GOTO SWIIVP .SETN V$'S$SWX' 'S$SWP' .GOTO SWITLP .; String symbol. Set its value to switch parameter: .SWIT4: .IFF L$ASRT .GOTO SWINNG .SETS V$'S$SWX' S$SWP .GOTO SWITLP (8.0) Multiple Precision Arithmetic Access to the carry bit is necessary (and sufficient) for most multiple-precision algorithms. If multiple-precision numbers are stored eight bits at a time in a Numeric Symbol array, the ninth bit can be used as the carry bit. If only eight bits of a numeric symbol are used, the standard precision of the ICP is sufficient for multiplication. Isolation of 8-bit results and the carry bit from each other (or of the low byte from the high byte in multiplication) is done using the bitwise AND function. Multiple Precision Arithmetic (8.1) Example (from BRU.CMD) BRU.CMD is a BRU preprocessor that generates mounts, dismounts, and BRU command lines based on user input and the current state of the system. It was desired to reproduce the same algorithm INI uses for calculating the initial and maximum index file size for a volume. This is a multiple precision algorithm. A portion of the addition routine is presented here to demonstrate the handling of eight bit results. The addends are stored in arrays OT$A and OT$B (elements 0 through 3), and the sum is formed in array OT$C (elements 0 through 3): .; Add the corresponding bytes of the two addends, .; with carry. .SETN OT$C0 OT$A0+OT$B0 .SETN OT$C1 OT$A1+OT$B1+(OT$C0/400&377) .SETN OT$C2 OT$A2+OT$B2+(OT$C1/400&377) .SETN OT$C3 OT$A3+OT$B3+(OT$C2/400&377) .; Strip out the carry bits. .SETN OT$C0 OT$C0&377 .SETN OT$C1 OT$C1&377 .SETN OT$C2 OT$C2&377 .SETN OT$C3 OT$C3&377 Subtraction is implemented similarly, but a "borrow" is assumed for all partial results (to avoid blowing up with OVERFLOW disabled), and stripped at the end. Multiplication is done by forming all useful cross-products, one at a time, and adding each to a running sum, shifted by the proper number of array elements. Division is done by the shift-and-subtract method, and is the only algorithm that requires iteration. Bibliography "Nifty Things to Do with RSX Indirect Command Files" Allen A. Watson RSX/IAS SIG Symposium Handout Spring 1983 DECUS US Symposium LA50 Printer Programmer Reference Manual Documents printer escape sequences. RSX LB:[1,2]ICP.HLP On-line help file for ICP. Contains some information that is not in the manual. RSX LB:[1,2]INDSYS.CLB Sample command routines. RSX-11M/M-Plus Task Builder Manual Documents object file layout. RSX-11M/M-Plus Indirect Command Processor Manual The primary reference for the ICP under RSX. RSX-11 Utilities Manual Reference for the librarian task (LBR). VT220 Programmer Pocket Guide Documents escape sequences for VT2xx terminals.