User-written exits are programs you code (in Assembler or COBOL) that DFSORT loads and calls during a sort or copy step. You put your logic in the exit—for example, to filter, reformat, or expand records—and tell DFSORT to use it via the MODS control statement. Writing an exit requires following the DFSORT exit interface: the parameter list layout, register conventions, and return codes that DFSORT expects. This page covers how to write and test user exits, where to place the load module, how to debug common problems, and how to use OPTION COPY and STOPAFT when developing.
DFSORT passes control to your exit with a specific calling convention and parameter list. Your program must use the same convention and interpret the parameter list exactly as documented; otherwise the step can abend or produce wrong results. The DFSORT Application Programming Guide for your product level describes, for each exit type (E15, E35, E32, etc.): the format of the parameter list (e.g. address of record, record length, and often a word reserved for the exit to store a pointer to its own save area), the meaning of each return code (e.g. 12 = use record, 8 = drop record), and how to code the exit in Assembler and in COBOL. You must use the correct return code so DFSORT knows whether to keep, drop, or accept multiple records from the exit.
The parameter list is typically a list of fullwords (or equivalent) passed by DFSORT to your exit. Common elements include the address of the current record, the record length, and a "user exit address constant" word. On the first call, the exit can obtain storage (e.g. via GETMAIN or the equivalent in COBOL) and save the address in that word; on later calls, the same word is passed so the exit can reuse that storage. That lets you maintain state across invocations—for example, a running total or a counter. Return codes are set in a register or in a field that DFSORT reads. Typical values (check your manual for the exact set) include: 12 to indicate "use this record" (as is or as modified), 8 to indicate "drop this record," and 4 (or similar) for one-to-many when the exit returns multiple records. The Application Programming Guide lists all valid return codes and their meanings for each exit type.
| Return code | Meaning |
|---|---|
| 12 | Use the record (pass or modified); normal continue |
| 8 | Drop/skip this record (do not include in sort or output) |
| 4 | Used for one-to-many; exit provides additional records (exact usage per Application Programming Guide) |
DFSORT loads your exit from a load library that the step can access. That is usually a dataset in the STEPLIB DD statement for the sort step, or in JOBLIB if you want the whole job to use it. The MODS statement in SYSIN names the load module (e.g. MODS=(MYE15)); DFSORT looks for a module with that name in the library concatenation. If the module is not found, you get a load failure (e.g. program not found). So after compiling and linking your exit, copy the load module to a PDS or PDSE that is in STEPLIB or JOBLIB for the test job.
When developing an exit, start with OPTION COPY. With COPY, DFSORT does not sort; it reads from SORTIN, calls your input exit (e.g. E15) for each record, and writes to SORTOUT. That lets you verify that the exit is called, that it receives the record correctly, and that it returns the right code (pass, drop, or multiple records) without the added complexity of sort keys, SUM, or OUTFIL. Once the exit behaves correctly with COPY, add SORT FIELDS and other options. Use OPTION STOPAFT=n to process only the first n records during debugging; for example, STOPAFT=1 or STOPAFT=10 so you can inspect a small amount of output and SYSOUT quickly.
If the step abends, check the abend code and the SYSOUT. Many abends in exits are due to incorrect use of the parameter list (e.g. using the wrong offset for the record address or length, or overwriting storage outside the record). Re-read the Application Programming Guide and ensure your code matches the interface. You can write diagnostic data into the record (e.g. a counter or a flag) and inspect the output to confirm the exit is being called and with what data. Some sites use a debugger (e.g. under TSO or in a batch debugging environment) to step through the exit. Keep the first version of the exit simple (e.g. pass through all records with return code 12) and add logic gradually so you can isolate failures.
Exits are commonly written in Assembler because the interface is register- and storage-oriented; you have direct control over the parameter list and return codes. COBOL is also supported; the guide describes how to define the parameter list (e.g. LINKAGE SECTION) and set the return code. Choose the language your team maintains more easily. Both must follow the same interface; the guide has examples for each.
The "user exit address constant" (or equivalent) in the parameter list is intended for the exit to save a pointer to its own storage. On the first call, the exit obtains storage (GETMAIN or COBOL equivalent), saves the address in that word, and uses the storage for work areas, counters, or running totals. On subsequent calls, the same word is passed in, so the exit can reload the pointer and reuse the storage. That way you can maintain state across all record calls in the step—for example, for running totals or for conditional logic that depends on previous records.
You are building a helper robot that the sorting machine will call. The machine gives the robot a piece of paper (the record) and a special box (the parameter list) where the robot can put a note for next time. The robot must answer with a secret number: "12" means "use this paper," "8" means "throw it away," and so on. You have to build the robot exactly the way the machine’s manual says, and put the robot in a place where the machine can find it (STEPLIB). When you first test the robot, you tell the machine to only move papers and not sort (COPY), and to only do a few papers (STOPAFT), so you can check that the robot does the right thing.
1. Where must the load module for your DFSORT exit reside?
2. Why is it recommended to test an E15 exit first with OPTION COPY?
3. What is the purpose of the parameter list passed to an E15 or E35 exit?
4. Which languages can you use to write DFSORT exits?
5. What can you use to limit the number of records processed when debugging an exit?