













        Programming in the RSX Indirect Command Language







                            - RX019 -





					T. R. Wyant
					E. I. DuPont de Nemours

					October 8, 1986

                          Housekeeping
                             Outline


Housekeeping
	Outline
	Goal & Caveats
	Acknowledgment
Command Procedure Libraries
Arrays
	Using a String Symbol as an Array
		Example (from PPORT.CMD)
	Using a String Symbol as an Attribute List
		Example (from SCRED.CMD)
	Using Groups of Symbols as an Array
		Example (from SCRED.CMD)
	Content-addressable Memory
		Example (from CRASHDUMP.CMD)
	Searching a (Very) Sparse Array
		Example (from CRASHDUMP.CMD)
Binary File I/O
	Example (from SYMDMP.CMD)
Screen Handling
	Screen Handling With FMS
	Screen Handling Without FMS
		Example (from SCRED.CMD)
Error Control
	Example (from SCRED.CMD)
Parsing an MCR- or DCL-like syntax
	Example (from SYMDMP.CMD)
Bibliography

                          Housekeeping





                              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" (RX018) should give sufficient background. 


These slides and all command files cited as examples will be 
distributed on the Fall, 1986 RSX SIG tape.






                             Caveats


The current releases of all the operating systems are assumed.

Since the things covered in this paper are "off the beaten 
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+ V2.1 C, except where noted. I will
mention bugs where I am aware of their existence.

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, "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. 

                   Command Procedure Libraries


It can be desirable to break a very large command procedure into 
separate modules. These will be easier to keep track of if they 
are kept in a Command Procedure Library. Examples include:

		LB:[1,2]INDSYS.CLB
		LB:[200,200]SYSGEN.CLB
		LB:[137,10]NETGEN.CLB


Principles:

	A Command Procedure Library is just a Universal Library 
		(as documented in the LBR manual), created as 
		follows:
			LBR library.CLB/CR::::UNI:CMD

	Once the command procedure library is created, modules 
		can be inserted and removed just as they are for
		a macro or object library.

	Modules in a Command Procedure Library can be executed 
		without extracting them from the library by:
			@library/LB:module


Options:

	A module in a Command Procedure Library can execute 
		another module in the same Command Procedure 
		Library by:
			@/LB:module

	If you do not specify a module of the Command Procedure
		Library to execute, module .MAIN. is executed.

	If you do not specify the /LB switch when invoking a 
		Command Procedure, the ICP checks the attributes
		of the file to determine whether it is a Command
		Procedure Library. So, you can call your Command
		Procedure Library "library.CMD", and execute 
		module .MAIN. by:
			@library

	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. module extract the 
		sources and build the package.

                             Arrays
                Using a String Symbol as an Array




Small arrays can be stored in a String Symbol and extracted 
by forming a substring.



Requirements:

	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 location 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


Recommendations:

	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.

                             Arrays
          Using a String Symbol as an Array (continued)
                    Example (from PPORT.CMD)


.; PPORT.CMD dumps a file to your printer port, after setting
.; your screen width and the horizontal pitch on your printer.

.; Initialize:

	.ENABLE SUBSTITUTION
	.SETS MCR ""
	.IF <CLI> <> "MCR"	.SETS MCR ""
	.SETN NJUNK 33
	.SETS ESCAPE "'NJUNK%V'"
	.SETS CSI ESCAPE+"["
	.SETN OLDWID <TICWID>
	'MCR'SET /BUF=TI:255.

.; Table to translate line length into pitch control character:

	.SETS PITCH "5555555555555555555555555555555555555555"
	.SETS PITCH PITCH+"66666666888888888888888888"
	.SETS PITCH PITCH+"000000000000002222222222222222"
	.SETS PITCH PITCH+"444444444444444444444444444444444444"

.; Table to translate line length into screen width:

	.SETS SCREEN "llllllllllllllllllllllllllllllllllllllll"
	.SETS SCREEN SCREEN+"lllllllllllllllllllllllllllllllll"
	.SETS SCREEN SCREEN+"lllllllhhhhhhhhhhhhhhhhhhhhhhhhhh"
	.SETS SCREEN SCREEN+"hhhhhhhhhhhhhhhhhhhhhhhhhh"

.; Main (and only) loop:

.LOOP:
	.ASKS FILE What file shall I print
	.IF FILE = ""	.GOTO EXIT

.; Get the record size to use as line length:

	.OPENR 'FILE'
	.PARSE <FILATR> "," RTYP RATT RSIZ JUNK
	.CLOSE

.; Extract proper characters from pitch and screen arrays:

	.SETS SCRCHR SCREEN['RSIZ'.:'RSIZ'.]
	.SETS PITCHR PITCH['RSIZ'.:'RSIZ'.]

.; Set screen width, turn on printer, and set printer pitch:

	.DISABLE DISPLAY
	;'CSI'?3'SCRCHR''CSI'5i'CSI''PITCHR'w

.; The rest of the command file is omitted.

                             Arrays
           Using a String Symbol as an Attribute List

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 string 
symbol, or a portion thereof.


Principles:

	The attributes are listed in the string symbol's value, 
		punctuated by a unique character.

	Attributes may be subdivided by using another unique 
		character.

	An attribute list can be searched for the presence of a
		given attribute using the two-argument .TEST 
		directive, with <STRLEN> = 0 denoting absence of
		the desired value from the list.

	Attributes can be extracted from the list using the 
		.PARSE directive (or a series of them to extract
		subattributes).


Requirements:

	The character chosen as separator may not appear in any 
		of the attributes.


Recommendations:

	If the primary use of the attribute list is to search 
		using .TEST, it may be helpful to start the list
		off with a punctuating character.


Options:

	If the attributes are all one byte long, and the only 
		purpose of the list is to use it with the .TEST 
		directive, the punctuation may be omitted.

                             Arrays
     Using a String Symbol as an Attribute List (continued)
                    Example (from SCRED.CMD)


.; SCRED.CMD is a single-screen editor. The active function
.; keys are:
.;	The arrows - move cursor in the given direction;
.;	PF1 - coarse motion - multiplies vertical arrows by 8,
.;		and horizontal arrows by 16.

	.; 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 "LINE,8,-,1.,<"	 ! <CSI>A = Up arrow.
	.SETS ARROWB "LINE,8,+,23.,>"	 ! <CSI>B = Down arrow.
	.SETS ARROWC "COLUMN,16,+,80.,>" ! <CSI>C = Right arrow.
	.SETS ARROWD "COLUMN,16,-,1.,<"	 ! <CSI>D = Left arrow.
			.
			.
			.
	.; Note: Code used to recognize an escape sequence is 
	.;	discussed later. Suffice it for the moment
	.;	to say that they are recognized, and if an
	.;	arrow key is struck, the code below is entered
	.;	with:
	.;
	.;	    CHAR = last character of escape sequence;
	.;	    ESCA0 = numeric value of first argument.


	.; An arrow key generates these escape sequences:

.CSI101:.;	<CSI>A = Up arrow;
.CSI102:.;	<CSI>B = Down arrow;
.CSI103:.;	<CSI>C = Right arrow;
.CSI104:.;	<CSI>D = Left arrow.

	.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 NJUNK 'AXIS'		! Save old location.
	.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.

                             Arrays
               Using Groups of Symbols as an Array


An array of arbitrary size can be constructed by using a group
of symbols with similar names. 


Principles:

	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). 

	Arrays can have more than one dimension.

	Arrays can be indexed by Numeric Symbols, String 
		Symbols, or Logical Symbols, or by a mixture of 
		types of symbols.

	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).


Requirements:

	Substitution can not be done on an arbitrary array 
		element. The value of that array element must
		be assigned to another, "constant-named" symbol,
		which is used instead in the desired 
		substitution.

	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.


Recommendations:

	Use %RnZ format control on Numeric Symbol indices, 
		if the index can be more than one digit. This is
		especially true for multi-dimensioned arrays.

                             Arrays
         Using Groups of Symbols as an Array (continued)
                    Example (from SCRED.CMD)


.; SCRED.CMD is a single-screen editor. The active function
.; keys are:
.;	The arrows - move cursor in the given direction;
.;	PF1 - coarse motion - multiplies vertical arrows by 8,
.;		and horizontal arrows by 16.


	.OPENR 'FILE'
	.SETN LINE 0.
.INPLP:
	.INC LINE
	.READ LINE'LINE'
		.
		.
		.
	.GOTO INPLP

                             Arrays
                   Content-addressable Memory

This is really just an extension of the concept of using a group
of symbol names as an array. There is no logical reason why you
can't use a string symbol as an array subscript, provided the 
contents of the symbol give rise to a valid symbol name. The 
same consideration applies to allowing the array name to shrink 
to zero bytes. What you have left is a system where the entire 
symbol table is an array, where the symbol names are chosen to 
describe the information stored in the symbol.



Requirements:

	The string symbol that contains the information to be
		looked up had better be validated first to be
		sure it's 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.


Recommendations:

	Since it is probably not desirable to literally use the 
		whole symbol table, a subset is selected (eg: 
		all symbols with alphanumeric names), and 
		symbols used otherwise in the command procedure 
		are selected to fall outside this subset (eg: 
		names with embedded dollar signs).

                             Arrays
             Content-addressable Memory (continued)
                  Example (from CRASHDUMP.CMD)



;	Run the crashdump analyzer.

.; 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 - <LIBUIC>
.;				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 - <SYSUIC>
.;				name ------ RSX11M
.;				type ------ .STB
.;	hlptxt	is identifying text for the system.
.;

.SETS HOST "CDAFSL;256;DR;2;;RSX-11M+ system."
.SETS FRONT "CDA41;124;DX,DY;1;[1,64];RSX-11S system."
.SETS OTHER "CDAFSL;512;DR;2;OTHER;Another M+ system."

.;
.;	Get the system being dumped.
.;

.SYSASK:
	;
	.DISABLE LOWERCASE
	.ASKS [0:6:<NETNOD>] S$SYS What system is crashdump for
	.ENABLE LOWERCASE
	.IFT <ESCAPE>	.GOTO SYSHLP
	.IFF <ALPHAN>	.GOTO SYSERR
	.TEST S$NOGO ",'S$SYS',"
	.IF <STRLEN> > 0	.GOTO SYSERR
	.IFDF 'S$SYS'	.GOTO SYSOK

                             Arrays
                 Searching a (Very) Sparse Array


One of the disadvantages of using sparsely populated arrays is
the inefficiency of weeding out nonexistent elements when
iterating over the entire array. A better alternative may be to
iterate over the entire symbol table, searching for elements of
the array.


Principles:

	Each time the Special String Symbol <NXTSYM> is referred
		to, it returns the name of the next symbol in 
		the Symbol Table. You can use this fact to 
		iterate over the entire Symbol Table. When the 
		end of the Symbol Table is reached, <NXTSYM> 
		returns a null string.


Requirements:

	To initialize the iteration, you must:
			.SETS <NXTSYM> ""

	You must refer to <NXTSYM> only once in each iteration,
		or you will skip symbols. A useful way to do 
		this is:
			.SETS SYMNAM <NXTSYM>


Recommendations:

	The documentation of <NXTSYM> contains warnings about 
		its availability for general use. My experience 
		is that you might have to fiddle a bit to get it
		to work. See:
			LB:[1,2]INDSYS/LB:SYMDMP
		for an example.

	I recommend against defining any new symbols inside the 
		iteration loop.

                             Arrays
           Searching a (Very) Sparse Array (continued)
                  Example (from CRASHDUMP.CMD)



.SYSERR:;
	; Error - System name "'S$SYS'" is invalid, or not
	;		supported by this command file. 
.SYSHLP:;
	; Valid system names are:
	.SETS <NXTSYM> ""

