Integrating C functions with normal RPG IV gives you the best of both worlds.
Editor's Note: This article is an excerpt from the MC Press book Functions in Free-Format RPG IV.
Most RPG programmers don't know the C programming language and avoid technical articles and discussions that have anything to do with it. In fact, I will go so far as to say that many RPG programmers get a little “testy” when someone says that C is better than RPG, since it is newer, uses functions, etc., etc., etc. I have to admit that I was not interested in the C language when it was first available. I was busy on a midrange IBM platform that didn’t even have a C compiler.
All that changed in 1993 when I took some graduate-level classes in computer science at a major university. I was faced with classes that used C exclusively for programming lab assignments. Oh, boy! I was cornered. I faced this new challenge and tore into it rigorously. C was different, for sure, but it didn’t take too long to appreciate a concept that is pervasive in this language but was conspicuously absent in RPG—user-written functions!
It took a few months for me to get used to this new style of coding. By the middle of the semester, I was pounding it out as well as those who knew C before coming to classes.
After the college classes, I went back into the world of RPG, with RPG IV making its appearance in late 1994. The new incarnation of RPG was easy to learn and in a few years became the standard on the AS/400, iSeries, or whatever the system name of the day was.
Sometime around V3R2/V3R7, IBM provided support for a new idea: subprocedures in RPG IV. These new subprocedures required the use of ILE, binding, and a non-default activation group. The concept didn’t exactly take the RPG programming world by storm. It has taken many years for us to adopt these cute little mini-programs that return a value. To tie my C experience into this discussion, the subprocedure facility was and is user-written functions—just like the ones in C.
So now, when we need a function of some kind, do we code a subprocedure? To answer my own question: maybe. I hedge because there are dozens of functions ready to go in a function “library” provided to us RPG programmers. I refer of course to the C language operations. But why? Isn’t RPG IV good enough?
It's true that RPG IV has a rich complement of opcodes and built-in functions, so why even consider accessing functions designated for the C language? The answer is that the C language provides some functions that we don’t have in RPG IV, as well as some functions that are simply more efficient than our native RPG operations. This leads us to believe that we need to drop the adversarial attitude we have acquired about the C language and see what it can do for us. With a little learning and practice, we can integrate some C functions into our everyday RPG IV code, giving us the best of both language worlds.
“Doing It” Details
To access a C function, you need to know the function’s interface, including the function name, number of parameters, parameter data types, and the return value.
To see how a C function might be useful to an RPG program, let’s look at a couple of examples. First, let’s look at a need for a random number. RPG IV does not have a random number function. To get a random number, we should look at the scheme used by the C language. There is an operation called rand that returns the next random number from a previous value. However, rand requires that you initialize the internal value that rand uses to generate the next random number. This initialization is called “seeding” the random number generator. This is done with the C operation called srand. So to get a random number, we must use both srand and rand. The output (return value) from rand is an unsigned integer whose value can be anywhere from 0 to 32767. If we want some other range, say 1 to 100, then we must do some range manipulation. Srand has no return value; it takes a parameter value and sets the internal random number initial value. There is something you need to know about this scheme. The parameter you send to srand needs to be random. Here’s why: rand produces output that is predictable in the sense that if you give it value x, it returns y. If, at some time later, you happen to give it the same value of x, it predictably returns y. To avoid any problems, don’t use a constant as the parameter to srand. My choice is to use the microseconds from the system clock from the %timestamp BIF (only milliseconds are available right now). This is pretty random by itself. Here’s the code that I would suggest:
D Seed S 5u 0 inz(0)
D Index s 5u 0
// Prototypes for C functions – and use of Extproc keyword
D Set_Random pr Extproc('srand')
D Seed 5u 0 Value
D Get_Random pr 5u 0 Extproc('rand')
Dow Seed = 0;
Seed = %subdt(%timestamp():*MS)/1000; // Milliseconds from time
If Seed <> 0;
Set_Random(Seed); // Set the seed
// Obtain the random number,
// then scale it to be from 1 to 100
Index = Get_Random(); // Index now 0 to 32767
Index = %rem(index:100); // Index now 0 to 99
Index += 1; // Index now 1 to 100
*Inlr = *On;
At the end of the routine, the random number derived from the C function rand (Prototype Get_Random) is scaled using division by 100 and using the remainder (0 to 99), and then adding 1 to get a number from 1 to 100. If your needs include producing a list of random numbers with no duplicates, you will need to set up a loop after the “seed” section, storing the results of the random number computation (possibly in an array) and verify each time that you get a new number that it is not a duplicate. If it is a duplicate, throw it out and go through the loop again until you have your list, with no duplicates.
The little program above uses data type “u” for the seed and index variables. This data type is an unsigned integer. The reason for the unsigned integer data type for the seed variable is that the srand function requires an unsigned integer for input. The length 5 means that a value for the variable lies between 0 and 65535. Unsigned integer was also used for the index variable since the return value from rand is integer from 0 to 32767.
Perhaps you noticed the use of the keyword VALUE in the Set_Random prototype. This is important. When passing parameters to another procedure, RPG IV normally uses a technique called passing by reference, which means that a pointer address is used. The C language uses a parameter-passing technique called passing by value. In this scheme, the actual value of the parameter is passed. The RPG IV language can accommodate the C language requirement by using the keyword VALUE on the parameter to be passed.
In addition to srand and rand C functions, there are APIs available that will also provide random numbers, with larger values.
There is another C function that you will find interesting and time-saving when the need arises. I am referring to the C function strtok. The function name means string-token. It is used to parse character strings into their token components. A token is considered to be a character string up to a delimiter. If the strtok function is used with the string “See Spot run,” and a blank (space) is specified as the delimiter
character, then you would get “See” with one pass, “Spot” with a second pass, and “run” with the third pass. The return value for this function is a pointer to the token. When a return value of null is received, then no more tokens are available.
For an example, I will use a real-life situation in which a data conversion required changing a name field that included all portions of a name, such as Mr. John Q. Jones, into separate field components of title, first name, middle initial, and last name. This task had already been done using RPG opcodes of scan, check, and subst. However, once I was familiar with strtok, I wanted to see how this task could be done using the C function.
First, here is the prototype to the C function:
d GetToken pr * ExtProc('strtok')
d BigName * Value Options(*String)
d Delimit * Value Options(*String)
There are lots of pointers here! The return value is a pointer to the token, or null. The two parameters are pointers to the big name and the delimiter fields. Also keywords VALUE are used since C uses passing by value, and the OPTIONS (*String) is used to have a null value appended to our character strings. C works with character strings as a single dimension array, with a null character at the end.
Not seen in the next section of code is the field FullName, which exists in the physical file. It is the field that contains the full name, including the title, first name, middle initial, and last name. Here are some work fields needed for this program.
d artok s like(Fullname) dim(30)
d Token s Like(FullName)
d ReturnAdr s *
d count s 5u 0
d Space c ' '
There are other work fields not shown here because they are not related to the parsing routine.
First, set up a data file read loop.
If %eof(File1); // End of file – leave Do loop
Now, clear the output fields and work fields:
Then, check for the all-blank name possibility:
// Not at end of file
If FullName = *blank; // If Name is all blank –
Iter; // Get next file record
Next, since we now have a non-blank name, possible leading blanks are removed (as setup to the strtok function coming next):
FullName = %triml(Fullname); // Remove leading blanks
ReturnAdr = GetToken(FullName:Space); // Get first token
Dow ReturnAdr <> *Null; // Load Tokens into Artok array
Token = %str(ReturnAdr); // From null terminated to normal
Count += 1; // Count for array index
Artok(count) = %trim(Token); // Put the token into the array
ReturnAdr = GetToken(*Null:Space); // Get next token
Enddo; // The *Null above means continue where you left off
From here on, the processing is to place the array elements into the correct field: title, first name, middle initial, or last name. The count field is quite valuable in knowing how many total tokens were found in the full name field and then what to do with each array element.
The use of the strtok C function makes parsing a long string very easy to do.
The two examples above are meant to show you that interfacing with C functions can provide some capabilities that are useful to you as an RPG IV programmer. On the rare occasion when trigonometry or other higher math is needed, the appropriate C function can make overall programming much easier.
This article contains excerpts from my new book, Functions in Free-Format RPG IV. Also explained in this book are the RPG IV built-in functions, subprocedures coded as functions, prototypes, and ILE concepts.
We are entering a new phase in our coding of RPG IV, writing smaller programs and using ILE to provide procedure interconnectivity and good performance. We are writing reusable routines as subprocedures and placing them in service programs. And we are using coding standards. If you cringed on that last statement, check out Appendix A of the book for some suggestions on coding standards. This is an exciting new era for RPG. Have fun!