× 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: Starting with RPG IV Procedures (LONG code examples) - was extract BIFs
  • From: Buck Calabro <mcalabro@xxxxxxxxxxxx>
  • Date: Thu, 23 Sep 1999 09:43:10 -0400

Dan,

>>Don't give up on procedures.  Think of them as programs that do
>>one thing and accept parameters.  Once you get the definition and
>>declaration (prototype and interface) syntax down it's no big deal.
>
>You're right, of course.  I just got to do the _FIRST_ one!  
>When I've got a few hours to burn.  I know, I know, just DO it!

Joel is absolutely right!  Jump right in!  I personally feel very
comfortable putting in a procedure where I used to use a subroutine.  The
"trick" is to identify the subroutine's input and output, so you can make
them parameters instead of allowing them to be accessed globally.  I don't
think I'd get much argument by saying that global variables should be used
less than GOTO's, and for the same reasons.

At the risk of completely wearing out my welcome, here is a "how I thought
about building a procedure" example.  This is a great place for anybody else
to critique both my thinking and it's results.  We could all learn some cool
stuff this week!  :-)

A very typical place to start with new procedures is to prototype a system
API, like the translate API.  Original inline code looked like this:

C                     CALL 'QDCXLATE'      
C                     PARM           FLDLEN
C                     PARM           TEXT  
C                     PARM           TBLNAM
C                     PARM           LIBNAM

This code frag was in 3 places in the program: a perfect candidate for a
subroutine.  There were 3 different fields being translated to upper case:
TEXT, DESC and TITLE.  This meant inline code that looked like this:

C                     MOVELTEXT      XFIELD
C                     EXSR UCASE           

C                     MOVELDESC      XFIELD
C                     EXSR UCASE           

C                     MOVELTITLE     XFIELD
C                     EXSR UCASE           

with a subr like:

C           UCASE     BEGSR                 
C                     CALL 'QDCXLATE'       
C                     PARM           FLDLEN 
C                     PARM           XFIELD 
C                     PARM           TBLNAM 
C                     PARM           LIBNAM 
C                     ENDSR                 

This subr can easily be turned into a procedure:

C                   CallP     UCASE(Text)
                                                      
 * Translate lower to upper case                      
P UCASE           B                                   
D UCASE           PI                                  
D  WorkString                   50 
                                                      
C                   CALL      'QDCXLATE'              
C                   PARM                    FLDLEN    
C                   PARM                    WorkString
C                   PARM                    TBLNAM    
C                   PARM                    LIBNAM    
C                   Return                            
P UCASE           E                                   

This procedure has a problem: it isn't stand-alone because of the three
global variables FLDLEN, TBLNAM and LIBNAM.  In  order to use this procedure
in another program, I'd need to define and populate these exact field names
in the new program.  Sounds like a perfect use for some more parameters:

C                   CallP     UCASE(Text:'QSYSTRNTBL':'QSYS')
                                                                   
 * Translate lower to upper case                                   
P UCASE           B                                                
D UCASE           PI                                               
D  WorkString                   50                                 
D  XlateTableNam                10    Value                        
D  XlateTableLib                10    Value                        
                                                                   
D WorkStringLen   S              5p 0                              
                                                                   
C                   Eval      WorkStringLen = %len(WorkString)     
                                                                   
C                   CALL      'QDCXLATE'                           
C                   PARM                    WorkStringLen          
C                   PARM                    WorkString             
C                   PARM                    XlateTableNam          
C                   PARM                    XlateTableLib          
C                   Return                                         
P UCASE           E

This is a bit better because if I decide to change the length of the input
string, I don't need to change the guts of the code - it determines the
length using the %len BIF.  But still, it seems kind of goofy to specify the
translate table name for every CALLP to a procedure named UCASE.  This
procedure really does the function TRANSLATE.  If I rename this one
TRANSLATE, I could make a new procedure called UCASE that will only perform
the uppercase function:

C                   CallP     UCASE(Text)
                                                                 
 * Translate lower to upper case                                 
P UCASE           B                                              
D UCASE           PI                                             
D  WorkString                   50                               
                                                                 
C                   CallP     Translate(WorkString:'QSYSTRNTBL':'QSYS')
C                   Return                                       
                                                                 
P UCASE           E                                              

 * Translate string according to supplied table               
