19
Wed, Jun
3 New Articles

TOUPPER--Convert Lowercase Letters to Uppercase

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times
Throughout my nearly 25 years of writing RPG programs, I've found that one task is consistently bewildering to developers: converting lowercase characters to uppercase characters. Back in 1977 while in college, I was required to convert a lowercase "a" to uppercase. The input was from an 80-column punch card, and the output was a printed report. I thought I could just compare the input field to the letter "a," and when it matched, I'd replace it with an uppercase "A." Simple, right?

 

So I wrote this code (old RPG II stuff):

.....CSRn01n02n03Factor1+++OpCodFactor2+++ResultLenDXHiLoEq...
     C           INP,X     COMP 'a'                      58
     C      58             MOVE 'A'       INP,X

Then the requirement changed: convert all the lowercase letters to uppercase. This presented a problem. How could I justify inserting 26 COMP and MOVE instructions to do simple conversion? So I redesigned the solution using fewer instructions, but this time, it worked with all 26 lowercase characters.

 

To convert any single character to uppercase, you simply need to set on bit 1 of the 8 bits in the EBCDIC character. For example, I rewrote the previous solution in one line of code, as follows:

     C                     BITON'1'       INP,X

Of course there was a looping routine that caused the BITON opcode to be run for each character of the field needing to be converted. Since capital letters already had their "bit 1" set on, using a BITON operation on them left them intact, while converting lowercase letters to uppercase.

 

To this day, this is still the fastest way to convert lowercase to uppercase. Unfortunately, it isn't very practical to use this kind of technique today since typically we work with fields of data rather than bits and bytes (in RPG anyway). Another minor factor is that it is not a portable technique. That is, it will not work on an ASCII-based RPG compiler, such as CrossWorks Inc.'s Open-RPG product. But I'm guessing that's not an issue for most iSeries RPG programmers.

 

I knew there had to be a more-refined method for converting lowercase to uppercase. Well, there is. In RPG III and RPG IV, there is an XLATE operation code. This operation code uses a simple translation "table" technique to translate each character in the field specified in Factor 2 . Factor 1 contains the translation characters as a pair of values. For example:

     C     find:replace  XLATE     OrgValue      NewValue

 

Factor 1 contains one or more "find" characters followed by a corresponding number of "replace" characters, with a colon separating the lists. Once a character in the find string is located in the field being translated (Factor 2), the corresponding character in the replace string is moved into the Result field. If no translation match is detected, the original character is moved into the Result field.

 

The replacement is done on a position-by-position basis. So the ordering of the data in Factor 1 is irrelevant. At least one find character and one replace character must be specified. Note the following example:

     C     'abc':'ABC'   XLATE     'bob cozzi'   NewValue

 

After the XLATE operation is performed, the NEWVALUE field contains the translated value 'BoB Cozzi'. Not necessarily useful, but you get the idea.

 

Likewise, if I wanted to create a cipher table, I might do this:

     C     'abc':'123'   XLATE     'bob cozzi'   NewValue

 

I would end up with '2o2 3ozzi' in the NEWVALUE field. Again, not so useful unless I subsequently do the following:

     C     '123':'abc'   XLATE     NewValue      OrgValue

 

Which turns it back into 'bob cozzi'.

 

Okay, so how do you get the entire alphabet into Factor 1? It is, after all, only 14 positions wide. Easy--you use named constants. You can specify fields, literal values, or named constants as the from and to translation patterns in Factor 1. In order to fit the entire alphabet in Factor 1, you simply write a couple of named constants, as follows:

     D lower           C                   Const('abcdefghijklmnopqrstuvwxyz')
     D upper           C                   Const('ABCDEFGHIJKLMNOPQRSTUVWXYZ')

 

Then, you use the LOWER and UPPER named constants in Factor 1 of the XLATE operation code to convert lowercase to uppercase, or, by switching them around, uppercase to lowercase.

 

Convert lowercase to uppercase:

     C     lower:upper   XLATE     OrgValue      NewValue

 

Convert uppercase to lowercase:

     C     upper:lower   XLATE     OrgValue      NewValue

 

