Converting a CLLE *DEC to a Message Data *DEC on IBM i


When creating messages in message files, a substitution variable of type *DEC can be used. However, it is not trivial to work with these types in CLLE programs.

The code snippet on the left shows how a decimal variable in CL can be transformed to the *DEC counterpart in message fields.

The message data expects a packed field. However, the message data field itself can also contain other fields like object name and other character fields. So how do we get a packed field into a character field in CL?

You will find that there is no way to convert a decimal CL field into a character field. All conversions like %DEC, %CHAR end up formatting the field in an unusable format for our purpose.

The trick is to map the CL decimal to a character field.

   dcl        &clDec *dec (5 0) value(0)
   dcl        &msgDec *char stg(*defined) len(3) defvar(&clDec)

The packed decimal field only uses 3 bytes of memory. Consider the value 12345. For a decimal CL field, this is stored in memory like this:

byte1 byte2 byte3
12      34     5F

The last half byte is F (1111) for positive and D (1101) for negative values.*

This is the reason why the &msgDec field is 3 bytes. By redefining the storage (memory location) of the &clDec var, we have two variables that point to the same memory location. By changing &clDec, e.g., by passing it as a parameter to an RPG program, the &msgDec is modified by (re)definition. This value of &msgDec is exactly what the message expects.

Finally, I know how to work with correctly formatted numbers in messages.

Cheers, Wim

* Decimal field lengths should preferably be uneven. It is not the half-byte memory waste I'm worried about but the programming ethics.

   pgm
     dcl        &clDec *dec (5 0) value(0)
     dcl        &msgDec *char stg(*defined) len(3) defvar(&clDec)
     dcl        &msgDta *char 100
     dltmsgf    qtemp/msgf
     monmsg     cpf0000
     crtmsgf    qtemp/msgf
     ADDMSGD    MSG0001 MSGF(QTEMP/MSGF) MSG('&1 &2') FMT((*char 6) (*DEC 5))
     chgvar     %sst(&msgdta 1 6) 'Number'
     chgvar     %sst(&msgdta 7 3) &msgDec
     SNDPGMMSG  MSGID(MSG0001) MSGF(QTEMP/MSGF) MSGDTA(&msgDta) TOPGMQ(*EXT)
     chgvar     &clDec 100
     chgvar     %sst(&msgdta 7 3) &msgDec
     SNDPGMMSG  MSGID(MSG0001) MSGF(QTEMP/MSGF) MSGDTA(&msgDta) TOPGMQ(*EXT)
     chgvar     &clDec 1234
     chgvar     %sst(&msgdta 7 3) &msgDec
     SNDPGMMSG  MSGID(MSG0001) MSGF(QTEMP/MSGF) MSGDTA(&msgDta) TOPGMQ(*EXT)
   endpgm                                                        

Tags: 

Add new comment