Providing solutions to dozens of technical dilemmas, this guide features 101 tips for evaluating and circumventing RPG IV's shortcomings to help end users create extensions and program features that are not available through standard RPG IV--the primary programming language used for business application development on IBM's midrange computer systems. Using nearly 20 years of AS/400, iSeries, and System i experience, the author's insights into RPG IV extensions and System i MI instructions allow even the most inexperienced programmer to implement wrappers using code directly from the book.
"synopsis" may belong to another edition of this title.
Bob Cozzi has been an RPG programmer since 1978 and is the author of Introduction for RPG IV and The Modern RPG IV Language. He lives in North Aurora, Illinois.
Title Page,
Copyright Page,
Dedication,
Acknowledgments,
Conventions Used in this Book,
1 - Prototype Everything,
2 - Prototyping a Call to a Program,
3 - An Alternative to QCMDEXC,
4 - Subprocedure-style Entry Parameter List for Programs,
5 - Add NOMAIN to the Header Specification of Secondary Modules,
6 - Monitoring C Function Runtime Errors,
7 - Use PSDS to Retrieve Job Information,
8 - Use QUALIFIED Data Structures,
9 - Copy Subfields Between Qualified Data Structures,
10 - Nested Data Structures,
11 - *ALL and *ALLX 'xx' — The Repeating Constants,
12 - Embed Compiler Parameters into Source Members,
13 - Avoid "Surprise Initialize",
14 - Qualified Externally Described Files (1),
15 - Qualified Externally Described Files (2),
16 - Calculate the End-of-Month Date,
17 - Using Free-Format Comments in Fixed-Format Code,
18 - Get Day-of-Week Name,
19 - Run CL Commands from an FTP Client,
20 - Put Your Program to Sleep,
21 - Use VARYING to Improve Performance,
22 - Converting Numeric to Character with %CHAR,
23 - Converting Character to Numeric,
24 - Easier Text Concatenation,
25 - Create an Auto-Extend User Space,
26 - Declare Data Structures as Arrays,
27 - Initialize Fields to Job Date, System Date, or User Profile,
28 - Use C Runtime Functions in RPG,
29 - Compare and Ignore Case,
30 - Free Online Prototypes for APIs, C Functions, MI Instructions,
31 - Checking for Valid Dates with the TEST OpCode,
32 - Using the Secret 'X' Edit Code to Convert Numeric to Character,
33 - %ADDR — Address of a Variable,
34 - Understanding API Documentation — Bin(4) Parameters,
35 - Understanding API Documentation — Pointer Parameters,
36 - Better Performance when Accessing User Space Data,
37,
38 - Sending a Program Message in RPG,
39 - Retrieve the Function Key Used on a Display File,
40 - Copying More than 64k of Data,
41 - Use %XFOOT with %LEN,
42 - Use %SUBARR to Subscript Arrays,
43 - Use EXTFILE to Avoid Needless Overrides,
44 - Subprocedure Parameters Rule 1 — Default Behavior,
45 - Subprocedure Parameters Rule 2 — CONST Parameters,
46 - Subprocedure Parameters Rule 3 — VARYING,
47 - Subprocedure Parameters Rule 4 — Optional Parameters,
48 - Subprocedure Parameters Rule 5 — Skipping Parameters,
49 - Data Structure Templates,
50 - Boolean Assignment,
51 - Creating Even-Length Packed Fields,
52 - Sorting Arrays with SubArrays,
53 - Convert between Lower- and Uppercase Letters,
54 - Overlapping Data Structures,
55 - Dynamic Arrays — Dynamically Allocated Array Elements,
56 - Converting Date Formats with the QWCCVDT API,
57 - Converting Date Formats with the CEExxxx APIs,
58 - Calculated Day of Week — Zeller's Congruence,
59 - Calculated Day of Week — API Method,
60 - LIKE Keyword Misbehavior — Zoned to Packed,
61 - Default Data-type: Not So Consistent,
62 - Debugging Variables that Have Debugger Command Names,
63 - Viewing Field Contents in Hex in Debug,
64 - Display the First Few Bytes During Debug,
65 - Display Contents of Local Variables with %LOCALVAR,
66 - Convert Character to Numeric — Using MI,
67 - Converting To and From Hexadecimal,
68 - Using Decimal Fields as Real-Date Values,
69 - Check Object Existence,
70 - Supporting Qualified Object Syntax,
71 - Explained: Bytes Provided, Bytes Available, and Bytes Returned,
72 - Converting To or From ASCII and Other Character Sets,
73 - Register an Exit Routine for a Program or Service Program,
74 - Specifying IFS File Names Correctly,
75 - Checking if IFS Files Exist,
76 - RC4 Encryption Using Encryption APIs,
77 - Writing Text to the Joblog,
78 - Reading Save Files with RPG IV,
79 - Encrypting Save Files in RPG IV,
80 - Global and Local Variables,
81 - Create Source Members Used to Create Service Programs,
82 - Binder Source for a Service Program,
83 - Creating Binder Language the Easy Way,
84 - Linking to a Service Program from an RPG IV Program,
85 - Swap Bytes — Big Endian to Little Endian in RPG IV,
86 - Dumping the Call Stack with QpØzDumpStack,
87 - Using Subprocedure Return Values,
88 - How Does the %EDITC (Edit Code) Built-in Function Work?,
89 - Solid Parameter Testing,
90 - Create ASCII Text Files on the IFS,
91 - High-level Math in RPG IV,
92 - Program Described Print File with Dynamic Spacing,
93 - Aligning or Centering Text in a Character Field,
94 - Debug a Batch Job,
95 - Find and Replace with Regular Expressions,
96 - Use DLTOVR when Using OVRDBF OVRSCOPE(*JOB),
97 - Use a FOR Loop to Allow Multiple Exit Points,
98 - Source-level Debugger for Legacy RPG III,
99 - Set and Get Environment Variables from within RPG IV,
100 - Simple Scan with Ignore Upper/Lowercase,
101 - Set the CLASSPATH for Java within RPG IV,
Epilogue,
Appendix - Source Member RPGTnT in QCPYSRC,
Prototype Everything
Prototypes are the basis for call operations in RPG IV. Without prototypes you cannot call a program, subprocedure, or API using either free format or hybrid fixed format. The old call/parm opcodes have been deprecated in RPG IV and should no longer be used.
A prototype is simply a declaration of "stuff" used by the compiler. At compile-time, the compiler uses the prototype to check the syntax in your call to a program, subprocedure, or API. It does this to ensure that the data for the parameters of the call are specified correctly.
A prototype begins with the so-called PR statement. This is a Definition specification that identifies the name of the prototype and optionally, the name of the program or subprocedure being called, as follows:
D GetBalDue PR 7P 2
As illustrated, the prototype name in positions 7 to 21 of the Definition specification indicates the name of the prototype and not the name of the subprocedure that is evoked when the prototype is called. Without additional coding, a prototype defaults to a subprocedure with the same name as the prototype. Therefore, the prototype in the example above is used to call a subprocedure named GETBALDUE.
But what about when a different subprocedure should be evoked when GETBALDUE is called?
The EXTPROC keyword must be included in the prototype when a subprocedure whose name is different from the prototype is being called. For example, if the subprocedure to be evoked is named RTVCSTBAL, the following prototype statement could be used:
D GetBalDue PR 7P 2 EXTPROC('RTVCSTBAL')
Subprocedures and programs may be prototyped. To control whether a program or subprocedure is evoked when the prototyped is called, specify the EXTPGM for program calls and EXTPROC for subprocedure calls.
If the EXTPROC and EXTPGM keywords are not specified, EXTPROC is implied, and the name of the prototype is used as the name of the subprocedure to evoke. The EXTPGM keyword indicates that a program is being called:
D GetBalDue PR 7P 2 extPgm('CMBALDUE')
Here, the EXTPGM keyword indicates that a program named CMBALDUE is evoked when the prototype GETBALDUE is called. The sole parameter of EXTPGM is the name of the program being prototyped. This parameter is optional and, if omitted, defaults to the name of the prototype.
Other than inspecting the EXTPGM/EXTPROC keywords of a prototype, there is no way to distinguish between a program call and a subprocedure call.
The subprocedure name on the EXTPROC keyword and the program name on the EXTPGM keyword must be enclosed in quotes and are case sensitive. It is very common to have subprocedure names consisting of mixed upper- and lowercase letters; however, virtually all program names are specified in uppercase.
When writing subprocedures, the compiler creates an external name for the subprocedure using the name specified on the EXTPROC keyword of the corresponding prototype. If EXTPROC is not specified, the prototype name is used after it is converted to all uppercase.
To define a subprocedure name with upper-, lower-, or mixed-case letters, specify the subprocedure name on the EXTPROC keyword:
D GetBalDue PR 7P 2 EXTPROC('GetBalDue')
In this example, the subprocedure name assigned to our subprocedure is 'GetBalDue'. If EXTPROC('GetBalDue') were not specified, the subprocedure name would be 'GETBALDUE'.
Most prototypes created for RPG IV subprocedures use all-uppercase names. Consequently, the EXTPROC keyword is frequently omitted from prototypes. When prototyping subprocedures for APIs — such as those from the Unix-style APIs, C functions, or MI instructions — the majority of them use either mixed-case or all-lowercase names. The EXTPROC keyword must be used to ensure that the correct API name is prototyped.
Following a PR statement, the parameters for the program or subprocedure are specified. These are similar to specifying subfields of a data structure but often include several additional keywords, such as CONST, VALUE, and OPTIONS. For example, the QCMDEXC API (see Tip #2) would be prototyped as follows:
Simple Prototype for the QCMDEXC API
D QCMDEXC PR EXTPGM('QCMEXC')
D cmdString 32702A Const OPTIONS(*VARSIZE)
D nCmdLen 15P Const
D dbcsFlag 3A Const OPTIONS(*NOPASS)
Prototyping a Call to a Program
In addition to subprocedures, programs may have a prototype created for them. This allows them to be called using natural expression syntax or used in free-format RPG IV.
Prototyped programs can be called using the CALLP opcode or in /free syntax by specifying the prototype name along with its parameters enclosed in parentheses:
/free
callp qcmdexc('ADDLIBLE XTOOLS;: 15);
qcmdexc('RMVLIBLE XTOOLS': 15);
/end-free
To prototype a program, create a prototype in the same way you would for a subprocedure. To indicate that a program and not a subprocedure is being called, specify the EXTPGM keyword, as follows:
Use EXTPGM to Prototype Program Calls
D QCMDEXC PR EXTPGM
D cmdString 32702A Const OPTIONS(*VARSIZE)
D nCmdLen 15P 5 Const
D dbcsFlag 33A Const OPTIONS(*NOPASS)
The QCMDEXC API is prototyped above. Note the EXTPGM keyword on the first line. This indicates that a program is to be called. The name of the program being evoked by this prototype is the same as the prototype name. To call QCMDEXC using this prototype, use the CALLP opcode, as follows:
c callp qcmdexc('ADDLIBLE XTOOLS;: 15)
or in free format:
/free
qcmdexc('ADDLIBLE XTOOLS': 15);
/end-free
The name of the prototype and the name of the program do not need to be the same. When the prototype name is not the same as the program being prototyped, specify the program name on the EXTPGM keyword, as follows:
Using EXTPGM with an Alternate Prototype Name
D runcmd PR extPgm('QCMDEXC')
D szCmdStr 32702A Const OPTIONS(*VARSIZE)
D nCmdLen 15P 5 Const
D dbcsFlag 3A Const OPTIONS(*NOPASS)
Note that in the example above, the prototype name is RUNCMD but the EXTPGM keyword identifies QCMDEXC as the program to call.
To call QCMDEXC using this prototype, specify it as follows:
C callp runcmd('ADDLIBLE XTOOL; : 15)
or
/free
runcmd('ADDLIBLE XTOOLS': 15);
/end-free
Perhaps a more conventional (and easier) way to call QCMDEXC would be to declare a variable length field and store the command in that field. Then pass the variable length field to the program when it is called, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
In the example above, the %LEN built-in function is used to calculate the length of the command string; this is used as the second parameter of the call to RUNCMD.
CHAPTER 3An Alternative to QCMDEXC
An alternative to QCMDEXC is the system() function. This function is a C runtime interface that may be called from RPG IV. There are differences between system() and QCMDEXC:
• There is no parameter 2 on system() — meaning that the length of the command string is determined by the system() interface itself rather than requiring it to be calculated in advance.
• When a MONITOR/ON-ERROR handler is used, a call to QCMDEXC will evoke the ON-ERROR handler when an error occurs while processing the CL command. A call to system() does not evoke the ON-ERROR handler when an error occurs in processing the CL command.
The prototype for system() follows:
Prototype for the System() Function
D system PR 101 0 extProc('system')
D cmdString * Value Options(*String)
The system() function, as prototyped above, may be called using the so- called hybrid syntax in RPG IV, as follows:
c callp system('ADDLIBLE XTOOLS')
or in free format, as follows:
/free
system('ADDIBLE XTOOLS');
/end-free
To use this or any C runtime function, the Binding Directory named QC2LE must be included on the BNDDIR parameter when the source member is compiled. See Tip #28 for information on including the QC2LE Binding Directory in RPG IV programs.
Most people prefer to specify the BNDDIR keyword on the Header specification in the source member, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
Here, the BNDDIR('QC2LE') keyword is specified. In addition, the C runtime library's _EXCP_MSGID variable is imported, and its value is assigned to the field named CPFMSG. After a call to system(), it returns either zero or non-zero. If non-zero is returned, the CL command failed. If a CPF message is issued, it is returned in the CPFMSG variable.
CHAPTER 4Subprocedure-style Entry Parameter List for Programs
Legacy applications accepted input parameters — commonly referred to as *ENTRY/PLIST — by using the PLIST and PARM statements in fixed-format Calculation specifications, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
RPG quietly added a method to declare an entry parameter list for programs when it added subprocedures to the language back in version 3.2 and 3.7 of the operating system. Instead of the traditional *ENTRY/PLIST statements, a new method that replaces these statements with a Prototype and Procedure Interface is available. The name of the Prototype and Procedure Interface must be the same as the program name and must appear at the top of the Definition specifications, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
The entry parameter list for the program PRTAGING is specified using a Prototype and Procedure Interface instead of the old-fashioned *ENTRY/PLIST. The prototype must appear before the procedure interface. The EXTPGM keyword on the prototype is not strictly required; however, my experience is that it always works when EXTPGM('myPgmName') is specified.
In addition, if you want to call PRTAGING from another RPG IV program, you should store the prototype in its own external source member (sometimes called a "/copy member" or "copybook") and then /COPY or /INCLUDE that source member into the caller's source member.
One major benefit from using this syntax is that data structures and arrays may be declared as parameters much more easily.
If a parameter is a data structure, the LIKEDS keyword can be used to define the parameter (see Tip #49 for more details).
CHAPTER 5Add NOMAIN to the Header Specification of Secondary Modules
When a source member is compiled, a huge amount of unnecessary RPG Cycle code is included in the compiled *MODULE object. This extra code is required for the main program module but not for any of the so-called secondary modules. Secondary modules are those that are used to create a multi-module program.
To avoid the overhead of the RPG Cycle in these secondary modules and reduce the final size of the program, add the NOMAIN keyword to the Header specification of all secondary modules in a program.
Use NOMAIN in All Secondary Modules' Source Members
H NOMAIN
Do not add NOMAIN to the primary or "main" module or to programs that are made up of only one module.
The same thing can be applied to creating modules for Service Programs. When creating a *SRVPGM (Service Program), there is no situation where using this extra RPG Cycle code is required. Therefore, always use the NOMAIN keyword on the Header specification for all source members used in a service program.
CHAPTER 6Monitoring C Function Runtime Errors
When a C runtime function is used in RPG IV (and more and more applications are using C runtime functions), it can add a great deal of functionality to the application. When that function fails, retrieving and determining the error can be a completely new experience to RPG IV programmers.
To understand how to trap and handle errors that occur when a C function is used in RPG IV, you have to understand how this is accomplished in C and many other languages.
Unlike RPG IV, the C language doesn't really have the concept of an opcode. Instead, virtually everything that is accomplished in C is done through functions. A function is identical to a subprocedure in RPG IV. For example, to copy data from one text field to another, the MOVEL or EVAL opcodes are used in RPG IV. In C, the strcpy() or memcpy() functions are used. Copying numeric values from one field to another is virtually identical in C and RPG IV.
When using C runtime functions, there are two methods for detecting error conditions:
• Inspect the runtime error code value.
• Inspect the global C runtime CPF message variable.
The runtime error code is returned to a program by calling the errno() function. Normally in C this is provided through a macro, but RPG doesn't have macros, so it makes a function available. To retrieve the C runtime error code, two declarations need to be specified, as follows:
D errno PR * extProc('___errno')
D nErrNo S 101 0 Based(pErrNO)
In the example above, the '___errno' function is prototyped. It has no parameters, so one line of code is all that's needed to prototype it. Calling this function returns a pointer to the most current error code generated from a call to another C runtime function; for example:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
In this example, the open64() function is used to open a file named NOTES.TXT. If the open fails, — 1 is returned by the open64(), and you must use errno() to retrieve the error number (i.e., reason code). This number in and of itself is not very useful unless you're an experienced C programmer. In fact, the error code numbers are not documented in the printed or PDF manuals. The only way to determine what they are is to open the ERRNO source member in the H source file in the QSYSINC library. That's SRCFILE(QSYSINC/H) SRCMBR(ERRNO). And yes, the source file name is just the letter H.
To make more sense of the error number returned by a call to errno(), another function can be used. This second function, strerror(), retrieves the text description for any error number, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
In this example, the strerror() prototype is added. It accepts an integer parameter and returns a text string with the description of the error number. Since C text strings are different from RPG character fields, the RPG IV built-in function %STR is used to convert the results of strerror() into RPG-readable data. The message description is then copied to the ERRMSG field.
To simplify retrieving and recording the C runtime error messages, the LOGERRNO() subprocedure is provided. This subprocedure retrieves the current errno() value, retrieves the text description of the error number (if one is returned), and then writes both the number and its text to the joblog, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
In the example above, the LOGERRNO subprocedure begins by calling the errno() function. If a valid result is detected, the error number is used on a subsequent call to strerror () to retrieve the error's text description. Both the error number and the text description are written to the joblog using a call to the Qp0zLprintf() API (see Tip #77). And finally, the error number is returned to the caller.
Using the LOGERRNO subprocedure can streamline C runtime error handline, as follows:
[PROGRAM LISTING NOT REPRODUCIBLE IN ASCII]
What about CPF Messages?
Sometimes C runtime functions produce a traditional CPF error message. This is notably true when calling the system() function to run CL commands (see Tip #3).
After a CL command has been performed, the exported '_EXCP_MSGID' variable can be tested for a traditional 7-position CPF exception/error message ID. To declare this variable in RPG IV, an IMPORT variable must be specified as follows:
RPG IV Declaration for C Runtime CPF Messages
D cpfmsgid S 7A IMPORT('_EXCP_MSGID')
The IMPORT keyword is used to link the RPG IV variable with the imported variable. In this case, the C runtime library has exported the '_EXCP_MSGID' variable and our program imports it. At runtime, the CPFMSGID field is used to access the data in '_EXCP_MSGID.'
The name of the variable in RPG IV is irrelevant, so be sure to use a name that can be used consistently throughout all applications.
Excerpted from RPG TnT by Bob Cozzi. Copyright © 2007 Robert Cozzi, Jr.. Excerpted by permission of MC Press.
All rights reserved. No part of this excerpt may be reproduced or reprinted without permission in writing from the publisher.
Excerpts are provided by Dial-A-Book Inc. solely for the personal use of visitors to this web site.
"About this title" may belong to another edition of this title.
Seller: Meadowland Media, Fayetteville, AR, U.S.A.
paperback. Ships same or next business day. Seller Inventory # D135-111325-S-106
Seller: GreatBookPrices, Columbia, MD, U.S.A.
Condition: New. Seller Inventory # 12470764-n
Seller: INDOO, Avenel, NJ, U.S.A.
Condition: New. Brand New. Seller Inventory # 9781583473641
Seller: Rarewaves USA, OSWEGO, IL, U.S.A.
Paperback. Condition: New. Providing solutions to dozens of technical dilemmas, this guide features 101 tips for evaluating and circumventing RPG IV's shortcomings to help end users create extensions and program features that are not available through standard RPG IV-the primary programming language used for business application development on IBM's midrange computer systems. Using nearly 20 years of AS/400, iSeries, and System i experience, the author's insights into RPG IV extensions and System i MI instructions allow even the most inexperienced programmer to implement wrappers using code directly from the book. Seller Inventory # LU-9781583473641
Seller: Grand Eagle Retail, Bensenville, IL, U.S.A.
Paperback. Condition: new. Paperback. Providing solutions to dozens of technical dilemmas, this guide features 101 tips for evaluating and circumventing RPG IV's shortcomings to help end users create extensions and program features that are not available through standard RPG IV--the primary programming language used for business application development on IBM's midrange computer systems. Using nearly 20 years of AS/400, iSeries, and System i experience, the author's insights into RPG IV extensions and System i MI instructions allow even the most inexperienced programmer to implement wrappers using code directly from the book. Shipping may be from multiple locations in the US or from the UK, depending on stock availability. Seller Inventory # 9781583473641
Seller: GreatBookPrices, Columbia, MD, U.S.A.
Condition: As New. Unread book in perfect condition. Seller Inventory # 12470764
Seller: Revaluation Books, Exeter, United Kingdom
Paperback. Condition: Brand New. 1st edition. 304 pages. 9.00x7.25x0.50 inches. In Stock. Seller Inventory # 1583473645
Quantity: 1 available
Seller: Kennys Bookshop and Art Galleries Ltd., Galway, GY, Ireland
Condition: New. Num Pages: 287 pages. BIC Classification: UKD; UM. Category: (G) General (US: Trade). Dimension: 230 x 182 x 18. Weight in Grams: 412. . 2011. 1st Edition. Paperback. . . . . Seller Inventory # V9781583473641
Quantity: Over 20 available
Seller: Kennys Bookstore, Olney, MD, U.S.A.
Condition: New. Num Pages: 287 pages. BIC Classification: UKD; UM. Category: (G) General (US: Trade). Dimension: 230 x 182 x 18. Weight in Grams: 412. . 2011. 1st Edition. Paperback. . . . . Books ship from the US and Ireland. Seller Inventory # V9781583473641
Seller: Rarewaves USA United, OSWEGO, IL, U.S.A.
Paperback. Condition: New. Providing solutions to dozens of technical dilemmas, this guide features 101 tips for evaluating and circumventing RPG IV's shortcomings to help end users create extensions and program features that are not available through standard RPG IV-the primary programming language used for business application development on IBM's midrange computer systems. Using nearly 20 years of AS/400, iSeries, and System i experience, the author's insights into RPG IV extensions and System i MI instructions allow even the most inexperienced programmer to implement wrappers using code directly from the book. Seller Inventory # LU-9781583473641