Download presentation
Presentation is loading. Please wait.
Published byΑλκιππη Μέλιοι Modified over 6 years ago
1
21st-Century CL Ted Holt Senior Software Developer, Profound Logic Software Senior Technical Editor, The Four Hundred
2
Today we’ll discuss . . . Scope Data Structured programming
Subroutines Built-in functions Files and database Miscellaneous enhancements Final thoughts
3
Scope
4
Scope Q: If you were designing a new computer language, would you include support for arithmetic? A: It depends. First you have to tell me the purpose of the language.
5
Scope CL falls into the category of job control languages.
(It is fair to say that CL is more than a JCL, since CL not only controls jobs, but all the operations on the system.) Job control languages do not need many of the capabilities of RPG and other high-level application languages. CL was introduced in 1980 with the first shipment of the System/38 and remained largely unchanged until 2002 (V5R3). Somebody with clout persuaded IBM that CL was not robust enough.
6
Thus was born 21st-Century CL!
20th-Century CL 21st-Century CL dcl &Libs *char 80 dcl &Lib *char 10 Next: chgvar &lib %sst(&Libs 1 10) call somepgm parm(&Lib) chgvar &Libs %sst(&Libs 11 70) if (&Libs *ne ' ') then(goto Next) dcl &Libs *char 80 dcl &Lib *char 10 + stg(*defined) defvar(&Libs 1) dountil (&Lib *eq ' ') call somepgm parm(&Lib) chgvar &Libs %sst(&Libs 11 70) enddo
7
Data
8
New Data Types Signed integer (*INT) Unsigned integer (*UINT)
Pointer (*PTR) These are the first new data types since 1980.
9
Integer Data Types Signed integer (*INT) Unsigned integer (*UINT)
Signed integer type is more straightforward than the %BINARY (%BIN) function (but the %BIN function is not obsolete). Signed integer type is used by many APIs. Length is in bytes, not digits, and must be 2, 4 or 8.
10
dcl &Dta. char 80 dcl &BytesRtn. int 4 stg(
dcl &Dta *char 80 dcl &BytesRtn *int 4 stg(*defined) defvar(&Dta 1) dcl &BytesAvail *int 4 stg(*defined) defvar(&Dta 5) dcl &Msglen *int 4 stg(*defined) defvar(&Dta 9) dcl &Keylen *int 4 stg(*defined) defvar(&Dta 13) dcl &Sequence *char 1 stg(*defined) defvar(&Dta 17) dcl &IncSender *char 1 stg(*defined) defvar(&Dta 18) dcl &Force *char 1 stg(*defined) defvar(&Dta 19) dcl &Text *char 50 stg(*defined) defvar(&Dta 20) dcl &NbrMsgs *int 4 stg(*defined) defvar(&Dta 73) dcl &NbrEntries *int 4 stg(*defined) defvar(&Dta 77) dcl &DSLength *int 4 dcl &QualDtaq *char 20 chgvar &DSLength %size(&Dta) /* Retrieve the data queue description. */ call qmhqrdqd (&Dta &DSLength 'RDQD0100' &QualDtaq)
11
Defined-on variables Allow one variable to overlay another in memory
Similar in function (but not in syntax) to data structures in RPG Syntax: STG(*DEFINED) DEFVAR(defined-on-variable beginning-position) Default beginning position is 1
12
Defined-on variable example
dcl &WorkDate *char 7 dcl &Century *char 1 stg(*defined) defvar(&WorkDate 1) dcl &DateYMD *char 6 stg(*defined) defvar(&WorkDate 2) dcl &Year *char 2 stg(*defined) defvar(&DateYMD 1) dcl &Month *char 2 stg(*defined) defvar(&DateYMD 3) dcl &Day *char 2 stg(*defined) defvar(&DateYMD 5) &WorkDate &Century &DateYMD &Year &Month &Day
13
Pointers A pointer variable stores a memory address.
You can use the ADDRESS parameter of DCL to initialize a pointer to the address of another variable. The %ADDRESS (or %ADDR) function lets you set a pointer. The %OFFSET (or %OFS) function lets you do pointer arithmetic. Pointers may be set to or tested for the *NULL constant.
14
Not the true size of the list, but we don't care.
pgm parm(&inList) dcl &inList *char 1 dcl &pInList *ptr dcl &ListSize *int stg(*based) basptr(&pInList) dcl &pElement *ptr dcl &CurElement *char 10 stg(*based) basptr(&pElement) dcl &Ndx *int 2 chgvar &pInList %addr(&inList) chgvar &pElement &pInList chgvar %offset(&pElement) (%offset(&pElement) + 2) dofor &Ndx from(1) to(&ListSize) /* do something with &CurElement */ chgvar %offset(&pElement) (%offset(&pElement) + 10) enddo Move forward to the next element.
15
&pInList is a pointer to the input parameter.
This example processes a list (&inList) that is passed in by a command. &pInList is a pointer to the input parameter. The first two bytes of the parameter tell how many elements are in the list. If you run the following command for this program: DOIT OBJECT(SQUEEZLE PUCKERT SNOOFLE GRIPPICK) &ListSize has the value 4, because there are four elements in the list. &CurElement assumes the following values on each iteration of the DOFOR loop. SQUEEZLE (offset 3 of &inList) PUCKERT (offset 13 of &inList) SNOOFLE (offset 23 of &inList) GRIPPICK (offset 33 of &inList) CMD PROMPT('Do something') PARM KWD(OBJECT) TYPE(*CHAR) LEN(10) MAX(12) + EXPR(*YES) PROMPT('List of objects') Important: If the number of elements of the list changes in the command definition, the program does not require modification!!!
16
Structured programming
17
Looping – DOWHILE Top-tested loop
Body of loop may not be executed at all Terminated by ENDDO
18
Not executed if &LIBS is blank!
DOWHILE example Not executed if &LIBS is blank! dcl &Libs *char 80 dcl &Lib *char 10 dowhile (&Libs *ne ' ') /* process the first library in the list */ chgvar &Lib &Libs do something with &Lib /* remove the library that was just processed */ chgvar &Libs %sst(&Libs 11 70) enddo
19
1. &LIBS is a list of library names, such as:
MYLIB YOURLIB HISLIB HERLIB BIGLIBNAME 2. &LIB is one library name. 3. The first CHGVAR command copies the first 10 bytes of &LIBS to &LIB. (We don’t need %SST (substring) because CHGVAR truncates, but we could use %SST if we wanted to clarify our intentions.) MYLIB 4. After the system has done something with that library name, the second CHGVAR removes the first library name from the list. After the first iteration, &LIBS looks like this: YOURLIB HISLIB HERLIB BIGLIBNAME 5. The loop continues until all libraries have been processed.
20
Looping – DOUNTIL Bottom-tested loop
Body is always executed at least once Terminated by ENDDO
21
DOUNTIL example Executed at least once.
dountil (&Status *eq '0') call qrcvdtaq (&DtaQ &DtaQLib &DtaLen &Dta &Wait) select when (%sst(&Dta 1 1) *lt '1') then( chgvar &Status '0') when (%sst(&Dta 1 1) *eq '1') then( call Pgm1) when (%sst(&Dta 1 1) *eq ‘2') then( call Pgm2) when (%sst(&Dta 1 1) *eq ‘3') then( call Pgm3) endselect enddo
22
Looping – DOFOR Top-tested loop Counted loop
Terminating condition evaluated on each iteration (a “moving target”) Terminated by ENDDO Control variable must be an integer Loop increment can be positive or negative
23
DOFOR example dcl &inOptions *char 82 /* list of options */ dcl &Ndx *uint 2 dcl &Option *char 8 dcl &OptOffset *uint 2 /* offset into the list */ dcl &ToReport *lgl chgvar &OptOffset 3 dofor var(&Ndx) from(1) to(%bin(&inOptions 1 2)) chgvar &Option %sst(&inOptions &OptOffset 8) select when (&Option *eq REPORT) then(chgvar &ToReport '1') when (&Option *eq NOREPORT) then(chgvar &ToReport '0') endselect chgvar &OptOffset (&OptOffset + 8) enddo (See for the complete example.)
24
LEAVE and ITERATE LEAVE jumps to the statement immediately following the end of the loop ITERATE jumps to the loop-control test Optional CMDLBL parameter allows you to specify which loop you wish to LEAVE or ITERATE
25
Looping – Middle-tested loops
Implemented with DOWHILE DOWHILE ‘1’ code that must run at least once IF COND(. . .) THEN(LEAVE) code that might not run at all ENDDO Must include a conditioned LEAVE to stop the loop
26
Middle-tested loop example
dclf Schedule opnid(s) dowhile '1' rcvf opnid(s) monmsg cpf0864 exec(leave) if (&s_active *ne A) then(iterate) do something to active record enddo Must be done at least once. Test to leave loop or not May not be done at all.
27
Case construct Implemented with SELECT/WHEN/OTHER/ENDSELECT keywords
THEN may be null to ignore a case May be nested up to 25 levels deep
28
SELECT example (with keywords)
select when (&Option *eq O) + then(chgvar &DevOption ('OUTQ(' *cat &OptValue *tcat ')')) when (&Option *eq D) + then(chgvar &DevOption ('DEV(' *cat &OptValue *tcat ')')) otherwise + cmd(chgvar &DevOption ('OUTQ(*DEV)')) endselect
29
SELECT example (without keywords)
select when (&Option *eq O) + chgvar &DevOption ('OUTQ(' *cat &OptValue *tcat ')') when (&Option *eq D) + chgvar &DevOption ('DEV(' *cat &OptValue *tcat ')') otherwise + chgvar &DevOption ('OUTQ(*DEV)') endselect
30
Limitations Maximum of 25 levels of DOxxx commands
Maximum of 25 levels of SELECT commands
31
Subroutines
32
Subroutines Follow the main routine and precede ENDPGM
Bounded by SUBR and ENDSUBR commands Invoked by CALLSUBR command RTNSUBR and ENDSUBR leave a subroutine RTNSUBR and ENDSUBR may return a signed integer value Labels are local Recursive subroutine calls are permitted GOTO is not allowed into or out of subroutines Stack size is 99 levels, and may be changed to 20 thru 9999 in the SUBRSTACK parameter of the DCLPRCOPT command DMPCLPGM includes the subroutine stack
33
Subroutine with RTNVAL
dcl &SubrStatus *int 4 dcl &Stat *int 4 dcl &RecCount *dec 10 callsubr Prepare rtnval(&SubrStatus) select if (&SubrStatus *eq 2) do sndpgmmsg msgid(usr1001) msgf(myusrmsgf) + msgdta('Prepare routine requires file POST40.') + msgtype(*escape) subr Prepare /* Return code */ /* 0 = all OK */ /* 1 = completed with warnings */ /* 2 = not completed due to a fatal error */ chgvar &Stat 0 chkobj post40 *file aut(*objexist) monmsg cpf9801 exec(rtnsubr rtnval(2)) rtvmbrd file(post40) nbrcurrcd(&RecCount) if (&RecCount *eq 0) chgvar &Stat '1' do something else endsubr rtnval(&Stat)
34
A more realistic example
Use subroutines to divide a program into logically-related pieces. callsubr PrcParms /* process parameters */ callsubr CrtWorkF /* create the work files */ callsubr Updt /* update the database */ return subr PrcParms code to process the parameters endsubr subr CrtWrkF code to create work files subr Updt code to update the database
35
Built-in Functions
36
Trim Functions %TRIM, %TRIML, %TRIMR
First parameter is the character value to trim Second parameter is the group of characters to trim If no second parameter, these functions trim blanks
37
%TRIM example dcl &File *char 10 dcl &Lib *char 10 dcl &Stmf *char 128 chgvar var(&Stmf) + value('/QSYS.LIB/' *cat + %trim(&Lib) *cat '.LIB/' *cat + %trim(&File) *cat '.FILE/' *cat + %trim(&File) *cat '.MBR') If &File is TEMP01 and &Lib is QTEMP, then &Stmf has a value like this: /QSYS.LIB/QTEMP.LIB/TEMP01.FILE/TEMP01.MBR
38
Case-conversion Functions
%UPPER, %LOWER First parameter is the character value to convert Second parameter is the CCSID in which the data is stored. The default is zero, which means the job’s CCSID.
39
Case-conversion example
Allow the operator to enter a value in uppercase, lowercase, or mixed case. dcl &Response *char 8 chgvar var(&Response) value(%upper(&Reponse)) if (&Response *eq RETRY) do
40
Scan Functions %SCAN find the position of one string within another one %CHECK search a string for a character that is not part of a set %CHECKR like %CHECK but search backwards from the end You may specify *LDA as the string to be searched/checked.
41
Example Does the list of options contain the value *REPORT?
dcl &Options *char 82 dcl &CrtRpt *lgl chgvar &CrtRpt (%scan('*REPORT ' &Options) *gt 0)
42
Type-conversion functions
%CHAR %DEC %INT %UINT
43
%CHAR discards leading zeros
Example dcl &DeleteCt *dec 7 call PurgePgm parm (&DeleteCt) SndPgmMsg ('Deleted' *bcat %char(&DeleteCt) *bcat 'orders.') Sample output: Deleted 105 orders. %CHAR discards leading zeros
44
Test Passed Parameters
%PARMS returns the number of parameters passed by the caller Avoids referencing unpassed parameters More reliable than monitoring for MCH3601 pgm (&pOption) dcl &pOption *char 8 dcl &Option *char value('NONE') if (%parms *ge 1) then(chgvar &Option &pOption)
45
Memory-allocation functions
%SIZE returns the number of bytes occupied by a variable %LEN returns the number of digits (if numeric) or characters in a variable For character data, both functions return the same value. For numeric data, the functions return different values Example: packed decimal 7, %LEN = %SIZE = 4
46
If someone changes the size of &Cmd, no mod is required here.
Example If someone changes the size of &Cmd, no mod is required here. dcl &Cmd *char 96 dcl &CmdLen *dec (15 5) chgvar &Cmd whatever chgvar &CmdLen %size(&Cmd) call qcmdexc (&Cmd &CmdLen)
47
Files and database
48
File support - Multiple Files
Up to five declared files in one CL procedure OPNID parameter assigns an identifier to each open file One file may have an OPNID of *NONE CL variables are prefixed with the OPNID value and an underscore OPNID is used for all file-related commands: DCLF, CLOSE, RCVF, SNDF, SNDRCVF, WAIT, ENDRCV
49
Example dclf QAFDMBRL opnid(MbrList) dspfd file(&srclib/&srcfile) type(*mbrlist) + output(*outfile) outfile(qtemp/fdmbrl) ovrdbf qafdmbrl tofile(qtemp/fdmbrl) dowhile '1' rcvf opnid(MbrList) monmsg cpf0864 exec(leave) do something with one or more &MBRLIST_ fields. . . enddo
50
File Support – CLOSE Allows you to close a file so it can be re-read
A RCVF against a closed file opens the file
51
File Support – RUNSQL Allows you to execute a single SQL statement in a CL procedure Work on those concatenation skills!
52
dcl &FromDate. dec 7 dcl &ThruDate. dec 7 dcl &Comma
dcl &FromDate *dec 7 dcl &ThruDate *dec 7 dcl &Comma *char 1 value(',') dcl &SQL *char 256 chgvar &SQL ('declare global temporary table SltData + (FromDate dec(7), ThruDate dec(7)) + with replace') runsql sql(&Sql) commit(*none) chgvar &SQL ('insert into session.SltData + values (' *cat %char(&FromDate) *cat + &Comma *cat %char(&ThruDate) *cat ')')
53
Miscellaneous enhancements
54
INCLUDE Tells the compiler to copy in source code
Like /COPY and /INCLUDE in RPG SRCMBR is the source member to copy SRCFILE is the file containing the copy member SRCFILE(*INCFILE) refers to the INCFILE parameter in CRTBNDCL, CRTCLPGM, CRTCLMOD
55
INCLUDE pgm include srcmbr(ErrorDcl) srcfile(qclsrc) more code include srcmbr(ErrorRtn) srcfile(qclsrc) endpgm
56
Compile from a stream file
CRTBNDCL PGM(QGPL/MYPGM) SRCSTMF('/home/mydir/mypgm.cl') Applies to CRTBNDCL, CRTCLMOD and CRTCMD, but not to CRTCLPGM.
57
Pass Parameters by Value
Allowed on CALLPRC (specify *BYREF or *BYVAL) Useful for binding to C and MI routines Also works for calling RPG routines!
58
dcl &Dest. char (11) dcl &Src. dec (10) value(-12652) dcl &Mask
dcl &Dest *char (11) dcl &Src *dec (10) value(-12652) dcl &Mask *char (18) value(x'34b1404e346034b2b2b2b2b2b2b2b2b2b2b2') dcl &DestLen *uint dcl &SrcLen *uint dcl &MaskLen *uint chgvar &DestLen value(%size(&Dest)) chgvar &SrcLen value(%len( &Src )) chgvar &MaskLen value(%size(&Mask)) callprc prc('edit_packed') parm((&Dest) (&DestLen *byval) + (&Src) (&SrcLen *byval) + (&Mask) (&MaskLen *byval))
59
Increased maximums Maximum number of parameters on PGM command increased from 40 to 255 Maximum number of parameters on CALL and TFRCTL commands increased to 255 Maximum number of PARM commands in command source increased from 75 to 99 Maximum size of *CHAR variables increased from 9999 to 32,767
60
Final thoughts
61
Final thoughts CL is probably more or less what it will be when it comes to end of life, so you may as well master what’s there. New RFE: Allow expressions in PARM parameter of CALL and CALLPRC commands!!! Please consider adding your vote!!!
62
Final thoughts CL is probably more or less what it will be when it comes to end of life, so you may as well master what’s there. We could already do what many of these enhancements do by calling HLL programs. Don’t try to replace RPG.
63
Take the pledge! I pledge to code loops with structured commands; to divide big programs into subroutines; to master the built-in functions; never to write 20th-century CL again!
64
ENDPGM
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.