Using BIFs in Expressions

The following code is an exercise in using the BIFs with expressions. The code was necessary to interpret HTML form data into 2 position numeric value. The really isnít any such creature in HTML. Input on a form is a form field, which by nature is a string object. It may contain characters, or numbers, and fixed decimal representation is a myth in HTML.

<INPUT TYPE="text" name=wgt$(ROW_NUM) size="8" maxlength="8" value="$(V_WCWKLO)">

If the form contained only a single decimal field, I would probably write a client-side JavaScript routine to validate the form data. But in this case, the text box is part of a table. There might be anywhere from 1 to 30 entries, each containing weight. So I passed the table to an RPG program to validate and update the database file.

So, aware that the incoming text data could contain anything, the only thing assured, was that the length will not exceed 8 characters ( by using the HTML INPUT tag attribute: maxlength=Ē8Ē). It may contain a decimal point or, it may not. The following code is an attempt to decide whether or not the string contains a valid data and if it contains merely numbers or numbers and a decimal point!

D $weight                        7  2
D  wgt_in                 1      7

D #VALID          C                   CONST(' .0123456789')
D #ZPAD           S              8    INZ('00000000')

I start by getting the value of the table data for the weight using the DTW APIís. The value is a text string 8 characters long from the address of the table value in the specified row and column. Notice the use of the address BIF (%ADDR) to determine the location of the table row and column. The string pointer(%STR) is used to make sure the length only includes characaters up to the string terminator (Hex'00')--in essense finding the maximum length of the string.

               ndRow = ndRow + 1;
               ndCol = 1;                          // Get weight
               ndRC = dtw_GetV(ndTable:%addr(ndValue):ndRow:ndCol);
               z$wght =  %trim(%str(ndValue:8));

               IF z$wght = *blanks;
                  p$err = 'MNF0003';
                  EXSR @exit;

Using the constant of digits, plus the decimal point (#VALID), I peform a quick check to see if I have a valid number; (no point in continuing if it does not contain digits).

               pos = %check(#valid:z$wght);   // Make weight contains valid characters
               IF pos > 0;
                  p$err = 'MNF0003';
                  EXSR @exit;

I use the length BIF to return the length of the weight that was entered. Then I use the %SCAN BIF to find the position of the decimal point in the string. If there are more than two digits to the right of the decimal point, I use the %SUBST BIF with the expression B + 2 as the third argument to truncate the string two positions following the decimal point.

               // *-------------------------------------------------------------
               // * Check for decimal point. If there are more than two decimal
               // *  positions, truncate the number.
               // *-------------------------------------------------------------

               IF %scan('.':z$wght) > 0;
                  A = %len(%trim(z$wght));
                  B = %len(%scan('.':z$wght));
                  D = A - B;
                  IF D > 2;
                     z$wght = %subst(z$wght:1: B + 2);

The next set of instructions uses EVALR to load a work field with the rightmost digits after the decimal point. Of course it is not quite that simple. If there are less than two digits to the right of the decimal point, it has to be padded to with zeros. The trim and substring BIF have values that are the result of an expression. The first half of the EVALR uses substring to get the value from the work field Z$WGHT beginning at the position of the decimal point + 1. It is concatenated with the necessary zero padding to insure the resulting string does not contain blanks. This expression takes advantage of the BIF's ability to accept expressions as an element of the function's argument list.

                  //* Right adjust only the numeric value after the decimal point

                  EVALR w$wrk8 = %trim(%subst(z$wght: %scan('.':z$wght)+1)) +
                          %subst(#ZPAD:1:2 - %len(%trim(%subst(z$wght:

Having retrieved the digits to the right of the decimal point, the next step is to grab the digits to the left of the decimal point. Using the substring BIF the digits are retrieved starting at the first position for the length returned by using the scan BIF as an expression (position of decimal minus one).

                  //* Get the substring of the value left of the decimal. Right adjust       
                  // * and concatenate with the value to the right of the decimalā

                  IF %scan('.':z$wght) > 1;
                     EVALR w$wrk8 = %trim(%subst(z$wght:1:
                                          %scan('.':z$wght)-1)) +
                  EVALR  wgt_in = w$wrk8;
                  w$wght = $weight;

Of course if no decimal point is present the process is much simpler. The length of the string is determined. Then the value is right adjusted and padded with zeros. I move the result into a work field then multiply 100 to create the additional two decimal positions.

                  len = 8 - %len(%trim(z$wght));
                   z$wght = %subst(#ZPAD:1:len) + %trim(z$wght);
                   EVALR  wgt_in = z$wght;
                   w$wght = $weight * 100;

               IF w$wght = 0;
                  p$err = 'MNF0003';
                  EXSR @exit;

BIF operations allow some complex instructions when the values are derived from expressions. The code as written extracts the digits from a text string, trimming blanks and stripping out the decimal point with just text string manipulation. The same operation could have been performed using arrays. And Iím sure if I spent more time, I could make this routine somewhat simpler and cleaner, perhaps by using the %XLATE BIF to flip all blanks after the decimal point to zero. But it seems to serve the purpose.