From:	SMTP%"groth@pupgg.princeton.edu" 12-SEP-1993 16:44:54.70
To:	EVERHART
CC:	
Subj:	RE: Please, sir?  May I have |more?

From: GROTH@pupgg.princeton.edu (Edward J. Groth   609-258-4361)
X-Newsgroups: comp.os.vms
Subject: RE: Please, sir?  May I have |more?
Message-Id: <1993Sep10.010733.9438@Princeton.EDU>
Date: 10 Sep 93 01:07:33 GMT
Article-I.D.: Princeto.1993Sep10.010733.9438
Sender: news@Princeton.EDU (USENET News System)
Reply-To: groth@pupgg.princeton.edu
Organization: Physics Department, Princeton University
Lines: 434
Originator: news@nimaster
Nntp-Posting-Host: pupgg.princeton.edu
To: Info-VAX@kl.sri.com
X-Gateway-Source-Info: USENET

In article <CD3IB7.Dt4@news.iastate.edu>, gvrod@isuvax.iastate.edu writes:
>>francois@italia.boeing.com (Francois VanSteertegem) writes:
>>
>>   Is there such a thing as |MORE for VMS?  I'd like to use it in conjunction
>                             ^
>>with vms-search. I could do a /output= or redefine sys$output and then
>>type/page the file, but that's awfully cumbersome.
>>   Any suggestions?
>
>oberman@ptavv.llnl.gov replies:
>>An enhanced file viewer, MOST, that does everything MORE (and LESS) do and a
>>few things they don't do is available. I think you can find it on both
>>ftp.spc.edu and cerritos.edu. I think the current version is 3.2.0. It can be
>>made for both Unix and VMS. It's also included as a part of the C-Swing package
>>from one or the other of those sites.
>>
>
>i beleive the main thing that Francois VanSteertegem was asking about
>was the ability to do pipes ("|"). VMS does not do pipes. you could
>create a command file that does a SEARCH/OUTPUT to a temporary file,
>then TYPE/PAGE (or use the MOST utility) the file to display the matches
>and then delete the temporary file before exiting.
>
>---
>rod eldridge   |   iowa state university   |   gvrod@isuvax.iastate.edu
>                      (515) 294-7498             rod@iastate.edu

Well, this is the third answer to this question I've seen, and at
least this one got the part about pipes right!  Here's a pipe for
vms! - Ed

