21
Fri, Jun
3 New Articles

The CL Corner: Just How Big Is That Variable?

CL
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

You can determine at run-time the size of a variable.

 

I recently conducted a workshop on best programming practices when working with system APIs. One of the practices I recommend is to avoid hard-coding values such as variable lengths (or anything else for that matter) throughout the program. Assume for instance that you're calling a retrieve type system API that has four parameters as shown here:

 

Required Parameter Group:

1

Receiver variable

Output

Char(*)

2

Format of receiver variable

Input

Char(8)

3

Length of receiver variable

Input

Binary(4)

4

Error code

I/O

Char(*)

 

 

 

If your Receiver variable parameter, named RcvVar for discussion purposes, is defined as an 80-byte structure, you want to use functions such as ILE RPG's %size(RcvVar) built-in or ILE COBOL's Length of RcvVar support for the third parameter. To hard-code the third parameter as the constant value of 80 is just looking for trouble down the road when someone changes the length of RcvVar and forgets to update the call, copy/pastes the API call changing the RcvVar variable name, or a host of other possibilities. At this point in my workshop, a bright (not to imply that any of the attendees were not bright!) student said, "I program primarily in CL. How do I avoid the hard-coding of parameter lengths in my CL program?" We have now reached the purpose of this article.

 

CL does not provide, at least through V6R1, a built-in that returns the length of a declared variable. CL does, however, allow us to extend the language through the addition of new CL commands. In this article, we'll create the command Retrieve Variable Size (RTVVARSIZ).

 

Rather than hard-coding the command message prompts, we will first create a message file. This message file, OURMSGS, will contain the prompts for our new command and also a message that we will use in a test program to display the size of various variables. This is the CL to create the message file and associated messages:

 

Pgm                                                                     

CrtMsgF    MsgF(OurMsgs)                                               

AddMsgD    MsgID(Msg0101) MsgF(OurMsgs) Msg('Retrieve Variable Size')  

AddMsgD    MsgID(Msg0102) MsgF(OurMsgs) Msg('Variable name')           

AddMsgD    MsgID(Msg0103) MsgF(OurMsgs) Msg('Variable size')           

        

AddMsgD    MsgID(Msg0301) MsgF(OurMsgs) Msg('The size is &1.') +       

             Fmt((*UBin 4))                                            

EndPgm

 

You can enter this source into QCLSRC member BLDOURMSGS, compile BLDOURMSGS using CRTBNDCL BLDOURMSGS, and then create the OURMSGS *MSGF with CALL BLDOURMSGS.

 

Here's the command source for RTVVARSIZ:

 

Cmd        Prompt(Msg0101)                                           

Parm       Kwd(Var)  Type(*Char) Len(1) RtnVal(*Yes) Min(1) +       

             Vary(*Yes *Int4) Prompt(Msg0102)                       

Parm       Kwd(Size) Type(*Int4) RtnVal(*Yes) Min(1) Prompt(Msg0103)

 

This source can be entered into QCMDSRC member RTVVARSIZ and compiled using this command:

 

 CrtCmd Cmd(RtvVarSiz) Pgm(RtvVarSiz) Allow(*IPgm *BPgm *IMod *BMod)

       PmtFile(OurMsgs)

 

Before looking at the command processing program (CPP) for RTVVARSIZ, let's look at the definition for the RTVVARSIZ command.

 

The first parameter, VAR, represents the CL variable (&RcvVar to return to our earlier example) that we want to know the allocated size of, and the parameter is prompted by message Msg0102. VAR is defined as accepting character variables and, due to the Vary(*Yes *Int4) specification, the variable does not have to be of a fixed size. The *Int4 argument of the Vary keyword indicates that the actual length of the variable is to be passed to the CPP as a 4-byte signed integer that is prefixed to the actual value of the CL variable. The length of the CL variable must be a minimum of one byte--Len(1)--and has no fixed maximum length other than what your current release allows for the length of a CL character variable. A CL variable is required when using the RTVVARSIZ command--Min(1)--and only one variable can be passed due to a default value of Max(1). The key specification, though, is RtnVal(*Yes). When passing a varying-length parameter from a command to a CPP, the length prefix is normally set to the actual length of the provided character data. That is, the length represents the number of characters in the CL variable with any trailing blanks removed. When RtnVal(*Yes) is specified for a varying-length parameter, the length prefix discussed earlier represents the allocated size of the CL variable. This is done so that the CPP can determine how many bytes of data can be safely returned to the CL program variable. It is this RtnVal(*Yes) provided length that we will use to determine the allocated size of the CL variable. We won't actually be returning any data in the VAR variable but will certainly take advantage of this information the command processor provides us.

 

The second parameter, SIZE, represents the CL variable that is used to return the allocated size of VAR, and the parameter is prompted by message Msg0103. SIZE is defined as a required parameter that must be a 4-byte signed integer. RtnVal(*Yes) is once again specified, but this time we will be returning data to the CL variable--namely, the allocated size of the VAR variable.

 

With that overview of the command definition out of the way, here's one possible set of source for the RTVVARSIZ CPP:

 

Pgm        Parm(&Var &Size)                

Dcl        Var(&Var) Type(*Char) Len(9999)

Dcl        Var(&Size) Type(*Int)           

                                           

ChgVar     Var(&Size) Value(%bin(&Var 1 4))

