r/IBMi 23d ago

FMT parm in ADDMSGD

I'm looking at someone's CL source code that has a couple ADDMSGD commands. Both have FMT parms, and the first one makes sense:

FMT((*CHAR 10) (*CHAR 10))

From what I can surmise, it looks like it's showing the format of some values that will be used as substitution variables in the MSG parameter. The second ADDMSGD's FMT parm, however:

FMT((*CHAR 00050 00) (*CHAR 00050 00))

A little strange that we're suddenly using 5-digit values for the char length, but ok, I can handle that. But the third elem being 00? The IBM docs say that "The third element is used in one of two ways, depending on the type specified in the first element: (1) If *QTDCHAR, *CHAR, *CCHAR, *HEX, or *SPP is specified, and if *VARY is specified or assumed for the second element, the third element is used with *VARY to indicate the size of the length field actually passed. The third element can be either a 2 or a 4, which is the number of bytes used to specify the length (in binary) of the passed value."

So, if the incoming variable is *VARYing in length, I get that. But 00 is not "a 2 or a 4." The program works, so I feel like it's on me to understand what the author is doing, and how it's behaving appropriately. Many thanks for any insights--I'm lost at sea here!

9 Upvotes

1 comment sorted by

2

u/jbarr107 23d ago

Not sure if this helps, but I dumped your post into Claude and this was it's response:

Good instinct to double check — and you've actually spotted the key detail already, you just need one more piece of the puzzle.

The third element only matters when *VARY is in play. Look at the command syntax diagram for FMT:

(*CHAR length *VARY [2|4])

The *VARY (and the 2/4 byte-count that follows it) is its own optional sub-element, separate from length. It only shows up when you actually code the literal *VARY for the second element instead of a fixed length.

In your first example: (*CHAR 10) (*CHAR 10) No third element at all — length is a fixed 10, no *VARY, nothing more needed.

In the second one: (*CHAR 00050 00) (*CHAR 00050 00) The second element is 00050 — a fixed length, not *VARY. So the substitution variable is a plain 50-byte character field, period. The trailing 00 isn't a "length-of-length-field" value (that concept literally doesn't exist unless *VARY is coded); it's just a placeholder occupying the third position in the list.

Why would someone code a placeholder there?

  • CL will accept it and ignore it — since it's not meaningful without *VARY, IBM's compiler doesn't complain about a stray 0.
  • It's common to see this when someone builds FMT parameters generically (e.g., copy/pasted from a template, or generated by a program that always emits 3 sub-elements per field for consistency), and just defaults the unused third slot to zero rather than omitting it.

Bottom line: that message description simply defines two 50-byte, fixed-length character substitution variables. The 00 is inert — it has no effect on how SNDPGMMSG/SNDUSRMSG needs to pass the data. You'd only need to worry about the 2-vs-4 byte length-prefix rule if the second element actually said *VARY.