To convert lowercase to uppercase, you only need to create two named constants (I keep them in a /COPY member that is included whenever they're needed). Then, use the XLATE operation code to do the conversion on an entire field. No more one-character-at-a-time process like we did back in RPG II.

 

Factor 2 and the Result field of the XLATE operation code can be different field names or the same field name.

 

XLATE can also be used for much more. It can be used to translate special characters from fields, create a cipher code, or filter out unwanted characters. For example, to change all occurrences of a decimal point in a field to blanks, use the following XLATE operation:

     C     '.':' '       XLATE     OrgValue      NewValue

 

So what's next? What if you need to do conversion for a comparison operation? Suppose you need to compare an end-user's input data to the value of a field in your program. You could use something like the following :

0001 C                   EXFMT     Input
0002 C     lower:upper   XLATE     CompName      UpperComp
0003 C     lower:upper   XLATE     CM_COMPANY    UP_COMPANY
0004 C                   if        UpperComp = UP_COMPANY
0005 C                   ...
0006 C                   endif

 

In this example, the COMPNAME and CM_COMPANY fields are converted to uppercase (lines 2 and 3). Then, on line 4, they are compared for equality.

 

This code is simple--easy to understand and maintain. But there's a problem with it. First, you need to declare two additional work fields--UPPERCOMP and UP_COMPANY--that have the same attributes as the original fields. With the LIKE keyword on the Definition specification, this is relatively easy; however, it will need to be done for each field you convert in your program. Also, the XLATE function is replicated each time the process is performed. From a performance standpoint, this might be good, but from a code-reuse and maintainability standpoint, it is questionable.

 

So what's the solution? Why not write your own procedure to convert lowercase to uppercase? By creating a simple procedure, you can integrate the case conversion routine into your toolbox and reuse it whenever you need to--no named constants to declare, no work fields, no redundant coding. But what would such a procedure look like? Look at the TOUPPER procedure in Figure 1 below:

.....PName+++++++++++..B...................Functions+++++++++++++++++++
0001 P ToUpper         B                   EXPORT

.....DName+++++++++++EUDS.......Length+TDc.Functions+++++++++++++++++++
0002 D ToUpper         PI          2048A   VARYING OPDESC
0003 D  InputStg                   2048A   VARYING VALUE 

0004 D lower           C                   'abcdefghijklmnopqrstuvwxyz'
0005 D upper           C                   'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

.....CSRn01..............OpCode(ex)Extended-factor2++++++++++++++++++++
0006 C                   If        %Parms=0
0007 C                   return    ''
0008 C                   endif

0009 C                   If        %len(InputStg) > 0
0010 C     lower:UPPER   xLate     InputStg      InputStg
0011 C                   endIf

0012 C                   Return    InputStg

.....PName+++++++++++..E...........
0013 P ToUpper         E

Figure 1: TOUPPER--a procedure to convert lowercase to uppercase

This procedure utilizes a lot of the components necessary when writing a good procedure. It tests for error conditions before they occur and avoids the errors. It also supports variable-length fields.

 

Though technically a function, the TOUPPER procedure accepts a single input value name, INPUTSTG (input string). This parameter is declared with both the VARYING and VALUE keywords (see line 3). You may have used VARYING before, but VALUE is often not utilized in RPG code. The VALUE keyword changes the default parameter behavior. Normally, parameters are passed by reference. That is, a pointer to (or the address of) the parameter is passed between programs and procedures. By specifying the VALUE keyword, you change that dynamic.

 

"Pass by value," as it is called, causes the compiler to generate code that creates a copy of the parameter. So rather than pass the address of the parameter, a copy of the parameter's data is sent down into the procedure. This means that changes made to the value in the called procedure do not impact the original parameter value. Why? Because a copy of the data is what the procedure is working on.

 

When the VALUE keyword is specified, you end up with much the same benefits you do when CONST is specified. There are performance differences, of course, and CONST parameters cannot be modified by the called procedure. Other than that, they are effectively the same.

 

So by specifying VALUE instead of CONST, you can work with the input parameter, modify its data, and not worry about the caller's original value being changed.

 

In effect, pass by value gives you the ability to use the parameter as a local variable.

 

In the TOUPPER procedure, on lines 6, 7, and 8, the number of parameters passed to the procedure are tested. If no parameters are passed, an empty string is returned to the caller. The only time this could happen is when the procedure is called with the CALLB operation code without a corresponding PARM operation.

 

Line 9 checks the input value to ensure that it is at least one character in length. If not, no translation is necessary and the program skips over the XLATE operation. Line 10 uses the translation capabilities of the XLATE operation code to convert the input value to uppercase. Remember, since the input value is passed by VALUE, you can use the INPUTSTG variable as if it were a local variable.

 

Finally, on line 12, the converted input string is returned to the caller. Note that the return value also uses the VARYING keyword (line 2). Since VARYING fields can be easily moved between fixed-length fields (i.e., regular fields in RPG) and variable-length fields, it does not matter whether the input or output is fixed- or variable-length fields.

 

Figure 2 illustrates a simple example of using this procedure in a program:

0001 H

0002 D ToUpper         PR          2048A   VARYING OPDESC
0003 D  InputStg                   2048A   VARYING VALUE 

0004 D myChar          S             15A   Inz('Bob Cozzi')
0005 D myVar           S             40A   Inz('Bob Cozzi')
0006 D nCount          S             10I 0

0007 C                   if        ToUpper(myChar) = ToUpper(myVar)
0008 C                   Add       1             nCount
0009 C                   endif
0010 C                   MOVE      *ON           *INLR

Figure 2: Example use of TOUPPER

In Figure 2, the TOUPPER procedure is used twice on line 7 to return the uppercase equivalent of both the MYCHAR field and the MYVAR field. The IF statement compares the two returned values for equality. If equal, the ADD operation on line 8 is performed and the counter field is incremented.

 

Lines 2 and 3 contain the prototype for the TOUPPER procedure. It must be /COPY'd into each source member that uses the TOUPPER procedure. I would suggest you place TOUPPER into an RPG TOOLS service program and bind it into the programs that need it.

 

To bind a service program to an RPG program, often the service program name is added to a binding directory and then the binding directory is specified on the BNDDIR parameter of either the CRTBNDRPG or the CRTPGM command. If the service program is not included in a binding directory (it really should be), only programs that use the CRTPGM command can bind to them using the BNDSRVPGM parameter.

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: