|
Hi Curt,When you reply to a digest, please change the subject of the message to match the thread you replied to. The name "RPG400-L Digest, Vol 5, Issue 676" doesn't tell us what the message is about.
In your reply, you said:
I am hoping that I don't have to do what Scott and Bob suggest and that would be to use the MI instruction. if that is the only way to accomplish this then that's what I will do, but wondering if there is another way.
There are other ways. For example, you could use the bitwise operations to examine the values of each packed digit, and from that create a zoned decimal number. (That'd be a lot of code, but it'd work.)
You could also left-pad your packed character data with x'00' to get it to a standard size, which you could then use in a daa structure to convert it...
IMHO, using the MI builtin is the fastest and easiest solution to the problem. It's certainly not the only solution!
For example, this uses the left-pad data structure approach:
H DFTACTGRP(*NO)
D ds
D packed 31P 0
D input 16A overlay(packed)
D zoned 31S 9
D CharStr s 100A
D Zeroes s 16A inz(*allx'00')
D start s 10I 0
D len s 10I 0
D decpos s 10I 0
/free
// 1 2 3
// 012345678901234567890 1 2 3 4 5678901
CharStr = 'Hey this is a string ' + x'0123321F' + ' lalala';
start = 22;
len = 4;
decpos = 2;
input = %subst(Zeroes:1:%size(input)-len)
+ %subst(CharStr:start:len);
zoned = packed / (10 ** decpos);
dsply %char(zoned);
*inlr = *on;
/end-free
The idea is that the variable called "packed" contains a packed number as
large as you'll ever need. You substring out the packed data from the
string into the character field (in this example, called "input") and you
pad it to the left with x'00'. The result should be a valid packed number
in the "packed" field, but without decimal positions.
Then, since you have it in a packed field, you can divide it to get the decimal positions and copy the result to a zoned field. This code is relatively short, but it's a little mysterious. The next guy might not have a clue what you're doing. Furthermore, since it uses division and exponentiation, it's probably not terribly efficient. (Though, I didn't benchmark it, so I may be wrong.)
I prefer _LBCPYNV because it's a little more obvious what it's doing, and because it's a documented feature of the iSeries -- the next guy to read your code need only search for LBCPYNV, and he'll get documentation that tells him what it does and what the parameters are, etc.
For example:
H DFTACTGRP(*NO)
/copy LBCPYNV_H
D CharStr s 100A
D PackPos s 10I 0
D Zoned s 31S 9
D in_attr ds likeds(LBCPYNV_attr_t)
D inz(*likeds)
D out_attr ds likeds(LBCPYNV_attr_t)
D inz(*likeds)
/free
// 1 2 3
// 012345678901234567890 1 2 3 4 5678901
CharStr = 'Hey this is a string ' + x'0123321F' + ' lalala';
PackPos = 21;
in_attr.type = TYPE_PACKED;
in_attr.decpos = 2;
in_attr.digits = 7;
out_attr.type = TYPE_ZONED;
out_attr.decpos = %decpos(Zoned);
out_attr.digits = %len(Zoned);
LBCPYNV( %addr(Zoned)
: out_attr
: %addr(CharStr) + PackPos
: in_attr );
dsply %char(Zoned);
*inlr = *on;
/end-free
to me, at least, it's pretty clear what this code is doing. It's
converting from packed to zoned, since the input & output parms describe
what's happening pretty well.
you'll note that some of the definitions used by LBCPYNV come from a /COPY member. I put everything I need to call LBCPYNV in a /copy member because it makes it easier for me to use in all of my programs.
Here's the contents of the /copy member:
/if defined(LBCPYNV_H_DEFINED)
/eof
/endif
/define LBCPYNV_H_DEFINED
D LBCPYNV_attr_t ds qualified
D type 1A inz(TYPE_INT)
D decpos 3U 0 inz(0)
D digits 3U 0 inz(0)
D 10I 0 inz(0)
D TYPE_INT c const(x'00')
D TYPE_FLOAT c const(x'01')
D TYPE_ZONED c const(x'02')
D TYPE_PACKED c const(x'03')
D TYPE_CHAR c const(x'04')
D TYPE_UINT c const(x'0A')
D LBCPYNV PR extproc('_LBCPYNV')
D Output * value
D OutAttr likeds(LBCPYNV_attr_t) const
D Input * value
D InpAttr likeds(LBCPYNV_attr_t) const
Another advantage that LBCPYNV has over coding your own routine using data
structures and padding is that it works for all data types. Sure, the
padding technique works for packed, but what happens when you want to
convert an integer or floating point? You'd need to write a whole new
routine. With LBCPYNV, you need only change the attributes to TYPE_INT or
TYPE_FLOAT.
Because LBCPYNV is an MI builtin, I expect that it runs very fast. Again, haven't benchmarked it so I don't know that for sure.
There are also ILE C functions that convert numbers from packed to other formats. (probably integer and floating point) but... you probably don't need more options!
Whatever you do, wrap it up in a subprocedure and stick it in a service program with other useful utilities. That way, you need not worry about it again!
As an Amazon Associate we earn from qualifying purchases.
This mailing list archive is Copyright 1997-2025 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].
Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.