.; Now, loop through the Symbol Table:

.SYSHLL:

	.; Get the next Symbol name; if none, we are done:

	.SETS S$SYS <NXTSYM>
	.IF S$SYS = ""	.GOTO SYSASK

	.; If it is not alphanumeric, we do not want it:

	.TEST S$SYS
	.IFF <ALPHAN>	.GOTO SYSHLL

	.; If it is not a String Symbol, we do not want it:

	.TEST 'S$SYS'
	.IF <SYMTYP> <> 4	.GOTO SYSHLL

	.; If it is COMMAN or P0-P9, we do not want it:

	.TEST S$NOGO ",'S$SYS',"
	.IF <STRLEN> > 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

                         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. 


Requirements:

	All records read or written must be less than 133 bytes
		long.

	Subject to the above restriction, any sequential file 
		can be opened for read or append access. Files 
		opened for output will have variable length 
		records, with "list" carriage control.


Recommendations:

	Use substitution with %V format control to convert bytes
		to their numeric values. If this is unavailable,
		the next best thing is probably to store all 256
		ASCII characters in a couple string variables in
		order, and use .TEST to do the conversion.


Options:

	If you wish to write a file with "unusual" attributes 
		(fixed length records, no spanned blocks, etc.) 
		you can invoke RMSDEF to create an empty file, 
		with the desired attributes, and then open it
		for append access. 

                         Binary File I/O
                    Example (from SYMDMP.CMD)


.; SYMDMP.CMD is a command file that reads a .OBJ or .STB file,
.; and displays the symbols it finds there.

.; The example covers decoding of binary bytes, binary words,
.; and RAD50 words. 

.; Read the next record:

.RDLP:
	.READ S$REC
	.IFT <EOF>	.GOTO CLOS

.; Strip off the first two bytes, and convert to numeric:

	.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)

.; Record type 2 signals end of items of interest:

	.IF O$W = 2	.GOTO CLOS

.; Record type 1 is what we want. Loop for others:

	.IF O$W <> 1	.GOTO RDLP

.; Strip off the record type:

	.SETS S$REC S$REC[3:*]

.; Process each symbol in the record:

.SYLP:
	.IF S$REC = ""	.GOTO RDLP

.; The symbol name is 6 RAD-50 characters; extract it from the
.;		4 bytes it is stored in, and convert to ASCII:

	.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'"

.; The flags byte is stored in binary; extract it:

	.SETS S$B0 S$REC[5:5]
	.SETN O$FLG 'S$B0%V'&377

                         Screen Handling
                    Screen Handling With FMS


The RSX-11M+ ICP comes with an interface to FMS-11. You can use 
this interface to generate a form-driven application. You can 
get a demonstration of the FMS capability of the ICP by:

	@LB:[1,2]INDSYS.CLB/LB:FMSDEM


Requirements:

	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. 

	Special Symbol <FILER2> will contain the status code for
		the previous FMS operation. You can also (if 
		necessary) use .IFDF <FILER2> to determine 
		whether .IFENABLED FMS will produce a syntax 
		error, if you really need to.

                         Screen Handling
                   Screen Handling Without FMS



If you don't own RSX-11M+ and FMS-11, you can write your own 
screen handler for the ICP.


Principles:

	The ICP does all input through the .ASKS directive.

	The terminal is conditioned so that escape sequences 
		generated by the function keys are passed at 
		the end of an input string.

	The prompt sequence of the .ASKS is used to position the
		cursor for input.


Requirements:

	You must issue the
			.ENABLE ESCAPE-SEQUENCE
		directive to allow the ICP to receive escape 
		sequences in response to the .ASKS directive.

	You must issue the MCR command
			SET /ESCSEQ=TI:
		or the DCL command
			SET TERMINAL/ESCAPE_SEQUENCE
		to allow the TT: driver to pass the escape 
		sequences through to your terminal.

	You must issue the
			.DISABLE DISPLAY
		directive to prevent the ICP from sending
		unwanted characters to your screen. 

	The ICP must parse the escape sequence off the end of 
		the .ASKS input string, and interpret it.

                         Screen Handling
             Screen Handling Without FMS (continued)



