[alt.msdos.programmer] Redirecting to/from spawnxx

burleigh@cica.cica.indiana.edu (Frank Burleigh) (07/06/90)

The Subject says pretty well what I want: to redirect the
output from, or input to, a program run from one of the
spawnxx() functions.  Can it be done?

As an example, suppose your program spawned a program that
might need a long list of files and that doesn't in its own
design take a command line option giving a file name of a
file containing those file names.  If one could redirect
such a file into the program, one might avoid rerunning
the spawned program over and over until the list of files
is exhausted.

I'm using TC2/MSC6.

Thanks in advance for any ideas and comments, yea or nea.

-- 
Frank Burleigh  burleigh@cica.cica.indiana.edu
USENET: ...rutgers!iuvax!cica!burleigh BITNET: BURLEIGH@IUBACS.BITNET
Department of Sociology, Indiana University, Bloomington, Indiana 47405

bobmon@iuvax.cs.indiana.edu (RAMontante) (07/06/90)

I believe that spawn...() doesn't start a command shell, which is what you
need to do redirection.  There is another call, system() I think, which
does start a command shell and feeds the arguments to it.  You could use
that.  The arguments should be essentially a command line that is to be
fed to command.com, but I don't have my manuals at hand to check any of this.

Or you could spawn...() a command.com, and build an arg list for it that
does what you need, but the system() call (in TC2.0) does all that for you.

pruss@ria.ccs.uwo.ca (? pruss) (07/07/90)

In article <49978@iuvax.cs.indiana.edu> bobmon@iuvax.cs.indiana.edu (RAMontante) writes:
>I believe that spawn...() doesn't start a command shell, which is what you
>need to do redirection.  There is another call, system() I think, which
>does start a command shell and feeds the arguments to it.  You could use
>that.  The arguments should be essentially a command line that is to be
>fed to command.com, but I don't have my manuals at hand to check any of this.
>
>Or you could spawn...() a command.com, and build an arg list for it that
>does what you need, but the system() call (in TC2.0) does all that for you.

No!  I agree that spawnxx() doesn't start a cmd shell;  however you
do NOT need a command shell to do redirection.  (Anything command.com
can do, in DOS 3+, a C program can do).  While it is true you can start
up command.com and feed correct arguments with '<' '>' or '>>' to it,
it is much simpler to simply redirect thru the redirect DOS call or
the dup2() function.  Below is a demo program that redirects the output
of command.com to a file.  (After arguing about the necessity of command.com,
I think I should have chosen a different program to run, but command.com
is probably the only DOS application that absolutely everyone has--or
4dos--or sh--or whatever).  If you change the spawn line, you can spawn
anything you like.

---TurboC (portable?) source---
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <io.h>
#include <fcntl.h>
/*
 * Demonstrate the use of dup() and dup2() functions to do i/o
 * redirection.  This will run $comspec with output redirected
 * to command.out
 */

#define REDIR_HANDLE  1  /* redirect stdout */

void main(void)
{
 int f_temp, f;
 char *com;
 f_temp=dup(REDIR_HANDLE);   /* REDIR_HANDLE==fileno(stdout);  a fileno() call is more portable */
 f=open("command.out",O_CREAT);
 dup2(f,REDIR_HANDLE);       /* stdout is now command.out */
/* change next 2 lines if you wish */
 com=getenv("COMSPEC");
 spawnl(P_WAIT,com,com,NULL);
/**/
 dup2(f_temp,REDIR_HANDLE);  /* restore old handle */
 close(f);
}
---demo src ends---

trier@cwlim.CWRU.EDU (Stephen C. Trier) (07/07/90)

To understand what the sample program someone has already posted does,
examine the MS-DOS dup(), dup2(), and spawn() calls.

The key to making redirection work is that the spawn() call passes the
currently open stdin, stdout, and stderr handles to its child.  Therefore,
all that a redirection must do is to change those three handles to point
to the proper alternate devices, do the spawn, and change the handles
back.

The first step in doing this is to save the current values of the standard
handles somewhere safe.  This is where dup() comes in.  For example,

    #define STDIN	0
    old_stdin = dup(STDIN);

