Bitwise Operations Made Easy

Article ID: 16175

Occasionally, developers ask how they can perform bitwise operations such as XOR (exclusive or) in an RPG program. A number of responses ensue, with the prevailing suggestions of using TestB, BitOff, and BitOn operations or using MI built-ins such as _XORSTR.

A solution that uses TestB, BitOff, and BitOn operations is unwieldy and requires a byte-by-byte manipulation. On the other hand, the MI built-ins solution is API-like and represents a reasonable solution, particularly when subprocedures in a service program encapsulate the bitwise functionality.

If you're squeamish about the use of the MI built-ins (some consider them complex), another less frequently suggested solution relies on SQL scalar functions to implement the bitwise operations. These scalar functions include:

  * LAND - logical AND
    This function accepts two or more character operands and returns the result
    of applying the AND operation. When operating on more than two operands, the
    function applies the AND operation to two operands to create a temporary
    result. The function then applies the AND operation to this temporary
    result and the next operand to produce a new temporary result. This process
    continues until all operands are processed.

  * LNOT - logical NOT
    This function accepts a single character operand and returns the result of
    applying the NOT operation.

  * LOR  - logical OR
    This function accepts two or more character operands and returns the result
    of applying the OR operation. When operating on more than two operands, the
    function applies the OR operation to two operands to create a temporary
    result. The function then applies the OR operation to this temporary
    result and the next operand to produce a new temporary result. This process
    continues until all operands are processed.

  * XOR  - exclusive OR
    This function accepts two or more character operands and returns the result
    of applying the XOR operation. When operating on more than two operands, the
    function applies the XOR operation to two operands to create a temporary
    result. The function then applies the XOR operation to this temporary
    result and the next operand to produce a new temporary result. This process
    continues until all operands are processed.

And, implementing these functions as subprocedures in a service program is simple!

I've included a service program, Bitwise, that encapsulates the scalar functions in the following subprocedures:

* GetBitwiseLogicalAND Accepts, as input parameters, two character operands to which to apply the AND operation. Returns a character value containing the result of the AND operation. To apply the AND operation to more than two operands, first invoke the subprocedure passing the first two operands. Then, repeatedly invoke the subprocedure passing the result of the previous invocation and the next operand until all operands are processed. * GetBitwiseLogicalNOT Accepts, as an input parameter, a single character operand to which to apply the NOT operation. Returns a character value containing the result of the NOT operation. * GetBitwiseLogicalOR Accepts, as input parameters, two character operands to which to apply the OR operation. Returns a character value containing the result of the OR operation. To apply the OR operation to more than two operands, first invoke the subprocedure passing the first two operands. Then, repeatedly invoke the subprocedure passing the result of the previous invocation and the next operand until all operands are processed. * GetBitwiseXOR Accepts, as input parameters, two character operands to which to apply the XOR operation. Returns a character value containing the result of the XOR operation. To apply the XOR operation to more than two operands, first invoke the subprocedure passing the first two operands. Then, repeatedly invoke the subprocedure passing the result of the previous invocation and the next operand until all operands are processed.