P Translate       B                                           
D Translate       PI                                          
D  WorkString                   50                            
D  XlateTableNam                10    Value                   
D  XlateTableLib                10    Value                   
                                                              
D WorkStringLen   S              5p 0                         
                                                              
C                   Eval      WorkStringLen = %len(WorkString)
                                                              
C                   CALL      'QDCXLATE'                      
C                   PARM                    WorkStringLen     
C                   PARM                    WorkString        
C                   PARM                    XlateTableNam     
C                   PARM                    XlateTableLib     
C                   Return                                    
P Translate       E                                           

If it turns out that I need to deal with French uppercasing next month, this
will fail, because QDCXLATE doesn't do different CCSID's  As our friend
Bruce Vining has been patiently repeating, the QLGCNVCS API supports
multiple CCSIDS, and is the recommended means for doing casing.  It's a
fairly simple matter to replace the call to QDCXLATE with a call to QLGCNVCS
in the Translate procedure, despite the fact that the parameter lists are
different.  This is because those differences are "hidden" because we don't
call Translate directly - we go through UCASE first.  The parameters for
UCASE won't change at all, so all the programs that need UCASE are
unaffected by the changes to Translate.  Here's the result of changing
Translate to use QLGCNVCS:

C                   CallP     UCASE(Text)

                                                                       
 * Translate lower to upper case                                       
P UCASE           B                                                    
D UCASE           PI                                                   
D  WorkString                   50                                     
                                                                       
C                   CallP     Translate(WorkString:'U':0)             
C                   Return                                             
                                                                       
P UCASE           E                                                    

                                                        
 * Translate to upper/lower according to supplied CCSID 
P Translate      B                                     
D Translate      PI                                    
D  WorkString                   50                      
D  CaseInp                       1    Value             
D  CCSIDInp                     10u 0 Value             
                                                        
 * Request Control Block                                
D ReqCtrlBlock    Ds                                    
 *  Requesting CCSID based casing                       
D  ReqTyp                       10u 0 Inz(1)            
 *  CCSID  0=job CCSID                                  
D  CCSID                        10u 0 Inz(0)            
 *  0=to upper, 1=to lower                              
D  CaseFlag                     10u 0                   
 *  Reserved for other casing types                     
D  Reserved                     10a                     
                                                        
 * API error structure                                  
D ErrStruc        Ds                                    
D  StrucSize                    10i 0                   
D  BytesReturned                10i 0                   
D  ErrorID                       7a                     
D  ErrReserved                   1a                         
D  ErrorData                   256a                         
                                                            
D Length          S              5p 0                       
D Input           S                   like(WorkString)      
D Output          S                   like(WorkString)      
                                                            
C                   Eval      CCSID = CCSIDInp              
                                                            
C                   Select                                  
C                   When      CaseInp = 'U'                 
C                   Eval      CaseFlag = 0                  
C                   When      CaseInp = 'L'                 
C                   Eval      CaseFlag = 1                  
C                   Other                                   
C                   Eval      CaseFlag = 0                  
C                   EndSl                                   
                                                            
C                   Eval      Length = %len(WorkString)     
C                   Eval      Input  = WorkString           
C                   Eval      Output = *Blanks              
                                                            
C                   Eval      StrucSize     = %len(ErrStruc)
C                   Eval      BytesReturned = 0             
C                   Eval      Reserved      = *Allx'00'  
                                                         
C                   CALL      'QLGCNVCS'                 
C                   PARM                    ReqCtrlBlock 
C                   PARM                    Input        
C                   PARM                    Output       
C                   PARM                    Length       
C                   PARM                    ErrStruc     
                                                         
 * Primitive error handling                              
C                   If        ErrorID <> *Blanks         
C                   Dump                                 
C                   Else                                 
C                   Eval      WorkString = Output        
C                   EndIf                                
                                                         
C                   Return                               
P Translate      E                                      

I hope this was of some use to folks who are in the early stages of using
RPG IV procedures.  I'd really appreciate feedback good and bad.  The
clearer I can present this stuff to OUR folks, the better our shop will
become!

Many thanks for your patience,

Buck Calabro
+---
| This is the RPG/400 Mailing List!
| To submit a new message, send your mail to RPG400-L@midrange.com.
| To subscribe to this list send email to RPG400-L-SUB@midrange.com.
| To unsubscribe from this list send email to RPG400-L-UNSUB@midrange.com.
| 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.