I found a great article on the web that explains how to do this. I'm just going to link to it, rather than reiterate the whole thing. It's pretty simple, just a bit awkward (what on MVS isn't? :-)
click here for the article
Monday, April 14, 2008
Wednesday, March 5, 2008
RACF, XMIT, and RECEIVE Basics
Oy! It's been a while since I've updated this thing. In all fairness though, I've been in class learning the mysteries of PL/X and Basic Assembler Language so I haven't had a lot of free time as of late.
So like everything else on the mainframe, performing simple tasks like sharing, sending, or receiving data sets can become a real pain in the tookus. There are about a million options for each command, most of which you really don't need to worry about. What follows is a quick-and-dirty guide to performing these basic tasks:
1) SETTING PERMISSIONS IN RACF
So here's the scenario. You've got a data set and you want your colleague to be able to view it so you can collaborate. How do you give him/her the ability to access your files?
In order to set a specific level of access to a data set, you need to create either a generic or discrete profile. A generic profile is used to set permissions on several data sets at once. For the purposes of this guide, we will only work with discrete profiles, which sets the permission level on a specific data set.
The first thing you need to do is determine whether or not the data set is already defined to RACF. You do this by issuing the following TSO command:
LISTDSD DA(dataset name) ALL
This will tell you if and in what manner the data set is defined to RACF. If the data set is covered by a generic profile, there will be a (G) next to the data set name. If there is no profile, or the data set is covered by a generic profile, you'll want to create a discrete profile to allow a specific user access to a specific, single data set. In the case where a data set is defined to RACF with both a generic and discrete profile, the discrete profile will take precedence. To create a discrete profile, use the following command:
ADDSD dataset UACC(NONE)
UACC stands for Universal Access Authority. Here are a few of the more useful UACC parameters:
NONE Does not allow users to access the data set.
READ Allows users to access the data set for reading only.
UPDATE Allows users to read from, copy from, or write to the data set.
ALTER Allows users to read, update, delete, rename, move, or scratch the data set.
By setting the default level to NONE, we ensure that nobody but the person(s) we specify have access to the data set. Now that we have the data set defined to RACF, we need to give your colleague access to it. You can do this by issuing the following command:
PERMIT dataset ID(user) ACCESS(level)
Congrats! You've now created a RACF profile to protect your dataset, and have allowed your coworker(s) access to it. I should note that there are lots of other fun things you can do with RACF, and that this is just a few basic commands. If you want to know more, the IBM publication z/OS Security Server RACF General User’s Guide is an excellent resource.
2) TRANSMITTING A DATA SET
This is actually pretty simple. You need to issue the following TSO command:
XMIT (node.user) DATASET(data set)
The node name is going to be specific to your system. Just ask around, one of your coworkers will be able to tell you what it is :-)
3) RECEIVE
When someone sends you a data set, you use the receive command to, well, receive it. This is another one of those commands with a lot of options that 99% of the time you don't need. This is a TSO command, and the following options are the ones that I find the most useful:
RESTORE: SPECIFIES THE TRANSMITTED DATA SHOULD BE RESTORED TO ITS ORIGINAL FORMAT. RESTORE IS THE DEFAULT.
DELETE: SPECIFIES THE FILE BE DELETED WITHOUT RESTORING IT.
DATASET(data set name): SPECIFIES THE NAME OF THE DATA SET TO BE USED TO CONTAIN THE RECEIVED DATA SET. IF THE NAME DOES NOT EXIST ALREADY, THE SYSTEM CREATES IT.
So when someone sends you a data set and you want to receive it, the command looks like this:
RECEIVE RESTORE/DELETE/DATASET(data set name)
That's it for now, hope you found this helpful!
So like everything else on the mainframe, performing simple tasks like sharing, sending, or receiving data sets can become a real pain in the tookus. There are about a million options for each command, most of which you really don't need to worry about. What follows is a quick-and-dirty guide to performing these basic tasks:
1) SETTING PERMISSIONS IN RACF
So here's the scenario. You've got a data set and you want your colleague to be able to view it so you can collaborate. How do you give him/her the ability to access your files?
In order to set a specific level of access to a data set, you need to create either a generic or discrete profile. A generic profile is used to set permissions on several data sets at once. For the purposes of this guide, we will only work with discrete profiles, which sets the permission level on a specific data set.
The first thing you need to do is determine whether or not the data set is already defined to RACF. You do this by issuing the following TSO command:
LISTDSD DA(dataset name) ALL
This will tell you if and in what manner the data set is defined to RACF. If the data set is covered by a generic profile, there will be a (G) next to the data set name. If there is no profile, or the data set is covered by a generic profile, you'll want to create a discrete profile to allow a specific user access to a specific, single data set. In the case where a data set is defined to RACF with both a generic and discrete profile, the discrete profile will take precedence. To create a discrete profile, use the following command:
ADDSD dataset UACC(NONE)
UACC stands for Universal Access Authority. Here are a few of the more useful UACC parameters:
NONE Does not allow users to access the data set.
READ Allows users to access the data set for reading only.
UPDATE Allows users to read from, copy from, or write to the data set.
ALTER Allows users to read, update, delete, rename, move, or scratch the data set.
By setting the default level to NONE, we ensure that nobody but the person(s) we specify have access to the data set. Now that we have the data set defined to RACF, we need to give your colleague access to it. You can do this by issuing the following command:
PERMIT dataset ID(user) ACCESS(level)
Congrats! You've now created a RACF profile to protect your dataset, and have allowed your coworker(s) access to it. I should note that there are lots of other fun things you can do with RACF, and that this is just a few basic commands. If you want to know more, the IBM publication z/OS Security Server RACF General User’s Guide is an excellent resource.
2) TRANSMITTING A DATA SET
This is actually pretty simple. You need to issue the following TSO command:
XMIT (node.user) DATASET(data set)
The node name is going to be specific to your system. Just ask around, one of your coworkers will be able to tell you what it is :-)
3) RECEIVE
When someone sends you a data set, you use the receive command to, well, receive it. This is another one of those commands with a lot of options that 99% of the time you don't need. This is a TSO command, and the following options are the ones that I find the most useful:
RESTORE: SPECIFIES THE TRANSMITTED DATA SHOULD BE RESTORED TO ITS ORIGINAL FORMAT. RESTORE IS THE DEFAULT.
DELETE: SPECIFIES THE FILE BE DELETED WITHOUT RESTORING IT.
DATASET(data set name): SPECIFIES THE NAME OF THE DATA SET TO BE USED TO CONTAIN THE RECEIVED DATA SET. IF THE NAME DOES NOT EXIST ALREADY, THE SYSTEM CREATES IT.
So when someone sends you a data set and you want to receive it, the command looks like this:
RECEIVE RESTORE/DELETE/DATASET(data set name)
That's it for now, hope you found this helpful!
Tuesday, January 29, 2008
Real Programmers don't eat Quiche
Well, it's January and you know what that means? Time to compile a new fortran Snoopy calendar!! I'm going to walk you through the process, but you're going to need a few things first:
1) read the article at the following link (don't worry, it's quite amusing)
Real Programmers Don't Use Pascal
2) download the IBM 1130 emulator here
3) download the snoopy calendar card deck here. Save this file to the IBM1130Software sub-directory created by the emulator under the name "snoopy.job".
4) *OPTIONAL* get yourself a dot matrix printer and do this old skool!
All set? Right, lets do this!
First you need to fire up the emulator. You'll see a GUI (which we won't really be using but it looks pretty), and a console window with a sim> prompt. At the prompt, enter the following commands:
attach dsk dms.dsk [ENTER]
att prt snoopy.txt [ENTER]
reset [ENTER]
boot dsk [ENTER]
This will bootstrap the system and create a text file called "snoopy.txt". This will be your calendar! Now type
attach cr snoopy.job [ENTER]
go [ENTER]
It'll run for a second, and afterwards, the Printer icon will change. Double click on it to see the output of your job.

If you scroll down, you should see a 1969 snoopy calendar! Now, as cool as it is to have a calendar from December 1969, you're probably thinking this would be a lot better if the calendar was for this year. Well don't fret, one simple change to the code you'll have an authentic Fortran Snoopy calendar that is current, usable, and will be the envy of all your friends! Open up SNOOPY.JOB in your favorite text editor and find the line that reads
12 1969 12 1969 1
(in my editor, it's line 319)
That line is a date range. What you are really saying to your trusty IBM1130 is "hey pal, print me a calendar containing all the months from at December 1969 to December 1969. So, for example, you want a calendar from January 2008 to March 2008, you would change that line to read:
1 2008 3 2008 1
With that, you should be able to print our own calendars. Enjoy!
1) read the article at the following link (don't worry, it's quite amusing)
Real Programmers Don't Use Pascal
2) download the IBM 1130 emulator here
3) download the snoopy calendar card deck here. Save this file to the IBM1130Software sub-directory created by the emulator under the name "snoopy.job".
4) *OPTIONAL* get yourself a dot matrix printer and do this old skool!
All set? Right, lets do this!
First you need to fire up the emulator. You'll see a GUI (which we won't really be using but it looks pretty), and a console window with a sim> prompt. At the prompt, enter the following commands:
attach dsk dms.dsk [ENTER]
att prt snoopy.txt [ENTER]
reset [ENTER]
boot dsk [ENTER]
This will bootstrap the system and create a text file called "snoopy.txt". This will be your calendar! Now type
attach cr snoopy.job [ENTER]
go [ENTER]
It'll run for a second, and afterwards, the Printer icon will change. Double click on it to see the output of your job.

