Saturday, March 26, 2011

Random Musings Regarding Programming

There are two items I wish to express my personal views about.  Mainly, these thoughts and feelings stem from articles I've read or discussions with colleagues.

The first is regarding "stodgy old IBM mainframes".  Don't know why I've seen this more often recently in print and in various online lectures, but there seems to be a lot of misunderstandings about the current state of the IBM mainframe world.  Granted, IBM mainframes are rather graphically-challenged, in many ways, but that's because they are designed to be back-end servers, and not in-your-face desktop systems.  What really gets me are those who ignore the investment and progress that the IBM mainframe has made since the days when these authors and lecturers had any hands-on experience.  The comparisons made generally are of current *nix or Windows capable back-end servers to MVS 3.8J-vintage S/370 mainframes.  The comparisons are as valid as someone comparing an current IBM zSeries mainframe to a Digital PDP/8 or PDP/11.

The reasons why all of these long-lived platforms are so long-lived is simply because they fulfill a business need.  They all have their strengths and weaknesses.  It's become apparent to me, that the computing platform of ones personal choice is very much like ones word-processor of choice.  It might not be the best out there at the time, it might not be the most favored, or not the newest; but it's the first one learned.  The very first word processor I learned was MS Word back in 1986 when everyone else in the world was using WordPerfect.  Personally, I've always like Word better than WordPerfect for one reason, it was my first word processor.  Likewise, my computing platform of choice is z/OS, simply because I learned MVS first.

It's easy to put down other computing platforms when writing articles or presentations where no feedback is permitted.  For me, though, I loose all respect and credibility for those authors or presenters who belittle other platforms with decades old information.  It simply shows me how uninformed they are, and how out of touch with the rest of the computing world that exists outside of their little bubble.  I still remember when back in the early 1990s when Bill Gates made the prediction that the last IBM mainframe would be shut off in 1995.  Not putting down Mr. Gates by any means, just want to express how easy it is for anyone to become out of touch from the greater computing universe.

The second item I wish to bring up is this whole discussion about Basic or Basic-like languages that are easier to learn.  The very first computing language I learned wan't basic at all.  It was the PDP/8-E assembler and macro language.  We didn't learn much, but enough to understand the basics regarding how the computer worked.  The real first computing language I learned was Digital's Edusystem-30 Basic.  At the ripe old age of 14, I was writing binary search routines, bubble sorts, and some simple games.  But the language didn't have to be Basic, it just had to be simple to learn.  There are alternatives out there that are available and free for almost every computing platform.  Recently, I've introduced Rexx to a number of people.  It's as simple to learn as Basic, it's free, and available on pretty much every platform.  Rexx is a great scripting language and teaching tool.  I wish people would take it more seriously!

Thanks for reading my musings and rants.  Please let me know your opinions!

Thursday, March 17, 2011

Still working on Continuum ....

Need to let Continuum just percolate in the back of my mind for a while.  Don't know if any other writer experiences this or not, but the story and my writing is best when not forced.  It's smoldering at the back of my mind or sometimes in my dreams.  When it's ready to be written, then I feel the need and desire to express it.  Otherwise, it sounds forced and contrived instead of envisioned and deep.

Not trying to say anything profound with Continuum.  During my writings so far and dreams I've had since its start, I've created an entire world and history with the Shahdoan.  History going back to when the Shahdoan were still on their home worlds, through the Great Crisis, up to the present day.

Our two peoples, Humans and Shahdoan, are intertwined at important points in each other's history thanks to the Continuum Weaver, Cosima.  Cosima enlisted help from each peoples at pivotal events in history of the other to guide, advise, and help.

If Continuum has anything to say, it's that everything and everyone is connected to each other.  In minor ways, but at times in major ways.  We all are threads woven into a continuum like tapestry.  Each thread adding it's own color, texture and strength to the whole.

