Perhaps my most useful routine is my common ERROR routine. I expect I'll add more, but I'm going to start with this.
The routine is intended to be in user programs that require input parameters, and while parsing that, tell the user that he/she has made a mistake. That said, today, the most common use is to tell me that I've messed up my program. I use that quite a lot. It points me directly to the place in my program that I've messed up. Okay,
The ERR routine can just print an info msg, or an error msg, or and error msg + input data
If the first char of the msg is blank, it's an informational msg, and control comes back. (otherwise it ABENDs.)
If the first char is "$" then the input data record is also printed.
Otherwise, just the error msg AND PROGRAM LOCATION is printed.
For example an error msg + data, from loc 0892. looks like.
ERR AT 0892 LOOKING FOR COMMA, FOUND=),
The minimal generated code to get to the error routine looks like ...
ERR BNE,'$UNKNOWN VALUE IN SETUP CONTROL'
+ BE SYS0006Z
+ BAL R14,ERR
+ DC AL1(30),C'$UNKNOWN VALUE IN SETUP CONTROL'
+SYS0006Z DS 0H
Or, one could have coded:
ERR BNE,'UNKNOWN VALUE IN SETUP CONTROL' and the err msg would be:
ERR AT 0892 UNKNOWN VALUE IN SETUP CONTROL
OR, one could have coded:
ERR BNE,' INPUT CONTROL CARDS ALL OKAY' and the msg would be:
MSG AT 0892 INPUT CONTROL CARDS ALL OKAY and execution would continue normally.
There are 2 macros that I use for this, both intended to generate the minimum amount of code possible (plus, of course, the actual ERR routine).
* ---------------------------------
With the ERR macro, I code "BE" (branch equal) and the generated code does a BNE (branch not equal) around the call to the ERR routine.
MACRO
&LBL ERR &BC,&MSG
LCLC &L
LCLA &N
&N SETA K'&MSG-3
&L SETC 'SYS&SYSNDX'
&LBL REVB &BC,&L.Z
BAL R14,ERR
DC AL1(&N),C&MSG
&L.Z DS 0H
MEND
* ---------------------------------
REVB is nice. I code "branch equal" to the error routine, and the generated code is branch not equal around the call and continue execution normally. This is shown above where I coded BNE and the assembled BRANCH instruction goes around the call and the program continues.
MACRO
&LABEL REVB &COND,&TO
LCLC &C,&B
LCLA &LEN
AIF ('&COND' NE 'B').ADDREM
&LABEL NOP &TO
MEXIT
.ADDREM ANOP
&LEN SETA K'&COND
AIF ('&COND'(2,1) NE 'N').ADD
&B SETC '&COND'(3,&LEN-2)
AGO .DOIT
.ADD ANOP
&B SETC '&COND'(2,&LEN-1)
&B SETC 'N&B'
.DOIT ANOP
&LABEL B&B &TO
MEND
* ---------------------------------
And the actual ERRor routine is ...
ERRMVC MVC LINE+12(0),1(R14)
DC F'0'
ERR LA R1,0(R14)
ST R1,ERR-4
*
MVC LINE,LINE-1 PRINT BOTH ERROR AND GENERAL MSG
SR R15,R15 LOAD DATA LENGTH-1
IC R15,0(R14)
EX R15,ERRMVC
MVC LINE(7),=C'ERR AT '
* --------------------------------------------------------------
SR R1,R13 IF NOT, WRITE THE MSG AND ABEND
ST R1,12(R13)
UNPK LINE+7(5),14(3,R13)
TR LINE+7(4),HEX-240
MVI LINE+11,C' '
*
CLI 1(R14),C' ' Q. DO WE ABEND
BNE *+14 NO.
MVC LINE(3),=C'MSG' YES, INDICATE MSG, NOT ERR
LA R14,1(R14) AND POINT PAST $
*
CLI 1(R14),C'$' Q. PRINT SYSIN CARD
BNE *+18 NO
LA R1,LINE+15(R15) YES CALC END OF MSG LOC
MVC 0(32,R1),PARM AND MOVE CARD DATA.
MVI LINE+12,C' '
*
PUT SYSPRINT,LINE-1
MVC LINE,LINE-1
* ----------------------------------------
L R14,ERR-4
CLI 1(R14),C' '
BNE ERRABEND
SH R14,=H'8'
LA R15,15
EX R15,0(R14)
ERRABEND ABEND 1
end