OK, so here is what the manuals say of your situation:
Enterprise COBOL Programming Guide
By default, DFSORT diagnostic messages are sent to the SYSOUT data set. If you want to change this default, use the MSGDDN parameter of the DFSORT OPTION control card or use the SORT-MESSAGE special register.
Enterprise COBOL Language Reference
You can use the SORT-MESSAGE special register to specify the ddname of a data set that the sort utility should use in place of the SYSOUT data set.
The ddname specified in SORT-MESSAGE is equivalent to the name specified on
the ’MSGDDN=’ control statement in the sort control file.
DFSORT Application Programming Guide (my emphasis)
//SYSOUT DD
Identifies the DFSORT message data set. The
default ddname is SYSOUT, but you can specify an
alternate ddname for the message data set using
the MSGDDN installation or run-time option.
Always supply a DD statement for the message
data set if a catalogued procedure is not used. (If
you are invoking DFSORT from a COBOL program
and are using the ddname SYSOUT for the
message data set, the use of DISPLAY in your
COBOL program can produce uncertain printing
results.)
DFSORT uses RECFM=FBA, LRECL=121, and the
specified BLKSIZE for the message data set. If the
BLKSIZE you specify is not a multiple of 121,
DFSORT uses BLKSIZE=121. If you do not specify
the BLKSIZE, DFSORT selects the block size as
directed by the SDBMSG installation option (see
z/OS DFSORT Installation and Customization).
If you use a temporary or permanent message data
set, it is best to specify a disposition of MOD to
ensure you see all messages and control statements
in the message data set.
And:
MSGDDN
MSGDDN=ddname
Temporarily overrides the MSGDDN installation option, which specifies an
alternate ddname for the message data set. MSGDDN must be in effect if:
v A program that invokes DFSORT uses SYSOUT (for instance, COBOL uses
SYSOUT) and you do not want DFSORT messages intermixed with the
program messages.
v Your E15 and E35 routines are written in COBOL and you do not want
DFSORT messages intermixed with the program messages.
v A program invokes DFSORT more than once and you want separate
messages for each invocation of DFSORT.
The ddname can be any 1- through 8- character name but must be unique
within the job step; do not use a name that is used by DFSORT (for example,
SORTIN). If the ddname specified is not available at run-time, SYSOUT is used instead. For details on use of the message data set, see z/OS DFSORT Messages,
Codes and Diagnosis Guide
Note: MSGDDN is processed only if it is passed on the OPTION control
statement in an extended parameter list or in DFSPARM.
What you have done, despite the advice in the manuals, is mix SYSOUT output from COBOL and DFSORT (indeed multiple invocations of DFSORT). You have done that whilst directing the SYSOUT to a sequential dataset, with different characteristics from that which DFSORT uses. Since DFSORT will always output messages, your dataset was guaranteed to be corrupted if the COBOL program used at least on DISPLAY in the run.
If you had directed the SYSOUT DD to a SYSOUT= (spool) dataset at any point during your testing (I'd guess close to 100% of people do it that way) you'd have noticed the mixed output on the SYSOUT dataset for that step. I'm not sure how it would have looked (having never done this, or known it to be done) but you would have been able to at least identify the source of the multiple use (the same COBOL program, doing its own DISPLAYs, and also doing multiple internal SORTs).
You have solved your problem by using DFSORT's MSGDD= to modify the default output DD (SYSOUT).
It is worth noting that you can also change the name of the DD used for COBOL DISPLAY, from its default (SYSOUT) to something else, with the compiler option OUTDD(somedd).
Language Environment also uses SYSOUT by default, but you can use the run-time option MSGFILE to modify that (LE run-time options can be set in various ways, consult the Language Environment documentation (I find the easiest to be a //CEEDOPT DD
in the JCL for a batch program).
Ensuring that files which are allocated for one execution of a program from within a Rexx program are then de-allocated afterwards, and the datasetnames are not re-used is something to watch for every time. Ensure that you always check RC, whenever something can set an RC. Don't specify options on statements which are not required.
Here's your data as shown by you before I pasted it into your question, from the program I provided:
0000000121
4FFFFFFFFFF
00000000121
' ` expected message text
4070007004
00D0009000
Second attempt:
expected message text
44
00
I'm not sure what "expected message text" means, nor the "the first record appears twice", nor "total 4 message lines".
The data isn't lined up. In your question, I corrected the 0000000121 part, but not the other record.
Ignoring the "expected message text" you are showing two data-records, in "hexadecimal" format (SET HEX ON in SDSF if you are using that to browse spool output).
The first blank may be an artifact of SDSF. When you first look at a spool file, if you look at the COLS, you'll see that the data starts at column two. If you move your screen to the left, you'll then see the first column, which is not data.
So, we could guess that you actually have two records. One which is 10 zoned-decimal digits (or "character") and one which is very definitely not the same.
The first record looks like a fixed-length record, of 10 bytes. The second looks live a variable-length record. In fact, it is a block of variable-length data.
This file will, with absolute certainty, give you your "wrong length record".
However, even given that, there is something not quite right with what you show. I think that what you have done is not copy all the trailing blanks.
We know you have an LRECL of 121, and for fixed-length records, that means the records will be 121 bytes long, yet you show 10 bytes. OK, could be written from something overriding the length to 10.
However, for the variable-lenght data, it goes like this
X'007D' = block length, 125 bytes, first half of the Block Descriptor Word (BDW) including the length (four) of the BDW.
X'0000' = second half of the BDW
X'0079' = record length, 121 bytes, first half of the Record Descriptor Word (RDW) including the length (four) of the RDW.
121 bytes of data, which you show as X'40'. So let's assume 121 bytes of space.
Let's therefore go back and assumed that the fixed-length record is 121 bytes with trailing blanks. Seeing that in your "answer" the first "line" was not aligned, we can assume you made an adjustment for the leading blank, and also on the second record.
It is not yet clear from where, but your file is definitely "a mix". You have one fixed-length record, then one variable-length block (containing only one record) You need paste exactly what you see once you have selected the spool file the output is in hex mode. All the way from left to right of your screen. Copy/paste, not screenprint.
Which do you think is the correct line? The blanks, or the 0000000121?
OK, still not a lot to work on :-)
Your problem is with tmpDS
. Can't see the content of that, but that is the problem.
It has a name that looks very temporary, but the content is making things much more permanent than you are expecting.
At the time the user who gets the failure is on your system and getting to the running of the COBOL program, the file, a dataset with that exact name, already exists on the system. COBOL is just going to blithely clobber it, probably with FBA 121. If the file being used previously was anything other than what COBOL clobbers it with, you will get the exact situation you detail.
There are multiple possibilities for how that has happened. Using the same name in different rexx programs is the easiest. Prefixing it with the TSO-userid may partly help, but you need to either let the system decide on the name or generate it yourself such that it cannot be duplicate.
Can't be certain of this without seeing your code. Only 99.3% sure, until you tell me otherwise :-)
Here's a short program you can use to read the file and see what is in there:
ID DIVISION.
PROGRAM-ID. STOB26.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT IN-FILE ASSIGN TO INFILE
FILE STATUS IS W-FILE-STATUS.
DATA DIVISION.
FILE SECTION.
FD IN-FILE
RECORD IS VARYING
DEPENDING ON W-REC-LENGTH
RECORDING MODE U.
01 IN-REC.
05 FILLER OCCURS 1 TO 32760 TIMES
DEPENDING ON W-REC-LENGTH PIC X.
WORKING-STORAGE SECTION.
01 W-FILE-STATUS PIC XX.
88 FILE-STATUS-GOOD VALUE "00".
88 FILE-STATUS-OK-FOR-INPUT VALUE "00" "10".
88 END-OF-FILE VALUE "10".
01 W-REC-LENGTH PIC 9(8) COMP.
PROCEDURE DIVISION.
DISPLAY 'Start of program'
OPEN INPUT IN-FILE
IF NOT FILE-STATUS-GOOD
DISPLAY
'OPEN FAILED'
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
PERFORM UNTIL END-OF-FILE
READ IN-FILE
IF NOT FILE-STATUS-OK-FOR-INPUT
DISPLAY
"READ FAILED"
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
DISPLAY
'Record length is>'
W-REC-LENGTH
'<'
DISPLAY
'Data is>'
IN-REC
'<'
END-PERFORM
CLOSE IN-FILE
IF NOT FILE-STATUS-GOOD
DISPLAY
'CLOSE FAILED'
'>'
W-FILE-STATUS
'<'
CALL 'FRED'
END-IF
DISPLAY 'End of program'
GOBACK
.
The JCL is very simple, and can be based on this:
//RUNIT EXEC PGM=VARA,TIME=(,2)
//STEPLIB DD DSN=loadlibrary,DISP=SHR
//SYSOUT DD SYSOUT=*
//INFILE DD DSN=yourbusteddsn,LRECL=32760,RECFM=U,DISP=SHR