CP/M+ PRINT SPOOLER USER GUIDE Version 1.3: May, 1989. (c) 1989 by Andy Metcalfe. CP/M+ Print Spooler User Guide Table of Contents 1. Introduction 2 1.1 Hardware Requirements 2 2. Using The Spooler 4 2.1 Spooler Capabilities & Setup Requirements 4 2.2 Spooling File(s) 4 2.3 Command Line Options 5 2.4 Listing the Spool Queue 6 2.5 Cancelling Printing of Spooled Files 7 2.6 Restrictions & Ideosyncrasies 8 3. Spooler Internal Operation 10 3.1 The Nature Of The Beast 10 3.2 Implementation 10 3.3 The Spool Loader 11 3.4 The Spooler RSX 12 3.4.1 The Re-entrancy Problem 12 3.4.2 BDOS Intercept Methods 13 3.4.3 The CCP Multiple Command RSX 14 3.4.4 Spooler Disk Buffering 14 3.4.5 Internal Spool Queue Format 15 3.4.6 Loader - RSX Communication 15 References 17 Appendices: A. Future Developments 18 - 1 - CP/M+ Print Spooler User Guide 1. Introduction One of the essential features of any multitasking or multiuser operating system - such as Concurrent CP/M, OS/2, Unix or VMS - is a means of printing a file without tying up the resources of the user's terminal, so that he/she can continue to perform other tasks in the meantime. This is typically accomplished by copying the file to be printed to a "spool directory" elsewhere on the system and printing it in the background. The user can then pick up the printout upon completion. Whilst the nature of a multitasking system encourages - even demands - such a utility, that of a single user system does not. Hence producing a print spooler under such a system will not be a trivial undertaking, and may require considerable compromises in design and functionality. It is however possible to write a print spooler to run under CP/M, examples of which are the D*g*t*l R*s**rch CP/M 1.4 DESPOOL utility, and the (public domain) CP/M 2.2 utility UNSPOOL on SIG/M Vol 115. Neither of these will, unfortunately, run on CP/M+, due to the substantially different nature of its internal operation. Obviously, such a program would be extremely useful, and therefore working on the principle that anything CP/M 2.2 could do, CP/M+ could also do - but maybe in a different way - I set about plugging the gap. 1.1 Hardware Requirements This program should run on any CP/M+ machine with an 8080, 8085, Z80 or 64180 CPU. While it will run on a system with only one disk drive, two or more are really required, since when the spooler is working the disk on which it stores the spooled files MUST NOT BE REMOVED. Failure to observe this will probably result in a system crash, and damage to the disk and drive if the spooler tries to access it when it is being removed. I would recommend running the spooler on a RAMdisk if you have one, since this avoids all of the above problems (see later for fuller details). In the general case it is also adviseable to setup the printer to accept continuous stationary, avoiding the need to hit the "printer loaded" key/softkey at the end of each page. Of course, if single sheet stationary is required it is necessary to set it up manually at the end of each page. The spooler will not run on CP/M 2.2 or earlier, due to the major differences in the structure of the two systems. Conceptually there is no reason why it could not be modified to do so, but since there is one already available for CP/M 2.2 I wouldn't bother. Use UNSPOOL instead. - 2 - CP/M+ Print Spooler User Guide If you have any queries about the spooler or its operation, compatibility etc, please feel free to contact me, either through the CP/M & MSDOS Users' Group (UK) or via the address given below: Andy Metcalfe, 82 Fabis Close, Swadlincote, Burton on Trent, Staffs. - 3 - CP/M+ Print Spooler User Guide 2. Using the Spooler 2.1 Spooler Capabilities & Setup Requirements In it's present form, then spooler will, when invoked, print specified files when the system is waiting for input, or checking console status. It can handle both wildcards and queued files, as well as limited print formatting (paging etc) through options on the command line. The spooler needs to have a disk drive allocated to it to store the files it is spooling - when first invoked it will use the "temporary file drive", or if this is not set the currently logged in drive. For convenience I recommend that you include the line: SETDEF m:,* [order=(SUB,COM),temporary=m:] (assuming you want the spooler to work from drive M:) in your PROFILE.SUB boot file (for this to work you must have SUBMIT.COM and SETDEF.COM on your boot disk, with at least 1k of free disk space). In mine I also copy various command files across to the RAMdisk (eg DIR, TYPE, PIP and the spooler files) so that I can access them at all times (the m:,* part of the above command causes CP/M to look for command files first on drive M:, and then on the default). The "order=(SUB,COM)" clause tells CP/M to search for .SUB files first (this is a good way of setting up an "alias" file to change default parameters - see Section 2.3). 2.2 Spooling File(s) The spooler is invoked by typing: SPOOL filespec[option1,option2,option3,...] which will copy the specified file(s) to the spool directory (user 15 on the temporary file drive), install the main body of the spooler (a Resident System Extension, or RSX, which is attached to the command file), and initiate spooling. After chaining SPQ.COM to display the spool queue the loader program will terminate, and the file(s) will be printed in the background. When spooling is completed, files in the spool directory are deleted and the resident portion of the spooler will remove itself at the next warm boot. At any time further files can be added to the spool queue, and will be printed when files already in the queue have been printed. It is also possible to list the spool queue or cancel printing of any (or all) files using additional programs (see Sections 2.4 and 2.5). - 4 - CP/M+ Print Spooler User Guide 2.3 Command Line Options When the spooler is invoked, options may be specified in the command line, within square brackets and separated by commas, as shown above. The available options are summarised below (further ones may be added in future releases). Note that the options may be specified in any order. F Filter out non ASCII characters. All control characters other than tabs, carriage returns, linefeeds and formfeeds are stripped. Gn Get files from user area n. This allows the spooling of files in a different user area (similar to the way PIP copies files between user areas). H Add page header. If paging is enabled, a header consisting of the filename and page number is printed at the top of each page. If paging is not enabled, this option is ignored. N No formfeed at end of file. Normally when a file is spooled a formfeed is appended to it, to ensure that the printer is at top of form for the next print (even if no paging is applied to the file). This options allows this to be disabled, to print pre-formatted files or to allow files to run together on a page. O Object file transfer. This option forces the spooler to ignore any end of file markers (control-Z) found in the source file. It is used in printing files of object printer data (eg graphics data). Pn Page file. This option allows a file to be paged with n lines per page. It is especially useful when used with the 'H' and 'T' options to print out listings. If page headers are also enabled, 2 lines less than the figure specified are available for the actual data. T Expand tabs. Replaces all tabs in the source files with sequences of spaces. Remember this is only meaningful for use on ASCII files! Wn Set output width. This option allows the user to specify the maximum line width to pass when spooling an ASCII file (any lines longer than this will be truncated, and the excess discarded). It also determines the horizontal location of the page number at the start of each page (which is right justified). Use this option if you are printing in a different pitch (10, 12 and 17 are the usual values). Z Zero high bits. This option zeroes the high bit on all bytes in the spooled file. It is useful when printing out documentation files produced by a wordprocessor such as Wordstar. If no options are specified the spooler defaults to [f,h,p58,t,w96,z]; otherwise all required options must be specified explicitly. - 5 - CP/M+ Print Spooler User Guide If you use the spooler a lot, you may find that you are continually specifying the same set of options. In this case you should consider modifying the default options. This may be achieved in two ways - either modify the initial values in the SPOOL.ASM file (and then regenerate the spooler), or set up a submit file containing the options required, eg: SPOOL $1[f,h,p55,t,w80,z] If the command above were to be entered into the file SP.SUB (for example), typing SP filespec would spool all of the files matching the file specification, using the options specified in the submit file. This approach has the advantage that several "default" command lines can be set up, using different submit files for each. For example, one could be used for program listings, another for pre-formatted ASCII output (eg from a wordprocessor) and yet another for output from a graphics package. To force CP/M+ to search for a submit (.SUB) file when the command SP filespec is entered use the SETDEF utility in your PROFILE.SUB file (see "The Amstrad CP/M Plus" for fuller details): SETDEF[order=(SUB,COM)] 2.4 Listing The Spool Queue At any time the current contents of the spool queue can be listed to the console, using the program SPQ.COM. When invoked, the program will either display a message stating that the spool queue is empty (which usually means the spooler RSX is not present) or list the queue entries in the format shown below: Position Filename Index Size ------------------------------------------------------------------------ 1 0A:FILE1 .EG 3 4k *** Printing *** 2 2B:FILE2 .EG 4 7k 3 5M:FILE3 .EG 7 16k Number of queue entries = 3 Numer of free queue entries = 11 The "position" column shows the file's current position in the queue, while size is the size of the file, in kbytes, before any print formatting (including tab expansion) was made on it. The "index" column gives the queue index number of each file. This is NOI the same as the queue position, as it directly indicates the physical position of the file's entry in the spool queue (see Section 3.4.5). It remains constant as long as the file is present in the queue, and is taken as a parameter by SPCANCEL.COM (see Section 2.5). - 6 - CP/M+ Print Spooler User Guide If SPQ is invoked with 'C' as a parameter (for continuous) SPQ will continually list the spool queue, updating it as files are printed, and quitting when either spooling completes or a key is pressed. Note that this uses terminal control sequences for clear screen & home cursor - to modify for another terminal use SID to patch the .COM file (the routines to patch start at the addresses given by CLVIEW & HOME in the .SYM file). It is installed for Amstrad machines. Note that, because all printers contain some amount of dedicated RAM, the file actually being printed will lag behind that indicated by SPQ. How far it lags depends upon the amount of RAM fitted. Note also that the number of free queue entries is not simply the difference between the maximum number of queue entries and the number currently in use, due to two factors: (1) The spool queue is a circular array: once the last physical queue position is filled the spooler RSX will allocate space at the front of the queue again, providing it is available. If not, no further files can be added to the queue until space becomes available. (2) If files are deleted the queue space freed is not reclaimed until printing passes that queue position (ie until qnow passes that index number). When a file is removed from the queue its index number entry is set to 0ffh, causing it to be passed over when the spooler reaches it. This byte is also checked by SPCANCEL.COM when attempting to cancel printing of a file (see below). 2.5 Cancelling Printing of Spooled Files Two transient programs, NOSPOOL.COM and SPCANCEL.COM, are provided to cancel the printing of spooled files. The former cancels printing of ALL spooled files - there are no options. It uses the "bugoff" function (see Section 3.4.6) to tell the spooler RSX to cancel all printing and uninstall, before deleting all SPOOLED.nnn files in the spool directory. SPCANCEL allows selective cancelling of printing, taking the queue index number (as shown in the queue list by SPQ.COM) as a parameter to indicate which file to cancel. If the queue index number is invalid or the file has already been deleted (or printed), an error is flagged. Note that when printing of file(s) is cancelled, the printer will not immediately stop functioning due to the data stored in its local RAM print buffer. There is no standard way of cancelling the printing of data which has already been buffered. After cancelling the printing of a file SPQ.COM is chained to display the modified spool queue. - 7 - CP/M+ Print Spooler User Guide 2.6 Restrictions & Ideosyncrasies (1) Due to the nature of the internal operation of the spooler RSX, it cannot be installed from within a submit file (unless it's the last command in the file), nor when GET.COM or PUT.COM are active. This is due to the way these utilities intercept BIOS calls. If the spooler cannot be installed, it will give an error message and terminate. I hope to do something about this at a later date (don't wait up for this one!). (2) Despite the above, it is safe to invoke GET, PUT or SUBMIT once the spooler has been installed. If the spooler completes its operation before GET/PUT/SUBMIT however, it will remain resident (but dormant) until the other routine has terminated. This is to allow the BIOS jump table to be correctly restored after the run, since the other RSX will restore the jumps to the intercept addresses set up by the spooler. Once this has been done, the spooler can restore them to their original values, and exit. A spooler RSX in this condition can, in fact, be reactivated by the loader if further files are spooled before it has completely uninstalled itself. (3) The spooler will not perform a disk access when a directory search is in progress in the foreground, until either a warm boot occurs or another disk call is made by the foreground program. This means that spooling will eventually cease if, for example, DIR is waiting for keyboard input after filling the screen. Similarly, it will not access the disk when the system is waiting for line input if any characters have been entered. This is due to the need to avoid re-entrancy (see Section 3.4.1). If no characters have been entered, the spooler will perform normally. In the event of spooling stopping for this reason, hit RETURN to allow it to restart. (4) The fact that the spooler "steals" CPU time means that the system will experience a performance degradation when it is running. This is particularly noticeable with programs which poll console status to detect ^C etc, where every console status call will cause a character to be printed (provided the printer is ready to accept characters). Examples of such programs are DIR, TYPE, PIP and MBASIC. In addition, I would not recommend running the spooler when a communications package such as UKM7 is active, since these tend to be time-critical. Any program which does not require console input or status will not be affected by any degradation. (5) Because the spooler takes up space at the top of the user TPA, the full 61k is NOT available to transient programs. This means that some programs requiring a large amount of memory may not run. The problem is compounded if further RSX utilities are present. The amount of space lost depends upon the size of the RSX code and disk buffers, and is in addition to the memory lost to the CCP LOADER. The code size is approx 3k, while the buffer size is variable, and initially set at 2k. - 8 - CP/M+ Print Spooler User Guide For most programs this will not cause a problem, the exceptions being those requiring a minimum amount of memory to run, including some application programs, compilers etc. Usually such requirements are mentioned in the documentation - if not, try it and see! Another class of programs which can have difficulty are low level software interfaces which hook themselves into the system, high in memory (like the spooler itself). The most common example is probably Digital Research's GSX graphics system, supplied with the PCW series machines, and used by such programs as DR Draw and DR Graph. GSX drivers need to be located in common memory (like the spooler), and since the DDFXHR8.PRL (Epson FX80 high resolution printer driver) file supplied is 16k in length, I doubt it will fit when any RSX is present (not just the spooler!). Smaller drivers such as the screen or low resolution printer driver don't suffer as badly. (6) As the spooler needs to read the spooled file from disk, DO NOT remove the disk from the drive until the spooler has finished. Use LISTRSX.COM (see below) to check for it if you're not sure whether it's still there. I don't suffer from this problem as I've set up a RAM disk as the temporary/spool drive. This also has the effect of speeding up the operation of the spooler, particularly if a small disk buffer size is being used to save TPA memory. Additionally, it results in the spooler operation being less obvious to the user. Note that this constraint also applies if GET, PUT or SUBMIT is being used to redirect I/O. Also make sure that the disk being used to hold spooled files has sufficient space to hold these files (bear in mind that tab expansion etc can enlarge a file considerably). Be very careful if you use an application program which is disk intensive (eg Wordstar) on the same drive as the spooler: otherwise you may find that your "save & continue" bombs because the spooler has pinched most of the disk space! (7) Because the spooler uses the BIOS List device in the background, foreground processes CANNOT use the printer while the spooler is running. Any such output will be binned by the spooler to avoid messing up the printer output. It may eventually be possible to redirect other list output to a file, and print it later (see Appendix A). The utility LISTRSX can be used to determine whether the spooler, or any other RSX, is resident, and is invoked simply by typing "LISTRSX ". Alternatively, use SID and trace the BDOS vector from 0005h using the "L" command. Full details of the internal operation of the spooler, and the reasons for the constraints above, are given in Section 3. It is not, however, necessary to understand this to use the spooler under normal circumstances. - 9 - CP/M+ Print Spooler User Guide 3. Spooler Internal Operation 3.1 The Nature Of The Beast The first step in implementing any piece of low level software is to understand the nature of the operating system upon which it is to run. CP/M+ is, to both user and programmer, substantially enhanced over CP/M 2.2. The extra features were achieved without encroaching upon the user TPA by writing into the system the ability to cope with banked memory; accordingly the BDOS and BIOS are split across two banks, the resident portions remaining in the TPA bank, and the rest in the system bank (bank 0). As a result, a 61k TPA is available, greater than that in any other version of the operating system. The available BDOS and BIOS functions themselves have been substantially expanded, while remaining largely compatible with previous releases. Among the relevant additional features provided are: (1) Buffered file I/O to speed up disk transfers. (2) A "System Control Block" containing various system flags, accessible to transient programs. (3) A user defineable "Temporary File Drive", to which temporary files can be directed. (4) A facility to add features to the operating system, by means of a "Resident System Extension" (RSX), which is loaded into the top of TPA, and can intercept BDOS & BIOS calls to modify their operation. The full extent of the facilities provided is detailed in "The Amstrad CP/M Plus", but those above are the most relevant to this application. In particular, the RSX facility allows a RELOCATABLE routine to be tagged on to a command file, and automatically loaded to the top of memory when the transient is invoked. The RSX can be temporary, and therefore removed when the program terminates - or semi-permanent, staying resident until the RSX has completed its task. The spooler RSX is of the latter type. 3.2 Implementation Bearing in mind the facilities mentioned above, the main spooler program was written in two parts: (1) A loader, which checks the CP/M version, and copies the spooled file to a "spool directory", actually located in User 15 on the temporary drive (set up on my system to be drive M:, the RAM disk). While doing so it applies any print formatting selected by the user. (2) An RSX, which takes a file passed to it by the loader, and prints it in the background while the system is waiting for console input. - 10 - CP/M+ Print Spooler User Guide 3.3 The Spool Loader This is intended to perform tasks which need only be done when a file is actually spooled, as well as essential functions such as error and version checking. This cuts down the size of the spooler RSX, and thus the amount of TPA space lost when the spooler is running. The functions performed by the loader are, in order: (1) CP/M Version Check - version 3.1 is required. (2) Search for files matching the given ambiguous specification, using the BDOS "Search for First" and "Search for Next" functions. This is performed by the library routine dscan(), which returns an array of fcbs matching the file specification given to it. If no files are found, the program is terminated. (3) Search for the spooler RSX in memory, using the library routine rsxchk(), which searches for an RSX with a specified name, and returns its address if present. In normal operation, this search will ALWAYS find the spooler RSX, since it should be attached to the command file. If this is not the case, the program will terminate. (4) The above test is then repeated, to see whether there is already a copy of the spooler RSX present. If this is the case, the loader will call the spooler to determine whether it is still active. If this is the case, the attached spooler does not need to be installed and files are spooled via the resident RSX. (5) If the attached RSX needs to be installed, a check is made to ensure whether it resides wholly in common memory (above 0C000H in a PCW8512 system). Since the spooler RSX intercepts BIOS calls (see later), it must reside wholly in common memory, or the system will crash. If the spooler cannot be installed due to this constraint, it is necessary to remove some or all of the RSX's occupying the top of the TPA (eg GET, PUT and SUBMIT). (6) If the RSX needs to be installed, each of the BIOS jump table entries redirected by the spooler RSX are first compared with the address of the BDOS entry point - since this is located in common memory it is resident in all banks, and therefore can be used to check whether another process has already redirected some or all of the BIOS jumps required by the RSX. If this is the case, the RSX cannot be installed. It is instructive to note that the utilities GET, PUT and SUBMIT, which redirect BIOS calls, actually convert BIOS character I/O calls to BDOS calls. This would prove disastrous if used with the spooler, since re-entrant BDOS calls could easily occur. Hence the above restriction. Note that the above check will fail if used on BIOS jumps which are always directed to the system bank (notably disk calls), since these are always below the common memory area. - 11 - CP/M+ Print Spooler User Guide (7) For each spooled file, the loader will signal the RSX to allocate an fcb in its directory. These are of the form SPOOLED.nnn, where nnn is the queue index number of the current file. (8) The spooled files are now copied, one by one, to the spool directory (user 15 on the temporary file drive), using buffered file I/O for speed. Print formatting is also applied at this stage. (9) The RSX is signalled to copy the queue entry for the file to its internal queue. (10) The loader will continue to perform steps 7 to 9 until either all files have been copied or the queue, or destination disk is full, in which case an error message is displayed and the program terminated. (11) The loader program terminates - the spooler should print the files in the background. (12) The spooler RSX will remove itself when printing of all queued files has been completed. 3.4 The Spooler RSX The spooler RSX is the real heart of the program, performing all of the background tasks involved in spooling the file without disturbing (waking up?) the user. Its function is essentially to intercept the BIOS jump table entries for console input and status, printing characters from the spool file when no keyboard input is waiting. In order to perform this function, the RSX needs to be able to read the spool file from disk, via BDOS. The most obvious method would be to perform a disk read, when required, from the BIOS intercept routine; unfortunately this will not work, due to the nature of the CP/M system, as detailed below: 3.4.1 The Re-entrancy Problem Re-entrancy is essentially a form of recursion, where a routine (directly or indirectly) calls itself, and as such, is only possible in language systems (eg Pascal) where local variables are stored on a common stack, and not in fixed memory locations (as generally done in assembler). The problem arises with the spooler as a result of the following turn of events: (1) A user program calls BDOS to (for example) read a character. (2) BDOS calls BIOS Conin to get the character from the keyboard. (3) The BIOS call is intercepted by the spooler, which finds that the input buffer is empty, and tries to read the disk file. It calls BDOS, and hence a re-entrant BDOS call has occurred, and CP/M will crash following the disk read. - 12 - CP/M+ Print Spooler User Guide Obviously, this cannot be allowed to happen, and some means of preventing re-entrant calls occurring must be found. The method used in the spooler is to monitor all BDOS calls, setting a disk access lockout flag before the call, and clearing it afterwards: gosys: mvi a,0ffh sta bdosfl ;BDOS call flag = TRUE call bdos ;Do the user's BDOS call push psw ;Save returned value xra a ;A=0 sta bdosfl ;BDOS call flag = FALSE pop psw ;Restore returned value ret ;To Caller When the spooler needs to do a disk read, it first checks the flag BDOSFL, and if it is true, meaning a BDOS call is in progress, it will not attempt it. Note that the call to fill the buffer could be made by a BDOS or BIOS intercept, so the spooler can also access the disk if a foreground program makes only direct BIOS character I/O calls. 3.4.2 BDOS Intercept Methods In order to be able to set/reset the internal disk lockout flag, the spooler needs to be able to intercept all BDOS calls, including those made by any other RSX. The standard method for an RSX to make BDOS calls is via its RSX header, where there is a jump vector to the next RSX up the chain, or to BDOS if there are no others above it. Unfortunately using this intercept would preclude using the spooler with any RSX above it, so a different method is required. In addition PUT, GET & SUBMIT make some of their BDOS calls directly to the BDOS entrypoint (0F606H on a PCW8512). These calls cannot be trapped via the RSX header, so a different approach is required. Examination of the BDOS entry point will reveal that it consists of a jump into BDOS proper: F606 JMP F624 This jump seems to be a general feature of CP/M systems, as it is also present on the Apple /// CP/M 2.2. Whilst this is a reserved area and therefore it is not good practice to rely upon it, there is no other way of intercepting all BDOS calls, and hence the spooler redirects this jump to pass through its "gosys" routine. Note that despite this, all communication between the spool loader and the spooler RSX is intercepted via the RSX header, allowing the RSX and loader to communicate before the BDOS jump has been set up. - 13 - CP/M+ Print Spooler User Guide 3.4.3 The CCP Multiple Command RSX One of the enhancements provided in CP/M Plus is the ability to enter a multiple command at the CCP prompt. This takes the form: A>command1!command2[options]!command3 The exclamation mark is the command separator. When the CCP has finished processing the first command, the second will be executed, and so on until the list is exhausted. The whole thing is implemented by an RSX, which sets flags in the System Control Block when it is ready to provide input. This affects the spooler because the multiple command RSX will also intercept BDOS function 10, and feed characters back to the calling routine. Therefore, if the multiple line RSX is ready to provide input the spooler cannot hang on function 10, as it would do normally, polling console status and printing characters, but must pass on the call. It is possible to determine when this is the case by reading two of the CCP/BDOS flags in the system control block, contained in the byte at offset 18H. The relevant flags are bits 5 and 7, which will be set and unset respectively in this event. If this is the case, the poll will be skipped and the call passed on without interruption. 3.4.4 Spooler Disk Buffering In order to minimise the number of disk accesses made by the spooler the disk input is buffered, using the byte at offset 04AH in the System Control Block (current Multi-Sector Count) and BDOS function 44 (Set Multi-Sector Count). The number of sectors buffered is set by the equate SECTRS in the source of the spooler RSX, and is initially set to 16 (a 2k buffer). This value is obviously a tradeoff between speed and memory useage, and can be reduced if the amount of memory lost (about 5k, including the RSX code) turns out to be a problem. Note that only one disk buffer is used by the RSX, to read the spool file as it is being printed. The copying of the spool file is handled by the spool loader. To further reduce the amount of memory required, the input disk buffer will, once used, overwrite the initialisation code in the RSX, since this is only called once. It is worth noting that spooled files do not contain a CP/M eof marker (control-Z), but are instead padded out with null characters (which are ignored by the printer). This is to allow the spooler to be used with files of object data (eg graphics output) - the spooler RSX does not check for control-Z, but instead detects PHYSICAL eof, ie the error code returned by BDOS following the next attempt to read (past the end of) the file. - 14 - CP/M+ Print Spooler User Guide 3.4.5 Internal Spool Queue Format The queue is stored within the spooler RSX, and consists of an array of 16 byte entries, one for each file, in the format shown below: Byte No(s) Contents 1 (high nybble) User Number 1 (low nybble) Source Drive 2-9 Filename 10-12 Filetype 13 Queue Index Number 14-16 File Size (in 128 byte sectors) Also maintained are two pointers: qnow and qnext, which are respectively the queue index number of the file currently being printed and the next free queue index number. As mentioned earlier, the queue number indicates directly the location of the entry for a particular file. This is used by SPQ and SPCANCEL, which use the qlist function, which returns qnow, qnext, qmax (the maximum number of queue entries) as well as the address of the queue itself. Knowing the queue number, the address of a particular entry can be found from: Address = (Base Address of Queue) + 16*(Queue index Number - 1) 3.4.6 Loader - RSX Communication The spool loader and RSX use BDOS function 60 (Call RSX) to communicate. The RSX functions currently implemented are: 40 (intspl): Install RSX. This is only called once, when the spooler is first invoked. 41 (getnxt): Return fcb for the next file to add to the queue. This is used by the loader to determine the name to use to store the file under in the spool directory. This will be of the form SPOOLED.nnn, where nnn is the next free queue index number. 42 (qcopy): Copy entry to queue. This call tells the RSX to copy the user no, source drive, filename and size of a spooled file to its internal queue, and update its internal pointers. 43 (getdir): Return spool directory. On receiving this call, the RSX returns the drive and user number of the spool directory. If it is waiting to uninstall this will be cancelled since the loader may be about to send it further files. 44 (qlist): List spool queue. Returns the address of the spool queue, primarily for use in cancelling files and listing the spool queue. - 15 - CP/M+ Print Spooler User Guide 45 (abortp): Cancel print. Cancels spooling of one file currently in the queue. If the file is currently being printed, a formfeed is sent to the printer. If the queue number is invalid, the request is ignored. 46 (bugoff): Un-install. Tells the RSX to cease spooling and restore the system to its normal state. This call is used by NOSPOOL to abort spooler operation. Note that this call does not cause the RSX to delete files in the spool directory - this must be handled by the calling program. Further functions are likely to be added with later versions. - 16 - CP/M+ Print Spooler User Guide References 1. "CP/M: The Software Bus", A. Clarke, J. M. Eaton and D. Powys-Lybbe, Sigma Technical Press, ISBN 0-905104-18-8, 1983. 2. "The Amstrad CP/M Plus", A. Clarke and D. Powys-Lybbe, MML Systems Ltd, ISBN 1-869910-00-1, 1986. 3. "CPMSDOSUKUG", The Journal of the CP/M User Group (UK). An Undisguised Plug I would recommend wholeheartedly that, if you use CP/M (or MS-DOS, Concurrent DOS and DOS+) on a regular basis, you join the CP/M & MS-DOS Users Group (UK). The group provides access to the entire public domain of CP/M and MS-DOS software, as well as providing an informal platform for users to exchange views and experience on applications, systems or any aspect of computing. Some extremely useful utilities are available from the Group, as well as languages (eg Lisp, Pascal, Small-C), applications (eg text processing) and much more. Software is supplied for a nominal disk copying fee (currently about £2.65). Enquiries about the Group should be directed to: Diana Fordred, CP/M & MS-DOS Users Group (UK), 72 Mill Road, Dartford, DA2 7RZ. Telephone: (0322) 22669. - 17 - CP/M+ Print Spooler User Guide Appendix A: Future Developments The following features are likely to be added with later revisions: A.1 Improved Operation with Submit Files At the moment there are one or two incompatibilities which slightly restrict the flexibility of the spooler (see Section 2.3). Hopefully some of these can be alleviated following further investigation. A.2 Redirection and Queueing of Other List Output At present any List output occurring when the spooler RSX is active will be thrown away (see Section 2.6). It may eventually be possible to redirect such output to a file and print it later, but note that this would require a separate disk buffer (using more TPA space) and could cause problems with re-entrancy (see Section 3.4.1): because list output can arrive at any time, the spooler would need the capability to write to disk at any time - otherwise characters could be lost. The main problem with this is the need to be able to write characters to a buffer, and therefore to disk, following a BDOS call - causing problems with re-entrancy. The functions in question are 1 (Console input), 2 (Console output), 5 (List output), 9 (print string), 10 (read console buffer), 111 (Print Block) and 112 (List Block). Of these, all but functions 5 and 112 are only relevant if the control-P print toggle in the System Control Block is true. One possible solution to this problem would be to "sense" in advance how many characters are likely to originate from each call (bearing in mind tab expansion by BDOS), and writing to disk before making the call if unsufficient space is present in the buffer. The actual buffering could then be handled by BIOS intercept routines similar in outline to those used in the RSX at present. Direct BIOS List output can be redirected with no problems, so long as it did not originate in BDOS. Whether this is the case can be determined simply using the existing BDOS lockout flag. As a still longer term project it may prove useful to make the spooler semi-permanently resident, and redirecting/queuing ALL list device output. This obviously requires much careful thought before coding can begin! - 18 - CP/M+ Print Spooler User Guide A.3 Monitoring The Progress Of Printing Of A File One problem with SPQ.COM (the queue listing program) at present is that, when printing a large file there is no way (apart from examining the printout, assuming you recognise parts of it) of telling how far through printing the file the RSX is. One way round this would be to display a "running count" of the number of disk sectors read so far against the total number in the file. This could be determined by examining the extent and current record bytes in the fcb of the file within the spooler RSX. A.4 Additional Command Line Options The following features could be added as command line options: * Banners could be prefixed to spooled files to identify them, along with the date and time of spooling of the file. * Page headers. If a long file of tabulated (but not pre-paged) data is printed out it is inconvenient to have only one table heading right at the beginning of page 1 - it would be much more sensible to print it at the head of each page. The spooler could be instructed to print this header (located in a .HDR file) at the top of each page, after the filename and page number (if present). - 19 -