$ ! Pipe emulator for VMS - E. J. Groth,  March, 1989 - Instructions at end.
$ pipe$input = ""
$ pipe$output = ""
$ on control_y then goto PIPE$HANDLE_CONTROL_Y
$ pipe$tmp = "TMP:"		!!!!! REPLACE FOR YOUR SYSTEM !!!!!
$ define/nolog pi sys$input
$ define/nolog po sys$output
$ pipe$pid = f$getjpi("","pid")
$ pipe$cmnd = f$edit("''p1' ''p2' ''p3' ''p4' ''p5' ''p6' ''p7' ''p8'","trim")
$ pipe$do_it_once = 1
$ if pipe$cmnd .nes. "" then goto PIPE$JUMP_IN
$ pipe$do_it_once = 0
$PIPE$MAIN_LOOP:
$ if pipe$do_it_once then exit
$ inquire/nopunct pipe$cmnd "Pipe> "
$PIPE$JUMP_IN:
$ pipe$n_cmds=0
$ pipe$first=1
$PIPE$FIND_FIRST:
$ pipe$cm = f$edit(f$element(pipe$n_cmds,"|",pipe$cmnd),"trim")
$ if pipe$cm .eqs. "|" then goto PIPE$MAIN_LOOP
$ pipe$n_cmds=pipe$n_cmds+1
$ if pipe$cm .eqs. "" then goto PIPE$FIND_FIRST
$PIPE$FIND_NEXT:
$ pipe$cmnext = f$edit(f$element(pipe$n_cmds,"|",pipe$cmnd),"trim")
$ pipe$last = 1
$ if pipe$cmnext .eqs. "|" then goto PIPE$DO_CMND
$ pipe$n_cmds = pipe$n_cmds+1
$ if pipe$cmnext .eqs. "" then goto PIPE$FIND_NEXT
$ pipe$last = 0
$PIPE$DO_CMND:
$ pipe$input = pipe$output
$ if f$search(pipe$input) .eqs. "" then pipe$input = "NLA0:"
$ pipe$output = "''pipe$tmp'pipe_''pipe$pid'_''pipe$n_cmds'.pipe"
$ pipe$sloc = f$locate("/",pipe$cm)
$ pipe$xloc = f$locate(" ",pipe$cm)
$ if pipe$sloc .lt. pipe$xloc then pipe$xloc=pipe$sloc
$ if f$extract(0,1,pipe$cm) .eqs. "@" then goto PIPE$IS_PROC
$ if f$locate("=",pipe$cm) .lt. pipe$xloc then goto PIPE$IS_ASSIGN
$ pipe$cm1 = f$extract(0,pipe$xloc,pipe$cm)
$ pipe$cm2 = f$extract(pipe$xloc,255,pipe$cm)
$ if f$type('pipe$cm1') .eqs. "" then goto PIPE$IS_COMMAND
$ if f$extract(0,1,'pipe$cm1') .nes. "@" then goto PIPE$IS_COMMAND
$ pipe$cm = 'pipe$cm1'+pipe$cm2
$ pipe$sloc = f$locate("/",pipe$cm)
$ pipe$xloc = f$locate(" ",pipe$cm)
$ if pipe$sloc .lt. pipe$xloc then pipe$xloc=pipe$sloc
$ goto PIPE$IS_PROC
$PIPE$IS_COMMAND:
$ if pipe$first
$ then
$   define/user/nolog sys$input sys$command
$ else
$   define/user/nolog sys$input 'pipe$input'
$ endif
$ if .not. pipe$last then define/user/nolog sys$output 'pipe$output'
$ goto PIPE$DO_IT
$PIPE$IS_PROC:
$ define/user/nolog sys$input sys$command
$ deassign/user sys$input
$ if .not. pipe$last
$ then
$   pipe$cm1 = f$extract(0,pipe$xloc,pipe$cm)
$   pipe$cm2 = f$extract(pipe$xloc,255,pipe$cm)
$   pipe$cm = pipe$cm1+"/output="+pipe$output+pipe$cm2
$ endif
$ goto PIPE$DO_IT
$PIPE$IS_ASSIGN:
$ pipe$output = "NLA0:"
$PIPE$DO_IT:
$ on severe_error then continue
$ 'pipe$cm'
$ 
$ if pipe$first
$ then
$   pipe$first = 0
$ else
$   set noon
$   if f$search(pipe$input) .nes. "" then delete/nolog/noconfirm 'pipe$input';*
$   set on
$ endif
$ if pipe$last then goto PIPE$MAIN_LOOP
$ pipe$cm = pipe$cmnext
$ goto PIPE$FIND_NEXT
$PIPE$HANDLE_CONTROL_Y:
$ set noon
$ if f$search(pipe$input) .nes. "" then delete/nolog/noconfirm 'pipe$input';*
$ if f$search(pipe$output) .nes. "" then delete/nolog/noconfirm 'pipe$output';*
$ set on
$ goto PIPE$MAIN_LOOP

                            End of PIPE Procedure
******************************************************************************
                         Beginning of LOOK Procedure
                        
$! procedure to run the TPU editor in READONLY MODIFIABLE mode
$! on a file specified in the command line
$! or the file specified by pipe$input.
$ if p1 .eqs. ""				!Check for command line file
$ then
$   if f$type(pipe$input) .eqs. ""		!Check for running pipe emul
$   then
$     write sys$output "No input file has been specified"
$     exit
$   else
$     if pipe$input .eqs. ""			!Check for pipe input
$     then
$       write sys$output "No input file has been specified"
$       exit
$     else
$       name=pipe$input				!Use pipe input
$     endif
$   endif
$ else
$   name=p1					!Use command line file
$ endif
$ if f$search(name,"") .eqs. "" 		!Does file exist?
$ then
$   write sys$output "File ",name," doesn't exist"
$ else
$   define/user/nolog sys$input sys$command
$   edit := edit/tpu/readonly/modify/nojournal	!Define a local symbol so no
$   edit 'name'					!conflict with user definition
$ endif
$ exit
                        
                            End of LOOK Procedure
*******************************************************************************
                         Beginning of PIPE/LOOK Help
                         
1 Pipe

 Pipe is a pipe emulator for VMS.  That is, you can string together
 a series of commands with the output of one command becoming the
 input to the next command.

 To run the pipe emulator, type pipe.

 You are prompted with Pipe> and you answer with one or more VMS
 commands separated by the character |.  The commands will be run in
 left to right order.  The output of each command (except the last) 
 becomes the input to the next command.  

 The input file for the first command in a pipe is SYS$COMMAND (your
 terminal) and the output file for the last command is SYS$OUTPUT
 (your terminal).

 If the commands in your pipe need to refer to their input or
 output files, they can use pi (pipe input) and po (pipe output). 
 These are logical names.
 
 If you execute command procedures in your pipe and they need to
 refer to the input or output file as symbols (rather than
 logical names), the symbols to use are pipe$input and
 pipe$output.

 To leave the pipe emulator, type EXIT at the Pipe> prompt.

2 Hints_and_Examples

 Most VMS commands expect an explicit specification of the input
 file and either write to the screen or to an explicitly specified
 output file.  This makes them a little hard to use with pipes.  To
 help overcome this problem, the logical names pi and po are
 defined.  pi denotes the input pipe and po denotes the output pipe. 
 So, if you have (as I do) t defined to be a symbol that translates
 to type/page.  You can page your directory listings by giving the
 command 

    dir | t pi

 You can sort them  and page the sorted listing with:

    dir | sort/key=<sort key data> pi po | t pi

 Note that if you want to sort a directory, you should probably use
 dir/columns=1 and specify the width of the name field so it's large
 enough to accommodate the longest file name.

 For something nicer than t pi, see the help topic Look. 
 
 The pipe emulator does not support redirection of input and output. 
 If the first command in your pipe doesn't accept an input file name
 and insists on using the standard input (SYS$INPUT), you can make
 the first command COPY <input file> po.  If the last command won't
 take an output file specification, you can make the last command
 COPY pi <file name>.  To emulate the Unix >> for appending to an
 output file, you can make the last command APPEND pi <file name>.

2 Look

 In place of t pi at the end of a pipe, you can use look. This
 runs the TPU editor on the pipe input and allows you to page
 through long listings, search for particular strings, etc. The
 editor is run in READONLY, MODIFY mode, and it uses your default
 TPU customizations.  The look procedure can also be used in
 "standalone" mode by saying look <file name>.  Thus, to look at
 a file without accidentally modifying it, use 

      look file

 To page through a long directory, use 

      dir | look