If you scroll down, you should see a 1969 snoopy calendar! Now, as cool as it is to have a calendar from December 1969, you're probably thinking this would be a lot better if the calendar was for this year. Well don't fret, one simple change to the code you'll have an authentic Fortran Snoopy calendar that is current, usable, and will be the envy of all your friends! Open up SNOOPY.JOB in your favorite text editor and find the line that reads
12 1969 12 1969 1
(in my editor, it's line 319)
That line is a date range. What you are really saying to your trusty IBM1130 is "hey pal, print me a calendar containing all the months from at December 1969 to December 1969. So, for example, you want a calendar from January 2008 to March 2008, you would change that line to read:
1 2008 3 2008 1
With that, you should be able to print our own calendars. Enjoy!
Monday, January 7, 2008
More on the x37 Abend (read this one first!)
Well it turns out that there is, in some cases, a much simpler method of dealing with the x37 abend. As I mentioned before, any x37 means you've run out of space. So dig this, when you save members of a data set, z/OS saves the old copies. After a while, those copies can cause you to run out of space. When you browse the dataset, enter "/" at the command field,

then choose option 12 "Compress Dataset".

This will delete the old copies and hopefully free up some space. This will not work in cases where you've run out of directory space. In other words, if compressing the data set doesn't work, then go ahead and fix it the hard way as described in the previous Abend x37 post.

then choose option 12 "Compress Dataset".

This will delete the old copies and hopefully free up some space. This will not work in cases where you've run out of directory space. In other words, if compressing the data set doesn't work, then go ahead and fix it the hard way as described in the previous Abend x37 post.
Friday, November 30, 2007
What the $#@! is does ABEND 0E37 mean?
Lemmie guess, you were working with a dataset via ISPF and tried to save your work and got an 0E37 abend. Sound about right? Well don't fret, it's an easy fix. Any x37 abend is an error having to do with space. You're going to have to free some space.
One way to do this is to create a new, bigger data set for your stuff. You'll copy the old data set into the new one, and work with the copy. Ready? lets get started!
First, exit out of the dataset by entering CANCEL at the command line. You'll lose any changes you've made since your last save, so cut-and-paste anything critical. Go into the UTILITY menu, then into the DATA SET sub menu (option 3.2 at the command line). Get the attributes of the data set you were using by entering its name on the NAME field under the heading OTHER PARTITIONED, SEQUENTIAL OR VSAM DATA SET. Once you do this, you should see a screen listing the attributes of the Data Set you were working with. Exit out of this screen.
Now we're going to create a new data set. At the same line you entered your data set name, enter a name for your new data set. Before you hit enter, type A at the OPTION line. This tells the mainframe you want to allocate a new data set. Go ahead and hit Enter. You'll see the same attributes screen you saw before. Here's where you are going to make your changes. Increase the size of your data set, then hit enter. You should see a message that says the data set has been allocated. Exit out to the UTILITY menu.
Now we are going to copy your old data into the new data set. Go into the MOVE/COPY sub-menu in the UTILITY menu (option 3.3). Under the heading FROM OTHER PARTITIONED OR SEQUENTIAL DATA SET, on the line entitled NAME, enter the name of the data set from which you want to copy. Don't hit the ENTER key just yet.
*IMPORTANT!* If you do not enter this name in quotes, z/OS will attach your user name as a high-level qualifier. For example, if your username is JSMITH, and you enter PROGRAMS.WORKING as the dataset name (note the lack of quotes), z/OS will change the name you entered to JSMITH.PROGRAMS.WORKING.
Okay, now that you've got the correct data set name entered, go ahead and type C at the OPTION line and hit ENTER. Now the system will want to know where you want to place the copied files. Under the heading TO OTHER PARTITIONED OR SEQUENTIAL DATA SET, on the line entitled NAME, enter the name of the data set from which you want to copy. Hit the ENTER key.
Now you see a list of all the members of the data set from which you want to copy. Select the members you want to copy by entering S next to the member name. You can copy more than one member at a time by selecting multiple members before hitting the ENTER key. When you are done, exit out of this screen. Check your new data set to make sure the copy went alright (ISPF option 3.4). Once you are satisfied with how everything turned out, delete the old dataset and rename the new one (if your old dataset was called PROGRAMS.WORKING and you copied everything into PROGRAMS.WORKING.TEMP, we need to delete PROGRAMS.WORKING and rename PROGRAMS.WORKING.TEMP to PROGRAMS.WORKING).
Deleting and renaming data sets is fairly painless. Via ISPF option 3.4, enter the name of the old dataset on the line titled DSNAME LEVEL and hit ENTER. You should end up at the DSLIST panel. type DELETE at the command field (the space to the left of your dataset name). Once you've deleted the old dataset, you can rename the new one. Return to ISPF option 3.4 and enter the name of the new dataset and hit enter. At the command field type RENAME and hit ENTER. You will be asked to enter a new data set name. Type the name of the data set you just deleted and hit ENTER.
All done! Now you've got a bigger, badder data set to work with and you shouldn't have to worry about Abend 0E37 for a while :-)
One way to do this is to create a new, bigger data set for your stuff. You'll copy the old data set into the new one, and work with the copy. Ready? lets get started!
First, exit out of the dataset by entering CANCEL at the command line. You'll lose any changes you've made since your last save, so cut-and-paste anything critical. Go into the UTILITY menu, then into the DATA SET sub menu (option 3.2 at the command line). Get the attributes of the data set you were using by entering its name on the NAME field under the heading OTHER PARTITIONED, SEQUENTIAL OR VSAM DATA SET. Once you do this, you should see a screen listing the attributes of the Data Set you were working with. Exit out of this screen.
Now we're going to create a new data set. At the same line you entered your data set name, enter a name for your new data set. Before you hit enter, type A at the OPTION line. This tells the mainframe you want to allocate a new data set. Go ahead and hit Enter. You'll see the same attributes screen you saw before. Here's where you are going to make your changes. Increase the size of your data set, then hit enter. You should see a message that says the data set has been allocated. Exit out to the UTILITY menu.
Now we are going to copy your old data into the new data set. Go into the MOVE/COPY sub-menu in the UTILITY menu (option 3.3). Under the heading FROM OTHER PARTITIONED OR SEQUENTIAL DATA SET, on the line entitled NAME, enter the name of the data set from which you want to copy. Don't hit the ENTER key just yet.
*IMPORTANT!* If you do not enter this name in quotes, z/OS will attach your user name as a high-level qualifier. For example, if your username is JSMITH, and you enter PROGRAMS.WORKING as the dataset name (note the lack of quotes), z/OS will change the name you entered to JSMITH.PROGRAMS.WORKING.
Okay, now that you've got the correct data set name entered, go ahead and type C at the OPTION line and hit ENTER. Now the system will want to know where you want to place the copied files. Under the heading TO OTHER PARTITIONED OR SEQUENTIAL DATA SET, on the line entitled NAME, enter the name of the data set from which you want to copy. Hit the ENTER key.
Now you see a list of all the members of the data set from which you want to copy. Select the members you want to copy by entering S next to the member name. You can copy more than one member at a time by selecting multiple members before hitting the ENTER key. When you are done, exit out of this screen. Check your new data set to make sure the copy went alright (ISPF option 3.4). Once you are satisfied with how everything turned out, delete the old dataset and rename the new one (if your old dataset was called PROGRAMS.WORKING and you copied everything into PROGRAMS.WORKING.TEMP, we need to delete PROGRAMS.WORKING and rename PROGRAMS.WORKING.TEMP to PROGRAMS.WORKING).
Deleting and renaming data sets is fairly painless. Via ISPF option 3.4, enter the name of the old dataset on the line titled DSNAME LEVEL and hit ENTER. You should end up at the DSLIST panel. type DELETE at the command field (the space to the left of your dataset name). Once you've deleted the old dataset, you can rename the new one. Return to ISPF option 3.4 and enter the name of the new dataset and hit enter. At the command field type RENAME and hit ENTER. You will be asked to enter a new data set name. Type the name of the data set you just deleted and hit ENTER.
All done! Now you've got a bigger, badder data set to work with and you shouldn't have to worry about Abend 0E37 for a while :-)
Thursday, November 29, 2007
ISPF is a harsh Mistress...
Whew, the past month or so has been more painful than usual. As much as I love the mainframe, there are times where I feel like working on these machines is akin to hammering a nail into a wall with your forehead. Developing an ISPF interface has proven to be one of those times.
Essentially, I'm creating an interface for an in-house tool that reads and parses source code. To do this, I'm using ISPF for the user interface and a bit of REXX to handle the processing. Essentially, a large block of source code gets written into a table which is then displayed to the user. The user is able to view and manipulate the table by removing blocks of code that are irrelevant. The program aids the user in determining what sections of the code are important. When all is said and done, the user then has the option to save the table to a dataset.
The main sticking points have been:
1) Figuring out what defaults get set when you engage ISPF panel services
2) How to create/manage dynamic content
3) How to efficiently manage the interactions between ISPF and the code that is driving it
Before I go on, I'm going to show you what the panel code looks like that drives the main page:
Essentially, I'm creating an interface for an in-house tool that reads and parses source code. To do this, I'm using ISPF for the user interface and a bit of REXX to handle the processing. Essentially, a large block of source code gets written into a table which is then displayed to the user. The user is able to view and manipulate the table by removing blocks of code that are irrelevant. The program aids the user in determining what sections of the code are important. When all is said and done, the user then has the option to save the table to a dataset.
The main sticking points have been:
1) Figuring out what defaults get set when you engage ISPF panel services
2) How to create/manage dynamic content
3) How to efficiently manage the interactions between ISPF and the code that is driving it
Before I go on, I'm going to show you what the panel code looks like that drives the main page:
)PANEL
)ATTR
! TYPE (OUTPUT)
+ TYPE (TEXT ) INTENS(LOW) COLOR (WHITE)
@ TYPE (OUTPUT) INTENS(LOW) COLOR (YELLOW) JUST(ASIS)
# TYPE (TEXT) INTENS(LOW) COLOR (GREEN) JUST(ASIS)
* TYPE (OUTPUT) INTENS(LOW) COLOR (WHITE) JUST(ASIS)
% TYPE (TEXT) INTENS(LOW) COLOR(RED) JUST(ASIS)
)BODY WIDTH(132)
+
+COMMAND -=>_CMDFLD +SCROLL -=>_SAMT+
+
+ TYPE "?" FOR ONLINE HELP
+ !MSG
+
# MVS SYSTEM INTEGRITY SCANNER: OUTPUT ANALYSIS TOOL
#
# ROW LOC OFFSET OBJECT CODE ADDR1 ADDR2 STMT SRC STATEMENT
# -----------------------------------------------------------------------------
)MODEL
+>_IN @AA
)INIT
&SAMT=PAGE
)PROC
)END
)ATTR
! TYPE (OUTPUT)
+ TYPE (TEXT ) INTENS(LOW) COLOR (WHITE)
@ TYPE (OUTPUT) INTENS(LOW) COLOR (YELLOW) JUST(ASIS)
# TYPE (TEXT) INTENS(LOW) COLOR (GREEN) JUST(ASIS)
* TYPE (OUTPUT) INTENS(LOW) COLOR (WHITE) JUST(ASIS)
% TYPE (TEXT) INTENS(LOW) COLOR(RED) JUST(ASIS)
)BODY WIDTH(132)
+
+COMMAND -=>_CMDFLD +SCROLL -=>_SAMT+
+
+ TYPE "?" FOR ONLINE HELP
+ !MSG
+
# MVS SYSTEM INTEGRITY SCANNER: OUTPUT ANALYSIS TOOL
#
# ROW LOC OFFSET OBJECT CODE ADDR1 ADDR2 STMT SRC STATEMENT
# -----------------------------------------------------------------------------
)MODEL
+>_IN @AA
)INIT
&SAMT=PAGE
)PROC
)END
First off, note the spacing in the ")ATTR" section. That's important. It seems that ISPF, much like JCL, is sensitive to row/column position of code. I should say that there is another way to develop ISPF panels called Dialog Tag Language (DTL). DTL appears to have more functionality, but there is a trade-off. In order to keep everything compatible, you write a panel in DTL, then run it through a conversion program by typing ISPDTLC at the command line. Once you do this, the panel gets converted into something that is non-human readable, but is compatible with ISPF. I found this to be problematic, as I have no idea what my DTL is getting turned into. True, the conversion utility has error checking, but it's not able to find logic errors. So there are instances where you attempt to develop a dialog via DTL, you wash it through the conversion utility, run the panel, and find out it's not doing what it's supposed to be doing. Now you can't tell if the problem is the DTL you wrote, or the manner in which ISPDTLC interpreted your DTL.
So why bother with it you ask? Well, from the looks of it, DTL provides functionality that the normal ISPF panel language does not provide. If you look at the panel code I showed you (go ahead and scroll up, I'll wait), you'll see that there is only one line of code in the "(MODEL" section. that line, specifically the "@AA" part, is what displays the table information. Every row of the table is displayed in the same way. This means that I can't dynamically change the color of a particular row of the table based on context. DTL would, in theory, allow me to do that. The problem is that DTL will ignore the profile keylist (the thing that defines what the PFKeys are set to). This means that you have to define them yourself, but the figuring out how to define the APPL that would drive that is akin to learning Mandrin Chinese in an hour. So in the end, it seems that the ISPF Panel language is the best way to go.
So let's take a quick tour of the panel code I showed you:
)PANEL
Panel section. Specifies a keylist to be used during the display of the panel, and identifies where to find the keylist
)ATTR
Attribute section. Defines the special characters in the body of the panel definition that represent attribute (start of field) bytes. ISPF panels are defined line-by-line with control characters. So in the case of + TYPE (TEXT ) INTENS(LOW) COLOR (WHITE), a line that starts with the control character "+" will be displayed as plain text, low intensity (brightness), and will be white.
)BODY
Body section. Defines the format of the panel as seen by the user and defines the name of each variable field on the panel. In the case of the sample above, WIDTH(132) pertains to the number of character columns that will be displayed when the panel is shown.
Now is a good time to note that there are built-in control characters. One of them is "_". This denotes an input field. So by saying _CMDFLD, I am defining an input field with the variable name CMDFLD.
In the sample above, you'll also note a message field. This is where any messages will be displayed in the panel.
)MODEL
Model section. Defines the format of each row of scrollable data. This section is required for table display panels. Only one )MODEL section is allowed per panel.
In the sample panel I've shown you, I've defined +>_IN @AA in the model section. This means a table will be displayed here. Each row will start with a ">", which will be displayed with the characteristics mapped to control character "+". Then, an input field called "IN" will be created, then the table row called "AA". Note that "IN" and "AA" have different control characters, and thus are displayed differently.
)INIT
Initialization section. Specifies the initial processing that is to occur before the panel is displayed. This section is typically used to define how variables are to be initialized.
)PROC
Processing section. Specifies processing that is to occur after the panel has been displayed or redisplayed. This section is typically used to define how variables are to be verified and translated.
)END
End section. Specifies the end of the panel definition, and consists only of the )END statement. ISPF ignores any data that appears on lines following the )END statement.
That about covers the ISPF end of things. The next post will go over the REXX that's driving everything. I hope this has been helpful :-)
---------------------------------------------------------------------------------------
The postings on this site are my own and don’t necessarily represent IBM’s positions, strategies or opinions.
So why bother with it you ask? Well, from the looks of it, DTL provides functionality that the normal ISPF panel language does not provide. If you look at the panel code I showed you (go ahead and scroll up, I'll wait), you'll see that there is only one line of code in the "(MODEL" section. that line, specifically the "@AA" part, is what displays the table information. Every row of the table is displayed in the same way. This means that I can't dynamically change the color of a particular row of the table based on context. DTL would, in theory, allow me to do that. The problem is that DTL will ignore the profile keylist (the thing that defines what the PFKeys are set to). This means that you have to define them yourself, but the figuring out how to define the APPL that would drive that is akin to learning Mandrin Chinese in an hour. So in the end, it seems that the ISPF Panel language is the best way to go.
So let's take a quick tour of the panel code I showed you:
)PANEL
Panel section. Specifies a keylist to be used during the display of the panel, and identifies where to find the keylist
)ATTR
Attribute section. Defines the special characters in the body of the panel definition that represent attribute (start of field) bytes. ISPF panels are defined line-by-line with control characters. So in the case of + TYPE (TEXT ) INTENS(LOW) COLOR (WHITE), a line that starts with the control character "+" will be displayed as plain text, low intensity (brightness), and will be white.
)BODY
Body section. Defines the format of the panel as seen by the user and defines the name of each variable field on the panel. In the case of the sample above, WIDTH(132) pertains to the number of character columns that will be displayed when the panel is shown.
Now is a good time to note that there are built-in control characters. One of them is "_". This denotes an input field. So by saying _CMDFLD, I am defining an input field with the variable name CMDFLD.
In the sample above, you'll also note a message field. This is where any messages will be displayed in the panel.
)MODEL
Model section. Defines the format of each row of scrollable data. This section is required for table display panels. Only one )MODEL section is allowed per panel.
In the sample panel I've shown you, I've defined +>_IN @AA in the model section. This means a table will be displayed here. Each row will start with a ">", which will be displayed with the characteristics mapped to control character "+". Then, an input field called "IN" will be created, then the table row called "AA". Note that "IN" and "AA" have different control characters, and thus are displayed differently.
)INIT
Initialization section. Specifies the initial processing that is to occur before the panel is displayed. This section is typically used to define how variables are to be initialized.
)PROC
Processing section. Specifies processing that is to occur after the panel has been displayed or redisplayed. This section is typically used to define how variables are to be verified and translated.
)END
End section. Specifies the end of the panel definition, and consists only of the )END statement. ISPF ignores any data that appears on lines following the )END statement.
That about covers the ISPF end of things. The next post will go over the REXX that's driving everything. I hope this has been helpful :-)
---------------------------------------------------------------------------------------
The postings on this site are my own and don’t necessarily represent IBM’s positions, strategies or opinions.
Subscribe to:
Posts (Atom)