Justin is one of a very few humans that Cosima enlisted to help the Shahdoan.  There have been and will be Shahdoan who likewise assist mankind.  In some future time, our two people will discover we are galactic neighbors and more alike than not.  Even though this is Justin's first visit with the Shahdoan, from his point of view, it's in fact the second time Justin was visiting the City.  He heads back to the City in his personal future, and the Shahdoans past to help them through their Great Crisis.  Justin, in fact, creates the prophecy of the Visitor.  Justin, during the time of the Great Crisis, prophecies about his first visit many many years later.

So please be patient.  When I feel the time is ready to write the next chapter or two, I will sit down and type up a storm.  My ex always said when I was typing and concentrating fully on what I was writing, my fingers would blur like Data from Star Trek: TNG.  Well, when one types all day for work, one has a tendency to become rather proficient at that task.  Other abilities suffer, though, like my handwriting.  Typing is so second nature to me, I have a hard time actually writing something.  Not that I have forgotten, I simply don't have the patience for it.  A strike of a key is so much faster than drawing the letter on the page.  My ex always struggled to type, even after typing lessons, but had the most elegant and beautiful handwriting.  Mine makes the scribblings of a medical doctor look like elegant calligraphy.  I'm lucky if I can ready what I wrote a few minutes earlier.

Another Regina REXX example

This example is intended more for the classic IBM Mainframe z/OS user.  Many times, when libraries are backed-up or downloaded, the PDS or PDSE members are downloaded into a folder as separate files.  While this might not be a big deal when dealing with the odd individual member from time to time, but when having to upload the entire folder or directory back into a PDS, dealing with FTP for each member might be a bit tedious.  Not to mention, having to validate the contents of the source for tabs, possible truncation issues, and other cross-platform and cross-character set incompatibilities that might crop up.

While a simple shell script could be written to upload all of the members using FTP individually, I personally like to opt for a single upload in IEBUPDT format.  IEBUPDT is a source update facility that dates back to the OS/360 days.  It's mostly used today to populate empty PDS or PDSEs with members from an installation library or product library.

So this Regina Rexx exec will read all files with a specific suffix within the current working directory and place them into a single IEBUPDT input file ready to be uploaded to z/OS.  This exec also replaces any tabs with spaces and validates the length of each line and spits out a message if the line length is greater than 80.  Of course, this length can be easily changed, but most source on the mainframe that's not-C/C++, is usually limited to 80 bytes.  The exec can be easily extended to check for character or Unicode-EBCDIC translation anomalies that is easily corrected when building the IEBUPDT input deck.

The exec can be easily extended to do a lot more.  Remember, this is just an example!  It also shows how to do file I/O and system calls from within Regina Rexx on Mac OS X 10.6.  Works pretty much as one would expect, but then again, Darwin does have it's differences from other *nix derivatives out there.

One side item to note.  When passing parameters to Rexx execs or rexx subroutines, the parameters are generally blank delimited, with each parameter being placed into each subsequent variable in the argument list.  With the exception of the last variable, which receives what ever is left over in the parameter list, regardless of how many parameters are there.  So, it's considered good form to include another variable at the end of the expected parameter list to accept the errant, unexpected parameters should they be there.  Some people use a period, some the variable Z; I personally like to use Uebrig which is German for "Remaining".  Kind of also reminds me of my time in Berlin.  Walking around on Sunday morning, you'd see rather tired or strung out partiers left from the night before.  Either on their way home or ... anyway.  They were referred to as "die Uebriggebliebene" -- literally "The Ones Left Over" ... as in left over from the night before.  Uebriggebliebene also refers to left over food too.

The exec can be used for more than simply recombining files within a folder back into a single file ready for z/OS.  In principle, one could adapt it as an archiver; or a facility to create a snapshot of the contents of part of a directory.  The LS command provides a lot of information regarding the file in question.  With the parsing power of Rexx, I'm sure there's quite a number of uses the basic structure of this exec could lend itself to.

