|
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-freeThe 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-freeto 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) constAnother 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-2024 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.