Service program Bitwise:

      *  *******************************************************************
      *  * Service program... Bitwise                                      *
      *  * Description....... Bitwise routines                             *
      *  *                                                                 *
      *  * Source type....... SQLRPGLE                                     *
      *  * Compile........... CrtRPGMod Module(YourLib/Bitwise)            *
      *  *                              SrcFile(YourLib/YourSrcFile)       *
      *  *                    CrtSrvPgm SrvPgm(YourLib/Bitwise)            *
      *  *                              Export(*All)                       *
      *  *******************************************************************

     H NoMain

      *  ===================================================================
      *  = Prototypes                                                      =
      *  ===================================================================

      *  -------------------------------------------------------------------
      *  - GetBitwiseLogicalAND - Get bitwise logical AND value            -
      *  -                                                                 -
      *  - Operand 1              Input                                    -
      *  - Operand 2              Input                                    -
      *  -                                                                 -
      *  - Return value: Bitwise logical AND value                         -
      *  -------------------------------------------------------------------

     D GetBitwiseLogicalAND...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - GetBitwiseLogicalNOT - Get bitwise logical NOT value            -
      *  -                                                                 -
      *  - Operand 1              Input                                    -
      *  -                                                                 -
      *  - Return value: Bitwise logical NOT result                        -
      *  -------------------------------------------------------------------

     D GetBitwiseLogicalNOT...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - GetBitwiseLogicalOR - Get bitwise logical OR value              -
      *  -                                                                 -
      *  - Operand 1              Input                                    -
      *  - Operand 2              Input                                    -
      *  -                                                                 -
      *  - Return value: Bitwise logical OR value                          -
      *  -------------------------------------------------------------------

     D GetBitwiseLogicalOR...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - GetBitwiseXOR - Get bitwise XOR value                           -
      *  -                                                                 -
      *  - Operand 1              Input                                    -
      *  - Operand 2              Input                                    -
      *  -                                                                 -
      *  - Return value: Bitwise XOR result                                -
      *  -------------------------------------------------------------------

     D GetBitwiseXOR...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

      *  ===================================================================

      *  = Procedure..... GetBitwiseLogicalAND                             =
      *  = Description... Get bitwise logical AND value                    =
      *  ===================================================================

     P GetBitwiseLogicalAND...
     P                 B                   Export

     D                 PI         32000    Varying
     D  Operand1                  32000    Varying
     D                                     Options( *VarSize )
     D  Operand2                  32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - Data definitions                                                -
      *  -------------------------------------------------------------------

     D Result          S          32000    Varying

      *  -------------------------------------------------------------------
      *  - Get bitwise logical AND value                                   -
      *  -------------------------------------------------------------------

     C/Exec SQL
     C+ Set :Result = LAND( :Operand1, :Operand2 )
     C/End-Exec

      *  -------------------------------------------------------------------
      *  - Set result length to largest operand length                     -
      *  -------------------------------------------------------------------

     C                   Select
     C                   When      %Len( Operand1 ) > %Len( Operand2 )
     C                   Eval      %Len( Result ) = %Len( Operand1 )
     C                   Other
     C                   Eval      %Len( Result ) = %Len( Operand2 )
     C                   EndSl

      *  -------------------------------------------------------------------
      *  - Return bitwise logical AND value to caller                      -
      *  -------------------------------------------------------------------

     C                   Return    Result

     P GetBitwiseLogicalAND...
     P                 E

      *  ===================================================================
      *  = Procedure..... GetBitwiseLogicalNOT                             =
      *  = Description... Get bitwise logical NOT value                    =
      *  ===================================================================

     P GetBitwiseLogicalNOT...
     P                 B                   Export

     D                 PI         32000    Varying

     D  Operand1                  32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - Data definitions                                                -
      *  -------------------------------------------------------------------

     D Result          S          32000    Varying

      *  -------------------------------------------------------------------
      *  - Get bitwise logical NOT value                                   -
      *  -------------------------------------------------------------------

     C/Exec SQL
     C+ Set :Result = LNOT( :Operand1 )
     C/End-Exec

      *  -------------------------------------------------------------------
      *  - Set result length to operand length                             -
      *  -------------------------------------------------------------------

     C                   Eval      %Len( Result ) = %Len( Operand1 )

      *  -------------------------------------------------------------------
      *  - Return bitwise logical NOT value to caller                      -
      *  -------------------------------------------------------------------

     C                   Return    Result

     P GetBitwiseLogicalNOT...
     P                 E

      *  ===================================================================
      *  = Procedure..... GetBitwiseLogicalOR                              =
      *  = Description... Get bitwise logical OR value                     =
      *  ===================================================================

     P GetBitwiseLogicalOR...
     P                 B                   Export

     D                 PI         32000    Varying
     D  Operand1                  32000    Varying
     D                                     Options( *VarSize )
     D  Operand2                  32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - Data definitions                                                -
      *  -------------------------------------------------------------------

     D Result          S          32000    Varying

      *  -------------------------------------------------------------------
      *  - Get bitwise logical OR value                                    -
      *  -------------------------------------------------------------------

     C/Exec SQL
     C+ Set :Result = LOR( :Operand1, :Operand2 )
     C/End-Exec

      *  -------------------------------------------------------------------
      *  - Set result length to largest operand length                     -
      *  -------------------------------------------------------------------

     C                   Select
     C                   When      %Len( Operand1 ) > %Len( Operand2 )
     C                   Eval      %Len( Result ) = %Len( Operand1 )
     C                   Other
     C                   Eval      %Len( Result ) = %Len( Operand2 )
     C                   EndSl

      *  -------------------------------------------------------------------
      *  - Return bitwise logical OR value to caller                       -
      *  -------------------------------------------------------------------

     C                   Return    Result

     P GetBitwiseLogicalOR...
     P                 E

      *  ===================================================================
      *  = Procedure..... GetBitwiseXOR                                    =
      *  = Description... Get bitwise XOR value                            =
      *  ===================================================================

     P GetBitwiseXOR...
     P                 B                   Export

     D                 PI         32000    Varying
     D  Operand1                  32000    Varying
     D                                     Options( *VarSize )
     D  Operand2                  32000    Varying
     D                                     Options( *VarSize )

      *  -------------------------------------------------------------------
      *  - Data definitions                                                -
      *  -------------------------------------------------------------------

     D Result          S          32000    Varying

      *  -------------------------------------------------------------------
      *  - Get bitwise XOR value                                           -
      *  -------------------------------------------------------------------

     C/Exec SQL
     C+ Set :Result = XOR( :Operand1, :Operand2 )
     C/End-Exec

      *  -------------------------------------------------------------------
      *  - Set result length to largest operand length                     -
      *  -------------------------------------------------------------------

     C                   Select
     C                   When      %Len( Operand1 ) > %Len( Operand2 )
     C                   Eval      %Len( Result ) = %Len( Operand1 )
     C                   Other
     C                   Eval      %Len( Result ) = %Len( Operand2 )
     C                   EndSl

      *  -------------------------------------------------------------------
      *  - Return bitwise XOR value to caller                              -
      *  -------------------------------------------------------------------

     C                   Return    Result

     P GetBitwiseXOR...
     P                 E

