[comp.lang.pascal] Redirecting output

derek@sun4dts.dts.ine.philips.nl (derek) (05/03/91)

Horrible! All these solutions of using a shell to redirect output. There
are two dos interrupts that allow filehandles to be duplicated. When
learning (Microsoft) C, I found two library routines dup and dup2 to be
very useful. I dug around abit in the interrupt list etc., and came up
with the following unit. This works in 5.0 and I checked that it complied
under 6.0. However, the dup/dup2 part _should_ work in any pascal with the
appropriate changes to call an interupt. 

Redirec and unredirec allow easy access to dup and dup2 for standard in
and out (input and output are reserved TP words) to a TEXT file that you
have previously opened (reset/rewrite/append as appropriate). It must be
opened - this allocates a file handle (a byte - you declare this, you'll
need it later to get your output back). If you don't unredirec to the 
right handle you could loose all your output to the file or a black hole -
be warned. 

You could make similar procedures to redirec/unredirec for redirection of
other standard handles (3 is printer (LST), 4 I think is STDERR  and 5
is AUX aren't they?)

Here's the unit:
============================= cut here ===================================

{$O+ $F+}

Unit DIREC;

Interface

FUNCTION dup (hand : byte; var error : boolean) : byte;
   { provides a new handle for an already opened device or file.
     If error, then the return is the error code - 4 no handles available or
     6, invalid handle.}

PROCEDURE dup2 (source, destination : byte;  var err : byte);
   { Makes two file handles refer to the same opened file at the same
     location. The destination is closed first.
     Err returns 0 if no error or error code as for dup.
     To redirect then return to normal - do as follows:
     1. Use DUP to save the handle to be directed (the source).
     2. Assign and rewrite/reset the destination.
     3. Redirect the handle using DUP2.
     4. Do the exec
     5. Use dup2 again restoring the saved handle.
     6. reset/rewrite the redirected items & close the destination}

Function Redirec (op : boolean; var f:text; var hand : byte) : boolean;
  {redirects standard out to (if op true) or standard in from file fn.
   returns handle in handle to be used by undirec, below, and true if
   successful.}

Procedure Undirec (op : boolean; hand : byte);
   {undoes the redirection from the previous redirec. Assumes file closed
    by caller.}

{////////////////////////////////////////////////////////////////////////}
Implementation

uses dos;

FUNCTION dup (hand : byte; var error : boolean) : byte;

Var
   regs : registers;

Begin
   with regs do begin
     AH := $45;
     BX := hand;

     Msdos (regs);

     error := flags and fcarry <> 0;  {error if carry set}

     dup := AX;
   end;
End;

PROCEDURE dup2 (source, destination : byte;  var err : byte);

Var
   regs : registers;

Begin
   with regs do begin
     AH := $46;
     BX := source;
     CX := destination ;

     Msdos (regs);

     if flags and fcarry <> 0  {error if carry set}
       then err := AX
       else err := 0;
   end;
End;

Function Redirec (op : boolean; var f:text; var hand : byte) : boolean;
  {redirects standard out to (if op true) or standard in from file fn.
   returns handle in handle to be used by undirec, below, and true if
   successful.}

Var
    err     : byte;
    error   : boolean;

Begin
  redirec := false;
  err := 0;
  if op then
  begin
    flush (output);
    hand := dup (textrec(output).handle, error)
  end
  else
  begin
    flush (input);
    hand := dup (textrec(input).handle, error)
  end;
  if error then
     exit;
  {$i-}
  if op then
     rewrite (f)
  else
     reset (f);
  {$i+}
  if ioresult <> 0 then
     exit;
  if op then
     dup2 (textrec(f).handle, textrec(output).handle,err)
  else
     dup2 (textrec(f).handle, textrec(input).handle,err);
  redirec := (err = 0)
End;

Procedure Undirec (op : boolean; hand : byte);
   {undoes the redirection from the previous redirec. Assumes file closed
    by caller.}

Var
   err : byte;

Begin
   if op then
   begin
	   dup2 (hand, textrec(output).handle, err);
      rewrite (output)
   end
   else
   begin
      dup2 (hand, textrec(input).handle, err);
      reset (input)
   end
end; {undirec}

END.

================================= cut here ===============================

And here is a sippet of code where I redirect the output of an archiver
listing to a temporary file to read back into the program.

  library: {list an archive means go to an archive mode}
    begin
      arcname := nm;
      {temp o/p file}
      assign (ft1, tmpdir + fn1);
      if redirec (op, ft1, handl) then
      begin  {redirect o/p to temp file successful}
        arclines := NIL;
        cmd := arcrec.dircmd + ' ' + nm;
        err := -1;  {don't show shell}
        command (cmd,err);
    {$I-}
        close (ft1);
    {$I+}
        undirec (op, handl);
        {now read in the redirected file}
        get_arc_dir;
      end
    end;

I hope this will find lots of use in your programs.

Best Regards, Derek Carr
DEREK@DTS.INE.PHILIPS.NL           Philips I&E TQV-5 Eindhoven, The Netherlands 
Standard Disclaimers apply.