Dr. Rx

Dr. Rx is hanging out his shingle.  As with regular doctors, the hanging out of the shingle doesn't necessarily signify knowledge or expertise.  It just means I got my shingle out before the rest of you.  But I'll try to keep up appearances...

So.  Bring me your questions.  I'll also pick up some juicy bits from the lists from time to time.

One final note.  To the dismay of some, and perhaps the delight of others, I'm doing my Rexxing in the NT environment.  Using Regina.  Looking warily at Object Rexx.  But I've Rexxed in OS/2 and CMS and MVS as well, so throw me your tough ones and I will at least know what most of you are talking about.

But what to do in this first column, before anyone has sent in their questions?

Let me share with you a Rexx help system.  In addition to being terminally lazy, Dr. Rx is compulsively anal where documentation is concerned (why does my house always need cleaning?  Why do papers drift inches deep on my desk?).

This system depends on a convention.  Rexx used to require a comment as the first line (and probably still does in some environments).  We began placing the name, creation date and owner ID in that comment. With multiple contributing developers, this seemed a good way to keep responsibilities straight.

It wasn't long before we began placing a line each of function, syntax, operands, and returned values in a comment block at the beginning of the Rexx.  Again by convention, these comments were preceded by a line beginning with "/*" and followed by a line beginning with "*/".

It didn't take long after _that_ for my friend Brian Barker to develop the prototype for a gadget, which we called HELPREXX, which would display the comments.  It's built around the fact that "sourceline(1)" returns the contents of the first line of the running Rexx, which by our convention contains the name of the file itself.  In the early versions we were parsing the name out and passing just the name to HELPREXX.  Later we realized that it was easier to pass the whole line, centralizing the parsing in HELPREXX itself, and in the current version, all that's needed in each Rexx is:

   if arg(1) = "/?" then exit "HELPREXX"(sourceline(1))

There's one other problem--when invoked, HELPREXX must then discover in which directory the Rexx resides.  In the early version of HELPREXX, we passed the path, but that quickly became very confusing.  That problem was solved with FINDPATH, which looks in each directory in the path till it finds the Rexx, then returns the full path.  This system was developed in OS/2, where the Rexxes had the extension ".cmd" and the Rexx interpreter could be invoked implicitly by typing the filename, if it were in any library in the path.  Other systems have other methods of locating Rexxes (e.g. the Regina_Macros environment variable), and in fact in Regina, "parse source" returns the full path, so FINDPATH wouldn't be needed there.  But what's one more convention?  Add folders containing Rexxes to the path, and HELPREXX/FINDPATH will work!

Well, almost.  As written, FINDPATH won't find a Rexx in a directory whose name is multiple words (like "Program Files").  But that could be fixed.

We fleshed out the system with a KEDIT macro which laid down the boilerplate for a new rexx, prompting for function, syntax and operands, and inserted the HELPREXX invocation.  This made the whole system pretty painless.

More than once, we were really glad the help facility was there to tell us what we'd written.  In addition, each new tool carried its high level documentation out to the users, reducing the number of "Tell me again, how do you..." phone calls.

I hope you find this system useful.  Drop Dr. Rx a line and let me know.  And send some questions for next issue's column!

Dr. Rx <dr_rx@hotmail.com>

/* helprexx.rex - Created 10/22/91 at 09:45:00 by BARKER */
**                                                                       **
** display help information in beginning of rexx.                        **
** Syntax: HELPREXX FILE-ID                                              **
** Operands: FILE-ID: either fn.ext or first line of rexx in std format  **
** Common usage: if arg(1) = "/?" then exit "HELPREXX"(sourceline(1))    **
**                                                                       **
arg fid , path
if fid = "/?" then exit "HELPREXX"(sourceline(1))
if left(fid, 2) = "/*" then parse var fid . fid .     /* parse out file id*/
if path <> "" then fid = path"\"fid                /* add path if supplied*/
else fid = "FINDPATH"(fid)        /* else get path in case not current dir*/
call SHOWHELP                                         /* display help info*/
exit 0

   do forever                                     /* skip down to comments*/
      x = linein(fid)
      if left(x, 2) <> "/*" then leave
   do forever                         /* display lines till end of comment*/
      if left(x,1) = "*" then x = strip(strip(x, , "*"))
      say x
      x = linein(fid)
      if left(x, 2) = "*/" then leave


/* findpath.rex - Created 11/12/91 at 14:20 by BUCK */
/*            Edited 07/23/93 11:52:55 by BUCK */
   find the first occurrence of fid in PATH.
   Syntax: x = "FINDPATH"(fid)
   Returns: drive:\path\fid, "" if not found
arg fid
if fid = "/?" | fid = "" then exit "HELPREXX"(sourceline(1))
parse source . Cmd .
if stream(fid,'c','query exists') <> "" then call OUT fid /* in curr dir? */
/* get path & tokenize: */
path = translate(value("PATH",,"OS2ENVIRONMENT"), " ", ";")
do i = 1 to words(path)
   try = word(path, i)
   if right(try, 1) <> "\" then try = try"\"
   try = try || fid
   if stream(try,'c','query exists') <> "" then call OUT try /* found one */

OUT: procedure expose Cmd        /* display results if cmd, return if fct */
   parse arg Path
   if Cmd = "FUNCTION" then exit Path
   say Path stream(Path,'c','query datetime')