Wednesday, March 16, 2016

New RPG compiler directives /SET and /RESTORE

I am not sure how I missed this, two new compiler directives were added to RPG in IBM i 7.2, and I presume the equivalent 7.1 TRs: /SET and its opposite /RESTORE. I would have thought /RESET would have been a better choice than /RESTORE, but I am not IBM.

/SET will temporarily change, what I can only describe as, the definition of definitions. For example, if I want part of my program to use a different CCSID than the rest. Or perhaps I have a piece of code in a "copybook" (a source file member that is only ever /COPY-ed into another) that uses a different date and time format.

What can I change using the /SET:

  • CCSID for alphanumeric definitions  CCSID(*CHAR:ccsid)
  • CCSID for graphic definitions  CCSID(*GRAPH:ccsid)
  • CCSID for UCS-2 definitions  CCSID(*UCS2:ccsid)
  • Date definitions  DATFMT(date format)
  • Time definitions  TIMFMT(time format)

So let's dive into some code, these are the control options I will be using in my example programs:

01  **free
02  ctl-opt option(*srcstmt) datfmt(*iso) timfmt(*iso) ;

Line 1: I am programming this program in fully free format RPG, therefore, I need to start the source code with the **FREE. The code can now start in the first position as there are no columns. Fully free came as a PTF with IBM i 7.2 TR2 and 7.1 TR11, for more information see Trying fully free RPG

Line 2: I am defining for this program that the default date format will be ISO (YYYY-MM-DD), and the time format will also be ISO (HH.MM.SS) too.

Let's start with changing the CCSID of alphanumeric definitions:

03  dcl-s Test1 char(10) ccsid(*utf8) ;

04  /set ccsid(*char:*hex)
05  dcl-s Test2 char(10) ;
06  /restore ccsid(*char)

07  dcl-s Test3 char(10) ;

08  Test1 = 'abcdef' ;
09  Test2 = Test1 ;
10  Test3 = Test1 ;

11  dsply ('Test1 = ' + Test1) ;
12  dsply ('Test2 = ' + Test2) ;
13  dsply ('Test3 = ' + Test3) ;

Line 3: The stand alone variable Test1 is defined with the CCSID of *UTF8.

Line 4: Here I set the CCSID for character variables to hexadecimal. As this is fully free RPG the slash ( / ) is in the first position. If I had used an earlier form of RPG the slash would be in seventh column, and the RPG could start in the eighth position.

Line 5: I don't have to include a CCSID keyword in the definition of the stand alone variable Test2 as the CCSID has been set by the /SET.

Line 6: To restore the CCSID for character definitions I have to give the CCSID(*CHAR). The program will compile if I just have /RESTORE with nothing following, but the change by the /SET is not reset.

Line 7: Test3 has been defined after the /RESTORE to prove that the default definition has been restored.

Lines 8 - 10: Test1 has 'abcdef' moved to it, and Test2 and Test3 are in turn populated with the contents of Test1.

Lines 11 – 13: The contents of the three variables are shown using the DSPLY operation code. Which shows me:

  DSPLY  Test1 = abcdef
  DSPLY  Test2 = /ÂÄÀÁÃ
  DSPLY  Test3 = abcdef

This shows that Test2 contains the hexadecimal equivalent of Test1. As the /RESTORE came after Test2 and before Test3 the contents of Test3 are back to "normal", not hexadecimal.

I can also use the /SET to change the definition of date and time fields. I will use the same first two lines as I did in the previous example, the date and time format are both ISO. Now I can define my stand alone variables:

03  dcl-s Date1 date inz(d'2016-06-10') ;
04  dcl-s Time1 time inz(t'11.53.00') ;

05  /set datfmt(*mdy) timfmt(*usa)
06  dcl-s Date2 date ;
07  dcl-s Time2 time ;
08  /restore datfmt

09  dcl-s Date3 date ;
10  dcl-s Time3 time ;

11  /restore timfmt
12  dcl-s Time4 time ;

Line 3: Date1 is defined in ISO format as that is set in the control option, on line 2.

Line 4: Time1 is also defined in ISO format for the same reason.

Line 5: The /SET changes the definition of date variables to MDY and times USA.

Line 6: Date2 is defined as having the MDY format as it follow the set.

Line 7: Time2 is defined as having the USA format for the same reason.

Line 8: This /RESTORE only restores the date format. As the time format is not given it remains with the same definition give with the /SET on line 5.

Line 9: Date3 will have the default definition, ISO.

