12
Tue, Nov
6 New Articles

Retrieving User Space Data

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

If you're a frequent reader of this column, then you probably know that I'm a big fan of user space objects and, likewise, not a fan of data areas.

However, there are shortcomings in user spaces. For example, there are no native Create User Space (CRTUSRSPC), Change User Space (CHGUSRSPC), or Retrieve User Space (RTVUSRSPC) commands. It seems there is a Delete User Space (DLTUSRSPC) command, though. This week, I want to solve the problem of one of those missing commands, RTVUSRSPC.

The Retrieve Data Area (RTVDTAARA) command has an interesting parameter list. In one parameter, you identify the data area, the starting position, and the length of the data you want to retrieve. Then, in a second parameter, you specify a CL variable that will receive the data being retrieved.

There are very few people left in the world using OS/400 who, I think, could write a clone of the RTVDTAARA command and create the correct command processing program (CPP) to run it. The command has a mixed-list parameter, also known as a list within a list. This is not too difficult to create in the command definition source, but the CPP structure to receive it is a bit unusual.

To create a command similar to RTVDTAARA, we'll need to reverse engineer it. Let's look at the command prompt to get an idea of what it does. Figure 1 illustrates the prompt for the RTVDTAARA command.



http://www.mcpressonline.com/articles/images/2002/Retrieving%20User%20Space%20Data00.png

Figure 1: The RTVDTAARA CL command prompt looks like this.

Back in the days of CPF and System/38, you could simply look at the microfiche and read the command definition source statements for any CL command. At one point, the clever folks at Advanced Systems Concepts, Inc. wrote a Retrieve Command Definition Source command. But that command has long since been lost to obscurity and the ever-advancing security levels in OS/400.

RTVUSRSPC--Command Definition Source

I had to reverse engineer the parameter structure of RTVDTAARA in order to create the command definition source for a RTVUSRSPC command. After looking at the prompter and pressing F4 on each parameter (to get its data type), I realized that even though it looks like there are at least four parameters, there are in fact only two: one for the data area name and another for the return variable. I suppose I could have figured that out by reading the CL reference manual, but typing in the CL command and pressing F4 was much faster.

The first parameter contains not only the data area name, but also the starting location and number of bytes to retrieve. To me, this means an ELEM list with three pieces: a qualified object name and two numeric entries. In reality, I ended up with an ELEM list that contains a qualified name and another ELEM list; that is, it is an ELEM list within an ELEM list.

The second parameter is interesting. It seems to allow a CL return variable of any data type and any length to be specified. Not being too good at remembering such obscure command definition source syntax, I wrote to the original author of CL commands and asked him. It seems I'm not the only one who hasn't done this kind of thing for a while. He didn't remember either.

Since I had written many commands with this type of parameter before, I just needed to locate an existing example. So I went back to my old archives of Q38, the newsletter for programmers of the IBM System/38, and tried to locate a command I had previously written that might have a similar parameter. Fortunately, I found one--as well as its corresponding CPP. So life is good! Listed in Figure 2 is the command definition source code for the RTVUSRSPC command.

RTVUSRSPC:   CMD        PROMPT('Retrieve User Space Data')
             /*  Command processing program is RTKRTVUS  */
             /*  Copyright 2004 – Robert Cozzi, Jr.      */
             /*  All rights reserved.                    */
             PARM       KWD(USRSPC) TYPE(E1) MIN(1) +          

                          PROMPT('User Space')
 E1:         ELEM       TYPE(Q1) MIN(1) PROMPT('User space name')
             ELEM       TYPE(E2) SNGVAL((*ALL 0)) MIN(1) +
                          PROMPT('Substring location')
 Q1:         QUAL       TYPE(*NAME) MIN(1) EXPR(*YES)
             QUAL       TYPE(*NAME) DFT(*LIBL) SPCVAL((*LIBL) +
                          (*CURLIB)) EXPR(*YES) PROMPT('Library')
 E2:         ELEM       TYPE(*INT4) RANGE(1 16776704) MIN(1) +
                          EXPR(*YES) PROMPT('Substring starting +
                          position')
             ELEM       TYPE(*INT4) RANGE(1 6000) SPCVAL((*END -1)) +
                          MIN(1) EXPR(*YES) PROMPT('Substring length')

             PARM       KWD(RTNVAR) TYPE(*X) LEN(1) RTNVAL(*YES) +
                          MIN(1) VARY(*YES *INT2) PASSATR(*YES) +
                          PROMPT('CL Variable for return value')

Figure 2: Here's the command definition source for RTVUSRSPC.

To compile the command definition for RTVUSRSPC, use the PDM option 14 or issue the following CL command:

CRTCMD CMD(RTVUSRSPC) PGM(TOOLKIT/RTKRTVUS) +

ALLOW(*IPGM *BPGM)

Most of the command definition source is very traditional: a qualified name and a mixed list. The RTNVAR parameter is more complicated and deserves additional explanation.

The RTNVAR parameter is a TYPE(*X) data type. This is an option that tells the command definition object to allow any type of value for this parameter. The RTNVAL(*YES) keyword indicates that this parameter accepts only CL variable names. This also means that when the CL command is compiled, you must specify ALLOW(*IPGM *BPGM) on the CRTCMD command.

When the CPP receives this parameter, a data structure is created that contains an attribute byte identifying the type and length of the CL variable. These additional pieces are created because I specified the PASSATR(*YES) and VARY(*YES *INT2) keywords on the PARM statement.

The PASSATR(*YES) keyword tells the parameter to include an extra attribute byte that indicates the type of data or CL variable type that is passed. The VARY(*YES) keyword tells the parameter to include the length of the value specified for the parameter as a prefix to the parameter's data. Since I specified VARY(*YES *INT2), the length is inserted as a 2-byte binary value. The actual data structure that I used in the CPP is illustrated in Figure 3.

     D RtnVar          DS
     D  nAttr                         3I 0
     D  nDataLen                      5I 0
     D   nDDec                        3I 0 Overlay(nDataLen)
     D   nDLen                        3I 0 Overlay(nDataLen:*NEXT)
     D  szRtnVar                   6000A

Figure 3: This is the RTNVAR parameter data structure.

The data-type attribute byte (subfield nAttr) indicates the kind of CL variable that was passed to the program (numeric, character, etc.). The data-type attribute is followed by the parameter's length. The length is broken down further into decimal field length and decimal positions. These additional fields are used when the data type is numeric.

The area that will receive the return value begins in position 4 of this data structure and continues for the length of the CL variable. Be careful when writing this kind of stuff yourself; even though the subfield szRtnVar is 6000 bytes in length, you can only access the positions that are within the length of the CL variable passed in. That is, if the data length is 10, then only the first 10 positions have storage that you may access. I made the subfield 6000 bytes long because that is the current maximum length of a CL variable. I've heard rumors that in V5R3 the maximum length will increase to a much larger value, but I can't speculate on what that new limit will be.

Figure 4 illustrates what the prompted RTVUSRSPC CL command looks like.

http://www.mcpressonline.com/articles/images/2002/Retrieving%20User%20Space%20Data01.png

Figure 4: And here's what the RTVUSRSPC CL command prompt looks like.

The RTVUSRSPC CL command can be used standalone or with the CRTUSRSPC and CHGUSRSPC commands that are included free with the RPG ToolKit. With these three CL commands and the capabilities of RPG IV and the RPG ToolKit, you can effectively replace data areas with user space objects and have a fairly seamless migration path.

RTVUSRSPC--Command Processing Program

Listed in Figure 5 is the RPG IV source code for RTKRTVUS, the CPP for the RTVUSRSPC command. If you own the RPG ToolKit, the program will compile and leverage the ease-of-use tools in the ToolKit. If you do not own the ToolKit, the program will also compile fine, but it will use significantly more lines of code to accomplish the same tasks. Nonetheless, it works fine with or without the ToolKit by activating or deactivating the /DEFINE compiler preprocessor directives.

     DFTACTGRP(*NO) BNDDIR('QC2LE')

      ** NOTE: To use the RPG ToolKit service program,
      ** change the comment below by replacing the * with a /
      ** Download the RPG ToolKit at:  www.rpglib.com
      *DEFINE RPG_TOOLKIT

      /IF DEFINED(RPG_TOOLKIT)
     BNDDIR('TOOLKIT/TOOLKIT')
      /INCLUDE TOOLKIT/QCPYSRC,RTKCONST
      /INCLUDE TOOLKIT/QCPYSRC,SPACE
      /INCLUDE TOOLKIT/QCPYSRC,APIPROTOS
      /INCLUDE TOOLKIT/QCPYSRC,CPROTOS
      /INCLUDE TOOLKIT/QCPYSRC,COMPARE
      /INCLUDE TOOLKIT/QCPYSRC,CONVERT
      /ELSE
     D memcpy          PR                  Extproc('memcpy')
     D  pTarget                        *   Value
     D  pSource                        *   Value
     D  nCopyLength                  10U 0 Value
      /ENDIF

     D InP1List        DS
     D  e1Count                       5I 0
     D  szUserSpace                  20A
     D  nStrOff                       5I 0
     D  e2Count                       5I 0
     D  eStart                       10I 0
     D  eLength                      10I 0

     D InP2List        DS
     D  nAttr                         3I 0
     D  nDataLen                      5I 0
     D   nDDec                        3I 0 Overlay(nDataLen)
     D   nDLen                        3I 0 Overlay(nDataLen:*NEXT)
     D  szRtnVar                   6000A

      /IF NOT DEFINED(RPG_TOOLKIT)
     D usAttr          DS                  Inz
     D  bRtn                         10I 0
     D  bAvail                       10I 0
     D  nUSSize                      10I 0
     D  bAutoExtend                   1N
     D  cInitValue                    1A
     D  szUSLibName                  10A

     D nUSALen         S             10I 0 Inz(%size(usAttr))
     D apiFmt          S              8A   Inz

     D lower           C                   'abcdefghijklmnopqrstuvwxyz'
     D UPPER           C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

     D RtvPtrUS        PR                  Extpgm('QUSPTRUS')
     D  UserSpace                    20A   Const
     D  rtnPtr                         *
     D  apiErrorDS                   16A   OPTIONS(*VARSIZE:*NOPASS)
      /ENDIF

     D CS_BIN          C                   Const(0)
     D CS_PKD          C                   Const(3)
     D CS_CHAR         C                   Const(4)

     D ptr             S               *   Inz

     D apiError        DS                  Inz
     D  BytesAvail                   10I 0 Inz(%size(apiError))
     D  apiErrRtnLen                 10I 0
     D  CPFMSGID                      7A
     D  Reserved1                    10A

     D nBytes          S             10I 0
     D nStart          S             10I 0
     D nLen            S             10I 0
     D nSize           S             10I 0

     D szUS            DS
     D  szUSName                     10A
     D  szUSLIB                      10A


     C     *ENTRY        PLIST
     C                   PARM                    InP1List
     C                   PARM                    InP2List

     C                   Eval      *INLR = *ON

     C                   Select
     C                   When      e2Count = 1
     C                   eval      nStart = eStart
     C                   eval      nLen = -1

     C                   When      e2Count = 2
     C                   eval      nStart = eStart
     C                   eval      nLen   = eLength
     C                   endsl

     C                   select
     C                   when      nAttr = CS_PKD
     C                   if        %REM(nDLen:2) > 0
     C                   eval      nBytes = %Int((nDLen+1)/2)
     C                   else
     C                   eval      nBytes = %Int((nDLen+2)/2)
     C                   endif
     C                   When      nAttr = CS_CHAR
     C                   eval      nBytes = nDLen
     C                   When      nAttr = CS_BIN
     C                   eval      nBytes = nDLen
     C                   endsl

      /IF DEFINED(RPG_TOOLKIT)
      **  Get the size of the user space (RPG ToolKit method)
     C                   eval      szUS = CvtCase(szUserSpace:CC_TOUPPER)
     C                   eval      nSize = GetUsrSpaceA(szUS : RTK_GS_SIZE)
      /ELSE
      **  If you don't have the RPG ToolKit then you need
      **  to do all of the following to get the size of the user space.
     C     lower:UPPER   XLATE     szUserSpace   szUS

     C                   CALL      'QUSRUSAT'
     C                   PARM                    usAttr
     C                   PARM                    nUSALen
     C                   PARM      'SPCA0100'    apiFMT
     C                   PARM                    szUS
     C                   PARM                    apiError
     C                   if        apiErrRtnLen > 0
     C                   return
     C                   endif
     C                   eval      nSize = nUSSize
      /ENDIF

      **  If no start, then use start position 1.
     C                   if        nStart <= 0
     C                   eval      nStart = 1
     C                   endif

      /IF DEFINED(RPG_TOOLKIT)
      **  Use User Space size as bytes to get?
     C                   if        nLen = -1
     C                   eval      nLen = min(nBytes:nSize - (nStart - 1))
     C                   endif

      **  Never get more than the return variable's length.
     C                   eval      nLen = min(nLen:nBytes)
      **  Get a pointer to the user space so we can copy from it.
     C                   eval      ptr = GetPtrUS(szUS)
      /ELSE
      **  Use the size of the User Space as byte count?
     C                   if        nLen = -1
     C                   if        nBytes < (nSize - (nStart - 1))
     C                   eval      nLen = nBytes
     C                   else
     C                   eval      nLen = nSize - (nStart - 1)
     C                   endif
     C                   endif

      **  Never get more than return variable's length.
     C                   if        nLen > nBytes
     C                   eval      nLen = nBytes
     C                   endif
      **  Get a pointer to the user space so we can copy from it.
     C                   callp     RtvPtrUS(szUS : ptr : apiError)
      /ENDIF

     C                   callp     memcpy(%addr(szRtnVar) :
     C                                   ptr + (nStart-1) : nLen)
     C

     C     ENDPGM        TAG
     C                   return

Figure 5: RTKRTVUS is the CPP for the RTVUSRSPC command.

Bob Cozzi has been programming in RPG since 1978. Since then, he has written many articles and several books, including The Modern RPG Language--the most widely used RPG reference manual in the world. Bob is also a very popular speaker at industry events such as RPG World and is the author of his own Web site and of the RPG ToolKit, an add-on library for RPG IV programmers.

BOB COZZI

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.


MC Press books written by Robert Cozzi available now on the MC Press Bookstore.

RPG TnT RPG TnT
Get this jam-packed resource of quick, easy-to-implement RPG tips!
List Price $65.00

Now On Sale

The Modern RPG IV Language The Modern RPG IV Language
Cozzi on everything RPG! What more could you want?
List Price $99.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

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: