HLASM Capstone Project: Build a z/OS Record Processing Utility

TT
Emily Ross
HLASM Capstone Project: Build a z/OS Record Processing Utility

HLASM Capstone Project: z/OS Record Processing Utility

This capstone project integrates every major topic from the HLASM Mastery course into a single, complete program. It is not a toy — it is the kind of utility that real z/OS shops write and maintain.

You will build EMPRPT — an employee record processing program that reads a sequential input file, validates each record, accumulates departmental salary totals in packed decimal, and writes a formatted summary report to an output file.


What You Will Build

EMPRPT performs the following tasks:

  1. Opens an input sequential file containing fixed-length employee records.
  2. Reads each record in a loop using the GET macro.
  3. Validates each record (department code in range, salary not zero, name not blank).
  4. Accumulates total salary per department using packed decimal arithmetic.
  5. Counts valid and invalid records.
  6. Closes the input file.
  7. Writes a formatted report to an output sequential file using PUT.
  8. Closes the output file and returns with a return code:
    • RC=0: all records valid
    • RC=4: some records were invalid but processing completed
    • RC=8: I/O error encountered

Record Layout and DSECT

The input file has RECFM=FB (fixed block), LRECL=80. Each record has the following layout:

text
Offset  Length  Type    Field
  0       8     CHAR    Employee ID (e.g., "EMP00042")
  8      30     CHAR    Employee Name (last, first)
 38       4     CHAR    Department Code (e.g., "ACCT", "ENGG", "SALE")
 42       7     PACKED  Annual Salary (PIC 9(13) packed = 7 bytes)
 49      31     CHAR    Filler / reserved

Define this layout as a DSECT so you can reference fields by name:

hlasm
EMPREC   DSECT
EMPID    DS    CL8            Employee ID
EMPNAME  DS    CL30           Employee Name
EMPDEPT  DS    CL4            Department Code
EMPSALRY DS    PL7            Annual Salary (packed decimal)
EMPFILL  DS    CL31           Filler
EMPRECLN EQU   *-EMPREC       Record length = 80

Program Structure

EMPRPT is organised into a main routine and five subroutines. Each subroutine has its own save area and follows standard z/OS linkage conventions.

text
EMPRPT (main)
├── INITIO    — Open input and output files
├── PROCREC   — Process one record (called in a loop)
│   ├── VALIDREC  — Validate a single record
│   └── ACCUMSAL  — Add salary to department total
├── WRTRPT    — Write the summary report
└── CLOSEIO   — Close both files

Complete Source Code

Main Program — EMPRPT

hlasm
*        EMPRPT — Employee Report Generator
*        Reads employee records, validates, accumulates salary totals,
*        writes department summary report.
*
EMPRPT   CSECT
         STM   R14,R12,12(R13)     Save caller's registers
         BALR  R12,0               Establish base register
         USING *,R12               Base register is R12
         ST    R13,SAVE+4          Chain save areas (forward)
         LA    R13,SAVE            Set R13 to our save area
         ST    R13,8(,R13)         Chain save areas (backward — for dumps)
*
*        Initialise counters and accumulators
         ZAP   TOTACCT,=P'0'       Zero ACCT department total
         ZAP   TOTENGG,=P'0'       Zero ENGG department total
         ZAP   TOTSALE,=P'0'       Zero SALE department total
         SR    R6,R6               R6 = valid record count
         SR    R7,R7               R7 = invalid record count
*
*        Open files
         BAL   R14,INITIO
         LTR   R15,R15             Check return code
         BNZ   IOERROR
*
*        Main processing loop
READLOOP GET   INFILE,INREC        Read next record
         USING EMPREC,INREC_ADDR   Map DSECT over input buffer
*
         BAL   R14,PROCREC         Process this record
         LTR   R15,R15
         BZ    VALIDCNT
         LA    R7,1(,R7)           Increment invalid count
         B     READLOOP
VALIDCNT LA    R6,1(,R6)           Increment valid count
         B     READLOOP
*
EOFFILE  DS    0H                  GET issues B to here at end-of-file
*
*        Write report
         BAL   R14,WRTRPT
*
*        Close files
         BAL   R14,CLOSEIO
*
*        Set return code
         LTR   R7,R7               Any invalid records?
         BZ    ALLGOOD
         LA    R15,4               RC=4: some invalids
         B     EXIT
ALLGOOD  SR    R15,R15             RC=0: all clean
EXIT     L     R13,SAVE+4
         L     R14,12(,R13)
         LM    R0,R12,20(R13)
         BR    R14
*
IOERROR  WTO   'EMPRPT: I/O INITIALISATION ERROR'
         LA    R15,8
         B     EXIT
*
*        --------------------------------------------------------
*        INITIO — Open INFILE and OUTFILE
*        --------------------------------------------------------
INITIO   DS    0H
         OPEN  (INFILE,(INPUT),OUTFILE,(OUTPUT))
         TM    INFILE+48,X'10'     Test OPEN successfully bit
         BNO   INITFAIL
         BR    R14
INITFAIL LA    R15,8
         BR    R14
*
*        --------------------------------------------------------
*        PROCREC — Process one record
*        Input: INREC contains current record
*        Output: R15=0 valid, R15=4 invalid
*        --------------------------------------------------------
PROCREC  STM   R14,R12,12(R13PROC)
         ...                       (Full linkage as in INITIO above)
*        (abbreviated for readability — full source in the lab kit)
*
*        Validate
         BAL   R14,VALIDREC
         LTR   R15,R15
         BNZ   PROCINV
*        Accumulate
         BAL   R14,ACCUMSAL
         SR    R15,R15
         B     PROCRET
PROCINV  LA    R15,4
PROCRET  ...                       Restore and return
*
*        --------------------------------------------------------
*        VALIDREC — Validate one record
*        Returns R15=0 (valid) or R15=4 (invalid)
*        --------------------------------------------------------
VALIDREC DS    0H
*        Check department code is one of ACCT, ENGG, SALE
         CLC   EMPDEPT,=CL4'ACCT'
         BE    DEPTVLD
         CLC   EMPDEPT,=CL4'ENGG'
         BE    DEPTVLD
         CLC   EMPDEPT,=CL4'SALE'
         BE    DEPTVLD
         LA    R15,4               Invalid department
         BR    R14
DEPTVLD  DS    0H
*        Check salary is not zero
         CP    EMPSALRY,=P'0'
         BE    INVALREC
*        Check name is not blank
         CLC   EMPNAME,=CL30' '
         BE    INVALREC
         SR    R15,R15             Valid
         BR    R14
INVALREC LA    R15,4
         BR    R14
*
*        --------------------------------------------------------
*        ACCUMSAL — Add EMPSALRY to the correct department total
*        --------------------------------------------------------
ACCUMSAL DS    0H
         CLC   EMPDEPT,=CL4'ACCT'
         BNE   TRYENGG
         AP    TOTACCT,EMPSALRY    Add to ACCT total
         BR    R14
TRYENGG  CLC   EMPDEPT,=CL4'ENGG'
         BNE   TRYSALE
         AP    TOTENGG,EMPSALRY
         BR    R14
TRYSALE  AP    TOTSALE,EMPSALRY
         BR    R14
*
*        --------------------------------------------------------
*        WRTRPT — Format and write summary report lines
*        --------------------------------------------------------
WRTRPT   DS    0H
*        Format header
         MVC   OUTREC,HEADER1
         PUT   OUTFILE,OUTREC
*        Format ACCT line
         MVC   OUTREC,DEPTLINE     Copy template
         MVC   OUTREC+2,=CL4'ACCT'
         ED    OUTREC+10,TOTACCT   Edit packed decimal to printable
         PUT   OUTFILE,OUTREC
*        (repeat for ENGG and SALE)
         ...
         BR    R14
*
*        --------------------------------------------------------
*        CLOSEIO — Close both files
*        --------------------------------------------------------
CLOSEIO  DS    0H
         CLOSE (INFILE,,OUTFILE)
         BR    R14
*
*        --------------------------------------------------------
*        Data areas
*        --------------------------------------------------------
SAVE     DS    18F                 Main program save area
INREC    DS    CL80                Input record buffer
INREC_ADDR EQU INREC
OUTREC   DS    CL133               Output record buffer (RECFM=FBA)
*
*        Department salary accumulators (15 digits packed = 8 bytes)
TOTACCT  DS    PL8
TOTENGG  DS    PL8
TOTSALE  DS    PL8
*
*        Report line templates
HEADER1  DC    CL133'  DEPARTMENT SALARY SUMMARY REPORT'
DEPTLINE DC    CL133'  XXXX          $9,999,999,999,999'
*
*        File DCBs
INFILE   DCB   DSORG=PS,MACRF=GM,DDNAME=INFILE,EODAD=EOFFILE,         X
               RECFM=FB,LRECL=80
OUTFILE  DCB   DSORG=PS,MACRF=PM,DDNAME=OUTFILE,                      X
               RECFM=FBA,LRECL=133
*
         LTORG
EMPREC   DSECT
EMPID    DS    CL8
EMPNAME  DS    CL30
EMPDEPT  DS    CL4
EMPSALRY DS    PL7
EMPFILL  DS    CL31
         END   EMPRPT

JCL to Run EMPRPT

jcl
//EMPRPTJB JOB  (ACCT),'CAPSTONE',CLASS=A,MSGCLASS=X
//*
//ASMSTEP  EXEC PGM=ASMA90,PARM='OBJECT,NODECK,LIST,XREF(FULL)'
//SYSPRINT DD  SYSOUT=*
//SYSLIN   DD  DSN=&&OBJ,DISP=(NEW,PASS),UNIT=SYSDA,SPACE=(CYL,(1,1))
//SYSUT1   DD  UNIT=SYSDA,SPACE=(CYL,(2,1))
//SYSLIB   DD  DSN=SYS1.MACLIB,DISP=SHR
//         DD  DSN=SYS1.MODGEN,DISP=SHR
//SYSIN    DD  DSN=MY.HLASM.SOURCE(EMPRPT),DISP=SHR
//*
//LNKSTEP  EXEC PGM=IEWBLINK,PARM='MAP,LIST',COND=(8,LT,ASMSTEP)
//SYSPRINT DD  SYSOUT=*
//SYSLIN   DD  DSN=&&OBJ,DISP=(OLD,DELETE)
//SYSLMOD  DD  DSN=MY.LOAD.LIBRARY(EMPRPT),DISP=SHR
//SYSUT1   DD  UNIT=SYSDA,SPACE=(CYL,(1,1))
//*
//RUNJOB   EXEC PGM=EMPRPT,COND=(8,LT)
//STEPLIB  DD  DSN=MY.LOAD.LIBRARY,DISP=SHR
//INFILE   DD  DSN=MY.TEST.EMPDATA,DISP=SHR
//OUTFILE  DD  DSN=MY.EMPRPT.OUTPUT,DISP=(NEW,CATLG),
//             SPACE=(TRK,(5,1)),RECFM=FBA,LRECL=133
//SYSOUT   DD  SYSOUT=*

Test Data

Create a test dataset MY.TEST.EMPDATA with RECFM=FB, LRECL=80 containing records like:

text
EMP00001SMITH         JOHN                  ACCT 000000007500000
EMP00002JONES         MARY                  ENGG 000000012000000
EMP00003BROWN         ROBERT                SALE 000000009500000
EMP00004DAVIS         LINDA                 XXXX 000000008000000  ← invalid dept
EMP00005WILSON        JAMES                 ACCT 000000000000000  ← zero salary

With these records, your program should produce RC=4 (invalid records found) and a report showing:

  • ACCT total: $75,000.00
  • ENGG total: $120,000.00
  • SALE total: $95,000.00

Extension Tasks

Once the core program works, tackle these additions to deepen your skills:

  1. Error report — Write rejected records to a third output file (ERRFILE DCB) with the rejection reason appended to each record.
  2. Grand total — Add a grand total across all departments using a fourth accumulator.
  3. Record count lines — Add a footer line showing total records read, valid, and invalid counts.
  4. Multiple base registers — If your program grows beyond 4096 bytes, implement a second base register using the USING and DROP pattern covered in the addressing modes module.
  5. ESTAE error recovery — Wrap the processing loop in an ESTAE macro to catch unexpected ABENDs, log the failing record, and continue processing rather than terminating.

Skills Checklist

Use this to verify you have applied the key course concepts:

  • Standard linkage in main program and all subroutines (STM, BALR, USING, RETURN)
  • DSECT used to map the input record layout
  • GET/PUT/OPEN/CLOSE MVS macros for file I/O
  • Packed decimal arithmetic (ZAP, AP, CP, ED)
  • CLC/CLI for character validation
  • Structured subroutine design with meaningful return codes
  • LTORG for literal pool placement
  • DCB definitions with correct MACRF, DSORG, RECFM, LRECL
  • EODAD for end-of-file handling
  • Conditional return code (RC=0, RC=4, RC=8)

Conclusion

Completing EMPRPT means you can write a production-grade HLASM program from scratch — one that opens files, processes structured records, performs packed decimal arithmetic, validates input, writes formatted reports, and returns meaningful return codes to JCL.

That is a real, marketable skill. z/OS shops that maintain legacy assembler code — and there are many of them — need developers who can read, modify, and extend programs exactly like this one.

You have completed the HLASM Mastery course. Review the full curriculum at HLASM Mastery Course and explore the 50 HLASM Interview Questions to prepare for mainframe assembler roles.