!pr2
ROGRAM TOO LARGE???..................................Lee Meador

I was writing an ampersand file-handling routine, using the File Manager in DOS as described in chapter 6 of Beneath Apple DOS.  I wanted my Applesoft program to be able to set ONERR and catch errors in files (wrong name, too short, etc.)  But I also wanted the error messages to come out in immediate mode or with no ONERR set.  Since I was doing my own file-handling, I was going to have to provide my own error outputs.  Originally I tried this:

!lm+5
ERROR  LDY #$0A        error code offset
       LDA ($04),Y     $04 -> FM parmlist
       JMP $A6D2       jump into DOS error handler
!lm-5

This worked OK when used in code that was called from an Applesoft program, but when I called it in immediate mode (from the "]") I would always get "ROGRAM TOO LARGE" when an error occurred.

You might guess that I have found a solution.  The problem is caused when we jump into DOS at $A6D2 with the IO hooks still pointing into DOS.  The routine starting at $A6D2 saves the error code in a temporary location at $AA5C and calls $A702 to print a "<return><beep><return>".  Since we entered illegally that output goes to DOS at $9EBD, then via a JSR to $9ED1 where the accumulator is saved in a temporary location -- $AA5C!  This leaves that last <return> in $AA5C.

When control returns to the error handler DOS then tries to look up error message number 141 ($8D) in the 16-entry table of offsets starting at $AA3F.  This loads the offset from location $AACC, which happens to contain the high-order byte of the address of the OPEN command handler ($AB22)!  This leaves the error message printer with an offset of $AB into the messages at $A971.  And that is what produces "ROGRAM TOO LARGE".  Look at the routines at $A6D2 and $A702 for more detail.  $A702 is meant to be called with the error code in the X register.

Now here's a method to have the error handled correctly:

!lm+5
OUT.HOOK  .EQ $36
HARD.COUT .EQ $FDF0

ERROR  LDA #HARD.COUT  point hook out of DOS
       STA OUT.HOOK
       LDA /HARD.COUT
       STA OUT.HOOK+1  DOS will fix it back
       LDY #$0A        index to error code
       LDA ($04),Y     $04 -> FM parmlist
       JMP $A6D2       do it ...
!lm-5

That takes care of getting the right error messages.  Now if I could just figure out some way to make sure that no errors ever occur. . .