EndPgm                                           

 

Rather straightforward. The program simply takes the first four bytes of the parameter &Var (the 4-byte signed integer allocated size provided by the command processor), copies this value to the parameter &Size, and returns.

 

The source can be entered into QCLSRC member RTVVARSIZ and compiled using CRTBNDCL RTVVARSIZ.

 

A test program such as...

 

Pgm                                                                    

Dcl        Var(&Char13)   Type(*Char) Len(13) Value('I am 13')         

Dcl        Var(&Char1000) Type(*Char) Len(1000) +                      

             Value('I am 1000 bytes long')                             

Dcl        Var(&VarSize)  Type(*Int)                                   

Dcl        Var(&SizeChar) Type(*Char) Len(4)                           

                                                                        

RtvVarSiz  Var(&Char13) Size(&VarSize)                                 

ChgVar     Var(%Bin(&SizeChar)) Value(&VarSize)                        

SndPgmMsg  MsgID(Msg0301) MsgF(OurMsgs) MsgDta(&SizeChar) ToPgmQ(*Ext) 

                                                                        

RtvVarSiz  Var(&Char1000) Size(&VarSize)                               

ChgVar     Var(%Bin(&SizeChar)) Value(&VarSize)                        

SndPgmMsg  MsgID(Msg0301) MsgF(OurMsgs) MsgDta(&SizeChar) ToPgmQ(*Ext) 

                                                                       

EndPgm                                             

 

...should show results such as...

 

The size is 13.    

The size is 1000.              

 

To call the retrieve type API mentioned in the first paragraph of the article, without hard-coding a length value for the third parameter, with a format name of 'ABCD0100' and an Error Code Bytes Provided of 0, you would do this:

 

Pgm                                                                   

Dcl        Var(&RcvVar)    Type(*Char) Len(80)                       

Dcl        Var(&LenRcvVar) Type(*Int)                                

Dcl        Var(&ErrCde)    Type(*Int)  Value(0)                      

                                                                      

RtvVarSiz  Var(&RcvVar) Size(&LenRcvVar)                             

Call       Pgm(SomeAPI) Parm(&RcvVar 'ABCD0100' &LenRcvVar &ErrCde)  

                                                                      

EndPgm                                                               

 

With this method of calling the API, the Length of receiver variable parameter will automatically adjust to changes in the definition of the RcvVar parameter. We have one less thing to remember when maintaining our application.

 

I mentioned earlier that the above source for the RTVVARSIZ CPP is one possible set of source. The CPP as provided is written such that it will work on any of the current releases. But it may not be obvious to someone picking up the code just what is being done. Another approach to writing the CPP--and my preferred solution due to it being a bit more obvious (to me anyway!) about what is happening--would be this:

 

Pgm        Parm(&Var &Size)                                    

Dcl        Var(&Var) Type(*Char) Len(32767)                   

 Dcl        Var(&VarSize) Type(*Int) Stg(*Defined) Len(4) +    

              DefVar(&Var)                                    

Dcl        Var(&Size) Type(*Int)                               

                                                              

ChgVar     Var(&Size) Value(&VarSize)                          

EndPgm                                                        

 

Here, we're using the V5R4 *DEFINED storage capability to define the parameter &Var as being a character variable but one in which the first four bytes represent the field &VarSize. The subfield &VarSize is then defined as a 4-byte signed integer, and the CPP simply changes the value of parameter &Size to the value of variable &VarSize. Performance-wise, there is no real difference between the two CPPs, but I find the intent of the CPP more obvious with the *DEFINED approach.

 

A third approach, and one that could leave a developer scratching his head for a while, would be this:

 

Pgm        Parm(&Var &Size)        

Dcl        Var(&Var) Type(*Int)    

Dcl        Var(&Size) Type(*Int)   

                                   

ChgVar     Var(&Size) Value(&Var)  

EndPgm                              

 

As parameters, when passed to a program, are passed by reference, there is no need to define the actual length of parameter &Var. Here, we simply define that portion of parameter &Var that we really care about (the initial signed integer representing the allocated length for the CL variable) and assign that value to the parameter &Size. Again, there is no real performance difference, but this code might cause many developers to jump to the conclusion that they are looking at the wrong source code. After all, what happened to the CL variable that was specified with the VAR keyword of RTVVARSIZ?

More CL Questions?              

Wondering how to accomplish a function in CL? Send your CL-related questions to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll try to answer your burning questions in future columns.

Bruce Vining

Bruce Vining is president and co-founder of Bruce Vining Services, LLC, a firm providing contract programming and consulting services to the System i community. He began his career in 1979 as an IBM Systems Engineer in St. Louis, Missouri, and then transferred to Rochester, Minnesota, in 1985, where he continues to reside. From 1992 until leaving IBM in 2007, Bruce was a member of the System Design Control Group responsible for OS/400 and i5/OS areas such as System APIs, Globalization, and Software Serviceability. He is also the designer of Control Language for Files (CLF).A frequent speaker and writer, Bruce can be reached at This email address is being protected from spambots. You need JavaScript enabled to view it.. 


MC Press books written by Bruce Vining available now on the MC Press Bookstore.

IBM System i APIs at Work IBM System i APIs at Work
Leverage the power of APIs with this definitive resource.
List Price $89.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$0.00 Raised:
$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: