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


  • Subject: Re: User space examples using List APIs
  • From: "Scott Klement" <infosys@xxxxxxxxxxxx>
  • Date: 07 Jun 1999 15:05:03 -0500

Hi Dan...

     I'll quote back your message, and reply at the bottom...

"Dan Bale" <dbale@genfast.com> wrote:
>
> I am looking for example code that shows how to process
> an API-created list in a user space.  The V4R2 ILE RPG
> Reference has an example program in chapter 10 under a
> section titled "Basing Pointer Data Type"; the Softcopy
> reference is 2.3.8.1.  This example program happens to
> show how to use the QUSLMBR api, which is exactly the
> one I was looking to use.  Unfortunately, it was (IMHO)
> poorly written, and did not compile due to a syntax
> error.  I was able to fix that error plus others so that
> the program compiled and runs, (correctly, I think), but
> I'm having a difficult time fully understanding how
> exactly list processing works.
>
> In the particular example program, even though the
> initial size of the user space is 9,999,999 bytes, it
> would appear that the maximum length of the usable user
> space is 32,767 bytes (based on the D-spec for the SP1
> variable).  But I also see a reference to DIM(32767) for
> a 10-character array size that seems to reference the
> list in the user space.
>
> Is there reference material out there that explains this
> stuff?  Does anyone have example code they could share?
> I would also be interested in example code that shows
> how to process a user index.
>


     I'm not really sure what you're trying to do here, or why you've
got the initial size of the user space set so high!  (I'd be very
surprised to find a database with so many members that the list was
10 mb!)

You also (in the above message) made references to both user spaces
and user indexes.   These are two completely different things.  A user
space is basically an area of memory/disk.  You might think of it as
being like a data area, except that it can be VERY big...

A user index is more like a database file.  You can look things up by
"key", and you have data thats associated with that key.

Since you need to use the QUSLMBR API, you want to use a user space.
The way it works is, the QUSLMBR API puts data into the user space
containing the information that you want.   That makes it possible
for it to send huge amounts of data without multiple calls to the
API.

The QUSLMBR API puts data in a "generic list format", which is also
used by most (if not all) of the "list to userspace" APIs that IBM
provides.

The data in the user space starts with a "generic header".   And this
header basically contains everything your program will need to know
in order to be able to read the list.   It tells you where the
API-specific header information is, where the input parameter is,
and most importantly, where the list data begins, how big each entry
in the list is, and how many entries there are.

The entries themselves will be in the format that you specify in
the "format" parameter to the API, in this case "MBRL0100"

For detailed info on the generic list format see:
http://publib.boulder.ibm.com:80/cgi-bin/bookmgr/DOCNUM/SC41-5801-01/
HDRFMTRTVI#HDRFMTRTVI

In the example code (below) this is what I'm doing:

1) Creating a user space with an initial size of 1 byte.   (The
     QUSLMBR API will expand it as necessary, so we're specifying
     a minimal size to save some disk space & some effort...)

     Since I'm making the user space in QTEMP, and specifying *YES
     for the Replace option, I'm not worried about the space already
     existing.

     In a "real" application, you'd probably want to check for an
     error after calling the create user space API, by checking
     the value of dsECBytesA.  For this sample, I'm skipping that :)

2) Telling the API to send a list of all members in the file
    LIBSOR/QRPGLESRC (thats my ILE RPG/400 source file) to the
    user space.   I'm telling it that each entry in the user
    space should be in the MBRL0100 format.

    If I wanted more info about each member, I might use the MBRL0200
    format, which would give me info like source type, create date,
    change date, etc.

    Again, I should REALLY be checking for an error here...  but for
    this sample, I will not.   You SHOULD however, so if it can't
    use/find the file I gave, it doesn't cause problems...

    When the QUSLMBR API is complete, my list of members will be
    in the MBRDATA user space in library QTEMP.  Now I've got to
    READ that space :)

3) Now I'm asking OS/400 to set a pointer (from my program) to point
    to the area of memory/disk that the user space is in.   This
    is handy, because its a fast and (semi-) easy way to read the
    user space.

   Since the pointer thats returned is the start of the user space,
   I'm using the pointer for my "generic header info" data structure.
   (p_LH -- which in my little world means "pointer to list header")

   Now, I've got the dsLH (List Header Data Structure) "BASED" on
   that same pointer.   This means that after the QUSPTRUS API
   completes, my dsLH data structure will be located in the same
   area of memory/disk as the user space is...   Since my data struct
   is in the format of the List Header, this effectively populates
   my data structure with the header info.

4) Really, all I'm interested in is getting the member names from the
   user space.  So, all I need from the header is:

       a) Where is the list?
       b) How many items are in the list?
       c) How far to I have to advance my pointer to go to the
            next entry in the list?

       The answer to (a) is in dsLHLstOff, which is the offset
       from the start of the user space to the list data.  In other
       words, its how many bytes I have to advance my pointer from
       dsLH to get to the start of the list...

       The answer to (b) is dsLHLstCnt.  The number of entries
       returned from the QUSLMBR API.

       The answer to (c) is dsLHEntSiz.  The size of each entry
       is also the number of bytes I need to advance my pointer
       to get to the next entry.

       Make sense?  the first entry is dsLHLstOff bytes from the
       start...   the second is dsLHLstOff + dsLHEntSiz bytes
       from the start, the third is dsLHLstOff + (dsLHEntSize*2)
       bytes from the start, etc.

       So, I loop through each entry, calculate the offset and
       move the pointer for my list data (p_MbrName -- pointer
       to the member name) to the new offset.  Then I can read
       the member name from the BASED variable (MbrName)