Back to the exec!  So here it is.  With comments.  Please feel free to make suggestions for improvement or ask questions!  Hope you old mainframers like this mixing of two computing worlds!

(The exec is available for download at files.me.com/bikerdiver/ljxem8 for the next 10 days).



#!/usr/bin/regina
/*  (c) 2011 T. Alan Tranter -- Use anyway you wish, but at your own risk. */
/* */
/*  Set global variables that might someday be better parameterized.       */
maxllen = 80                        /* max line length before warning.     */


/*  Parse input and open up output stream in the current working directory */
/*  File type (ftype) indicates the file extension.  If it's a period '.'  */
/*  then the user wishes to include all files.                             */
parse upper arg outfile ftype uebrig
if ftype = '.' then ftype =''


/* Rexx is a bit different when opening up files.  The first parameter is  */
/* a variable name that contains the information linking to the open file. */
/* Rexx does not use, file handles, per se, rather variable names.         */
rc = stream(outfile,'C','OPEN WRITE REPLACE')


/* Obtain a directory listing of the current working directory and place   */
/* the output into the stem variable dcont., where dcont.0 contains the    */
/* the number of output lines and dcont.1 through dcont.x is each line.    */
address SYSTEM "ls -le" with OUTPUT STEM dcont.
if .rc <> 0 then exit 8


/* Loop through each line.  We start with 2 because the first line is      */
/* always the "total" line.  Might be better to simply check to see if     */
/* the first line and first word in the first line is 'total' and skip it, */
/* but why introduct a compare for every single line.  Check the output    */
/* of your LS command and adjust if necessary!                             */
do e = 2 to dcont.0
 if substr(dcont.e,1,1) = '-' then do           /* - indicates a file.     */
    nextfile = word(dcont.e,words(dcont.e))
    if nextfile = outfile then iterate          /* skip the output file    */
    if ftype <> '' then do
       if ftype <> translate(strip(word(translate(nextfile,' ','.'),2))) then iterate
       end
    call addfile nextfile
    end
 end
 /* Directory listing has been processed.  Now add the IEBUPDT control     */
 /* card indicating it's the end of the input deck.                        */
 rec = './ ENDUP'
 rc = lineout(outfile,rec)
 /* Close output file.                                                     */
 rc = stream(outfile,'C','CLOSE')
 exit 0

/* addfiles subroutine to include the selected file into the IEBUPDAT      */
/* output stream.  Single parameter which is the name of the file.  Must   */
/* reside in the current working directory.                                */
 addfile: parse arg ifile uebrig
 rc = stream(ifile,'C','OPEN READ')
 if rc <> 'READY:' then do
    say 'Error opening input file' ifile ' stream OPEN returned' rc
    say 'file being skipped'
    return
    end
    
 /* Separate the file name from its extension and test if the extension    */
 /* matches the extension, if provided.                                    */
 member = translate(ifile,' ','.')

 /* PDS member names can only be up to 8 characters in length.  To make    */
 /* sure the file name, which will become the directory entry name, is     */
 /* no longer than 8 characters.  Should probably check to see that the    */
 /* contents of the name is also valid for PDSs.  Something for the reader */
 /* to do!                                                                 */
 if length(word(member,1)) > 8 then do
    say word(member,1) "name is too long - file is skipped"
    rc = stream(ifile,'C','CLOSE')
    end
 /* Add the IEBUPDT control card indicating the start of a new PDS or PDSE */
 /* member.  Must be upper case, and must start with a ./.  Check the z/OS */
 /* Utilities manual for more information regarding IEBUPDT.               */
 member = translate(substr(word(member,1),1,8))
 rec = './ ADD NAME='||member
 rc = lineout(outfile,rec)
 maxlen=0
 ftabs = 'N'
 /* The lines() function returns the number of lines left in the input     */
 /* stream - kind of.  It's basically 1 is there are one or more lines and */
 /* 0 if end of file has been reached.  The parameter provided to lines()  */
 /* is the variable name provided stream() open time.                      */
 do while lines(ifile)>0
    rec=linein(ifile)
    /* This check is to make sure the file being included doesn't itself   */
    /* have IEBUPDT control cards imbedded within the file.  This would not*/
    /* be good.                                                            */
    if substr(rec,1,2) = './' then do
       say '** WARNING **  CONTROL CARD FOUND --' rec
    end
    /* Test if there are any tabs, and expand them to 6 blanks if found.   */
    if countstr(d2x(9),rec) > 0 then do
       if ftabs = 'N' then do
          say 'Tabs found in' ifile
          ftabs = 'Y'
       end
       rec=changestr(d2x(9),rec,'      ')
