Can you imagine an electronics technician who can't solder? Would you want to eat the cooking of a chef who never uses a measuring cup? Would you hire a plumber who uses only a monkey wrench, no matter what the problem is?
You expect better of professionals. You expect them to have good tools and know how to use them.
We should expect no less of ourselves. Being professional programmers, we should have a thorough understanding of all aspects of CL, including how to effectively work with character strings.
CL is a control language used as the primary interface to OS/400, not an application programming language, so it doesn't provide the rich set of string-handling functions and operators you'll find in other languages. Nevertheless, CL's string capabilities are well-suited for the type of work it has to do.
Read on; you may discover that there's more to handling strings in CL than you thought.
CL provides a tool for working with parts of strings. A built-in function written as either %SUBSTRING or %SST, it operates on a character string contained in a CL character variable or in a local data area. The result of the %SST function is a subset of an existing character string. %SST has three parameters-a CL variable name or the special value *LDA, a starting position, and length. The starting position and length may be CL variables or literals.
%SST can be used in any CL command parameter that permits expressions. It is probably most commonly used in the Change Variable (CHGVAR) command, where both the VALUE and the VAR parameters permit expressions. In the VALUE parameter, %SST extracts a portion of a string. In the VAR parameter, it modifies a portion of a string.
1 contains excerpts from a CL program that uses the substring function. Some information about an imaginary factory is stored in a data area called INFO. The program starts by retrieving information from the data area into the &PLANT_INFO variable. The program uses portions of the data in &PLANT_INFO to display the plant name and location on a prompt screen.
Figure 1 contains excerpts from a CL program that uses the substring function. Some information about an imaginary factory is stored in a data area called INFO. The program starts by retrieving information from the data area into the &PLANT_INFO variable. The program uses portions of the data in &PLANT_INFO to display the plant name and location on a prompt screen.
After loading the &PLANT_INFO variable, the program uses the CHGVAR command to copy 20 characters-starting in position 5 of the plant data-into the variable &PLNAME. The program then uses a second CHGVAR command to load the &PLCITY variable from bytes 41 through 58 of the plant data.
Don't fall into the trap of thinking that you can only use %SST in the CHGVAR command. The job in 1 includes some programs that run only for assembly plants. The IF statement checks positions 96 through 98 of the information extracted from the data area to determine whether the factory running the job is an assembly plant. Using %SST, there's no need to copy those three bytes into a separate CL variable and test that CL variable in the IF command.
Don't fall into the trap of thinking that you can only use %SST in the CHGVAR command. The job in Figure 1 includes some programs that run only for assembly plants. The IF statement checks positions 96 through 98 of the information extracted from the data area to determine whether the factory running the job is an assembly plant. Using %SST, there's no need to copy those three bytes into a separate CL variable and test that CL variable in the IF command.
2 illustrates how to change part of a CL variable using the CHGVAR command and %SST. This job runs an Open Query File (OPNQRYF) command, which selects records for a certain type of company. You enter a valid company type code, and the program inserts it in positions 8 and 9 of the record selection string (for example, if you enter 83, &QRYSLT becomes 'COTYPE=83').
Figure 2 illustrates how to change part of a CL variable using the CHGVAR command and %SST. This job runs an Open Query File (OPNQRYF) command, which selects records for a certain type of company. You enter a valid company type code, and the program inserts it in positions 8 and 9 of the record selection string (for example, if you enter 83, &QRYSLT becomes 'COTYPE=83').
CL also has tools that combine two strings to form new strings. The three CL concatenation operators-*CAT, *TCAT, and *BCAT-differ in how they treat the first string.
There are two forms for each operator: a predefined special value beginning with the * character (e.g., *CAT) and a symbol (e.g., ||). Although the symbols may be slightly easier to key, I think it's better for readability to use the special values.
The *CAT (or ||) operator appends one string to the end of another. The new string contains all the characters of the first string followed by all the characters of the second one.
The *TCAT (or |<) operator trims trailing blanks from the first string before appending the second string.
The *BCAT (or |>) operator trims trailing blanks from the first string, appends one blank, and adds the second string.
3 gives some examples of how these operators combine data.
Figure 3 gives some examples of how these operators combine data.
Concatenation operators cannot be used with decimal values. If you want to concatenate a decimal value, you'll have to copy it to a character variable first and then concatenate the character variable.
CL also has access to string-handling tools that are not part of the CL language, such as the OS/400 APIs that work with strings. You can call these APIs from programs written in any AS/400 language, but since most high-level languages (HLLs) have their own string-handling functions, operators, and commands, you'll probably find them most useful for CL programming.
The QCLSCAN program looks for the occurrence of one string within another string. It may look a little scary because it has nine parameters, but it's really very easy to use.
4 illustrates how you might use QCLSCAN. Assume the program has read the value DOPF/DOOREP from a file and placed it into variable &INSTRING. To find the position of the slash, you put a single slash, left-justified, into &PATTERN and call QCLSCAN. After QCLSCAN, the value of &RTNCODE is 5, because the slash is in the fifth position of &INSTRING. If there were no slash in &INSTRING, &RTNCODE would be 0.
Figure 4 illustrates how you might use QCLSCAN. Assume the program has read the value DOPF/DOOREP from a file and placed it into variable &INSTRING. To find the position of the slash, you put a single slash, left-justified, into &PATTERN and call QCLSCAN. After QCLSCAN, the value of &RTNCODE is 5, because the slash is in the fifth position of &INSTRING. If there were no slash in &INSTRING, &RTNCODE would be 0.
Another useful program is QDCXLATE, which uses a translation table to alter a string. In its simplest form, QDCXLATE has three parameters-the string to be translated, the length of the string, and the name of the translation table to use. There are seven more parameters, but they are optional. A common use of this program is to capitalize lowercase letters. You can see an example program fragment using QDCXLATE in 5.
Another useful program is QDCXLATE, which uses a translation table to alter a string. In its simplest form, QDCXLATE has three parameters-the string to be translated, the length of the string, and the name of the translation table to use. There are seven more parameters, but they are optional. A common use of this program is to capitalize lowercase letters. You can see an example program fragment using QDCXLATE in Figure 5.
You can also use the QLGCNVCS Original Program Model (OPM) and QlgConvertCase Integrated Language Environment (ILE) APIs to carry out case conversion. You may find them more suitable for your needs, as they work from a coded character set ID (CCSID) rather than a translation table. CCSIDs are designed for the natural languages people speak, while a translation table merely converts data based on hexadecimal value.
I've presented these APIs only briefly. Read more about them in the AS/400 System API Reference manual.
If you are disappointed that CL doesn't offer other string-handling tools you need, relax. You can write your own programs to add functions to CL.
I can illustrate this capability with an idiosyncrasy of mine: I dislike leading zeros. Messages like "There were 00320 matches" bother me. CL doesn't have a function to remove leading zeros, so I wrote a program I call TRIMLDCHAR (shown in 6) that will trim any leading character from a string.
I can illustrate this capability with an idiosyncrasy of mine: I dislike leading zeros. Messages like "There were 00320 matches" bother me. CL doesn't have a function to remove leading zeros, so I wrote a program I call TRIMLDCHAR (shown in Figure 6) that will trim any leading character from a string.
My program requires four pieces of information-the untrimmed string, the leading character to remove (usually a zero or a blank), the trimmed string, and a flag called SETLR. If the character in the second parameter is not the leading character in the input string, the trimmed string is identical to the input string. I give SETLR some value other than 1 on all but the last call to TRIMLDCHAR, so the program remains active in my job. I deactivate TRIMLDCHAR on the last call by passing the value 1 through the SETLR parameter.
7 shows how to use the program to remove leading zeros from a CL variable. &MATCH_CT contains the number of hits from a search routine. The first CHGVAR command copies the decimal value into character value &MATCH_A because decimal values can't be used with concatenation operators. Program TRIMLDCHAR copies the value in &MATCH_A, without leading zeros, into &MATCH_B. Finally, the last CHGVAR builds the message text. Now, the message reads "There were 320 matches," which is more to my liking.
Figure 7 shows how to use the program to remove leading zeros from a CL variable. &MATCH_CT contains the number of hits from a search routine. The first CHGVAR command copies the decimal value into character value &MATCH_A because decimal values can't be used with concatenation operators. Program TRIMLDCHAR copies the value in &MATCH_A, without leading zeros, into &MATCH_B. Finally, the last CHGVAR builds the message text. Now, the message reads "There were 320 matches," which is more to my liking.
By adding this program to my toolbox, I have extended the CL language. I can call this utility from a CL program whenever I need to remove leading blanks, leading zeros, or some other leading character from a string. Of course, I can also call this utility from programs written in other languages, so I have extended the string-handling capabilities of the other AS/400 programming languages as well.
Since you can write utility programs, the ability of your CL programs to work with strings is limited only by your imagination.
By the way, this example uses the OPM model. If you're using ILE, you might want to consider converting it to an ILE RPG program.
Often, the only characteristic that distinguishes the professional from the amateur is the professional's greater skill with the tools of the trade. Be the best CL programmer you can be. Master CL's existing string-handling tools, and invent other tools as you need them.
Ted Holt is an associate technical editor for Midrange Computing.He can be reached by E-mail at
REFERENCES
AS/400 CL Programming (SC41-3721, CD-ROM QBKAUO00).
AS/400 CL Reference (SC41-3722, CD-ROM QBKAUP00).
AS/400 System API Reference (SC41-3801, CD-ROM QBKAVD00).
Working with Strings in CL Programs
Figure 1: Retrieving Substrings with the %SST Function
DCL VAR(&PLANT_INFO) TYPE(*CHAR) LEN(128) DCLF FILE(MYDSPF) ... RTVDTAARA DTAARA(INFO) RTNVAR(&PLANT_INFO) /* Variables &PLNAME and &PLCITY are defined in the display file */ CHGVAR VAR(&PLNAME) VALUE(%SST(&PLANT_INFO 5 20)) CHGVAR VAR(&PLCITY) VALUE(%SST(&PLANT_INFO 41 18)) SNDRCVF /* Prompt with display file */ ... /* processing for all types of plants */ CALL PGM1 CALL PGM2 /* processing for assembly plants only */ IF COND(%SST(&PLANT_INFO 96 3) *EQ 'ASM') THEN(DO) CALL PGM3 CALL PGM4 ENDDO
Working with Strings in CL Programs
Figure 2: Changing a Substring with the %SST Function
DCL VAR(&QRYSLT) TYPE(*CHAR) VALUE('COTYPE=XX') DCL VAR(&SELCODE) TYPE(*DEC) LEN(2 0) /* &SELCODE was entered by the user */ /* Insert it into the query selection expression */ CHGVAR VAR(%SST(&QRYSLT 8 2)) VALUE(&SELCODE) OPNQRYF ... QRYSLT(&QRYSLT)Working with Strings in CL Programs
Figure 3: Comparison of CL Concatenation Operators
Working with Strings in CL Programs
Figure 4: Example Using QCLSCAN
DCL &INSTRING *CHAR 512 /* String to search */ DCL &INLENGTH *DEC 3 VALUE(512) /* Length of string to search */ DCL &BEGPOS *DEC 3 VALUE( 1) /* Start searching at position */ DCL &PATTERN *CHAR 10 /* String to search for */ DCL &PATLEN *DEC 3 VALUE( 10) /* Length of search string */ DCL &XLATE *CHAR 1 VALUE('1') /* translate to uppercase */ DCL &TRIM *CHAR 1 VALUE('1') /*ignore trailing blanks in &PATTERN */ DCL &WILDCARD *CHAR 1 VALUE(' ') /* no wildcards in &PATTERN */ DCL &RTNCODE *DEC 3 /* position found or error code */ ... CALL QCLSCAN PARM(&INSTRING &INLENGTH &BEGPOS &PATTERN + &PATLEN &XLATE &TRIM &WILDCARD &RTNCODE)
Working with Strings in CL Programs
Figure 5: Capitalizing with QDCXLATE
DCL &INSTR *CHAR 75 /* String to translate */ DCL &INLEN *DEC 5 VALUE(75) /* Length of &INSTR */ DCL &TABLE *CHAR 10 VALUE('QSYSTRNTBL') /* Translation table name */ ... CALL PGM(QDCXLATE) PARM(&INLEN &INSTR &TABLE)
Working with Strings in CL Programs
Figure 6: Program TRIMLDCHAR
* Strip a leading character from a string * * Parameters: * IN - the string to be edited * LDCHAR - the leading character to be stripped * OUT - the edited string * SETLR - if "1", turn on the LR indicator * * If the input string contains only the character to be stripped, * this program places one character, left-adjusted, into the * output string. * *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7 C *ENTRY PLIST C PARM IN 32 C PARM LDCHAR 1 C PARM OUT 32 C PARM SETLR 1 * C LDCHAR CHECKIN PX 30 C PX IFGT *ZERO C SUBSTIN:PX OUT P C ELSE C MOVELLDCHAR OUT P C ENDIF * C SETLR IFEQ '1' C MOVE *ON *INLR C ENDIF * C RETRN *. 1 ...+... 2 ...+... 3 ...+... 4 ...+... 5 ...+... 6 ...+... 7
Working with Strings in CL Programs
Figure 7: Trimming Leading Zeros
DCL VAR(&MATCH_CT) TYPE(*DEC) LEN(5) DCL VAR(&MATCH_A) TYPE(*CHAR) LEN(32) DCL VAR(&MATCH_B) TYPE(*CHAR) LEN(32) DCL VAR(&MSG) TYPE(*CHAR) LEN(80) ... CHGVAR VAR(&MATCH_A) VALUE(&MATCH_CT) CALL PGM(TRIMLDCHAR) PARM(&MATCH_A '0' &MATCH_B '1') CHGVAR VAR(&MSG) VALUE('There were' *bcat &MATCH_B *bcat + 'matches.') ...
LATEST COMMENTS
MC Press Online