Recommendations:

	You should issue the
			.DISABLE DETACH
		directive, so that input from additional 
		keystrokes will not be lost if you type faster 
		than the ICP can process your input. Note that 
		if you do this, programs run by the ICP will not
		have access to your terminal.

	Literal escape sequences should not be embedded in the 
		command file. If you violate this rule, you may 
		not be able to TYPE the procedure on your 
		terminal.

	Constant escape sequences (eg: home cursor, clear
		screen, setup sequences) should be assigned to 
		appropriately named string symbols on 
		initialization. This enhances portability, and 
		makes it easier to handle multiple terminal 
		types.

	Variable escape sequences (eg: cursor postioning) should
		be generated in .GOSUB modules, for the same 
		reasons.

	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.


Options:

	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)
                    Example (from SCRED.CMD)



.; SCRED.CMD is a single-screen editor. The active function
.; keys are:
.;	The arrows - move cursor in the given direction;
.;	PF1 - coarse motion - multiplies vertical arrows by 8,
.;		and horizontal arrows by 16.

.; Required ICP initialization:

	.ENABLE SUBSTITUTION
	.DISABLE DISPLAY
	.DISABLE DETACH
	.ENABLE ESCAPE-SEQUENCE

.; Required TT: driver initialization (must come after the
.;		.ENABLE ESCAPE-SEQUENCE):

	.SETN TIWID <TICWID>
	.SETS MCR ""
	.IF <CLI> <> "MCR"	.SETS MCR "MCR "
	'MCR'SET /LOWER=TI:
	'MCR'SET /ESCSEQ=TI:
	'MCR'SET /BUF=TI:132.

.; Useful symbol definitions:

	.; The following are suitable for ASCII terminals:

	.SETN NJUNK 16			! Define SO to be a
	.SETS SO "'NJUNK%V'"		!    <Shift Out> char.
	.SETN NJUNK 17			! Define SI to be a
	.SETS SI "'NJUNK%V'"		!    <Shift In> char.
	.SETN NJUNK 33			! Define ESCAPE to be
	.SETS ESCAPE "'NJUNK%V'"	!    an <ESC> character
	.SETN NJUNK 217			! Define SS3 to be an
	.SETS SS3 "'NJUNK%V'"		!    <SS3> (="<ESC>O")
	.SETN NJUNK 233			! Define CSI to be a
	.SETS CSI "'NJUNK%V'"		!    <CSI> (="<ESC>[")

	.; The following are suitable for ANSI terminals:

	.SETS HOME ESCAPE+"[H"		! HOME homes cursor
	.SETS CLEAR ESCAPE+"[J"		! CLEAR clears screen

	.; 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

                         Screen Handling
             Screen Handling Without FMS (continued)
              Example (from SCRED.CMD) (continued)



.; And, some useful subroutines:

	.;
	.;	.GOSUB ASKE line;column
	.;
	.; Positions the cursor at the given line and column,
	.; and issues a .ASKS. On return,
	.;	TEXT contains the text part of the answer;
	.;	ESCSEQ contains the escape sequence;
	.;	<STRLEN> contains the location of the escape
	.;	    character.
	.;
.ASKE:
	.GOSUB POSITN 'COMMAN%C'
	.SETS ESCSEQ ""
	.ASKS TEXT 'COMMAN'
	.IFT <EOF>	.RETURN
	.TEST TEXT ESCAPE
	.IF <STRLEN> = 0	.TEST TEXT CSI
	.IF <STRLEN> = 0	.TEST TEXT SS3
	.IF <STRLEN> <> 0	.SETS ESCSEQ TEXT[<STRLEN>:*]
	.IF <STRLEN> <> 0	.SETS TEXT TEXT[1:<STRLEN>-1]
	.TEST TEXT
	.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)
              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 LOOP	! 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 LOOPI			! Trap unexpected chars.
	.GOTO 'ESCTYP''CVALUE'		! Handle this character.

	.; First character = <ESC>; set state:

