Contributor: STEPHEN M. OBERHOLTZER

(*
>          Hi, I am trying to write a program the writes to Standard output,
> and reads from Standard input from windows console (win95 dosprmpt, winnt
>  dosprmpt)... so the io can be redirected.  The program must be a windows
> program for the project to work:
>                  Using the program as a script for Microsoft Internet
> Information Server on Winnt 3.51, the web server will not execute dos based stdio
> programs.  I have tried using program script(input,output) which reports file not
> open  for write, I have added rewrite(output) which causes an error because output
not assigned.  I have assigned output to '' which outputs nothing to the
console or the redirected file.
>
>                  If anyone understands my problem, and has an idea or
> solution,
>  please help me.  Thank you.
>
>
Ok, here is the solution to your prob : you need to write a text file device
driver. I just happen to have code. You want the StdOut things, i can't
remember how it works =(
p.s. the file's attached.
(*)

unit SimultIO;
{$D-,F+,R-}
(* Unit for simultaneous I/O.
   This will be useful for redirection - when you write to a
   file assigned to by AssignSimult, data written to it will write to
   the file AND the screen. *)
interface
{$F+} procedure AssignSimult(var f : text;n : string); far; {$F-}
implementation
uses Dos,CRT;
var  R : Registers;
    OP : Text;
{$F+} function WriteByteToFile(FileHandle : Word;var value) : integer;far; {$F-}
var r : registers;
begin
 r.ah := $40;
 r.bx := FileHandle;
 r.cx := 1;
 r.ds := seg(value);
 r.dx := ofs(value);
 MsDos(R);
 if (r.flags and fcarry)<>0 then
  begin
   r.ah := $59; (* Get extended error info *)
   msdos(R);
   WriteByteToFile := r.ax; (* IOResult returns the value in InOutRes *)
  end
 else WriteByteToFile := 0;
end;
(*
            INT 21,40 - Write To File or Device Using Handle
        AH =  40h
        BX =  file handle
        CX =  number of bytes to write, a zero value truncates/extends
             the file to the current file position
        DS:DX =  pointer to write buffer

        on return:
        AX =  number of bytes written if CF not set
           =  error code if CF set  (see DOS ERROR CODES)

        - if AX is not equal to CX on return, a partial write occurred
        - this function can be used to truncate a file to the current
          file position by writing zero bytes                         *)
{$F+} function StdOut(var f: textrec) : integer; far;  {$F-}
var
  p,err : integer;
  r : registers;
begin
 if f.mode=fmclosed then
  begin
   StdOut := 103;
   exit;
  end;
  with F do
   begin
    for P := 0 to bufpos-1 do
     begin
      r.ah := $02;
      r.dl := ord(bufptr^[p]);
      msdos(R);
     end;
   BufPos:=0;
  end;
  StdOut:=0;
end;
{$F+} function SimultWrite(var f: textrec): integer; far;  {$F-}
var
  p,err : integer;
begin
 if f.mode=fmclosed then
  begin
   SimultWrite := 103;
   exit;
  end;
  with F do
   begin
    for P := 0 to bufpos-1 do
     begin
      err := WriteByteToFile(Handle,BufPtr^[p]);
      if err<>0 then
       begin
        SimultWrite := Err;
        BufPos := P+1;
        exit;
       end;
      Write(OP,BufPtr^[p]);
     end;
   BufPos:=0;
  end;
  SimultWrite:=0;
end;
{$F+} function SimultOpen(var f: textrec): integer; far;  {$F-}
var
  P: integer;
begin;
  case F.Mode of
   FMOutput : begin (* Rewrite *)
               if f.name[0]= #0 then
                begin
                F.InOutFunc:= @StdOut;
                F.FlushFunc:= @StdOut;
              end else begin
               r.ah :=  $3C;
               r.cx :=  $0000;
               r.ds :=  Seg(F.Name);
               r.dx :=  Ofs(F.Name);
               MsDos(R);
               if (R.flags and FCarry)<>0 then
                begin
                 R.AH :=  $59;
                 MsDos(R);
                 SimultOpen :=  R.AX;
                 exit;
                end;
               F.Handle :=  r.ax;
               (*
                  INT 21,3C - Create File Using Handle

        AH =  3C
        CX =  file attribute  (see FILE ATTRIBUTES)
        DS:DX =  pointer to ASCIIZ path name

        on return:
        CF =  0 if successful
           =  1 if error
        AX =  files handle if successful
           =  error code if failure  (see DOS ERROR CODES)

        - if file already exists, it is truncated to zero bytes on opening
*)
                F.InOutFunc:= @SimultWrite;
                F.FlushFunc:= @SimultWrite;
               end;
               F.BufPos:= 0;
               SimultOpen:= 0;
              end;
   FMInOut  : begin (* Append *)
               f.mode :=  fmOutput;
               r.ah :=  $3d ;
               r.al :=  $01;
               r.cx :=  $0000;
               r.ds :=  Seg(F.Name);
               r.dx :=  Ofs(F.Name);
               MsDos(R);
               if (R.flags and FCarry)<>0 then
                begin
                 R.AH :=  $59;
                 MsDos(R);
                 SimultOpen :=  R.ax;
                 exit;
                end;
               F.Handle :=  r.ax;
               r.bx :=  r.ax;
               r.al :=  $02;
               R.ah :=  $42;
               r.cx :=  $0000;
               r.dx :=  $0001; (* Seek past EOF *)
               MsDos(R);
               if (r.flags and fcarry)<>0 then
                begin
                 r.ah :=  $59;
                 msdos(R);
                 SimultOpen :=  R.AX;
                 exit;
                end;
               (*
               INT 21,42 - Move File Pointer Using Handle

        AH =  42h
        AL =  origin of move:
             00 =  beginning of file plus offset  (SEEK_SET)
             01 =  current location plus offset  (SEEK_CUR)
             02 =  end of file plus offset  (SEEK_END)
        BX =  file handle
        CX =  high order word of number of bytes to move
        DX =  low order word of number of bytes to move

        on return:
        AX =  error code if CF set  (see DOS ERROR CODES)
        DX:AX =  new pointer location if CF not set

        - seeks to specified location in file
                   INT 21,  - Open File Using Handle
        AH =
        AL =  open access mode
             00  read only
             01  write only
             02  read/write
        DS:DX =  pointer to an ASCIIZ file name
 =

        on return:
        AX =  file handle if CF not set
           =  error code if CF set  (see DOS ERROR CODES)
        Access modes in AL:

        =B37=B36=B35=B34=B33=B32=B31=B30=B3  AL
         =B3 =B3 =B3 =B3 =B3 =C0=C4=C1=C4=C1=C4=C4=C4=C4 read/write/updat=
e access mode
         =B3 =B3 =B3 =B3 =C0=C4=C4=C4=C4=C4=C4=C4=C4=C4 reserved, always =
0
         =B3 =C0=C4=C1=C4=C1=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4 sharing mode (=
see below) (DOS 3.1+)
         =C0=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4=C4 1 =  private, =
0 =  inheritable (DOS 3.1+)
=0D
        Sharing mode bits (DOS 3.1+):          Access mode bits:
        654                                    210
        000  compatibility mode (exclusive)    000  read access
        001  deny others read/write access     001  write access
        010  deny others write access          010  read/write access
        011  deny others read access
        100  full access permitted to all
*)
               F.InOutFunc :=  @SimultWrite;
               F.FlushFunc :=  @SimultWrite;
               F.BufPos:= 0;
               SimultOpen:= 0;
              end;
  else
   SimultOpen :=  12; (* Invalid file access code - you can only Rewrite=
 or Append this *)
  end;
end;

{$F+}function SimultClose(var F: textrec): integer; far;  {$F-}
var
  P: integer;
begin;
 if f.mode= fmclosed then
  begin
   SimultClose :=  103;
   exit;
  end;
(*
                  INT 21,3E - Close File Using Handle

        AH =  3E
        BX =  file handle to close

        on return:
        AX =  error code if CF set  (see DOS ERROR CODES)

        - if file is opened for update, file time and date stamp
          as well as file size are updated in the directory
        - handle is freed
=0D
 *)
  r.ah :=  $3E;
  r.bx :=  f.handle;
  MsDos(R);
  if (R.flags and fcarry)<>0 then
   begin
    r.ah :=  $59;
    MsDos(R);
    SimultClose :=  R.AX;
    exit;
   end;
  F.Mode :=  FMClosed;
  SimultClose:= 0;
end;

{$F+} procedure AssignSimult(var f : text;n : string); {$F-}
begin
  with textrec(f) do begin
    Mode     :=  fmClosed;
    Handle   :=  $FFFF;
    Bufsize  :=  SizeOf(Buffer);
    Bufpos   :=  0;
    Bufptr   :=  @Buffer;
    OpenFunc :=  @SimultOpen;
    CloseFunc:=  @SimultClose;
    if n[0]>#79 then n[0] :=  #79; (* Truncate the name down to 79 chars=
 *)
    Move(N[1],Name[0],79);
    Name[Length(N)] := #0; (* Name is null-terminated *)
  end;
end;
begin
 AssignCRT(OP);
 Rewrite(OP);
end.