Formatting output columns in DFSORT means controlling how report columns are laid out: where each field starts (position), how wide it is (length), and how much space separates it from the next column. You do this in the detail line with OUTREC FIELDS= or OUTFIL BUILD=, and in the column headers with HEADER2= (or HEADER3=) using position:value so titles line up with the data. Spacing between columns is done with nX (n spaces). For numeric columns you use edit masks (e.g. M11, M12) or EDIT= so numbers print with commas and decimals; the length of the edited field determines the column width. This page explains position notation, aligning headers with data, column width and spacing, and how to keep a report layout consistent. For numeric editing details, see Numeric formatting and Edit masks; for building the full report, see Building reports.
A readable report has aligned columns: the column title (e.g. "Amount") sits directly above the data values, and each column has a consistent width so that values in one column do not run into the next. In DFSORT you control this by (1) defining the detail line so each field starts at a known position and has a known length, and (2) defining the header line so that each title starts at the same position as its data column. When the positions match, the report looks correct regardless of the data values.
In HEADER1=, HEADER2=, TRAILER1=, and similar, you use position:value to place text at a specific column. The value can be a literal (e.g. 20:'Report Title'), a field reference (e.g. 41:31,8 to copy input bytes 31–38 to output position 41), or built-in keywords (e.g. 60:DATE=, 1:PAGE). So for column headers you might write:
1HEADER2=(1:'ID',11:'Name',35:'Dept',50:'Amount',65:'Date',/)
That puts "ID" at column 1, "Name" at 11, "Dept" at 35, "Amount" at 50, and "Date" at 65. The slash (/) starts a new line (or ends the header line). To align the data, the detail line (BUILD= or OUTREC=) must place the ID field at 1, Name at 11, Dept at 35, Amount at 50, and Date at 65. If the data starts at different positions, the columns will be misaligned.
The detail line is built with OUTREC FIELDS= or OUTFIL BUILD=. You list the items (fields, constants, spaces) in the order you want them in the output. Without explicit output positions, the first item goes at byte 1, the second immediately after the first, and so on. So if you list (1,10), 5X, (11,30), 5X, (31,8,PD,M12), the layout is: bytes 1–10 (ID), then 5 spaces, then bytes 11–30 (Name), then 5 spaces, then the edited amount. The "Amount" column effectively starts at 10 + 5 + 20 + 5 + 1 = 41. So in HEADER2 you would use 41:'Amount' (or 41:'Amount' and ensure the edited amount has a fixed length, e.g. 12, so the next column is predictable).
When your product supports output position in BUILD= (e.g. out_pos:start,len or out_pos:start,len,format,mask), you can place each field at an exact column. Then you can copy the same positions into the header. Example (conceptual):
12BUILD=(1:1,10, 11:11,30, 41:31,8,PD,M12,LENGTH=12, 55:50,8) HEADER2=(1:'ID',11:'Name',41:'Amount',55:'Date',/)
Here ID is at 1–10, Name at 11–40, Amount at 41–52 (12 bytes), Date at 55–62. Headers match. Exact BUILD= position syntax is product-dependent; see your manual.
nX means "n space characters" (blank). nZ means "n zero (X'00') bytes." For printable reports you use nX to separate columns. For example:
1OUTREC FIELDS=(1,10,5X,11,25,5X,26,8,PD,M12,LENGTH=12)
produces: 10 bytes (ID), 5 spaces, 15 bytes (Name, 11–25), 5 spaces, then the 12-byte edited amount. The 5X gives a visible gap between columns. Use the same spacing consistently so every detail line has the same total length and the same column start positions; then the header positions stay valid for all lines.
| Item | Meaning |
|---|---|
| nX | n blank (space) characters. Use between columns for readability. |
| nZ | n zero bytes. Used in some fixed layouts; for reports, nX is usual. |
| C'...' | Literal constant (e.g. C'-' or C' | ' as column separator). |
The width of a column is the number of bytes that field occupies in the output. For a copied character field it is the length you specify (e.g. 11,20 is 20 bytes). For an edited numeric field the width is determined by the edit pattern or by LENGTH=n when supported. Predefined masks (M11, M12, etc.) have a fixed length; EDIT=(pattern) length is the number of characters in the pattern. If the amount column is 12 characters wide, the next column must start at (current start + 12). If you use LENGTH=12 for the edited amount, the column is 12 bytes; place the next field or header at start + 12 so columns do not overlap or shift.
Numeric edit masks typically produce right-justified output: the digits (and sign if present) are right-aligned within the edited length, with leading spaces. So if you reserve 12 bytes for an amount, the number "1,234.56" will have leading spaces so it ends at byte 12. That gives a right-aligned number column. To get the column in the right place, place the edited field at a fixed output position (e.g. 50:31,8,PD,M12,LENGTH=12) so the 12-byte result sits at 50–61. The header "Amount" can be left-aligned at 50 or right-aligned by placing it so it ends at 61 (e.g. a short literal at a later position).
A simple approach is to decide the start position and length of each column first (e.g. ID 1–10, Name 11–35, Amount 41–52, Date 55–62). Then:
If you add or remove a column, or change a width, update both the detail layout and the header so they stay in sync. Otherwise the report will look misaligned.
You can put column titles on one line and a line of dashes (or underlines) on the next to separate the header from the data. Use / to start the second line and use the same positions for the underlines:
12HEADER2=(1:'ID',11:'Name',41:'Amount',/, 1:'--',11:'----',41:'------',/)
The first line has the titles; the second line has short underline strings at the same positions so the underlines sit under each column. Adjust the number of dashes to match the column width if you want a full underline per column.
For reports sent to a printer or viewed as fixed-width text, column alignment is done with fixed positions as above. If the output has carriage control (e.g. ASA control character in column 1), the first byte of each record may be consumed by the printer for page eject or spacing. Use REMOVECC if you want to strip that for viewing or for a file that should not have control characters. For more on printable output (control characters, spacing), see Printable formatting.
Imagine a table: you write "Name" at the top of one column and "Amount" at the top of another. The names and amounts below must start right under those titles, or the table looks messy. In DFSORT we tell the program "put the title at position 11 and the amount title at position 41," and we also tell it "put each person's name starting at 11 and each amount starting at 41." When the positions are the same, everything lines up in columns.
1. How do you align a report header (e.g. column title) with the data column below it?
2. What is the purpose of nX (e.g. 5X) in BUILD= or OUTREC FIELDS=?
3. How do you place a field at a specific output column (e.g. start amount at column 50)?
4. Why does the length of an edited numeric field matter for column layout?
5. What is a common way to get right-aligned numbers in a report column?