This code creates a new handle with exactly the same attributes as the
current stdin and stores its number in the variable old_stdin.  Note that
since we're dealing with low-level I/O instead of with C's high-level
functions, all of these calls deal with numerical handles instead of FILE *'s.

    new_stdin = open(filename, O_RDONLY);

This line is straightforward enoguh; note that I'm using open, not C's
freopen, since freopen changes the C stdin file pointer.  It is _not_
guaranteed to change the underlying MS-DOS stdin handle.

    dup2(new_stdin, STDIN);

This is the critical line, the one that actually does the redirection.
It forces handle number STDIN to point to the same file as new_stdin.

    spawnlp("program", ...);

Use whatever version of spawn is needed; they all treat redirection in
the same manner.

    dup2(old_stdin, STDIN);

This dup2 line "undoes" the redirection, returning the MS-DOS stdin handle
to whatever it originally was.

    close(new_stdin);

Don't forget to close the redirected file; otherwise you'll quickly face
the MS-DOS 20-file limit!  :-)

And that's all it takes to do input redirection.  If you want to add output
or error redirection, just add a line with "stdout" or "stderr" for every
line of "stdin" above.  The description seems long, but it's only 7 lines
of C.

There's also a library function to do some I/O redirection, borrowed from
Unix.  It's called popen(), for "pipe open".  popen() allows you to use
the C I/O library (fgets, fputs, and so on) to read or write to a pipe to
a child program.  I found two implementations of popen() in the
comp.sources.misc archives.  I also wrote a simplified version for smail/PC.
I'd be happy to mail copies of the functions; just ask.

#include <stdio.h>

main()
{
    FILE *fp;

    fp = popen("smail sct", "w");
    fprintf(fp, "Hello, world!\n");
    pclose(fp);
}

And presto!  The first program in K&R moves into the e-mail era.

-- 
Stephen Trier                              Case Western Reserve University
Home: sct%seldon@scl.cwru.edu              Information Network Services
Work: trier@cwlim.ins.cwru.edu
                 I do _not_ speak for the University.

silver@xrtll.uucp (Hi Ho Silver) (07/07/90)

In article <49978@iuvax.cs.indiana.edu> bobmon@iuvax.cs.indiana.edu (RAMontante) writes:
$I believe that spawn...() doesn't start a command shell, which is what you
$need to do redirection.  There is another call, system() I think, which
$does start a command shell and feeds the arguments to it.  You could use
$that.  The arguments should be essentially a command line that is to be
$fed to command.com, but I don't have my manuals at hand to check any of this.

   That's one way, yes; do something like system ("command_name < file_name");
The other way is to do the redirection yourself.  I'm not sure of the exact
procedure to do this, but if you look up the functions dup(), dup2() and
freopen(), somewhere you should find the information you need.
-- 
   /Nikebo \ Nikebo says "Nikebo knows how to post.  Just do it."\silver@xrtll/
  /---------\_____________________________________________________\----------/
 /yunexus!xrtll!silver (L, not 1)\ Hi Ho Silver \   just silver for short   /
/Silver:  Ever Searching for SNTF \  Life sucks. \  someone buy me a BEER! /

sjg@sun0.melb.bull.oz.au (Simon J. Gerraty) (07/09/90)

In article <2589@cica.cica.indiana.edu> burleigh@cica.cica.indiana.edu (Frank Burleigh) writes:
> The Subject says pretty well what I want: to redirect the
> output from, or input to, a program run from one of the
> spawnxx() functions.  Can it be done?

Indeed it can.  The process under DOS is:

use dup() to save the current stdin and stdout fd's
open the desired files..
use dup2() to associate the new fd's with stdin etc
do the spawn
close the new stdin etc, (don't forget to flush() stdout).
use dup2() to again associate the old files with stdin etc.
eg.
	ostdin = dup(0);
	fp = fopen(name, "r");
	nstdin = fileno(fp);
	dup2(nstdin, 0);
	...
	spawnxxx(...);
	fclose(fp);
	dup2(ostdin, 0);
	fflush(stdout);
	...
I have removed all the normal error detection for brevity :-)

--
Simon J. Gerraty
sjg@sun0.melb.bull.oz.au - NET
..!{hplabs,mcvax,nttlab,ukc,uunet}!munnari!sun0.melb.bull.oz.au!sjg - UUCP
#include <disclaimer>             /* imagine something *very* witty here */