2 One-Shot_Mode

 You can run the pipe emulator in a "one-shot" mode from the DCL $
 prompt.  Do this by saying Pipe <pipe commands>.  If <pipe
 commands> contains more than 8 separate tokens, enclose the whole
 line in quotes (").  For example

  pipe "dir/column=1 dev:[dir] | sort/key=... pi po | t pi"

 Note that the pipe characters (|), when separated from the other
 characters by blanks, count as a token.

2 Restrictions

 An interactive command such as EDIT or MAIL must be the only
 command in a pipe.

 If one of your commands is WRITE SYS$OUTPUT <something> or a symbol
 which translates to WRITE SYS$OUTPUT <something>, it can only be
 used alone or as the last command in a pipe.  Otherwise, you will
 get a file not opened by DCL message.  However, it's OK to have
 WRITE SYS$OUTPUT commands in a procedure.

 When you execute a procedure, don't leave any blanks between the
 @ and the procedure name:  @proc is OK, but @ proc is no good. 
 Also, if you define symbols to execute procedures, the same rule
 applies to the symbol translation.  The same is true for symbol
 assignment:  symbol=value is OK, but symbol = value is no good.

 DCL swallows up quotes.  Therefore if you want enter a string
 containing quotes, surround the entire string with quotes and
 represent each internal quote with a double quote ("").

 The pipe emulator is not smart enough to know that a | enclosed in
 quotes should not be used as a command separator.

 A control-Y or an untrapped control-C terminates the pipe, but not
 the pipe emulator.  Type EXIT to leave pipe.

 When you type something at the Pipe> prompt it can be (1) a
 request to run a program (for example the DIRECTORY command runs
 the directory program), (2) a request to run a procedure (starts
 with @), (3) a symbol assignment, (4) a symbol that translates
 to a request to run a program or procedure. The pipe emulator
 tries to determine what kind of object each command is.  If it
 is a program, the input and outputs are redirected as described
 under the main help for pipe.  If it is a procedure, only the
 output is redirected, the input is always the procedure itself. 
 Any output from the previous segment of the pipe is lost.  If it
 is a symbol assignment, there is no redirection at all.  Any
 output from the previous segment is lost and the input to the
 next segment is null.

2 Scratch_Files

 The output of each command in a pipe is saved in a scratch file and
 deleted after the next command in the pipe is finished with it. The
 scratch files are written in a directory pointed to by the logical
 name TMP.  This is the system scratch directory, but you can
 redefine TMP before running pipe in order to put your scratch files
 somewhere else.

                                 End of Help
*******************************************************************************
                      Befinning of Pipe Code Description

Description of pipe emulator code (the code is uncommented to make it go
faster):

First we define symbols for the input and output scratch files (so we don't
get undefined symbol errors if we try to delete them after control-Y), define
what to do on control-Y, define the scratch file directory, and define pi and
po.

Then we put together the command line arguments and decide if we are in one
shot mode or not.

Pipe$cmnd is the entire command string which is broken apart using
f$element.  Pipe$n_cmds tells us which element we're looking for.

The code after PIPE$FIND_FIRST either finds the first non-null command in
the command string or if there is no non-null command, it returns to the
MAIN_LOOP.  The first command is contained in pipe$cm.

The code after PIPE$FIND_NEXT finds the next non-null command or sets the
last flag indicating that the last command in the pipe will be executed.

The code after PIPE$DO_CMND saves the output file from the previous segment (to
be used as the input file for the current segment and then deleted) and
generates a unique file name for the output of the current segment.  Then we
try to figure out what kind of an object we've got.  

We save for later use the location of the first slash or blank in the command.  

If the command starts with @ we go to the procedure part.

Otherwise, if the command has an equals sign before the first slash/blank, it
must be a symbol assignment, so we go to the symbol assignment part.

At this point we have either a regular command or a symbol that translates to a
command or a procedure.  So we separate the command into the part up to the
first blank or slash and the part after (and including) the first blank or
slash.  If the first part is not a symbol, we must have had a regular command
and we go to the command part.  If the first part is a symbol but it's
translation doesn't start with @, we again go to the command part.

At this point, what we're left with is a symbol that translates to @something,
so we construct a new command which is the translation of the symbol followed
by whatever was after the blank or slash.   Then we determine the location of
the earliest blank or slash in the new command and go to the procedure part.

To execute a command, we redirect the input to SYS$COMMAND (if the first
command in the pipe) or a scratch file (if not the first command).  If the
command is not the last in the pipe, we also redirect the output.  Then we go
to the command execution part.

To execute a procedure, we define and then deassign sys$input so that TYPE
SYS$INPUT commands in procedures work properly.  If it's not the last command
in the pipe, we need to redirect the output, but we can't do it with a define! 
Instead, we have to break the command at the first blank or slash and insert
/output=scratch_file_name at that point.  The we go to the command execution
part.

For a symbol assignment, we don't do any redirection.  We do however set the
name that will be used for the input file in the next segment of the pipe to
the null device.

Finally, we execute the command (after setting the error action so if the
command generates an error, we keep going).  The blank line after the command
is intentional.  It is to protect against a command ending with - and the
line after the command being interpreted as a continuation line.

After executing the command, we reset the first flag (if it was the first
command in the pipe) and delete the input file (if it was not the first
command in the pipe).  If it was the last command in the pipe, we go to the
MAIN_LOOP.  Otherwise, we set the command to be executed to the previously
found next command and go to FIND_NEXT to determine if there is another
command in the pipe and to execute the command we still have.

The control-Y handler deletes any scratch files and goes to the MAIN_LOOP.

As noted earlier, the scratch files are written in a directory pointed to
by the logical name TMP. On my system, TMP translates to DISK2:[TMP] which
is a scratch directory on a disk with no quotas and usually plenty of
space.  You might want to pick a different directory or make the directory
user specific on your system. You can do this by changing the definition of
pipe$tmp near the top of the file.

                           End of Code Description
******************************************************************************
                    Beginning of Installation Instructions

Installation:

These procedures will run only on VMS V5.0 and later systems (because they use
the if then else endif constructs).

Put pipe.com somewhere.  Extract the look procedure and put it somewhere 
as look.com.  In SYLOGIN.COM, put the lines 

$ pipe :== @dev:[dir]pipe
$ look*at :== @dev:[dir]look

Put the help above in a help library.

You might want to change the definition of pipe$tmp to something suitable for
your system.  If so, you probably want to change the help on Scratch_Files.
You can also modify pipe.com and look.com to get rid of the if then else endif
constructs which will let you run it on V4 systems.  (I think - it hasn't been
tested on V4 systems to my knowledge.)  Finally, if your users want to use
EDT, you can change the definition of EDIT in look.com


                       End of Installation Instructions
******************************************************************************
                           Beginning of Update Log

Update log:
6-Apr-89 - EJG - to treat commands, procs, assignments, differently.
7-Apr-89 - EJG - to detect assign, = must occur before both /, blank
2-Nov-89 - EJG - added blank line after command - this is to protect
                 against user giving a command like dir - | t pi.
                 The - will make it try to get a continuation line.
                 Now the continuation line is blank.
                 Also changed pipe$file_to_delete to pipe$input
                 and pipe$file_saved to pipe$output for procedures
                 that need to reference the input and output files
                 as symbols rather than logical names.
		 Also added look.com



/----------------------------------------------------------------------\
| Edward J. Groth            | Phone: 609-258-4361                     |
| Physics Dept., Jadwin Hall | Fax:   609-258-6853 <- Changed 1-Feb-93 |
| Princeton University       | SPAN/HEPNET:  PUPGG::GROTH=44117::GROTH |
| Princeton, NJ 08544        | Internet:     groth@pupgg.princeton.edu |
\----------------------------------------------------------------------/

