Thursday, August 21, 2008

How to search for PDS members in ISPF

I've just discovered a really simple way to find stuff on the mainframe. Let's say you are looking for a file called INDEX and you only know the high level qualifier of the dataset it's in. After you do your DLIST (ISPF option 3.4) of the HLQ (hlq.** for example), you type

member index

at the command line. The system will show you all the data sets where a file called INDEX resides. You can also use wildcards. So, for example, let's say there are lots of files you want to find, all starting with INDEX (INDEX00, INDEX01, INDEX02, etc). Then you'd type

member index*

and you'll be shown all the files that begin with the word index. Cool huh? The only thing I've noticed is that if your data set has been migrated, this won't work. You'll have to recall the data set before you do your search.

Hope you find it useful :-)

Wednesday, August 6, 2008

Master the Mainframe and GDDM

The Master the Mainframe contest is just around the corner and as I'm on the contest team this year, I was asked to come up with a coding challenge. The one I came up with last year was a simple ISPF macro challenge I ripped from the pubs (ISRBOX) and added a few bugs too. This year I wanted to do something spectacular so I dug deep and dove into IBMs Graphical Data Display Manager, or GDDM for short.

What's so cool about GDDM? Well my friends, it allows the mainframe to display graphics and interact with things like mice and light pens and all sorts of other cool peripherals. ISPF can be made to act like a simple GUI with a point and click interface. It is also the means by which OS/2 displayed it's windows and such. With the advent of the web, however, this feature became somewhat depricated and nobody, to my knowledge, really uses it anymore.

So what am I doing messing around with this thing? Well, as fun as looking at endless streams of green text can be (and believe me, it's a hoot), I figured some colorful graphics might be a nice change of pace. I decided to create an implementation of Mandelbrot Set. The man who discovered this method, BenoƮt Mandelbrot, was an IBM fellow so it seemed fitting.

So I got to coding, pestered my co-workers when I got stuck or when the math got over my head, and finally I was able to get the thing working. It should be noted that I got some help, especially with the zooming bit, from here.

So I get the stupid thing working,


it looks amazing, it zooms (sortof) at the click of a mouse, I get my ooohs and aaaahs. After all that, it can't be included in the contest because none of the TN3270 emulators on the market (save the IBM one) can handle host graphics. No host graphics means no GGDM. The contestants won't be using the IBM TN3270 program so they won't be able to see the image.

...probably should've looked into that before I spent all that time coding the thing.

Oh well. As there isn't much good information on the web about GDDM I thought I'd post the code, written in C, for the Mandelbrot Generator. In order to use GDDM, you're going to have to play with your JCL and include some libraries so this compiles/links properly.

*NOTE* There are [] around the includes so Blogger doesn't think it's some sort of tag

#include [stdio.h]
#include [string.h]
#include [admucina.h]
#include [admtstrc.h]
#include [admucinf.h]
#include [admucing.h]
#include [admucins.h]


#pragma linkage(asread,OS)
#pragma linkage(chhatt,OS)
#pragma linkage(chhead,OS)
#pragma linkage(gsuwin,OS)
#pragma linkage(gschar,OS)
#pragma linkage(gsseg,OS)
#pragma linkage(gssati,OS)
#pragma linkage(gsscls,OS)
#pragma linkage(gsenda,OS)
#pragma linkage(gsarea,OS)
#pragma linkage(gsqcho,OS)
#pragma linkage(gsqloc,OS)
#pragma linkage(gspat,OS)
#pragma linkage(gsenab,OS)
#pragma linkage(gssaga,OS)
#pragma linkage(gsmove,OS)
#pragma linkage(gscol,OS)
#pragma linkage(gsline,OS)
#pragma linkage(gsview,OS)
#pragma linkage(gslw,OS)
#pragma linkage(gsflw,OS)
#pragma linkage(gsarc,OS)
#pragma linkage(fsinit,OS)
#pragma linkage(fsterm,OS)

#define width 320
#define height 200

main ()
{

/*SETUP THE GDDM ENVIRONMENT**********************/
float xoff, yoff, oldcx, oldcy;
int temp;
float scale;
int flag;
int number;
float cx = -0.5;
float cy = 0;
int inwin;
int type;
int val;
int count;
int id_type;
int id_id;
double x,y;
double xstart,xstep,ystart,ystep;
double xend, yend;
double z,zi,newz,newzi;
double colour;
int iter,input;
long col;
int i,j,k;
int inset;
int fd;

fsinit();
flag = 0;
gsenab (1,0,1);
gsenab (1,1,1);
gsenab (2,1,1);
gsuwin(0,640,0,480);
gsms(9);

xstart = -2;
xend = 1;
ystart = -1;
yend = 1;
xoff = 0;
yoff = 0;
iter = 200;
scale = 1;
xstep = ((xend-xstart)/width) * scale;
ystep = ((yend-ystart)/height) * scale;

/*DISPLAY AND ZOOM LOOP***************************/

while (flag == 0)
{
flag = 1;

x = xstart;
y = ystart;

for (i=0; i
{

for (j=0; j
{
z = 0;
zi = 0;
inset = 1;

for (k=0; k
{
/* z^2 = (a+bi)(a+bi) = a^2 + 2abi - b^2 */
newz = (z*z)-(zi*zi) + x;
newzi = 2*z*zi + y;
z = newz;
zi = newzi;

if(((z*z)+(zi*zi)) > 4)
{
inset = 0;
colour = k;
k = iter;
}

}

if (inset)
{
gscol(-1);
}
else
{

while (colour > 7)
{
colour = colour / 8;
}

gscol(colour);
}

x += xstep;

/*DRAW YOUR FRACTAL!******************************/
gsmark (j,i);

}

y += ystep;
x = xstart;

}

/*SEND THE GDDM DATA TO THE SCREEN****************/

gsread(1,&id_type,&id_id);

if (id_type == 2)
{

scale = scale * 0.75;
flag = 0;
oldcx = cx;
oldcy = cy;

gsqloc(&inwin,&cx,&cy);


if (cx > 320)
{
cx = 320;
}

if (cy > 200)
{
cy = 200;
}

cx = (cx * xstep) - 2 + xoff;
cy = (cy * ystep) - 1 + yoff;

xoff = (xoff + (cx - oldcx));
yoff = (yoff + (cy - oldcy));

xstart = cx + (-1.5 * scale);
xend = cx + 1.5 * scale;
ystart = cy + (-1 * scale);
yend = cy + 1 * scale;

xstep = xstep * scale;
ystep = ystep * scale;

}

}

fsterm();
}

Enjoy (and good luck to this years Master the Mainframe contestants!)

Monday, June 2, 2008

What are the PA keys for?

If you're used to dealing with PCs and you suddenly find yourself working with a mainframe, there is a lot you have to get used to. Hitting the [ctrl] key instead of [enter] is a big one. Another is getting used to the fact that historically, the mainframe terminal keyboard had keys that aren't included on your AT-style PC keyboard. So what are those keys and what are they for?

Well, to start, let's talk a bit about what you're really doing when you log into a mainframe. When you log in, regardless of what terminal program you're using, you are emulating an IBM 3270 terminal. Here's a pic:


This machine was sometimes called a "dumb" terminal because it didn't have any computational power on it's own. Its purpose was to provide an interface between the mainframe and the user. So, let's take a look at that keyboard layout:


Looks a bit different, huh? Most of these keys you're already familiar with. Let's start on the right:

PF1-PF12, are Program Function keys. They are identical to the "F-keys" on your PC keyboard.

The "PA" keys are Program Attention keys, and are defined by whatever program you are running. For example, under TSO, PA1 will interrupt a command, and PA2 will redisplay the current screen. Under SDSF, PA1/2 will both redisplay the screen contents.

DUP places the DUP Field symbol on the screen and the cursor moves to the first position of the next unprotected field. Handling of the symbol is dependant on the application program.

INS MD Queries the session's operator information area to determine if the keyboard is in InsertMode mode.

CLEAR, or "CLR", sets all buffer locations to nulls and all character attributes to X'00'. The cursor moves to the top left corner of the screen.

ERASE INPUT erases the contents of all input fields in the screen and moves the cursor to the beginning of the first unprotected field. If the screen has no unprotected field, the cursor moves to the top left corner; no data is erased. If the screen is unformatted, this function clears the screen and moves the cursor to the top left corner.

ERASE EOF erases all characters (the characters are replaced with NULL) from the cursor position to the end of the field while the cursor is in an unprotected field. The cursor does not move. On an unformatted screen, this function erases all characters from the cursor position to the end of the screen.

TEST RQ sends a test request to the host system.



Well, that's about it. I hope that helps :-)

Monday, April 14, 2008

How to Write to or Read from a File in REXX

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

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!

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!

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.