NOTE:  The OffsetPtr sub-proc simply advances the pointer by
       however many bytes I specify.  It does this by putting
       a character string in the area of memory specified by
       its first parameter, and then finding the address of
       the position thats (parm 2) bytes later in the string.

       The reason I'm using this routine is because I'm at
       V3R2 of OS/400, which doesn't support directly adding
       to the value of a pointer!   At V4R2, however, this
       should not be necessary You should be able to do the
       pointer arithmetic directly....

       Instead of doing:
       p_MbrName = OffsetPtr(p_LH: Offset)

       You could do:
       p_MbrName = p_LH + Offset


Hope that helps...

Scott Klement
Information Systems Manager
Klement's Sausage Co, Inc.




D* Create User Space API
D*
D CrtUsrSpc       PR                  ExtPgm('QUSCRTUS')
D   UsrSpc                      20A   CONST
D   ExtAttr                     10A   CONST
D   InitSiz                     10I 0 CONST
D   InitVal                      1A   CONST
D   PubAuth                     10A   CONST
D   Text                        50A   CONST
D   Replace                     10A   CONST
D   ErrorCode                  256A

D* Retrieve Pointer to User Space API
D*
D RtvPtrUS        PR                  ExtPgm('QUSPTRUS')
D   UsrSpc                      20A   CONST
D   PtrUsrSpc                     *

D* Sub-Procedure to Offset a Pointer (LOCAL)
D*
D OffsetPtr       PR              *
D   pePointer                     *
D   peOffset                    10I 0 Value

D* API Error Code Structure
D*
D dsEC            DS
D*                                    Bytes Provided (size of struct)
D  dsECBytesP             1      4B 0
D*                                    Bytes Available (returned by API
D  dsECBytesA             5      8B 0
D*                                    Msg ID of Error Msg Returned
D  dsECMsgID              9     15
D*                                    Reserved
D  dsECReserv            16     16
D*                                    Msg Data of Error Msg Returned
D  dsECMsgDta            17    256

D* List Header Data Structure
D*
D p_LH            S               *
D dsLH            DS                   BASED(p_LH)
D*                                     Filler
D   dsLHFill1                  103A
D*                                     Status (I=Incomplete,C=Complete
D*                                             F=Partially Complete)
D   dsLHStatus                   1A
D*                                     Filler
D   dsLHFill2                   12A
D*                                     Header Offset
D   dsLHHdrOff                  10I 0
D*                                     Header Size
D   dsLHHdrSiz                  10I 0
D*                                     List Offset
D   dsLHLstOff                  10I 0
D*                                     List Size
D   dsLHLstSiz                  10I 0
D*                                     Count of Entries in List
D   dsLHEntCnt                  10I 0
D*                                     Size of a single entry
D   dsLHEntSiz                  10I 0

D* List Members (QUSLMBR) API
D*
D ListMbrs        PR                  ExtPgm('QUSLMBR')
D   UsrSpc                      20A   CONST
D   Format                       8A   CONST
D   DataBase                    20A   CONST
D   Member                      10A   CONST
D   Override                     1A   CONST
D   ErrorCode                  256A

D* Data Section of List for QUSLMBR API
D*
D p_MbrName       S               *
D MbrName         S             10A   BASED(p_MbrName)

D Offset          S             10I 0

c* set length of Error Code Structure
c                   eval      dsECBytesP = 256

C* (1) create a user space
C                   callp     CrtUsrSpc('MBRDATA   QTEMP':'USRSPC':
C                             1:x'00':'*ALL':'List of Members in File'
c                             '*YES': dsEC)

C* (2) list members into user space
C                   callp     ListMbrs('MBRDATA   QTEMP':'MBRL0100':
C                             'QRPGLESRC LIBSOR':'*ALL':'0':dsEC)

C* (3) get a pointer to the start
C*     of the user space...
C                   callp     RtvPtrUS('MBRDATA   QTEMP':p_LH)

C* (4) Loop through all the
C*     list entries returned.
C                   do        dsLHEntCnt    Entry             4 0

C*      calculate the number of bytes from the start
C*      of the user space, and put our pointer there...
c                   eval      Offset = ((Entry-1) * dsLHEntSiz)
c                               + dsLHLstOff
c                   eval      p_MbrName = OffsetPtr(p_LH: Offset)

C*      show the result
c     MbrName       dsply

c                   enddo

C* thats it!
c                   eval      *INLR = *On
c                   Return


P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P* Return a pointer at a specified offset value from another ptr
P*
P*  (Since IBM hates me and won't let me do pointer arithmetic
P*   without spending a fortune on a RISC box)
P*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
P OffsetPtr       B
D OffsetPtr       PI              *
D   pePointer                     *
D   peOffset                    10I 0 Value

D p_NewPtr        S               *
D wkMove          S              1A   DIM(4097) BASED(p_NewPtr)

c                   eval      p_NewPtr = pePointer

c                   if        peOffset > 0

C                   dow       peOffset > 4096
C                   eval      p_NewPtr = %addr(wkMove(4097))
c                   eval      peOffset = peOffset - 4096
c                   enddo

C                   eval      p_NewPtr = %addr(wkMove(peOffset+1))

c                   endif

c                   return    p_NewPtr
P                 E
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* This is the RPG/400 Discussion Mailing List!  To submit a new         *
* message, send your mail to "RPG400-L@midrange.com".  To unsubscribe   *
* from this list send email to MAJORDOMO@midrange.com and specify       *
* 'unsubscribe RPG400-L' in the body of your message.  Questions should *
* be directed to the list owner / operator: david@midrange.com          *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *


As an Amazon Associate we earn from qualifying purchases.

This thread ...


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.