end
/* Strip any trailing blanks and test the length.  If greater than 80,  */
/* than spit out a message indicating such.  The hwm length for the file*/
/* is saved, but no message is issued until the entire file has been    */
/* processed.                                                           */
    rec=strip(rec,'T')
    if maxlen < length(rec) then maxlen=length(rec)
    rc=lineout(outfile,rec)
 end
 /* Close up the input file and issue warning if max length is greater than */
 /* 80.                                                                     */
 rc = stream(ifile,'C','CLOSE')
 if maxlen > maxllen then ,
  say '** WARNING **' ifile "maximum record length is" maxlen
 return

Tuesday, March 1, 2011

First Example Rexx Exec

In the previous Blog, I described how to install and customize the Regina Rexx interpreter for Mac OS X Snow Leopard.  Any comments or installation instructions are based upon that blog.

Today, I thought I'd share a short exec that I use in place of the LS command.  Coming from a Windows/DOS world, I kind of missed my DIR command.  This seems like a reasonable replacement.  Hope you find it useful!


#!/usr/bin/regina
address SYSTEM "ls -le" with OUTPUT STEM wdir.
if rc = 0 then do l = 2 to wdir.0
   say wdir.l
end
address SYSTEM "pwd" with OUTPUT STEM wdir.
if rc = 0 then do
   say
   say "Current directory is:" wdir.1
   say
end
exit 0

Save the above text as ~/Shells/dir then issued the terminal commands:

cd ~/Shells
chmod u+x dir


Once done, you can simply type in DIR, just like good old DOS and see the directory listing.  Below is the output when using DIR to list my home directory:


MacIron:~ ttranter$ dir
drwxr-xr-x  24 ttranter  staff     816 Feb 27 15:23 Backed Up
drwxr-xr-x   3 ttranter  staff     102 May  3  2010 CPA
-rw-r--r--@  1 ttranter  wheel  518992 Feb 24 17:14 CUPS-PDF Spool
drwx------   4 ttranter  staff     136 Feb 28 18:07 Desktop
drwx------  28 ttranter  staff     952 Feb 18 23:06 Documents
drwx------   5 ttranter  staff     170 Mar  1 13:53 Downloads
drwx------  55 ttranter  staff    1870 Feb 28 11:22 Library
drwx------   7 ttranter  staff     238 Feb  7 23:44 Movies
drwx------   8 ttranter  staff     272 Mar  2  2010 Music
drwx------  14 ttranter  staff     476 Feb  6 11:25 Pictures
drwxr-xr-x  25 ttranter  staff     850 Feb 27 23:27 Projects
drwxr-x-wx   6 ttranter  staff     204 May 17  2010 Public
drwxr-xr-x@ 31 ttranter  staff    1054 Mar  1 21:30 Shells
drwxr-xr-x+  6 ttranter  staff     204 Mar 15  2010 Sites
 0: group:everyone deny delete
-rw-r--r--@  1 ttranter  staff  519112 Feb 25 23:29 eBooks


Current directory is: /Users/ttranter


MacIron:~ ttranter$ 

Hope you find it useful!

For you IBM Mainframe loving Mac OS X users ...

This entry probably will not be of interest to most reader, but for the select few who know REXX from the IBM mainframe world and wish they could use it on their Mac, then these next few blogs are for you!

Basics and Installation

One nice feature that *nix systems have is the ability to indicate which shell interpreter to use from within the script itself.   The the first line of the script start with characters #!, then the rest of the string, up to the first space, indicates the directory and interpreter name.  In TSO/E, it is similar to adding a /* REXX */ in the first line to indicate it's a rexx exec vs a standard CLIST.

There are many good free rexx interpreters for various non-mainframe environments.  The one I've chosen to use and write about is the Regina Rexx interpreter.  There is a pre-buit version for the Mac that is easy to install.

As  much as I like Regina rexx (from now on simply Regina), its Mac OS X documentation is sometimes misleading or simply wrong.  Have a feeling the documentation simply needs to be updated for the newer versions of Mac OS X.  I'm using Snow Leopard (10.6), so anything in these Regina inspired next few blogs will pertain only to that level of Mac OS X.

Before continuing, I'd make myself somewhat familiar with using the Terminal application inside of the Utilities sub-directory within Applications.  Apple has also provided quite a nice document titled The Shell Scripting Primer.

Once you install Regina, you need to customize the installation for your use.  The customization steps are what I personally recommend, but are not necessarily the only or the best for your situation.  If anything, I hope it provides a good starting point.  So, the following steps are best for me, adjust for yourself as necessary or if preferred.

1) Create a "Shell" subdirectory within your home directory.  I also listed it my Finder's sidebar Places list.  This is where I keep any shell scripts I write, regardless of interpreter.

2) There are a couple of variables that need to be defined as part of the initial default shell.  There is a hidden directory and file in your home directory.  The hidden directory is .MacOSX.  There is a plist file aptly named environment.plist within the .MacOSX directory.  If there is no .MacOSX or environments.plist entries, you an simply create them from the normal TextEdit program.  There is a Snow Leopard trick to see hidden files and directories.  Once in the normal Open Dialog, just press the key combination of command-shift-period, and that will toggle on and off the display of hidden files and directories.  This key combination works for pretty much all applications with the exception of the Finder.  You can also use the Properties List Editor as well.  Below is the contents of my environments.plist file:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LIBPATH</key>
<string>/usr/lib</string>
<key>PATH</key>
<string>/users/ttranter/shells:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin</string>
</dict>
</plist>

My home directory is /users/ttranter, please alter according to the name of your home directory.  Also make sure you include any other PATH contents that currently exist. See the Shell Primer document for more information.  The LIBPATH variable is used by Regina to locate various Dylds and other components of the interpreter.  This normally should be set to /usr/lib.  The first directory entrie in my PATH statement indicate where my shell scripts reside.  Some people create a rexx subdirectory within /usr (example /usr/rexx) and include that entry within the PATH statement as well for any rexx execs that can be globally used by any user on the Mac.  

3) Once ~/.MacOSX/environments.plist has either been altered or created, log-out then log back on.  Reboot is not necessary.  Frankly, Don't even know if re-logging is really necessary.  For my Mac, I found it was.  Better safe the sorry.

Okay, installed and customized!  Below is a small rexx execs.  Use TextEdit (or equivalent like TextWrangler) and place it inside of the Shells directory as reginatest.

#!/usr/bin/regina
/*  The Regina Rexx Test Exec */
parse version whoami
say "Executing Interpreter --" whoami
exit 0

Make sure you issue the chmod u+x reginatest too!  The output should look similar to:

MacIron:~ ttranter$ reginatest
Executing Interpreter -- REXX-Regina_3.5(MT) 5.00 31 Dec 2009
MacIron:~ ttranter$ 

Think that's enough for this blog.  Good luck!  Next couple of blogs will describe a few interesting rexx execs I've written for the Mac!