[mod.computers.vax] Minimal pipe package for DCL programming

carl@CITHEX.CALTECH.EDU (Carl J Lydick) (11/02/86)

The following is a starter kit for those readers of this TC who've always
wanted to use pipes with DCL commands but who don't have the DECshell.
Any criticisms of the programs offered are welcome, as are any utilities
interested readers might write to augment the programs below.

Two annoying deficiencies in VMS (in my opinion) are the unwillingness of
most DCL commands to paginate their output and the fact that there is no
easy way to create a mailbox that will stick around long enough to be useful
to somebody programming in DCL.  Well, I've finally gotten around to writing
a little code to remedy both of these problems, and thought there might
be some readers of this TC who'd like a copy of the results.  Therefore:

The following C program creates a temporary mailbox, then reads a record
from it and exits (note: you DO NOT want to run this program other than
with the SPAWN/NOWAIT command; otherwise it hangs your process):
/*---------------------------------Cut Here-----------------------------------*/
/* USR$SYSTEM:LIFEMBX -- create a mailbox and wait for a write to it          */
/* Copyright (C) 1986, The Caltech Odd Hack Committee, no rights reserved     */
#include <ssdef.h>
#include <iodef.h>
#include <descrip.h>
#include <ctype.h>
main(nargs, args)
int nargs;
char **args;
{  long chan, stat, n;
   long len[2] = { 82, 410 };
   $DESCRIPTOR(devname, "MAILBOX");
   char *ptr;

   if (--nargs > 0)
   {  len[0] = atol(*++args);
      len[1] = 5 * len[0];
      if (--nargs > 0)
      {  ptr = devname.dsc$a_pointer = *++args;
         devname.dsc$w_length = strlen(*args);
         for (n = 0; n < devname.dsc$w_length; ++n, ++ptr)
            if (islower(*ptr))
               *ptr = toupper(*ptr);
         if (--nargs > 0) len[1] = atol(*++args);
      }
   } if ((stat = SYS$CREMBX(0, &chan, len[0], len[1], 0, 0, &devname)
      & 7) != 1) exit(stat);
   if ((stat = SYS$QIOW(0, chan, IO$_READVBLK, len, 0, 0, 0, 0, 0, 0, 0, 0))
      != SS$_NORMAL) exit(stat);
   if ((len[0] &= 0xFFFF) != SS$_BUFFEROVF)
      exit(len[0]);
}
/*---------------------------------Cut Here-----------------------------------*/
Next is a simple DCL procedure to run the above program, assign a (nearly
permanent) DCL channel to the mailbox so created, write to the mailbox so the
subprocess can die, and put the name of the mailbox in the JOB logical name
table (where it will be useful).  It uses the old VMS "feature" that if
you deassign a logical name created with an OPEN command, the channel still
remains open, but you no longer have access to it.  This is to keep you
from accidentally closing the file and deleting the mailbox, thus ensuring
that the mailbox will hang around until the current process dies.

$!---------------------------------Cut Here-------------------------------------
$! USR$SYSTEM:LIFEMBX.COM -- create a semi-permanent mailbox, with an entry for
$!		             it in the job logical name table
$! Copyright (C) 1986, The Caltech Odd Hack Committee, no rights reserved
$	if p1 .eqs. "" then write sys$output -
		"Usage: @lifembx [size] name [size2]"
$	if p1 .eqs. "" then exit
$	if p2 .eqs. "" then p2 = p1
$	if p2 .eqs. p1 then p1 = 132
$	if p3 .eqs. "" then p3 = p1
$	spawn/nowait/nolog mcr usr$system:lifembx 'p1' 'p2' 'p3'
$ wait:	wait 0:0:1.0
$	open/read/write/share=write/err=wait tmpfile 'p2':
$	write tmpfile ""
$	deassign tmpfile
$!---------------------------------Cut Here-------------------------------------

Finally, the procedure to run DCL commands with pagination, using the above
two programs to create a mailbox, running the command with output to the
mailbox, and then using the command TYPE/PAGE to display the results

$!---------------------------------Cut Here-------------------------------------
$! USR$SYSTEM:PAGINATE.COM -- paginate the output of a DCL command
$! Copyright (C) 1986, The Caltech Odd Hack Committee, no rights reserved
$	if f$trnlnm("PAGEPIPE") .eqs. "" then -
$		@USR$SYSTEM:lifembx 132 pagepipe 132
$	if p1 .eqs. "" then exit
$	cmd =  p1+" "+p2+" "+p3+" "+p4+" "+p5+" "+p6+" "+p7+" "+p8
$	cmd = f$edit(cmd, "TRIM")
$	spawn/nowait/output=pagepipe:/input=nl:/nolog/proc=paginate cmd
$	type := type/pag
$	type pagepipe:
$	set noon
$	msg = f$env("MESSAGE")
$	set message/noid/nosev/nofac/notext
$	stop paginate
$	set message'msg'
$ loop:	open/read tmpfile pagepipe:
$	read/time=0/end=done/err=done tmpfile fubar
$	goto loop
$ done:	close tmpfile
$!---------------------------------Cut Here-------------------------------------

The executable from the C program and both procedures should be kept in
the directory USR$SYSTEM.

To avoid having somebody tell me "Yes, that's all very nice, but you could
just redirect output from the command to a disk file, then type the result",
I should point out that these programs don't require that the command complete
before you look at the output, so if you decide from early output that you
want to abort the command, doing it this way can save considerable time.
The first two programs also, of course, open the way for a DCL equivalent
to pipes; hence the naming of the mailbox in the third program.