zOs/REXX/ERR

/* copy err begin *** errorhandling, messages, help    ***************/
errIni: procedure expose m.
    if m.err_ini == 1 then
        return
    m.err_ini     = 1
    call utIni
    m.err_saySay  = 1
    m.err_sayOut  = 0
    m.err_handler  = ''
    m.err_handler.0 = 0
    m.err_cleanup = '\?'
    m.err_opt     = ''
    m.err_nest    = 0
    parse source m.err_os .
    m.tso_ddAll   = ''
    m.err_ispf    = 0
    m.err_screen  = 0
    if m.err_os \== 'LINUX' then do
        address tso 'profile MsgId'   /* brauchen wir in tsoAlloc| */
        if sysVar('sysISPF') = 'ACTIVE' then do
            m.err_ispf = 1
            address ispExec 'vget (zScreen zScreenD zScreenW) shared'
            m.err_screen = zScreen
            m.err_screenD = zScreenD
            m.err_screenW = zScreenW
            end
        end
    return
endProcedure errIni

/* configure err ----------------------------------------------------*/
errReset: procedure expose m.
    call errIni
parse arg m.err_opt, m.err_handler
    upper m.err_opt
    call errSetSayOut '-'
    m.err_handler.0 = 0
    if pos('I', m.err_opt) > 0 & m.err_ispf then
        address ispExec 'control errors return'
    return
endSubroutine errReset

/*--- set sayOut and sysSay -----------------------------------------*/
errSetSayOut: procedure expose m.
parse upper arg flags
    if flags \== '-' then
        m.err_opt = space(translate(m.err_opt, '  ' ,'OS')flags, 0)
    m.err_sayOut = pos('O', m.err_opt) > 0
    m.err_saySay = pos('S', m.err_opt) > 0 | \ m.err_sayOut
    return
endProcedure errSetSayOut

/*--- set rc for ispf: ------------------------------------------------
    if a cmd is run by ispStart, its RC is ignored,
         but ISPF passes the value of the shared variable zIspfRc
         back as return code
---------------------------------------------------------------------*/
errSetRc: procedure expose m.
parse arg zIspfRc
    if m.err_ispf then
        address ispExec vput 'zIspfRc' shared
    return zIspfRc
endProcedure errSetRc

/* push error handler -----------------------------------------------*/
errHandlerPush: procedure expose m.
parse arg aH
    ex = m.err_handler.0 + 1
    m.err_handler.0 = ex
    m.err_handler.ex = m.err_handler
    m.err_handler = aH
    return
endProcedure errHandlerPush
/* push error handler return Constant value -------------------------*/
errHandlerPushRet: procedure expose m.
parse arg rv
    call errHandlerPush "return '"rv"'"
    return
/* pop  error handler -----------------------------------------------*/
errHandlerPop: procedure expose m.
    if m.err_handler.0 < 1 then
        call err 'errHandlerPop but err_handler.0='m.err_handler.0
    ex = m.err_handler.0
    m.err_handler = m.err_handler.ex
    m.err_handler.0 = ex - 1
    return
endProcedure errHandlerPop
/* pop  error handler -----------------------------------------------*/
errHandlerCall:
    interpret m.err_handler
    m.err_handlerReturned = 0
    return ''
endProcedure errHandlerCall
/*--- error routine: abend with message -----------------------------*/
err:
    parse arg ggTxt, ggOpt
    if abbrev(ggOpt, '^') then
        return substr(ggOpt, 2)
    call errIni
    ggNx = m.err_nest + 1
    m.err_nest = ggNx
    m.err_nest.ggNx = ggTxt
    if ggNx \== 1 & ggNx \== 2 then do ggNx=ggNx by -1 to 1
        say '  error nesting.'ggNx '==>' m.err_nest.ggNx
        end
    drop err handler cleanup opt call return stackHistory
    if ggOpt == '' & m.err_handler <> '' then do
        m.err_handlerReturned = 1
        ggRet = errHandlerCall()
        ggDoR = m.err_handlerReturned
        m.err_handlerReturned = 1
        if ggDoR then do
            m.err_nest = m.err_nest - 1
            return ggRet
            end
        end
    call errSay ggTxt
    call errCleanup
    if ggOpt == '' then
        ggOpt = m.err_opt
    upper ggOpt
    if pos('T', ggOpt) > 0  then do
        trace ?r
        say 'trace ?r in err'
        end
    if pos('H', ggOpt) > 0 & m.err_cat == 'f' then
        x = show + stackHistory + by + bad + arithmetic + conversion
    call errSay ' }errorhandler exiting with exit(12)'
    m.err_nest = m.err_nest - 1
    exit errSetRc(12)
endSubroutine err

/*--- error routine: user message cleanup exit ----------------------*/
errAddCleanup: procedure expose m.
parse arg code
    call errIni
        /* concatenate backwards, then it is executed also backwards */
    m.err_cleanup = '\?'code || m.err_cleanup
    return
endProcedure errAddCleanup

