My colleagues and I came up with an interesting problem earlier: I have a 3 long field and I want to increment the value in it. We need to have the maximum possible number of values in the field before it returns to the initial value.
If I use numbers I have 1,000 values, 0 – 999.
If I used alphanumeric values for a range of 000 – ZZZ I would have 46,656 values. But how can I add 1 to the letter A?
This scenario is on one of our IBM i server partitions. We do not have the programming language C++ or Java, just CL and RPGLE.
If you define a variable in RPG as alphanumeric it is not possible to add 1 to it, see below:
dcl-s TestValue char(3) inz('000') ; TestValue += 1 ; C ADD 1 TESTVALUE *inlr = *on ; COMPILE ERRORS Msg id Sv Statmnt Message text RNF7421 30 000300 Operands are not compatible with the type of operator. RNF7421 30 000300 Operands are not compatible with the type of operator. RNF7044 30 000400 The field TESTVALUE on the C specification is not numeric; the specification is ignored.
After much debate I came up with the following method using two constants and the %XLATE built in function.
In this example the value will be written to a file, TESTPF, which define as:
A R TESTPFR A TESTVALUE 3A
In the new RPG "all free” this file is coded as:
01 dcl-f TESTPF usage(*output) ;
I also need two constant, which are defined with dcl-c, and a "counter” field which is defined using dcl-s:
02 dcl-c Before '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' ; 03 dcl-c After '123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0' ; 04 dcl-s i uns(5) ;
Notice that the two constants are, I cannot think of a better word, "staggered". Before starts with zero, and After with 1.
I use a FOR operation to perform 10,000 increments of TESTVALUE, see below:
05 TestValue = '000' ; 06 for i by 1 to 10000 ; 07 if (%subst(TestValue:3:1) = 'Z') ; 08 exsr Increment ; 09 else ; 10 %subst(TestValue:3:1) 11 = %xlate(Before:After:%subst(TestValue:3:1)) ; 12 endif ; 13 write TESTPFR ; 14 endfor ;
First I have to test to see if I need to "roll over” from a Z to a zero in the third position, line 7. If I do I will perform the subroutine Increment, line 8, which I will explain below.
If I do not have to "roll over” I perform the %XLATE built in function. As the values in the constants are "staggered" zero is translated to 1, 1 to 2, etc. until I come to 9. 9 is translated to A, A to B, etc. until I reach to Z. This translation sort of emulates adding 1 to a character whether or not it is a number. I cannot translate Z to zero without incrementing the second position, hence the statements on lines 7 and 8.
The subroutine Increment starts by "rolling over" the third position to zero, line 17 below.
16 begsr Increment ; 17 %subst(TestValue:3:1) = '0' ; 18 if (%subst(TestValue:2:1) = 'Z') ; 19 %subst(TestValue:2:1) = '0' ; 20 if (%subst(TestValue:1:1) = 'Z') ; 21 %subst(TestValue:1:1) = '0' ; 22 else ; 23 %subst(TestValue:1:1) = %xlate(Before:After:%subst(TestValue:1:1)) ; 24 endif ; 25 else ; 26 %subst(TestValue:2:1) = %xlate(Before:After:%subst(TestValue:2:1)) ; 27 endif ; 28 endsr ;
I think the code above is pretty self evident.
The second position is "incremented", line 26, if it does not need to be "rolled over" to zero, line 21, as it is equal to Z. If it was "rolled" then the first position either needs to be incremented, line 23, or "rolled”, line 21.
If you know of a better way please send it to me via the Contact Form on the right, rather than post it as a comment. That way I can make it into a post and give you credit for it.
You can learn more about the %XLATE built in function in RPGLE on the IBM website here.
This article was written for IBM i 7.1.