Line 10: Time3 will take its definition from the last /SET, line 5.

Line 11: This /RESTORE resets the time format to the program's default.

Line 12: Time4, as it follows the restore, will have the program's default definition, ISO.

The rest of the program just moves the date and time values to the various variables, and then their contents are displayed using the Display operation code:

13  Date2 = Date1 ;
14  Date3 = Date1 ;

15  Time2 = Time1 ;
16  Time3 = Time1 ;
17  Time4 = Time1 ;

18  dsply ('Date1 = ' + %char(Date1)) ;
19  dsply ('Time1 = ' + %char(Time1)) ;
20  dsply ('Date2 = ' + %char(Date2)) ;
21  dsply ('Time2 = ' + %char(Time2)) ;
22  dsply ('Date3 = ' + %char(Date3)) ;
23  dsply ('Time3 = ' + %char(Time3)) ;
24  dsply ('Time4 = ' + %char(Time4)) ;

I have to use the %CHAR built in function on each of the DSPLY lines to convert the value from a date or time to an alphanumeric value that can be included in the string to be displayed:

  DSPLY  Date1 = 2016-06-10
  DSPLY  Time1 = 11.53.00
  DSPLY  Date2 = 06/10/16
  DSPLY  Time2 = 11:53 AM
  DSPLY  Date3 = 2016-06-10
  DSPLY  Time3 = 11:53 AM
  DSPLY  Time4 = 11.53.00

Date1 and Time1 are the program's default, ISO. Date2 and Time2 show that the /SET has changed their definitions. Date3 is ISO as the /RESTORE reset the date format. But as it did not reset the time format, Time3 is still in USA format. Time4 occurs after the /RESTORE to reset the time format, therefore, it is in the program's default ISO.

When a /SET is used in a "copybook" a /RESTORE is assume at the end of the member. Here is a "copybook" I created for this example:

01   /set datfmt(*mdy)
02  D CopyDs          DS                  qualified
03  D   Date                          D

I have written this in fixed format to illustrate that the /SET does not care which kind of definition I use, and to illustrate that it is possible to insert fixed format code into a totally free RPG program. This "copybook" defines a data structure, CopyDs, on line 2, with one subfield a date, line 3. The /SET, line 1, defines that date fields will be in MDY format. There is no /RESTORE.

Now for the program, again I am using the same first two lines in the previous examples:

03  dcl-s Date1 date inz(d'2016-06-10') ;

04  /copy mylib/devsrc,copyrpg

05  dcl-s Date2 date ;

06  Date2 = Date1 ;
07  CopyDs.Date = Date1 ;

08  dsply ('Date1 = ' + %char(Date1)) ;
09  dsply ('CopyDs.Date = ' + %char(CopyDs.Date)) ;
10  dsply ('Date2 = ' + %char(Date2)) ;

This looks very similar to the previous example program I gave. Note that Date2 is defined after the /COPY, if the "copybook" does not have a default /RESTORE at its end then this date will be in MDY format.

When this program is run I see the following:

  DSPLY  Date1 = 2016-06-10
  DSPLY  CopyDs.Date = 06/10/16
  DSPLY  Date2 = 2016-06-10

Date2 displays a ISO, proving the assumed /RESTORE.

 

You can learn more about this from the IBM website:

 

This article was written for IBM i 7.2.

3 comments:

  1. I think it might be incomplete to say 'Test2 contains the hexadecimal equivalent of Test1.' I find that people catch on to CCSIDs faster if I present the same concept as 'TEST2 is set to "Do not convert CCSID"' Because that's what is happening; EVAL is converting the contents of TEST1 as it moves the data to TEST2 and TEST3.

    TEST2 gets a bit for bit copy, due to TEST2 being CCSID(65535)

    TEST3 gets a conversion from 1208 to 37 because TEST3 is CCSID(*JOB) - in my case, that's 37.

    The reason DSPLY TEST1 shows plain text for TEST1 is because DSPLY does a conversion between the variable CCSID(1208) and the interactive job CCSID(37). The same holds for TEST3, which requires no conversion for DSPLY to get it to the interactive job.

    But when DSPLY tries to send TEST2 to the interactive job, it does not do a conversion due to TEST2 being CCSID(65535) - no convert. So the bits go as they are. Since the interactive job is CCSID(37), those bits show up 'funny'.

    ReplyDelete
  2. Interesting topic and useful information thank you Simon

    ReplyDelete
  3. Wheeewww! This is a new topic for me! Very good

    ReplyDelete

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.