A FAILURE condition happens when there is some severe error that an add-on Function you call in a DLL, or (non-REXX) program that you run, encounters as a result of doing its work. For example, if you try to run some program that downloads a web page to a file, and that program can't be found, a FAILURE condition may occur.

Note: If your script is not trapping FAILURE, but is trapping ERROR, then REXX will raise ERROR whenever it would otherwise raise FAILURE. In other words, if you want reported only critical errors with add-on DLLs or EXEs you run (but not other errors), then trap only FAILURE (not ERROR). If you want reported both critical and all other errors with add-on DLLs and EXEs, then you need trap only ERROR (not FAILURE).


FAILURE error/sub-error numbers

Whenever a FAILURE condition is raised, an error number, and possibly a sub-error number as well, is associated with that instance of the condition being raised. Each one of the numerous reasons for FAILURE being raised will produce a different combination of error/sub-error numbers. So, by checking the error/sub-error numbers, you can deduce exactly what went wrong in your script (ie, why the FAILURE condition was raised).

Your handler can use the CONDITION() built-in function's 'E' option to fetch the error and sub-error numbers associated with a given instance of that condition. CONDITION('E') will return the two numbers separated by a dot. For example, 80.81 will be returned for a FAILURE condition raised because an environment chose to raise this condition when you passed the environment a particular command. You'd have to consult the documentation with the environment to determine why it may have reacted this way to that particular command.

The error number can be thought of as a "general category number". And the sub-error number is a specific error within that category.

The following chart lists the error and sub-error numbers associated with the FAILURE condition, and what is the meaning of each combination of error/sub-error number.

65 An untrapped FAILURE condition occurred in a child script. Reginald-only. CONDITION('D') reports the script name, exact error, and line number.
40 An error in running an executable.
  1 An environment raised a FAILURE condition when it was passed a command.
  2 Your script tried to pass a command to an environment that does not exist and can't be autoloaded.
  3 An executable (EXE) run by your script raised a FAILURE condition.
  4 An exit handler raised a FAILURE condition when you tried to pass a command to an Environment.
  5 The GETENV() or VALUE() built-in function failed to return an environment variable's value.
50 An error in registering an add-on Function in a DLL.
  10 There is another function already registered with the same REXX name.
  40 The DLL (in which the add-on function is supposed to be located) can't be found.
  50 The add-on function name can't be found in the DLL.
70 A FUNCDEF registered function was defined to return a str, char[], or struct, but it did not return the expected item. This happens only if you ask to be informed of errors via the FAILURE condition when you FUNCDEF the function.

For errors under categories 40 and 50, the RXFUNCERRMSG() built-in may return a more informative error message than CONDITION('D').

Note: Reginald's CONDITION() function has an additional option. CONDITION('M') will present a pop-up message box containing the error message, the name of the script in which FAILURE was raised, the source line and line number upon which ERROR was raised, and a Help button to bring up a help page for that error. This is preferable to trying to create your own message to present to the person running your script, since the online help may be supplied by the entity raising the condition.

Here's an example of how we try to register two add-on Functions named "Function1" and "Function2" in a DLL named "mydll". We trap the FAILURE condition to check for any problems (instead of checking each return from RXFUNCADD()):

/* Put everything inside a DO/END so we can use CATCH FAILURE. */
DO

   /* Register add-on "Function1". */
   RXFUNCADD("Function1", "mydll", "Function1")

   /* If the above RXFUNCADD fails, REXX will do the CATCH FAILURE. */

   /* Register add-on "Function2". */
   RXFUNCADD("Function2", "mydll", "Function2")

   /* If the above RXFUNCADD fails, REXX will do the CATCH FAILURE. */

   /* Here we could RXFUNCADD or FUNCDEF more functions. */

   CATCH FAILURE
      /* Let Reginald display the error message box. */
      CONDITION('M')

      /* Because it is RXFUNCADD() that caused this FAILURE,
       * a more informative error message may be returned
       * by RXFUNCERRMSG(), so let's display that too,
       * preferably using REXX GUI's GuiSay.
       */
      IF RXFUNCQUERY('GUISAY') == 0 THEN GUISAY(RXFUNCERRMSG())
      ELSE SAY RXFUNCERRMSG()

      /* Get out of here. */
      RETURN 

END

/* If we got here, then none of our above RXFUNCADD's failed.
 * We could now continue with the rest of our script. As you can
 * see, by using FAILURE, we can eliminate a lot of error
 * checking for numerous calls to RXFUNCADD, but this works
 * only with Reginald (ie, not other interpreters).
 */

Trapping FAILURE in a child script

The Reginald interpreter allows you to trap an ERROR condition raised in any child script you call (as well as any other child script that the first child calls), if that script doesn't trap ERROR for itself.

Your script must use a CATCH FAILURE instruction where you call the child script. If FAILURE is then raised by the child script, the child script will abort on the line where FAILURE occurs, and Reginald will raise FAILURE in your script (on the line where you called the script). In this case, CONDITION('E') returns an error number of 65 to indicate that it was a child script (as opposed to your script) in which FAILURE was raised. CONDITION('D') will return an error message that reports the name of the child script in which FAILURE was raised, the line number where it occurred in the child script, and a reason why the condition was raised.

What this means is that, using the CATCH FAILURE, if a child script doesn't handle FAILURE for itself, you can force that child script to be aborted and have that FAILURE automatically reported back to you by REXX.

Here is an example handler that would differentiate between FAILURE raised in your script versus another script that you called:

CATCH FAILURE
   IF CONDITION('E') == '65' THEN DO

      PARSE VALUE CONDITION('D') WITH . '"' scriptname '"' . 'line ' linenum ': ' reason

      /* CONDITION('M') is preferable to this SAY. */
      SAY 'FAILURE condition raised in "'|| scriptname ||'" at line' linenum ':' reason

   END

   ELSE

      /* CONDITION('M') is preferable to this SAY. */
      SAY 'FAILURE condition raised in this script:' CONDITION('D')

   RETURN

RC variable

When you're passing a command to some environment, or telling the operating system (ie, 'CMD' environment) to run some program, the special variable RC will be set to any error message or number returned by the program you run, or by the environment to which you pass a command. This variable is set regardless of whether you have your own FAILURE handler, so you can always check the RC variable to see what error message or number a program or environment has returned. Often, the number 0 will be returned to indicate success, but this is just a guideline.

Note: The RC variable is created by the REXX interpreter, which assigns it a value when a condition is raised. You should never name your own variable RC, but may reference this variable.