Problem solve Get help with specific problems with your technologies, process and projects.

String functions help in cross-language development

Ron Turull, editor of Inside Version 5, explains how character strings can enhance your cross-language development. Ron covers null-terminated strings, C functions, the %STR RPG built-in function and much more.

Admin tip ... The string functions help in cross-language development by Ron Turull

Ron Turull

One of the first things you learn about C is that it stores character strings as null-terminated strings. This means that character strings are variable length with the end of the string marked by a null character (hexadecimal 00, or x'00'). Most standard C string functions, which are sort of the equivalent to RPG op-codes and built-in functions, operate on null-terminated strings.

This is important to you even if you don't have and don't intend to use the C compiler. Here's why:

  • Most of i5/OS is written in C;

  • Most of the APIs are written in C;

  • Many APIs expect at least some of its parameters to be passed as null-terminated strings; and,

  • Perhaps most importantly, all of the C functions are stored as procedures in service programs with names starting with QC2 and located in library QSYS (and yes, every AS/400-iSeries has the C compiler). Some of the string functions are very powerful and you can use them freely, but for the most part you must use null-terminated strings.

    The %STR RPG built-in function can help

    The %STR RPG built-in function can be used to both store and extract null-terminated strings. However, the latter use is its best. The main point to remember about using this function is that it requires pointers. For example, to extract a null-terminated string, you would use a statement, such as:

    Eval RPGString = %Str(pNullTermString)

    In the above example, the null-terminated string pointed to by pNullTermString is extracted and placed in the field represented by RPGString. So if you had a null-terminated string in Field1, you could code the following statement to have it extracted and placed into Field2:

    Eval Field2 = %Str(%Addr(Field1))

    To make a "normal" RPG string a null-terminated string, you could code the following:

    Eval %Str(%Addr(Field1): %Size(Field1)) = Field2

    Notice in the above code the addition of a second parameter on the %Str function. This is required to tell the %Str function the number of bytes allocated at the storage area pointed to by the first parameter (in this case, the size of Field1). If the string in Field2 is longer than the size of Field1 minus one (minus one so there is room for the null terminator), the string will be truncated before the null-character is appended to it.

    If you are certain that Field2 is smaller than Field1, you could also use the following possibly more intuitive statement to do the same thing:

    Eval Field1 = %TrimR(Field2) + x'00'

    Note, the above is only suitable if you do not want trailing blanks to be included in the resulting null-terminated string. If you do want trailing blanks, you can use the %Str function as described above, or the following:

    Eval Field1 = Field2 + x'00'

    The %Subst function is also useful

    %Subst is the built-in function version of the Subst op-code, but it is much more intuitive. The generic format is:

    %Subst(String: StartPos: Length)

    The Length parameter is optional. Like the %Str function, the %Subst function can also be used to both extract and store substrings. For example, to extract the substring starting at byte 10 of the string in Field1 and continuing to the end of the field, you could code the following:

    Eval Field2 = %Subst(Field2: 10)

    Notice that no length is specified. To extract exactly three bytes, starting at byte 10 of the string in Field1, you could code the following:

    Eval Field2 = %Subst(Field2: 10: 3)

    As mentioned, the %Subst function can also be used to store – actually, modify is probably a better word – a sub-stringed portion of a character variable. For example:

    Eval %Subst(Field2: 10: 3) = 'ABC'

    – will place 'ABC' into the 3 bytes of Field2 starting at byte 10 (i.e., bytes 10, 11 & 12). Here is a variation:

    Eval %Subst(Field2: 10) = 'ABC'

    This is a little different. If Field2 is 12 bytes or longer, then the two previous statements are operate equivalently. However, if Field2 is less than 12 bytes long, then the first statement (the one with the length specified) will result in a run-time error, whereas the second statement will simply insert the substring until the end of Field2 is reached. So, if Field2 is 10 bytes long, the previous statement will insert an 'A' in byte 10 and then stop.

    About the author: Ron Turull is editor of Inside Version 5. He has more than 20 years' experience programming for and managing AS/400-iSeries systems.

  • Dig Deeper on iSeries CL programming

    Start the conversation

    Send me notifications when other members comment.

    Please create a username to comment.