There are folks who think that AI can replace programmers. I disagree.
A bit ago, I did ask AI to write a COBOL program to copy a file, and it did that correctly.
Today I asked Claude to write a couple assembler programs, and it left
a bit to be desired. One mistake in both programs was it's handling
of the save area linkage. I suspect that could be corrected.
Other than that, the simple copy would work. But then, that logic is
sufficiently simple, that it's not worth a gold star.
Claude does not USE the GET LOCATE, PUT MOVE logic that is normal.
That's true in both programs, unfortunately.
FILECOPY CSECT
FILECOPY AMODE 31
FILECOPY RMODE ANY
*===================================================================*
* FILECOPY - Sample assembler program to copy a sequential file *
* *
* Function: Reads records from INPUT DD and writes them, , *
* unchanged, to OUTTUT DD until end of file. *
* *
* JCL DDNAMEs required: *
* INPUT - input dataset (DCB defined below, RECFM=FB,LRECL=80)*
* OUTPUT - output dataset (same attributes) *
* SYSPRINT- for messages *
*===================================================================*
SAVE (14,12),,FILECOPY_&SYSDATE_&SYSTIME
LR R12,R15 Establish addressability
USING FILECOPY,R12
LA R13,SAVEAREA Get our own savearea
ST R13,8(,R13) (chain not strictly needed here,
* shown for completeness)
B INIT
*
SAVEAREA DS 18F
*
INIT DS 0H
*--------------------------------------------------------------------
* Open the input and output files
*--------------------------------------------------------------------
OPEN (INDCB,(INPUT),OUTDCB,(OUTPUT))
LTR R15,R15 OPEN macro sets return info; check
* DCBs individually below instead
*
TM INDCB+DCBOFOPN,X'10' Is input DCB open? (OFOPEN bit)
BZ OPENERR
TM OUTDCB+DCBOFOPN,X'10' Is output DCB open?
BZ OPENERR
*
* My comment. Why to the LTR 15,15 if nothing will be done after it.
* The TM is incorrect, and will cause an assembly error.
* It should be:
* TM INDCB+DCBOFOPN-IHADCB,X'10'
*--------------------------------------------------------------------
* Main copy loop: GET a record, then PUT it, until end-of-file
*--------------------------------------------------------------------
MAINLOOP DS 0H
GET INDCB,INAREA Read a record (MOVE mode)
* control returns here normally;
* EODAD=EOF below on end-of-file
PUT OUTDCB,INAREA Write the record just read
B MAINLOOP
*
*--------------------------------------------------------------------
* End of file reached on input - close files and finish normally
*--------------------------------------------------------------------
EOF DS 0H
CLOSE (INDCB,,OUTDCB)
WTO 'FILECOPY: COPY COMPLETED SUCCESSFULLY'
LA R15,0 Return code 0 = success
B RETURN
*
*--------------------------------------------------------------------
* Error handling: files did not open correctly
*--------------------------------------------------------------------
OPENERR DS 0H
WTO 'FILECOPY: ERROR - UNABLE TO OPEN INPUT OR OUTPUT FILE'
LA R15,8 Return code 8 = open failure
B RETURN
*
*--------------------------------------------------------------------
* Common return path
*--------------------------------------------------------------------
RETURN DS 0H
L R13,4(,R13) (would restore caller savearea if
* chained; harmless here)
RETURN (14,12),RC=(15)
*
*====================================================================
* DCBs - Data Control Blocks for input and output files
* RECFM=FB LRECL=80 BLKSIZE=8000 - adjust to match your data
*====================================================================
INDCB DCB DDNAME=INPUT,DSORG=PS,MACRF=GM,EODAD=EOF, *
RECFM=FB,LRECL=80,BLKSIZE=8000
*
OUTDCB DCB DDNAME=OUTPUT,DSORG=PS,MACRF=PM, *
RECFM=FB,LRECL=80,BLKSIZE=8000
*
*====================================================================
* Work areas
*====================================================================
INAREA DS CL80 Record buffer (matches LRECL)
*
LTORG
END FILECOPY
---------------------------------------------------------------
The copy file is close. Not perfect, but close.
Note that the base register setup is different between
the copy program, and the program to search for the PARM string.
The copy base is correct. The PARM scan base is wrong.
Next copy only records that contain the string
specified in the PARM field.
Note that the CLC against loc-1 then loc-2 then loc-3 is slow.
It works, but reading a large file, locked up the 195 when
my boss ran it. If you check only for 1 character and then
only do the full compare when you find that, it's much faster.
-----------------------Claude------------------------------------
MVS Assembler Program: Conditional Record Copy Using PARM Field
This program reads records from an input file, checks each record
for a search string supplied via the JCL PARM field, and copies
only matching records to the output file.
Program Logic
Parse the PARM field (format: half-word length prefix + search string)
Open input and output files
Read each record from input
Search for the string using EX with CLC
Write matching records to output
Close files and return
Assembler Source
asm
COPYPARM CSECT
COPYPARM AMODE 31
COPYPARM RMODE 24
STM R14,R12,12(R13) SAVE CALLER'S REGISTERS
BALR R12,0 ESTABLISH BASE REGISTER
B SKIP1
DC CL8'COPYPARM'
SKIP1 EQU *
LR R12,R12
USING SKIP1,R12 -------it has done the base register wrong
LA R15,SAVEAREA
ST R13,8(R15) and the save area logic is wrong
ST R15,8(R13)
LR R13,R15
L R1,0(R1) LOAD PARM ADDRESS (FROM R1 ON ENTRY)
LH R2,0(R1) PARM LENGTH (HALFWORD)
LTR R2,R2
BZ NOPARM NO PARM SUPPLIED - ERROR
CH R2,=H'256'
BNH *+8
LA R2,256 TRUNCATE IF TOO LONG (SAFETY)
BCTR R2,0 LENGTH - 1 FOR EX INSTRUCTION
LA R3,2(R1) POINT TO ACTUAL PARM TEXT
MVC SRCHLEN,2(R1) SAVE LENGTH (ORIGINAL HALFWORD)
EX R2,MVCPARM MOVE PARM STRING TO WORK AREA
STH R2,SRCHLN1 SAVE EXECUTE LENGTH (LEN-1)
B OPENFLS
MVCPARM MVC SRCHSTR(0),0(R3) EXECUTED - MOVES VARIABLE LENGTH
OPENFLS OPEN (INDD,(INPUT))
OPEN (OUTDD,(OUTPUT))
LTR R15,R15
BNZ OPENERR
READLOOP GET INDD,INREC
* GET SETS UP EODAD ON END OF FILE
LH R4,SRCHLN1 EXECUTE LENGTH (ACTUAL LEN - 1)
LA R5,INREC START OF RECORD
LA R6,LRECL1 MAX COMPARE START (RECLEN-SRCHLEN+1)
LH R7,SRCHLEN
BCTR R7,0
S R6,=F'0' (PLACEHOLDER, COMPUTED BELOW)
*--------------------------------------------------------------*
* SEARCH FOR STRING WITHIN THE RECORD (BRUTE FORCE SCAN) *
*--------------------------------------------------------------*
LA R5,INREC RESET SCAN POINTER
LA R8,0 OFFSET COUNTER
LH R9,RECLEN LENGTH OF RECORD
LH R7,SRCHLEN LENGTH OF SEARCH STRING
SR R9,R7 MAX VALID START OFFSET
LA R9,1(R9) INCLUSIVE COUNT OF POSITIONS
LTR R9,R9
BNP NOMATCH SEARCH STRING LONGER THAN RECORD
SCANLOOP EX R4,COMPARE COMPARE AT CURRENT POSITION
BE MATCH FOUND - GO WRITE RECORD
LA R5,1(R5) ADVANCE SCAN POINTER ONE BYTE
BCT R9,SCANLOOP DECREMENT AND LOOP
B NOMATCH
COMPARE CLC 0(0,R5),SRCHSTR EXECUTED WITH LENGTH IN R4
MATCH PUT OUTDD,INREC WRITE MATCHING RECORD TO OUTPUT
NOMATCH B READLOOP GO READ NEXT RECORD
EOFRTN CLOSE (INDD)
CLOSE (OUTDD)
L R13,4(R13)
LM R14,R12,12(R13)
SR R15,R15
BR R14
NOPARM L R13,4(R13)
LM R14,R12,12(R13)
LA R15,16
BR R14
OPENERR L R13,4(R13)
LM R14,R12,12(R13)
LA R15,12
BR R14
*--------------------------------------------------------------*
* DATA AREAS *
*--------------------------------------------------------------*
SAVEAREA DS 18F
SRCHLEN DS H LENGTH OF SEARCH STRING
SRCHLN1 DS H LENGTH - 1 (FOR EXECUTE)
RECLEN DS H LENGTH OF CURRENT RECORD
LRECL1 DS F
SRCHSTR DS CL256 SEARCH STRING WORK AREA
INREC DS CL133 ADJUST TO YOUR RECORD LENGTH
INDD DCB DDNAME=INDD,DSORG=PS,MACRF=GM,EODAD=EOFRTN
OUTDD DCB DDNAME=OUTDD,DSORG=PS,MACRF=PM
LTORG
END COPYPARM
Important Notes / Caveats
This is illustrative MVS HLASM code, not a turnkey compile-and-run solution.
A few things you'll want to verify or fix for your actual environment:
DCB attributes: I used MACRF=GM/PM (move mode, get/put)
assuming fixed or variable records matching your dataset.
You'll need LRECL, RECFM, BLKSIZE either hardcoded in the DCB macro
or supplied via JCL DCB= override.
RECLEN: For fixed-length records you can hardcode this constant;
for variable-length (RECFM=V/VB) you need to extract the
RDW (first 4 bytes of the record) to get actual length
instead of an assumed constant.
PARM parsing: This assumes the standard convention
— first halfword = length, followed by the text,
with no leading length-prefixed sub-parameters.
If your shop's PARM has multiple values (e.g., comma-separated), you'll
need to write a scan/parse routine to isolate just the search string.
AMODE/RMODE: Set for 31-bit; drop those statements if you're targeting
an OS/VS or pre-XA environment running in 24-bit mode only.
Register conventions: Standard linkage assumed (R13 save area chain,
R1 parameter pointer, R15 return code) — verify against your shop's
linkage standards if calling from a different language or under a CALL macro.
-----------------------------------------------------------
In the end, my take is that if you're a programmer, your job is probably safe.