Here, I'll illustrate three interesting items available to OS/400 programmers that may not be widely known but are certainly useful:
1. Convert numbers to characters in RPG IV
2. Retrieve the operating system version
3. End a program or activation group anywhere
Convert Numbers to Characters
It's been covertly easy to turn a number into a character string in RPG IV for quite some time now. The %EDITC() built-in function has had this ability since it was introduced, and the %CHAR() built-in function easily converts numbers into text strings.
The %EDITC() built-in function converts a numeric value or expression into a character string after applying an edit code. The first parameter of the %EDITC() built-in function is the numeric value (field or expression) that will be converted to character. The second parameter is the edit code that is used to convert the value. This is essentially the same as using an edit code on a numeric field in the Output specifications, but you're storing the result in a character field in your Calculation specifications.
When using %EDITC(), the character value returned occupies the same number of positions as the original value's declared length plus additional room for a negative sign (if applicable), a decimal point, and any thousands notation (e.g., commas). This means that a seven-digit packed field with two decimal positions that's edited with %EDITC() and the 'J' edit code will occupy 10 positions when converted to character--seven for the original value, one for the decimal position, one for the thousands notation, and one for the negative sign. If edit code '3' were used, eight positions would be returned--seven for the original value and one for the decimal notation.
If the value of the variable being edited is shorter than the field's length (which is a normal situation), empty positions are returned as blanks. This means that the return value's length is consistent for the same variable, regardless of its current value, and that the result is right-justified in the returned character string. To effectively use this built-in function in an expression, you need to trim off the leading blanks using some function, such as %TRIML().
A less widely known method to convert numeric values into character strings is to use the %CHAR() built-in function. This built-in function performs simple numeric-to-character conversions.
%CHAR() returns a "tighter" value than %EDITC() does. Only the value is returned, no empty positions (i.e., blanks). %CHAR() will convert a seven-position packed field with two decimals containing the value 15.25 to the character string '15.25', whereas %EDITC() with the 'J' edit code would return '####15.25#' (where # indicates blanks).
Let's look as some real examples. Listed below are several fields declared on RPG IV Definition specifications. The first field, ITEMPRC (item price) is a seven-position packed field with two decimal positions. I've initialized the field to 15.25 for illustration purposes, but this field's value could have come from a display file or database file just as easily. See Figure 1.
|
Figure 1: Use these Definition Specifications for numeric-to-character conversion.
In addition to the ITEMPRC field, there are four work fields that will contain the results of our conversion testing. Each field is named MSGx, where x is the symbol for the edit code used to convert the number into text. Note that MSGC is used to hold the result of the %CHAR() built-in function, while the others hold the results of various %EDITC() built-in functions.
Figure 2 contains three EVAL operations. The first operation uses the 'J' edit code along with %EDITC() to convert the ITEMPRC field's value to text. The result is concatenated with a message. The second statement uses the '3' edit code, while the third line uses the 'X' edit code. The 'X' edit code allows you to convert a numeric field to character and avoid zero-suppressing the result. That is, leading zeros are not removed and using 'X' avoids inserting any other type of editing symbols, such as negative signs or decimal notation.
|
Figure 2: Convert numeric to character using %EDITC.
Figure 3 illustrates the results of the three EVAL operations that were performed in Figure 2.
|
Figure 3: Here are the results of the EVAL assignments with %EDITC().
Using %CHAR() to return the value is a little cleaner for messages. To use %CHAR(), simply replace the %EDITC() built-in in the example in Figure 2, as shown in Figure 4.
|
Figure 4: Convert numeric to character using %CHAR.
No edit formatting code is required with %CHAR(), and the resulting value is left-justified, as shown in Figure 5.
|
Figure 5: Here's the result of the EVAL assignment with the %CHAR.
The bottom line is that, most of the time, %CHAR() is the built-in function you want to use, but if the result needs to be right-aligned, %EDITC() is a better choice. Also, you can use edit code 'X' to return the value with leading zeroes, which I've seen used in many EDI and utility-type applications.
Retrieve the Operating System Version
For years, many OS/400 developers have use the RTVOBJD command to extract the version of OS/400 on which their programs were running by retrieving the object description of the QCMD program in QSYS and inspecting the data returned to the SYSLVL parameter. With the introduction of APIs, you could simulate that capability by calling the QUSROBJD API. But is there another way?
As it turns out, a little-known ILE API was introduced a while ago that provides just that kind of support. And, unlike the QUSROBJD API, this ILE API is easy to call.
The CEEGPID API is a bindable API, which means its object code is embedded in your program. Rather than have the overhead of a bound call (which is minimal), the actual routine is sort of /COPYed into your program as object code. This avoids the overhead associated with a true bound procedure call.
Calling CEEGPID is easy; simply call it and pass two parameters. Both parameters must be INT4 values (10i0 in RPG IV). They receive data from the API.
Returned in the first parameter is the operating system release! The second parameter is less important; it returns to you the platform identifier, which is always the number 4 for OS/400, so you can ignore it. It is that first parameter that's of value.
To declare a value that will receive the version of OS/400, declare a 4-byte integer value as illustrated in Figure 6.
|
Figure 6: Here, INT4 fields are used as return values from CEEGPID.
Simply pass the fields from Figure 6 to the CEEGPID API as parameters one and two, respectively. See Figure 7.
|
Figure 7: Call CEEGPID using the CALLB operation.
Once the API has been called, the value of the first parameter will contain a 3-digit number representing the Version, Release, and Modification level of OS/400 running on your system. If, for example, V5R1 is installed on your machine, the value 510 is returned.
This API is widely used in the RPG ToolKit to check for release compatibility with certain APIs and features. It checks the version number and then either runs or bypasses the feature, accordingly.
The OSPlatform parameter will always be equal to 4 since your code is running on OS/400. However, if you port your code to OS/2 or MVS, the documentation identifies other values that will be returned.
End a Program or Activation Group
The final tip is about giving a program the ability to end itself and its parent activation group. Suppose you are five invocation levels deep in a call stack, and you need to end the program and return to the point just prior to that which started the activation group. Of course, calling an ILE program causes an activation group to be created if is isn't already created, so you are essentially returning to a menu or CL program that called the program that created the activation group.
The API you need is CEETREC (Normal Activation Group End). It ends an activation group up to the nearest control boundary. This means it ends the activation group in which the API is called. There are other APIs that allow you to control this kind of termination, but in and of itself, this API can be called anywhere (any invocation) within a specific activation group to end the activation group. The only caveat is that the default activation group cannot be terminated with or without this API.
To call the API, use the CALLB operation as shown below:
That's all there is to it. Simply call CEETREC, and your program and its activation group are terminated. All files opened through normal means are closed normally, and all ILE programs are removed from memory--no additional code is run in that activation group unless a routine is registered with the CEERTX API. If CEERTX is used, the corresponding exit procedure is evoked. A full explanation of CEERTX is beyond the scope of this article. For more information, go to IBM's CEERTX page.
Figure 8 contains a single RPG IV program that you can use to test out the techniques illustrated in this issue of Midrange Developer. To compile the sample program, use the CRTBNDRPG command or PDM option 14. The source is set up to handle the necessary parameters; however, be sure to add DBGVIEW(*SOURCE) so that you can debug the sample and view the results in the variables.
|
Figure 8: This sample program illustrates the tips from this issue.
Bob Cozzi has been programming in RPG since 1978. Since then, he has written many articles and several books, including The Modern RPG IV Language--the most widely used RPG reference manual in the world. Bob is also a very popular speaker at industry events such as COMMON and RPG World and is the author of his own Web site, www.rpgiv.com, and of the RPG ToolKit, an add-on library for RPG IV programmers. Bob runs his own one-man iSeries consulting and contract programming firm in the Chicago area.
LATEST COMMENTS
MC Press Online