× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.




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 thread ...

Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

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.