errRmCleanup: procedure expose m.
parse arg code
    call errIni
    cx = pos('\?'code'\?', m.err_cleanup)
    if cx > 0 then
        m.err_cleanup = delStr(m.err_cleanup, cx, length(code)+2)
    return
endProcedure errRmCleanup

errCleanup: procedure expose m.
    call errIni
    m.err_saySay  = 1
    m.err_sayOut  = 0

    if m.err_cleanup <> '\?' then do
        do while m.err_cleanup <> '\?'
            cx = pos('\?', m.err_cleanup, 3)
            c1 = substr(m.err_cleanup, 3, cx-3)
            m.err_cleanup = substr(m.err_cleanup, cx)
            say 'errCleanup doing' c1
            interpret c1
            end
        say 'errCleanup end doing err_cleanup'
        end
    if m.tso_ddAll <> '' then
        call tsoFree m.tso_ddAll, 1
    return
endProcedure errCleanup

/*--- say an errorMessage msg with pref and linesplits --------------*/
errSay: procedure expose m.
parse arg msg
    return errSaySt(splitNl(err_l, 0, errMsg(msg)))

errSaySt: procedure expose m.
parse arg st
    if m.err_saysay | \ m.err_sayOut then
        call saySt st
    if m.err_sayOut & \ ( m.err_saySay & m.j.out == m.j.say) then
        call outSt st
    return st
endProcedure errSaySt

/*--- prefix an errormessage with pref,
          split it into lines at \n to stem m.err -------------------*/
errMsg: procedure expose m.
parse arg msg
    m.err_cat = 'f'
    do while substr(msg, 2, 1) == '}'
        parse var msg m.err_cat '}' msg
        end
   if m.err_cat == ' ' | m.err_cat == 'o' then
        return msg
   pTxt = ',fatal error,error,input error,scanErr,warning,onlyMsg,'
   px = pos(','m.err_cat, pTxt)
   if px < 1 then do
       px = 1
       m.err_cat = 'f'
       end
   pre = substr(pTxt, px+1, pos(',', pTxt, px+2)-px-1)
   if m.err_cat == 's' then
       return pre msg
   parse source . . s3 .              /* current rexx */
   return pre 'in' s3':' msg
endProcedure errMsg

/*--- fill stem st with lines of msg separated by \n ----------------*/
splitNl: procedure expose m.
parse arg st, sx, msg
    bx = 1
    sx = firstNS(sx, 1)
    do lx=sx+1 to sx+999
        ex = pos('\n', msg, bx)
        if ex < bx then
            leave
        m.st.lx = substr(msg, bx, ex-bx)
        bx = ex+2
        end
    m.st.lx = substr(msg, bx)
    m.st.0 = lx
    return st
endProcedure splitNl

/*--- out msg lines separated by \n ---------------------------------*/
outNL: procedure expose m.
parse arg msg
    return outSt(splitNl(err_outNl, 0, msg))

/*--- say msg lines separated by \n ---------------------------------*/
sayNl: procedure expose m.
parse arg msg
    return saySt(splitNl(err_outNl, 0, msg))

/*--- say (part of) the lines of a stem -----------------------------*/
saySt: procedure expose m.
parse arg st, fx, tx
    do lx=firstNS(fx, 1) to firstNS(tx, m.st.0)
        say strip(m.st.lx, 't')
        end
    return st
endProcedure saySt

/*--- say a trace message if m.trace is set -------------------------*/
debug: procedure expose m.
parse arg msg
    if m.debug == 1 then
        say 'debug:' msg
    return
endProcedure debug

/*--- output a trace if m.trace is set ------------------------------*/
trc: procedure expose m.
parse arg msg
    if m.trace == 1 then
        call out 'trc:' msg
    return
endProcedure trc

/*--- assert that the passed rexx expression evaluates to true ------*/
assert:
    interpret 'if ('arg(1)') == 1 then return 1'
    interpret 'call err' quote('assert failed' arg(1)':' arg(2) '==>'),
                        arg(2)
endProcedure assert

/*--- abend with Message after displaying help ----------------------*/
errHelp: procedure expose m.
parse arg msg
    call errSay 'i}'msg
    call help 0
    call err 'i}'msg
endProcedure errHelp

/*--- display the first comment block of the source as help ---------*/
help: procedure expose m.
parse arg doClear
    if doClear \== 0 then
        address tso 'clear'
    parse source . . s3 .
    say right(' help for rexx' s3, 72, '*')
    do lx=1 while pos('/*', sourceLine(lx)) < 1
        if lx > 10 then
            return err('initial commentblock not found for help')
        end
    doInc = 1
    ho = m.err_helpOpt
    do lx=lx+1 to sourceline() while pos('*/', sourceline(lx)) = 0
        li = strip(sourceLine(lx), 't')
        cx = lastPos('{', li)
        if cx > 0 then do
            if length(ho) = 1 then
                doInc = cx = length(li) | pos(ho, li, cx+1) > 0
            li = left(li, cx-1)
            end
        if doInc then
            say li
        end
    say right(' end help for rexx' s3, 72, '*')
    return 4
endProcedure help

/* copy err end   ****************************************************/