4. Documentation

As with all good things, documentation is a must. If you have a large number of useful routines then they should be documented somewhere. This will allow you to look for a routine in your library and from that, find out its input & output parameters and which file it lives in.

A suitable template that you could use for each subroutine is as follows :

*------------------------------------------------------------------------------
* NAME
* DEPENDENCY (1)
* DEPENDENCY (2)
* PURPOSE
* INPUTS
* OUTPUTS
*------------------------------------------------------------------------------

The above looks very like comments in a source file - this implies that we could add the documentation to the source file and then run a utility program to extract the details and store them in a text file - which you can edit and/or print as desired.

Having a standard header above each subroutine also implies that you could write a utility program to scan the entire library and ask you which ones you want to include in your output file - which will be you source file for your next masterpiece - before extracting them all and writing them to this file.

As for the subroutines themselves, I mentioned above that they exist in a draft form when you simply extract the code from the 'wordy' source and add an RTS to the end. This is fine, but it could be that you need to preserve certain registers so that the code calling the subroutine doesn't need to keep saving and restoring them. The updates required are :

Check which registers will be used by the code explicitly - save them before and restore them after the main part of the subroutine code.

Check which system calls are made by the subroutine and look up the QDOSMSQ documentation to see which registers are trashed by the system call. Add these registers to the save and restore routines.

Save the registers as the first line of code in the subroutine and restore them as the line immediately before the RTS (or as near to the RTS as possible).

Always have the subroutine return an error code and/or the flags set to signal if an error occurred or not.

An actual example follows :

*------------------------------------------------------------------------------
* NAME          CLS
*------------------------------------------------------------------------------
* DEPENDENCY    None
* PURPOSE       To clear a screen/console channel.
* DESCRIPTION   Clears the screen channel whose ID is supplied in A0.
* INPUTS :
*               A0.L = channel ID
* OUTPUTS :
*               D0 = Error code
*               Z flag set if no errors, unset otherwise.
*------------------------------------------------------------------------------
cls             move.l   d1/d3/a1,-(a7) ; These will be corrupted by SD_CLEAR
                moveq    #sd_clear,d0   ; CLS (SD_CLEAR defined in GWASL)
                moveq    #-1,d3         ; Infinite timeout
                trap     #3             ; CLS the window
                move.l   (a7)+,d1/d3/a1 ; Restore corrupted registers
                tst.l    d0             ; Set Z flag if all ok, else not set
                rts

In the above example, I have extended the 'cls' code from our original subroutine as follows :

Note that although D0 is used by the code and by the system call, I have not preserved it. This is quite simply because I use D0 to return any error codes back to the caller. As I have documented its corruption in the header, I assume that the user of the subroutine will read this and know all about it !

Bullet proofing the code like this helps to reduce unexpected bugs in your programs when you forget to save a register and after a subroutine call, assume it still has the same value as before. I know, I have been there. Of course, there is not much you can do to prevent the documentation you use from being wrong (been there too) but at least you did your best !