Contributed by: Doug Rickman
The standard failure mode for REXX results in termination of execution but provides information about the error and gives the line that failed. This routine provides the same information and a little additional detail and then returns to the program. Thus execution can continue. If run inside a VisProREXX routine information is provided via a dialog window, otherwise a say instruction is used.
To use this routine place a line like "signal on syntax name GenericError" into your program and add this subroutine.
/* --- begin subroutine - GenericError: -------------*/
/* A generic error handler. The user will get information about the error */
/* and processing will continue. Hopefully the calling routine will be able */
/* to handle the fact something is messed up. */
/* */
/* This routine is designed to be used within a generic REXX program or in a */
/* VisProRexx program. It will handle VisProRexx routines when executed in */
/* testing mode, i.e. when doing a "CNTRL-R" while editing a VisProRexx */
/* program, and when running a VisProRexx .exe. If this is used in a */
/* VisProRexx program a dialog box will provide the information to the user, */
/* otherwise the say instruction is use. */
/* */
/* Returns the condition and line number. Example: SYNTAX Error: 3023 */
/* The general form of the return is: */
/* condition('c') 'Error:' SourceLineN_generating_error */
/* */
/* With two exceptions variables used internal to this routine start with */
/* the string "GenericError." Example: "GenericError.1SourceLineN" */
/* Note that tails of "GenericError." all start with the character "1". */
/* These are all dropped before the routine returns. One exception is the */
/* variable "RC". I figured this one was surely safe. ;-) The other */
/* exception is "GenericErrorQUIET". If this equals 'YES' then the output */
/* to the user is suppressed. */
/* */
/* GenericErrorQUIET should be set somewhere in the main program. */
/* */
/* Programmer's notes: */
/* I created this because I've a large suite of binary files which I must */
/* read and decipher. The files are buggy and trying to handle all possible */
/* syntax errors was too difficult. Therefore a graceful syntax handler was */
/* needed. I realized that what I created was not specific to syntax and */
/* could be used generically if desired. */
/* */
/* SEE THE NOTE AT THE END OF THIS SUBROUTINE IF USING VISPROREXX! */
/* */
/* Doug Rickman May 8, 20000 */
GenericError:
GenericError.1SourceLineN = SIGL
GenericError.1ReturnErrorCode = RC
/* Default values. These will be changed if program is not VisProREXX code. */
GenericError.1VisProRexx = 'YES'
GenericError.1Offset = 2
GenericError.1LineEnd = '0a'x
parse source . . GenericError.1Source
parse value parsefn(GenericError.1Source) with,
GenericError.1drive,
GenericError.1path,
GenericError.1exe,
GenericError.1extension
/* Read the source file into memory. */
GenericError.1Size=stream(GenericError.1Source,'c','query size')
GenericError.1rc =stream(GenericError.1Source,'c','open read')
GenericError.1Data=charin(GenericError.1Source,,GenericError.1Size)
GenericError.1rc =stream(GenericError.1Source,'c','close')
/* Find where to start. A VisProRexx program adds complication. */
/* We are looking for a string VisPro uses at the start of a program. But */
/* we have to dodge the fact that the same string is in the comment block at */
/* the end of this subroutine. */
GenericError.1Start = pos('_VPAppHandle = VpInit()' ,GenericError.1data)
GenericError.1Startb = pos("'_VPAppHandle = VpInit()'",GenericError.1data)
if GenericError.1Startb = GenericError.1Start -1 then do
GenericError.1VisProRexx = 'NO'
GenericError.1start = 1
GenericError.1Offset = 0
GenericError.1LineEnd = '0d0a'x
end
parse var GenericError.1data . =(GenericError.1Start) GenericError.1Data
/* Read the source file. */
do GenericError_LoopCounter = 1 to GenericError.1SourceLineN-GenericError.1Offset
parse var GenericError.1data GenericError.1v '0a'x GenericError.1data
end GenericError_LoopCounter
GenericError.1v = strip(GenericError.1v,'T','0d'x)
select
when GenericError.1ReturnErrorCode='RC' then do
GenericError.1rc=' '
GenericError.1mesg=' '
end
/* If there is special handling for certain error codes, insert them here.*/
otherwise GenericError.1mesg=sysgetmessage(GenericError.1ReturnErrorCode)
end /* select */
message='A serious REXX ERROR has occurred! I do not know what.' GenericError.1LineEnd GenericError.1LineEnd,
"Other information for a programmer's use:" GenericError.1LineEnd,
'The program line that generated this error is:' GenericError.1SourceLineN GenericError.1LineEnd,
'"' GenericError.1v '"' GenericError.1LineEnd,
GenericError.1LineEnd,
'Condition:' condition('c') GenericError.1LineEnd,
'Instruction:' condition('i') GenericError.1LineEnd,
'Description:' condition('d') GenericError.1LineEnd,
'Status:' condition('s') GenericError.1LineEnd,
'RC: 'GenericError.1ReturnErrorCode GenericError.1mesg GenericError.1LineEnd,
'Good luck, Sucker.'
select
when GenericErrorQUIET = 'YES' then nop
when GenericError.1VisProRexx = 'YES' then
response=VpMessageBox(window,'Oops! Oh now what is the problem!',message)
otherwise say message
end /* select */
rc = condition('c') 'Error:' GenericError.1SourceLineN
drop GenericError. GenericError_LoopCounter
return rc
/* THIS NOTE MUST NOT BE MOVED TO HEAD OF SUBROUTINE. IT CONTAINS A COPY OF */
/* THE KEY STRING USED TO RECOGNIZE A VISPROREXX PROGRAM. */
/* */
/* The routine searches the source for the string "_VPAppHandle = VpInit()" */
/* which normally denotes the start of a VisProREXX program. If your code */
/* also explicitly has this string and is not a VisProREXX program you will */
/* want to add an additional check or modify GenericError(). */
/* */
/* --- end subroutine - GenericError: -------------*/
/*---------------------------------------------------------------------------*/