This idea came to me the other night. And may be explained by the slight
fever induced by my flu vacination. As a bit of background, I like to
write my HLASM code to be non-self-modifying (i.e. can be loaded and run
successfully in R/O key zero memory, like LPA). I was always upset
because IBM did not have any kind of standard setup macro to help me
with this. In reading, I came across the CEEENTRY macro. This macro
makes my start up and shutdown easier. Well, easier than coding up my
own. So, especially for my UNIX programs, I started using the CEEENTRY
macro and LE subroutines; that is the CEE* programs. Soon afterwards, it
dawned upon me that since all the regular IBM compilers are LE, that I
could use "C" routines (or PL/I or Fortran) in COBOL code. This was
helpful because "C" has some useful routines for strings that I could
use in COBOL.
So I started looking to see how C run-time routines might be helpful in
HLASM. I don't need most of the C string routines, since it is easy to
do that stuff in HLASM. The only C string routine that I've found
helpful
is the snprintf() routine. It is wonderful for easily formatting a nice
human readable message. I use snprintf() to format the message into a
buffer, then write the buffer out using QSAM.
First an aside, who else is disappointed that IBM has not really
addressed the need to do QSAM/BSAM/BPAM code in RMODE(31)? This was an
irritation to me the other day when I was writing some test code to
learn about the IEFPRMLB macro. All the "crap" that I had to go through
to write my normal RO code, which precludes just having a DCB in the
module and OPEN'ing it. I've got either copy the DCB into RMODE(24)
dynamic storage, or maybe do some "tricks" with the binder and
RMODE(SPLIT). DCBs are a pain. So, in my fever, I thought "too bad I
can't just use printf() to write my messages, rather than snprintf() to
format them, then QSAM to print the formatted string." Of course, this
lead to the revelation: I can!
This has lead me into the world of the weird. Where possible, instead of
using QSAM to do my printing to SYSPRINT, I can do a fopen() and
fprintf() with fclose() at the end. These routines free me from the
necessity of having a DCB in my program. I can simply write code like:
L R15,FOPEN
LA R1,PLIST
CALL (15),(DD_SYSPRINT,WRITE),VL,MF=(E,(1))
LTR R15,R15
JZ BADOPEN
ST R15,FILEPTR SAVE FILE * VALUE FROM FOPEN()
...
*
* AT THIS POINT WE'VE DONE SOMETHING WHICH RESULTS IN A RETURN
* CODE IN R15 AND A REASON CODE IN R0. I WANT TO FORMAT THEM
* AND WRITE THEM OUT, IF R15 ISN'T ZERO.
LTR R15,R15
JZ GOOD
*
* CREATE CALL PARAMETER LIST FOR FPRINTF(FILE *,CHAR *FMT, ...)
MVC PLIST+0(4),FILEPTR FILE * FOR SYSPRINT
MVC PLIST+4(4),=A(FMT1) ADDR OF FORMAT CONTROL
ST R15,PLIST+8 RETURN CODE
ST R0,PLIST+12 REASON CODE
L R15,FPRINTF ADDRESS OF FPRINTF()
LA R1,PLIST ADDRESS OF PARAMETER LIST
BASR R14,R15 CALL FPRINTF - NOTE VL=1 NOT NEEDED IN C
...
MVC PLIST+0(4),FILEPTR
LA R1,PLIST
L R15,FCLOSE
BASR R14,R15 CLOSE SYSPRINT FILE
...
FOPEN DC V(FOPEN)
FPRINTF DC V(FPRINTF)
FCLOSE DC V(FCLOSE)
FILEPTR DS A
PLIST DC 20A(0) GENERAL PARM LIST AREA
DD_SYSPRINT DC C'//DD:SYSPRINT',X'00' X'00' IS C STRING TERMINATOR
WRITE DC C'W',X'00'
FMT1 DC C'SOME ERROR MESSAGE. RC=%d, REASON=%d',X'15',X'00'
* NOTE X'15' IS END-OF-LINE FOR FPRINTF
* X'00' IS END OF STRING DELIMITER FOR C
Ok, maybe the above is just a bit too weird for actual use. But I found
it interesting to at least think about. If you want a full example of
the above, which I used to do some test learning about the IEFPRMLB
macro, the code is here:
https://gist.github.com/JohnArchieMckown/a08e0e4b6777cd36f57bbae78e28abcc
More about the use & abuse of IEFPRMLB later.