Notice (in the procedure prototypes) that each subprocedure defines its input parameters using keywords Varying and Options(*VarSize). Keyword Options with argument *VarSize lets your applications define the input parameters with any length up to the maximum defined length of 32000 bytes. However, this mechanism doesn't pass information about the length of the parameter. That fact can be problematic. The Varying keyword comes to the rescue in that varying fields carry with them their actual length. Unfortunately, you can't specify keyword Options(*VarSize) for return values. Each procedure therefore defines its return value as a varying field with 32000 bytes allocated. Your applications must use the same definition for any variable(s) they use for return values.

Each procedure simply uses SQL's Set operation to assign the result of its respective bitwise operation to field Result. Shorter operands are automatically padded with blanks before applying the bitwise operation. Next, field Result's length is set to the length of the longest (or only) operand before returning the value to the caller.

I've also included a program, BitwiseEx, that demonstrates each subprocedure's use. You can use the debugger to view the results of the operations in the program. You'll need to view the fields in hexadecimal format. You request hexadecimal format on the Eval debugger command by adding :X at the end of the command. For example, Eval String1:X shows field String1 in hexadecimal format. Because the bitwise operand and result fields are defined with keyword Varying, the first two bytes of each contains the field's actual length.

Program BitwiseEx:

       //  ****************************************************************
       //  * Program....... BitwiseEx                                     *
       //  * Description... Bitwise routine examples                      *
       //  *                                                              *
       //  * Source type....RPGLE                                         *
       //  * Compile....... CrtRPGMod Module(YourLib/BitwiseEx)           *
       //  *                          SrcFile(YourLib/YourSrcFile)        *
       //  *                CrtPgm    Pgm(YourLib/BitwiseEx)              *
       //  *                          BndSrvPgm(YourLib/Bitwise)          *
       //  ****************************************************************

       //  =================================================================
       //  = Prototypes                                                    =
       //  =================================================================

       //  -----------------------------------------------------------------
       //  - GetBitwiseLogicalAND - Get bitwise logical AND value          -
       //  -                                                               -
       //  - Operand 1              Input                                  -
       //  - Operand 2              Input                                  -
       //  -                                                               -
       //  - Return value: Bitwise logical AND value                       -
       //  -----------------------------------------------------------------

     D GetBitwiseLogicalAND...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

       //  -----------------------------------------------------------------
       //  - GetBitwiseLogicalNOT - Get bitwise logical NOT value          -
       //  -                                                               -
       //  - Operand 1              Input                                  -
       //  -                                                               -
       //  - Return value: Bitwise logical NOT result                      -
       //  -----------------------------------------------------------------

     D GetBitwiseLogicalNOT...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )

       //  -----------------------------------------------------------------
       //  - GetBitwiseLogicalOR - Get bitwise logical OR value            -
       //  -                                                               -
       //  - Operand 1              Input                                  -
       //  - Operand 2              Input                                  -
       //  -                                                               -
       //  - Return value: Bitwise logical OR value                        -
       //  -----------------------------------------------------------------

     D GetBitwiseLogicalOR...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

       //  -----------------------------------------------------------------
       //  - GetBitwiseXOR - Get bitwise XOR value                         -
       //  -                                                               -
       //  - Operand 1              Input                                  -
       //  - Operand 2              Input                                  -
       //  -                                                               -
       //  - Return value: XOR result                                      -
       //  -----------------------------------------------------------------

     D GetBitwiseXOR...
     D                 Pr         32000    Varying
     D                            32000    Varying
     D                                     Options( *VarSize )
     D                            32000    Varying
     D                                     Options( *VarSize )

       //  =================================================================
       //  = Data definitions                                              =
       //  =================================================================

     D String1         S             10    Varying
     D                                     Inz( 'GARY' )
     D String2         S             20    Varying
     D                                     Inz( 'GUTHRIE' )
     D Result          S          32000    Varying

      /Free

       //  =================================================================
       //  = Perform bitwise operations                                    =
       //  =================================================================

       //  -----------------------------------------------------------------
       //  - Get bitwise logical AND value                                 -
       //  -----------------------------------------------------------------

             Result = GetBitWiseLogicalAND
                      (
                        String1 :
                        String2
                      ) ;

       //  -----------------------------------------------------------------
       //  - Get bitwise logical NOT value                                 -
       //  -----------------------------------------------------------------

             Result = GetBitWiseLogicalNot
                      (
                        String1
                      ) ;

       //  -----------------------------------------------------------------
       //  - Get bitwise logical Or value                                  -
       //  -----------------------------------------------------------------

             Result = GetBitWiseLogicalOR
                      (
                        String1 :
                        String2
                      ) ;

       //  -----------------------------------------------------------------
       //  - Get bitwise XOR value                                         -
       //  -----------------------------------------------------------------

             Result = GetBitWiseXOR
                      (
                        String1 :
                        String2
                      ) ;

       //  =================================================================
       //  = End of program                                                =
       //  =================================================================

             *InLR = *On ;

      /End-Free

ProVIP Sponsors

ProVIP Sponsors