BOILER - Boiler Plate Files =========================== It is usually desirable to keep a more-or-less standard interface when writing programs on a system. For this reason, four boiler-plate files are provided. While it is not intended that the user should rigorously follow the same standards as I have adopted, I strongly recommend that he modify the files to suit himself, and then follow them when writing software. the four files are discussed individually in the following sections. 1. BOILER.CMD - Boiler-Plate Command File ====================================== This is not so much a boiler-plate command file as a command-file which will create other command files (to assemble and build MACRO-11 programs) according to a standard boiler-plate. It incorporates the following standards:- 1. Multi-user tasks will generally have a three-character name XXX. The source file will exist as XXX.MAC, the build command file as XXX.CMD and the task will have a taskname of ...XXX. Non-multi-user tasks will generally have a name of more than three characters, say XXXXX. The source file will be XXXXX.MAC, the build command file XXXXX.CMD and the task will usually have a taskname of XXXXX. 2. The user will have available, and wish to use, SRD.TSK, BIGMAC.TSK and BIGTKB.TSK, and each of these, if not installed, should be installed for the duration of the run and removed at the end. 3. Any special Task Builder command file required to build the task will be dynamically created by the build command file during the assembly phase, will be called XXX.BLD and will be deleted after the Task Builder finishes. 4. A listing and map file will be produced during the run. Neither will be automatically spooled to the lineprinter, and both will contain a cross-reference listing. 5. The only macro/prefix files that the program might wish to access will be LB:[1,1]EXEMC.MLB and LB:[11,10]RSXMC.MAC. 6. The command file will be run from the account containing the source file, though not necessarily with the disk containing it set as system disk. All output files will be created on the same disk as that containing the source file. 7. The only 'conditional' required in the build will be whether or not the task should be built with ODT and this will be implemented by allowing 'DEBUG' as an optional parameter (i.e. @XXX builds XXX without ODT, @XXX DEBUG builds XXX with ODT). The boiler-plate command file is invoked by @[1,1]BOILER. It will first ask: WHAT IS THE NAME OF YOUR PROGRAM? [S]: to which you should reply with the name (XXX or XXXXX in the above examples) of your program. It will then ask: WHAT DOES IT DO? [S]: to which you should reply with a short (one-line) description of the program's function, which will be used in a comment at the top of the created command file. The command file with then ask the two questions: DO YOU WANT TO REFERENCE LB:[1,1]EXEMC.MLB? [Y/N]: DO YOU WANT TO REFERENCE LB:[11,10]RSXMC.MAC? [Y/N]: which should be answered according to the needs of the given program. It will then ask: WHAT IS THE TASKNAME [D: xxxxxx]? [S]: where the default is ...XXX if the program name had only three characters, and XXXXX if the program name had other than three characters. If you wish to leave the default type just a carriage return, otherwise enter the taskname you wish to use. Next you will be asked: ENTER ANY SWITCHES FOR TKB IN ADDITION TO /CP/MM/-FP [S]: to which you should reply with any extra switches you want on the task image side of the task builder line (e.g. /PR for privileged) or just a carriage return if there are no special switches (it is assumed that all MACRO-11 tasks will want to be Checkpointable, built for a Mapped System and will not use the Floating Point Unit - hence the hard-wiring of /CP/MM/-FP). It will then ask: ENTER ANY FURTHER COMMAND LINES TO TKB [S]: to which you should reply with any additional lines you want specified to the Task Builder at the command stage (e.g. user libraries). This question will repeat until it is answered with just a carriage return at which point you will be asked: HOW MANY UNITS? [D D:6.]: to which you should reply with the number of units (in decimal) that the program references, or just a carriage return if the default of 6 is acceptable. You will then be asked: WHAT PRIORITY? [D D:50.]: to which you should reply with the default priority (in decimal) you want the task to run at, or just a carriage return if the default of 50 is acceptable. Finally it will ask: ENTER ANY FURTHER OPTION LINES TO TKB [S]: to which you should reply with any lines you want passed to the Task Builder at the option stage (e.g. STACK=n or ASG=DDn:m). This question will repeat until you enter just a carriage return at which point the whole process is complete, and your command file (XXX.CMD) is built. 2. BOILER.MAC Boiler-Plate Program Source File ================================================ This boiler-plate file is intended as an aid to writing simple MACRO-11 programs without fuss. In particular it contains examples of using the handy, but awkward, tools like CSI and $EDMSG. The emphasis is mainly on speed of writing and not on speed/size of execution as the aim is more to get rid of all those untidy little utilities that get written and have lousy user interfaces and unhelpful error messages. Using this boiler-plate it is easy to write a simple utility (such as one to interrogate a task header and print out the switch settings) in only an hour or so, and yet still have the standard multi-user interface and decent error reporting. The source code itself amply describes the different aspects of the file, and how they should be used, but the following list should give a rough idea of what is included and why. 1. $EDMSG. The data section defines an output area for building messages in (80 bytes) and an argument block (15 words) for use with $EDMSG. The code section contains a routine (OUT) which expects R1 to contain the address of the relevant format string, but will then set up R0 and R2 and call $EDMSG (R0-R2 are destroyed). The data section also contains a long comment describing the various edit symbols to use with $EDMSG. 2. Error Handling. Errors are divided into two categories - fatal and non-fatal - handled by two macros FERR and DIAG, respectively, which are defined at the top of the program. Each stores all specified arguments (except the first) in successive words of ARGBLK, sets R1 to the address of a string called I.xxxx (where xxxx is the first argument) and invokes its corresponding routine (FERR: and DIAG:) which both call OUT (see 1) to format the error message, output it and either close all files and exit (FERR) or return to the line after the macro (DIAG). Both macros will destroy R0-R2 - though it is hardly relevant in the case of FERR. FERR will allow up to 14 'secondary' arguments (to handle SSTs - see later), DIAG up to 4. Note that in practice these would be used similarly to: DIAG NSYM,(R4),2(R4) where I.NSYM would be the relevant format string, and R4 points to a 2-word argument. Note that all arguments are assumed to be words - any byte values (e.g. I/O errors) must be sign-extended first. 3. CSI/GCML. It is always nice, in a multi-user utility, to have all the facilities like prompting with XXX>, accepting an indirect command-file as input, and such-like - but it is usually difficult to remember/work out how to do it. The majority of the code in this file is to do just that. In the data area it defines a CSI block and a GCML block (with a prompt of XXX> on LUN CMDLUN - set to 1 by default -, skeletal input and output switch tables (with comments on how to add your own switches), a default switch mask (SWMSK$) and a large number of error messages associated with the common CSI/GCML errors. In the program area, the file assigns the command LUN to TI: (something that is often forgotten & takes a while to find), and sets up a loop (GETCMD) to get the first/next command-line, checking for errors and terminating as per RSX-11M utility standards. For each command-line it then calls a routine (CMDFIX) to allow the user to change anything in the line that CSI will object to (that way he can allow someone running the utility to specify, say, /AF:12:00, where 12:00 is a time to passed intact, and can stop CSI from treating it as two arguments). It then parses the line and sets up FDBs corresponding to any input and output file-specifications given on the line (defaulting the output to TI: if no '=' specified and to SY: otherwise - again as standard for RSX-11M). It includes (optional) code for checking for multiple input/output specifications, and then calls a separate routine (PROCESS) for the user to do the real work, before closing all files and returning for the next commandline. 4. Help. The file includes code to support a /HE switch on all utilities to give the user help (would that all DEC Utilities did the same). This is done in a very simple manner - by spawning a line to MCR saying HELP XXX. This enables the user to maintain only one set of help, whilst being able to supply it both from MCR and from the utility. The one requirement is, of course, that the system should support parent/offspring tasking, but in the event that it does not the program will still work - but will just not supply any help. 5. Files-11. Most programs need to do some File I/O, and, after CSI/GCML, it is probably the most complicated part of programming in Assembler. This file calls in ALL the macros that you are likely to use (and often forget to ask for) and sets up skeletons for two input files and one output file, demonstrating the most common macros and the use of Default File Name Blocks and Dataset Descriptors. In addition there is a long comment discussing the initialization macros and how to use them. In the program section FINIT$ is invoked (something else often forgotten) and the files are opened/closed/read in the course of the other code supplied. 6. SST Handling. Another of the irritating parts of programming in MACRO-11 is that the information given when an SST trap occurs is not really adequate. The file sets up its own SST trap and outputs a message giving the trap number, the contents of registers R0-R7 and the contents of the top word of the stack (after throwing away any trap specific words). The routine also closes all files, and contains code to prevent recursion in the SST routine (just in case!). 7. STB access. Often the user wants to write a utility that accesses the Executive data areas (for some nefarious purpose). Unfortunately, beacuse of the current system that means that the utility must be rebuilt every time the system changes. Furthermore, if it is not rebuilt there is a fair chance of it crashing the system as soon as it is run. This is not really acceptable, particularly in an environment where you rarely run on the same system two weeks running, so an alternative method was adopted. Basically it is very simple - instead of building the values from RSX11M.STB in at task-build time, they are calculated by the utility at run-time. The method used is fairly straightforward. The user sets up a table of the global symbols he wishes to access in RAD50 in the order they appear in RSX11M.STB (global labels in alphabetical order, followed by global symbols in alphabetical order). The routine provided (STBRTN) is called as soon as the program starts and reads LB:[1,54]RSX11M.STB sequentially, checking for each of the required items. Each time it gets a match it replaces the first word of the two-word name with the address/value of the item. If it reaches the end of the file without finding the required symbol it outputs an error message and rewinds the file. The idea is that if the table includes, say SRSTD: .RAD50 /$SRSTD/ then where the user would usually say CALL $SRSTD he now says CALL @SRSTD The method seems to work very well and, while there is obviously an overhead in program size and execution time, it is not really noticeable in utilities which are, after all, usually waiting for terminal I/O. 3. BOILER.MUN - Boiler-plate MUNG file =================================== Given the flexibility of writing MUNG programs, it might seem a little odd to have a boiler-plate MUNG file. The point of this one, however, is to implement the MUNG chaining procedure that had been put into our version of TECO. This is just a method whereby one can get a list of all the available MUNG programs by typing MUN or MUN HELP. What happens is that MUN invokes the MUNG program MUNG.MUN which, after outputting its own message, sets up a macro in Q-register 8 and invokes each of the .MUN files in LB:[1,2] and then in the user's account, in turn. The .MUN files (as in the boiler-plate) detect that this is a special invocation of them and just output a header line and execute the macro in Q-register 8, qhich will chain to the next file, and so on. When the MUNG program is invoked direct TECO sets up Q-register 8 to contain just 'EX' and the program ignores the header, executes its code & then exits. While this does work under the current implementation it is not too satisfactory as it means that the program will only execute fully under specialist conditions (Q-register 8 having a value of -103 and a 2-character text string) whereas it would be more portable if the opposite were true (i.e. it only didn't execute under specialist conditions) so that the MUNG programs were then more portable. If/when I have time I will change the boiler-plate/TECO accordingly. 4. BOILER.SUB - Boiler-plate Subroutine Header =========================================== Subroutines are less liable than main programs to use similar code, so that all this boiler-plate really does is set up a skeleton heading for the subroutine indicating its calling sequence, and include the call to PRMCHK. PRMCHK is any standard routine that the user wishes to invoke to check the parameters passed to him - a version is supplied which does standard things like checking the right number of parameters were supplied, saving all work registers and so on (see the PRMCHK writeup for more details). Basically the standards that I have tried to adopt with subroutines is as follows:- 1. The subroutine will use the standard R5 linkage mechanism so that it can be called from any high-level language, or from MACRO-11. (Exceptions are simple subroutines that manipulate registers & hence have no meaning from a high-level language.) 2. The subroutine will be set up so that it either returns its error/success status in the last parameter in a subroutine call or as the value of a function as defined in FORTRAN. 3. The error/success status variable will always be a single-word integer and is to be regarded as optional in the subroutine call. 4. The subroutine will return a value of 0 for success, a negative value for an error (e.g. invalid parameters) and a positive value for conditional success (some values not converted). Several of the above points are implemented more through PRMCHK (which see) than through the boiler-plate.