/* Copyright 2003-2023 James F. Duff */
/* License and disclaimer: http://www.eight-cubed.com/disclaimer.html */

#define __NEW_STARLET 1

#include <stdio.h>
#include <stdlib.h>
#include <ssdef.h>
#include <stsdef.h>
#include <descrip.h>
#include <chfdef.h>
#include <lib$routines.h>
#include <starlet.h>

#include "errchk.h"

#ifndef SS$_UNLOCKED
#define SS$_UNLOCKED 4764
#endif


/******************************************************************************/
static int handler (struct chf$signal_array *sig_array,
                    struct chf$mech_array *mech_array) {
/*
** This is a condition handler.  Usually condition handlers return SS$_CONTINUE
** or SS$_RESIGNAL, depending on if they can or cannot handler the condition.
** A third method to return exists, and that is to call SYS$UNWIND.
*/

static int r0_status;
static unsigned int flags;

static int index;

static unsigned char outadr[4];
static char message[256];
static char outbuf[512];

static struct dsc$descriptor_s message_d = { 0,
                                             DSC$K_DTYPE_T,
                                             DSC$K_CLASS_S,
                                             message };
static struct dsc$descriptor_s outbuf_d = { 0,
                                            DSC$K_DTYPE_T,
                                            DSC$K_CLASS_S,
                                            outbuf };

static unsigned int ss$_unwind = SS$_UNWIND;
static unsigned int ss$_abort = SS$_ABORT;
static unsigned int ss$_unlocked = SS$_UNLOCKED;

    index = lib$match_cond ((unsigned int *)&sig_array->chf$is_sig_name,
                            &ss$_unwind,
                            &ss$_abort,
                            &ss$_unlocked);
    switch (index) {
        case 0 :
            /*
            ** We can't handle this exception.  Resignal.
            */
            return SS$_RESIGNAL;
            break;
        case 1 :
            /*
            ** Unwinding.  Usually just do nothing.  For this demo, say
            ** what's going on.
            */
            (void)printf ("Unwinding...\n");
            break;
        case 2 :
        case 3 :
            /*
            ** Display appropriate message.
            */
            message_d.dsc$w_length = sizeof (message);
            r0_status = sys$getmsg (sig_array->chf$is_sig_name,
                                    &message_d.dsc$w_length,
                                    &message_d,
                                    flags,
                                    outadr);
            errchk_sig (r0_status);

            if (sig_array->chf$is_sig_args > outadr[1]) {
                outbuf_d.dsc$w_length = sizeof (outbuf);
                r0_status = sys$faol (&message_d,
                                      &outbuf_d.dsc$w_length,
                                      &outbuf_d,
                                      &sig_array->chf$is_sig_arg1);
                errchk_sig (r0_status);

                (void)printf ("%-.*s\n",
                              outbuf_d.dsc$w_length,
                              outbuf_d.dsc$a_pointer);
            } else {
                (void)printf ("%-.*s\n",
                              message_d.dsc$w_length,
                              message_d.dsc$a_pointer);
            }

            if (index == 2) {
                /*
                ** For SS$_UNLOCKED, return to the module that established
                ** the handler, i.e., routine ()
                */
                r0_status = sys$unwind (0, 0);
            } else {
                /*
                ** For SS$_ABORT, return to the caller of the module that
                ** established the handler, i.e., main ()
                */
                r0_status = sys$unwind ((unsigned int *)&mech_array->chf$is_mch_depth,
                                        0);
            }
            errchk_sig (r0_status);
            break;
        default :
            (void)printf ("Unexpected index from lib$match_cond (): %d!\n",
                          index);
            (void)sys$exit (SS$_ABORT);
            break;
    }
    return SS$_CONTINUE;
}


/******************************************************************************/
static void routine (void) {

static $DESCRIPTOR (lock_d, "Pandora's box");

    /*
    ** Establish a condition handler.
    */
    (void)lib$establish (handler);

    /*
    ** Signal SS$_UNLOCKED.  Note you can pass parameters via the signal
    ** array to the condition handler by including optional arguments to
    ** LIB$SIGNAL.
    */
    (void)lib$signal (SS$_UNLOCKED, &lock_d);

    /*
    ** Because the condition handler called unwind with zero as the first
    ** parameter, control returns here.
    */
    (void)printf ("After unlocked\n");

    /*
    ** Signal SS$_ABORT.
    */
    (void)lib$signal (SS$_ABORT);

    /*
    ** Because the condition handler called unwind with an appropriate depth
    ** as the first parameter, control never returns here.  It returns to the
    ** caller of the routine that established the handler.  That is, the
    ** main () routine.  Therefore, this printf statement never executes.
    */
    (void)printf ("After abort\n");
}


/******************************************************************************/
int main (void) {

    routine ();

    /*
    ** Control returns here after the second call to unwind.
    */
    (void)printf ("After routine ()\n");
}

Back to the master examples list.