|
Time to make Trial 2 into a client/server. Well, I may be abusing the
context of the phrase, but that's what we're doing. We're going to turn
AG02 (the List member API) into a service program. This will provide (for
now) the single service of filling an array with list member information.
The client will be AG03, our "mainline" or controlling code.
Rather than re-use AG02 and 03, I'll copy AG02 into AG04, and copy AG03 into
AG05. This'll give me some new source members so I can leave the existing
code as-is for comparison purposes.
First, the service program, AG04. Converting this isn't much work really.
We need to make a prototype, a procedure interface and some binder source.
The PR:
* Return a single page of member name/text
* from specified source file
d getMbrList pr
d inpFile 10 value
d inpLib 10 value
d outMbrArray 60 dim(10)
I put this in a source member in QPROTOSRC so all my prototypes are in one
place. That makes it easier to search for them - sort of a
poor-programmer's library. I call it AG04. That way it's easy to tell what
prototype goes with what source member and which service program.
The PI:
p getMbrList b export
d getMbrList pi
d inpFile 10 value
d inpLib 10 value
d outMbrArray 60 dim(10)
This goes in right after the 'dbgview(*list)' comment line. You'll need to
drop a
' p e' line at the very end of the source member in
order to complete the procedure definition.
The last change is to remove the *ENTRY PLIST section. It's being replaced
by our PR.
The binder source is used to explicitly tell what we intend to make public
for this version of the code (there will be future versions, and we don't
want to re-compile clients that only need this primitive functionality.) I
put the binder source in QSRVSRC and call it AG04. Same name as everything
else. I'm not bright enough to remember a complex naming scheme so I make
everything the same!
STRPGMEXP PGMLVL(*CURRENT) SIGNATURE(' 1.00 08 Mar 02')
EXPORT SYMBOL(getMbrList)
ENDPGMEXP
To make it easy on everybody still interested, here's the complete RPG IV
source for AG04:
* Get an array of members using the list member API
h nomain
h debug option(*srcstmt: *nodebugio)
* crtmod dbgview(*list)
* CRTSRVPGM SRVPGM(AG04) ACTGRP('QILE')
d/copy qprotosrc,ag04
p getMbrList b export
d getMbrList pi
d inpFile 10 value
d inpLib 10 value
d outMbrArray 60 dim(10)
d* These "D" specs were copied from the IBM library QSYSINC
d* and then modified
D*******************************************************************
D*Type Definition for the Input Parameter Section of the user
D*space in the QUSLMBR API.
D*******************************************************************
DQUSQLI00 DS
Qdb Ldbm Input
D QUSSPACE00 1 10
Userspace
D QUSULIB00 11 20
Userspace Library
D SPC 1 20
combined
D QUSFN03 21 28
Format Name
D QUSFILN00 29 38
File Name
D QUSFILLN00 39 48
File Library Name
D QUSMN 49 58
Member Name
D QUSRRIDE00 59 59
Override
D*
D*******************************************************************
D*Type Definition for the MBRL0200 format of the userspace in the
D*QUSLBMR API.
D*******************************************************************
DQUSL0200 DS
Qdb Ldbm MBRL0200
D QUSMN01 1 10
Member Name
D QUSST 11 20
Source Type
D QUSCDT 21 33
Creation Date Time
D QUSLSDT 34 46
Last Source Date Tim
D QUSMD 47 96
Member Description
D QUSCCSID05 97 100i 0
Member Description C
D*
* Generic header
d GENHDR DS INZ
d USRARA 1 64
d SIZGEN 65 68i 0
d RLSLVL 69 72
d UFMTNM 73 80
d APIUSE 81 90
d DATTIM 91 103
d INFSTS 104 104
d SIZUSE 105 108i 0
d OFFINP 109 112i 0
d SIZINP 113 116i 0
d OFFHDR 117 120i 0
d SIZHDR 121 124i 0
d OFFLST 125 128i 0
d SIZLST 129 132i 0
d NUMLST 133 136i 0
d SIZENT 137 140i 0
d* Error code
d ERRRTC ds INZ
d ERRSIZ 1 4i 0 Inz(%size(ERRRTC))
d ERRAVL 5 8i 0
d ERRID 9 15
d SSTART s 10i 0
d SLEN s 10i 0
d qualFile s 20
d i s 10i 0
c* Name of space to hold list
c MOVEL(P) 'QUSLMBR ' QUSSPACE00
c MOVEL(P) 'QTEMP' QUSULIB00
c* Create user space to hold list
c CALL 'QUSCRTUS'
c PARM SPC
c PARM *BLANKS SPCATR 10
c PARM 100000 SPCSZE 10 0
c PARM x'00' SPCINT 1
c PARM '*ALL ' SPCAUR 10
c PARM *BLANKS SPCTXT 50
c PARM '*YES ' SPCRPL 10
c PARM ERRRTC
c* Check for errors
c If ErrID<>*Blanks
c Dump
c Goto EndofPgm
c Endif
c* Set up parms for spooled file list API
c eval QUSFN03 = 'MBRL0200'
c eval qualFile = inpFile + inpLib
c eval QUSMN = '*ALL'
c eval QUSRRIDE00 = '0'
c* Put the list into the space
c CALL 'QUSLMBR'
c PARM SPC
c PARM QUSFN03
c PARM QualFile
c PARM QUSMN
c PARM QUSRRIDE00
c PARM ERRRTC
c* Check for errors
c If ErrID<>*Blanks
c Dump
c Goto EndofPgm
c Endif
c* Determine how many entries,
c* where they begin
c* by examining the generic header
c*
c Z-ADD 1 SSTART
c Eval SLEN=%size(GENHDR)
c*
c CALL 'QUSRTVUS'
c PARM SPC
c PARM SSTART
c PARM SLEN
c PARM GENHDR
c PARM ERRRTC
c* Check for errors
c If ErrID<>*Blanks
c Dump
c Goto EndofPgm
c Endif
* Did the list fit in the space? (list complete)
c if INFSTS <> 'C'
c 'Not complete'Dump
c Goto EndofPgm
c endif
c* Working offset will be changed in the loop, but for the start, point
to the list and
c* retrieve "list entry size" bytes
c OFFLST ADD 1 SSTART
c eval slen = SIZENT
* Did the API return more data than my structure can hold?
* maybe the API returns more information in this release...
c if SIZENT > %size(QUSL0200)
c 'API struc' Dump
c endif
c* Extract list from user space 1 at a time
c DO NUMLST i
c CALL 'QUSRTVUS'
c PARM SPC
c PARM SSTART
c PARM SLEN
c PARM QUSL0200
c PARM ERRRTC
c* Check for errors
c If ErrID<>*Blanks
c Dump
c Goto EndofPgm
c Endif
* Load as far as the array and no farther
c if i <= %elem(outMbrArray)
c movel QUSMN01 outMbrArray(i)
c move QUSMD outMbrArray(i)
c else
c leave
c endif
c* Next entry
c ADD SIZENT SSTART
c ENDDO
c EndofPgm Tag
c return
p e
Compile this with PDM option 15 - CRTRPGMOD. Then create the service
program with CRTSRVPGM ACTGRP('QILE'). Because I have a bad memory, I put
special compiler options and the lot in comment lines after my
H-specifications. Then I can use the Windows copy/paste commands to put
them on the command line. So when taking PDM option 15, I paste
'dbgview(*list)' on the command line before I press Enter. This means I
don't have to prompt the command and try to locate the right panel to make
the change on. It works best when I'm re-compiling several modules at the
same time.
That's our service program. It has one function that the outside world can
use: getMbrList. When I say 'outside world', I mean code outside of the
service program. We'll add more functions later.
Now for the client; the mainline code (Has ANYBODY got a better name for
this?)
AG05 needs a copy of the prototype (the compiler is strongly typed, so it
wants to know the specifics of the parameter list to make sure we're using
the procedure right.) Because the prototype is in a /COPY member, referring
to it is as easy as
d/copy qprotosrc,ag04
before the D-specifications.
In the loadSfl subroutine, we need to replace the CALL/PARM with
c callp getMbrList(wname: wlib: array)
For convenience, here is the complete source for AG05:
* Work with a single page of source members
h debug option(*srcstmt: *nodebugio)
* crtrpgmod ag05 dbgview(*list)
* crtpgm ag05 bndsrvpgm(*libl/ag04) dftactgrp(*no) actgrp(QILE)
fag03 cf e workstn
f SFILE(mbrsfl:dspRRN)
* get the prototype definitions for member service program
d/copy qprotosrc,ag04
d dspRRN s 4s 0
d array s 60 dim(10)
d i s 10i 0
d sds
d tmname 244 253
* initial display
c seton 42
sfldspctl
c setoff 41
sfldsp
c setoff 30
alarm
c exfmt mbrctl
* continue to display
c dow *in03 = *off
c exsr loadSfl
c exfmt mbrctl
* see what option was chosen
c if *in41 = *on
sfldsp
c do 10 dspRRN
c dspRRN chain mbrsfl
c if %found
c select
c when wopt = 'P'
c call(e) 'AG01CL'
c parm wname
c parm wlib
c parm wmbr
c endsl
c eval wopt = *blank
c update mbrsfl
c endif
c enddo
c endif
c exfmt mbrctl
c enddo
c seton lr
c loadSfl begsr
* clear the existing page
c setoff 42
sfldspctl
c seton 40
sflclr
c write mbrctl
c setoff 40
sflclr
c setoff 41
sfldsp
c seton 42
sfldspctl
c eval dspRRN = 0
* get the list
c callp getMbrList(wname: wlib: array)
* load a single page - artificially stupid to make the code simple
c do 10 i
c eval dspRRN = dspRRN + 1
c movel array(i) wmbr
c move array(i) wtext
c write mbrsfl
c seton 41
sfldsp
c enddo
c endsr
Compile this with PDM option 15 and then create the program with CRTPGM ag05
bndsrvpgm(*libl/ag04) dftactgrp(*no) actgrp(QILE). This will create a
program object that will refer to the service program AG04. When you CALL
AG05 for the first time, not only will AG05 activate, but AG04 will, too.
All of the storage for AG04 and 05 will get initialised, default file opens
will occur, etc. Should I detail that 'etc.' or has everyone read the ILE
Concepts manual? It's at
http://publib.boulder.ibm.com/pubs/html/as400/v5r1/ic2924/books/c415606502.h
tm#ToC or http://makeashorterlink.com/?Y3165148 Activation is discussed in
Chapter 3.
The client (AG05) and service program (AG04) both run in AG('QILE'). This
means that no matter how many times you call them during the say, they will
be activated just once; initialised just once, etc. Unless you issue a
RCLACTGEP('QILE'). Since you know the name of the AG, you can clean up just
this one AG and leave others (like GL or AP) intact for this job. Something
to think about: Does this application need shared storage/overrides or will
it run correctly (produce the proper output) if it didn't? If AG04 ran in a
different AG than AG05, would it make a difference in terms of the output of
AG05? Test your assumptions by re-creating them to run in separate AGs.
I'll give you a chance to get these two compiled and tested (CALL AG05)
before posting the next bit; Trial 3, in which AG05 becomes *NEW and AG04
becomes *CALLER.
--buck
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.