C for Yourself - part 48

Aborting jobs and entering the printing loop - Steve Mumford explains

Last time round, I introduced the principle of using a structure of type _kernel_oserror to determine whether an SWI command had completed successfully; the _kernel_swi function returns a pointer to a structure of this type, so it's possible to test for errors in the following manner:

_kernel_oserror *ERR = NULL;
ERR = _kernel swi(PDriver_DrawPage, &in, &out);
if (ERR != NULL)
  /* Deal with the error */

If we haven't been given a pointer to an error structure, we're safe. On the other hand, if something has gone wrong, it's nice to know a little more about it: Here's what the structure actually contains, as declared in <kernel.h> - we're given the appropriate error number and associated zero-terminated string:

typedef struct
  int errnum;
  char errmess[252];
} _kernel_oserror;

Assuming the error didn't occur in the middle of something critical, this information would enable the programmer to pop up a standard error dialogue box with very little work necessary, using one of the functions already set up:

au_report_error(ERR->errnum, ERR->errmess, 0, appname);

However, producing such an error window when we're in the middle of a print job could prove disastrous - if the error occurred during the PDriver_GetRectangle loop, it would probably compound the problem and destroy all hope of the program recovering gracefully. This is where we have to employ one of several escape routes.

Aborting printer jobs

The SWI call that's most useful in this situation is PDriver_AbortJob; this command allows the programmer to pull the plug on a job before things get out of hand. The SWI should be called as soon as a fatal error has been detected, and before any attempt has been made to convey the message to the user by way of an error box. It takes one parameter, the file handle of the job to be terminated, in register zero - given this, the SWI will stop redirection of output to the printer and once you've closed the associated files, the program can continue. At this stage, it's safe to inform the user that something was amiss.

During the development of a program, the chances are that the programmer will come across the odd error that causes the printer drivers to go haywire; if this is the case, there's a 'silver bullet' SWI that will abort all active print jobs on the system. PDrlver_Reset takes no parameters and, due to its somewhat ruthless nature, shouldn't be used in the normal course of events.

The drawing loop

Now we know how to shut down the printer in an emergency, we can continue with the output cycle - having reached the stage of calling PDriver_GiveRectangle to define what output should appear on the printed page, along with any rotations or transformations, the next step is to call PDriver_DrawPage and enter the actual drawing cycle. The SWI takes four parameters, but only the first two are vital:

_kernel_oserror *ERR=NULL;
_kernel_swi_regs in, out;

in.r[0] = copies;
in.r[1] = (int) &box;
in.r[2] = 0;
in.r[3] = 0;
ERR = _kernel_swi(PDriver_Drawpage, &in, &out);
if (ERR != NULL)
  /* bail out gracefully */

Register 0 holds an integer representing the number of copies you wish to make of the current page, and R1 points to a four-word block of memory that will hold the coordinates of the first rectangle the printer driver wishes you to print. R2 holds the number of the page about to be printed, and R3 points to a textual string representing the page number - these allow PostScript output to adhere more strongly to Adobe's guidelines, but if you don't wish to make use of them, setting both registers to zero will disable this function.

On return, if register 0 is non-zero, it indicates that the coordinates of an area have been placed in the block pointed to by R1 (low x and y coordinates first, followed by high x and y), and you should draw any objects contained within that rectangle. After this first round of plotting, the programmer should call PDriver_GetRectangle, with R1 pointing to the four-word block already in use.

It's essentially a continuation of the former SWI, setting R0 according to whether anything remains to be printed and returning another block of coordinates if appropriate. As soon as this call returns R0 with a value of zero, you should stop printing the current page and repeat the process from PDriver_GiveRectangle if you wish to print any more. Otherwise, a call to PDriver_EndJob with R0 set to the print job file handle, followed by the closing of the file itself, will bring the procedure to a close.

Source: Acorn User - 192 - March 1998
Publication: Acorn User
Contributor: Steve Mumford