.INI33:	.SETS ESCTYP "ESC"		! Go to escape "state".
	.GOTO ESCPSR			! Get next character.

	.; First character is <SS3>, or

.INI217:.;

	.; First was <ESC> and second is "O"; set state:

.ESC117:.SETS ESCTYP "SS3"		! Go to SS3 "state".
	.GOTO ESCPSR			! Get next character.

	.; Got <SS3>P = PF1 - use it as shift key:

.SS3120:.SETT GOLD			! Set shift flag.
	.GOTO ESCPSI			! Get next escape seq.

                          Error Control


It can be useful to perform an operation even though it may 
produce an error in the ICP. Although the ICP can not be set to 
ignore such errors, it can be set to dispatch them to the label 
of your choice for handling.


Principles:

	To cause errors to be trapped to your error handler, 
		issue the ICP directive:
			.ONERR label
		The next error encountered will cause control to
		be transferred to the given label.

	Errors are divided into numbered classes, as described 
		in the ICP documentation. You can set bits in 
		Special Numeric Symbol <ERRCTL> to determine 
		which classes are trapped to your error handler. 
		Untrapped errors will cause the ICP to abort. By 
		default, only Class 1 errors are trapped.

	On entry to the error handler, Special Numeric Symbol 
		<ERRNUM> contains the Error Class Number of the 
		error encountered.


Requirements:

	The .ONERR directive must be reasserted after each 
		error trapped.


Recommendations:

	The Error Classes are pretty broad (there are only two),
		and don't tell you very much about what actually
		caused the fault. 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, as the state of the
		ICP is indeterminate. I have found that it works
		in some cases, but recommend trying each case
		out before you build an application around it.

                          Error Control
                    Example (from SCRED.CMD)



	.; Initialize the parse by turning off the "GOLD" key:

.LOOPI:
	.SETF GOLD


.; Main input loop:

	.; Ask for data, and insert the text part into the line
	.; buffers:

.LOOP:
	.GOSUB ASKE 'LINE';'COLUMN'
	.IFT <EOF>	.GOTO CLENUP
	.SETS JUNK LINE'LINE'[1:COLUMN-1]
	.SETN COLUMN COLUMN+<STRLEN>
	.IF COLUMN > 80.	.SETN COLUMN 80.
	.SETS LINE'LINE' JUNK+TEXT+LINE'LINE'[COLUMN:*]
	.SETS LINE'LINE' LINE'LINE'[1:80.]


.; 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 LOOP	! 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 LOOPI			! Trap unexpected chars.
	.GOTO 'ESCTYP''CVALUE'		! Handle this character.

               Parsing an MCR- or DCL-like Syntax


Command Files can be invoked in much the same way as a CLI
command, and 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.


Requirements:

	You need to design a command syntax that is both clear 
		and easily parsed. Either MCR or DCL can serve 
		as a model.


Recommendations:

	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 not passed in the command line.


Options:

	If the syntax for switches is properly defined, your 
		switch parser code will be completely generic - 
		that is, you can add switches without modifying 
		the parser. This is done by:

	    Defining a consistent symbol name convention for 
		    storing switch settings. In the example,
		    "V$xx" is used, where "xx" represents the 
		    switch name, and the Symbol Type of V$xx 
		    determines how the switch is processed.

	    Defining a consistent and restricted syntax. In the 
		    example, no switch may have more than one 
		    argument.

               Parsing an MCR- or DCL-like Syntax
                    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
              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 <ALPHAN>		.GOTO SWIBAD
	.IFNDF V$'S$SWX'	.GOTO SWIBAD

.; Dispatch the rest based on the symbol type:

	.TEST V$'S$SWX'
	.GOTO SWIT'<SYMTYP>'

.; 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 <NUMBER>	.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

                          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-11 MCR Operations 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.
