v02i068: UN*X pipes for MSDOS

reynolds at uunet.uu.net reynolds at uunet.uu.net
Sun Mar 6 09:09:36 AEST 1988


Submitted-By: "A. Nonymous" <reynolds at uunet.uu.net@hsvpmi.UUCP>

Archive-Name: msdos-pipes


Comp.sources.misc: Volume 2, Issue 68
Submitted-By: "A. Nonymous" <reynolds at uunet.uu.net@hsvpmi.UUCP>
Archive-Name: msdos-pipes

[I'm not so sure I see the point of this....  ++bsa]

Here is an MS-DOS version of the UN*X popen(3S) routine, inspired
by an  off-the-cuff article from  the net  (no, I don't  have the
reference... :-). It works under  TURBO-C, and is compatible with
the MKS Toolkit (but it works fine without it).

Compile with  the -DDEMO switch  to generate a demo  program used
like this:

	popen command ....

to  run  'command  ...'  from  a read-mode  pipe.  If  the  shell
environment  variable  SHELL  is   set,  that  program  is  used;
otherwise  the  variable  COMSPEC  is  used;  failing  all  that,
COMMAND.COM in the current working directory is used.

Caveat programme...

---------
Tom Reynolds			 voice: (205) 721-1200 x 303
Phoenix microsystems, inc.	 uucp:  ..!uunet!ingr!hsvpmi!reynolds
991 Discovery Drive		
Huntsville, AL 35806	 "First curse the darkness, then light the candle"

   o  /      o  /      o  /      o  /      o  /      o  /      o  /   
---- x ------- x ------- x ------- x ------- x ------- x ------- x ------- 
   o  \      o  \      o  \      o  \      o  \      o  \      o  \   
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	getswitch.c
#	makefile
#	popen.c
#	popen.h
#	turboc.cfg
# This archive created: Wed Mar  2 17:24:28 1988
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'getswitch.c'" '(274 characters)'
if test -f 'getswitch.c'
then
	echo shar: "will not over-write existing file 'getswitch.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'getswitch.c'
	X#include <stdio.h>
	X#include <dos.h>
	X 
	Xstatic	char	SW = 0;		/* DOS switch character, either '-' or '/' */
	X
	Xint
	Xgetswitch()
	X{
	X   if (SW == 0) {
	X      /* get SW using dos call 0x37 */
	X      _AX = 0x3700;
	X      geninterrupt(0x21);
	X      SW = _DL;
	X   }
	X   return( SW & 0xFF );
	X}
SHAR_EOF
if test 274 -ne "`wc -c < 'getswitch.c'`"
then
	echo shar: "error transmitting 'getswitch.c'" '(should have been 274 characters)'
fi
fi
echo shar: "extracting 'makefile'" '(226 characters)'
if test -f 'makefile'
then
	echo shar: "will not over-write existing file 'makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'makefile'
	Xpopen.exe: popen.obj getswitch.obj
	X	cc -epopen popen.obj getswitch.obj
	X
	Xpopen.obj: popen.c
	X	cc -c -DDEMO popen.c
	X
	Xclean:
	X	rm -f *.obj core *.map
	X
	Xclobber: clean
	X	rm -f *.exe install
	X	
	Xinstall:
	X	cc -c popen.c
	X	@echo What next?
SHAR_EOF
if test 226 -ne "`wc -c < 'makefile'`"
then
	echo shar: "error transmitting 'makefile'" '(should have been 226 characters)'
fi
fi
echo shar: "extracting 'popen.c'" '(9895 characters)'
if test -f 'popen.c'
then
	echo shar: "will not over-write existing file 'popen.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'popen.c'
	X/* popen/pclose:
	X *
	X * simple MS-DOS piping scheme to imitate UNIX pipes
	X */
	X
	X#include <stdio.h>
	X#include <ctype.h>
	X#include <alloc.h>
	X#include <string.h>
	X#include <errno.h>
	X#include <setjmp.h>
	X#include <process.h>
	X
	X#include "popen.h"
	X
	Xextern char *getenv( char * );
	X
	X#ifndef	_NFILE
	X# define	_NFILE	OPEN_MAX	/* Number of open files */
	X#endif	_NFILE
	X
	X#define READIT	1			/* Read pipe */
	X#define WRITEIT	2			/* Write pipe */
	X
	Xstatic char *prgname[ _NFILE ];		/* program name if write pipe */
	Xstatic int pipetype[ _NFILE ];		/* 1=read 2=write */
	Xstatic char *pipename[ _NFILE ];	/* pipe file name */
	X
	X/*
	X *------------------------------------------------------------------------
	X * stoupper: Convert string to uppercase (in place)
	X *------------------------------------------------------------------------
	X */
	X
	Xstatic void
	Xstoupper( s )
	Xchar *s;
	X{
	X   int c;
	X   for( ; (c = *s) != '\0'; ++s ) {
	X      if( islower( c ) ) *s = _toupper( c );
	X   }
	X}
	X
	X/*
	X *------------------------------------------------------------------------
	X * strsave: Copy string into malloc'ed memory and return address
	X *------------------------------------------------------------------------
	X */
	X 
	Xstatic char *
	Xstrsave( s )
	Xchar *s;
	X{
	X   char *sp = malloc( strlen( s ) + 1 );
	X   if( sp != (char *) NULL ) (void) strcpy( sp, s );
	X   return( sp );
	X}
	X
	X/*
	X *------------------------------------------------------------------------
	X * strfree: Returm strsave'd string memory
	X *------------------------------------------------------------------------
	X */
	X
	Xstatic void
	Xstrfree( s )
	Xchar *s;
	X{
	X   if( s != (char *) NULL ) free( s );
	X}
	X
	X/*
	X *------------------------------------------------------------------------
	X * run: Execute command via SHELL or COMSPEC
	X *------------------------------------------------------------------------
	X */
	X
	Xstatic int
	Xrun( command )
	Xchar *command;
	X{
	X   jmp_buf panic;			/* How to recover from errors */
	X   int lineno;				/* Line number where panic happened */
	X   char *shell;				/* Command processor */
	X   char *s = (char *) NULL;		/* Holds the command */
	X   int s_is_malloced = 0;		/* True if need to free 's' */
	X   static char *command_com = "COMMAND.COM";
	X   int status;				/* Return codes */
	X   char *shellpath;			/* Full command processor path */
	X   char *bp;				/* Generic string pointer */
	X   static char dash_c[ 3 ] = { '?', 'c', '\0' };
	X   if( (lineno = setjmp( panic )) != 0 ) {
	X      int E = errno;
	X#ifdef	DEMO
	X      fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
	X#endif	DEMO
	X      if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
	X      errno = E;
	X      return( -1 );
	X   }
	X   if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
	X   /* Determine the command processor */
	X   if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
	X       ((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
	X   stoupper( shell );
	X   shellpath = shell;
	X   /* Strip off any leading backslash directories */
	X   shell = strrchr( shellpath, '\\' );
	X   if( shell != (char *) NULL ) ++shell;
	X   else                         shell = shellpath;
	X   /* Strip off any leading slash directories */
	X   bp = strrchr( shell, '/'  );
	X   if( bp != (char *) NULL ) shell = ++bp;
	X   if( strcmp( shell, command_com ) != 0 ) {
	X      /* MKS Shell needs quoted argument */
	X      char *bp;
	X      if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL ) 
	X	 longjmp( panic, __LINE__ );
	X      *bp++ = '\'';
	X      while( (*bp++ = *command++) != '\0' );
	X      *(bp - 1) = '\'';
	X      *bp = '\0';
	X      s_is_malloced = 1;
	X   } else s = command;
	X   dash_c[ 0 ] = getswitch();
	X   /* Run the program */
	X#ifdef	DEMO
	X   fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
	X#endif	DEMO
	X   status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
	X   if( s_is_malloced ) free( s );
	X   return( status );
	X}
	X
	X/* 
	X *------------------------------------------------------------------------
	X * uniquepipe: returns a unique file name 
	X *------------------------------------------------------------------------
	X */
	X
	Xstatic char *
	Xuniquepipe()
	X{ 
	X   static char name[ 14 ];
	X   static short int num = 0;
	X   (void) sprintf( name, "pipe%05d.tmp", num++ );
	X   return( name );
	X}
	X
	X/*
	X *------------------------------------------------------------------------
	X * resetpipe: Private routine to cancel a pipe
	X *------------------------------------------------------------------------
	X */
	X
	Xstatic void
	Xresetpipe( fd )
	Xint fd;
	X{
	X   char *bp;
	X   if( (fd >= 0) && (fd < _NFILE) ) {
	X      pipetype[ fd ] = 0;
	X      if( (bp = pipename[ fd ]) != (char *) NULL ) {
	X	 (void) unlink( bp );
	X	 strfree( bp );
	X	 pipename[ fd ] = (char *) NULL;
	X      }
	X      if( (bp = prgname[ fd ]) != (char *) NULL ) {
	X	 strfree( bp );
	X	 prgname[ fd ] = (char *) NULL;
	X      }
	X   }
	X}
	X
	X/* 
	X *------------------------------------------------------------------------
	X * popen: open a pipe 
	X *------------------------------------------------------------------------
	X */
	X
	XFILE *popen( prg, type )
	Xchar *prg;			/* The command to be run */
	Xchar *type;			/* "w" or "r" */
	X{ 
	X   FILE *p = (FILE *) NULL;	/* Where we open the pipe */
	X   int ostdin;			/* Where our stdin is now */
	X   int pipefd = -1;		/* fileno( p ) -- for convenience */
	X   char tmpfile[ BUFSIZ ];	/* Holds name of pipe file */
	X   char *tmpdir;		/* Points to directory prefix of pipe */
	X   jmp_buf panic;		/* Where to go if there's an error */
	X   int lineno;			/* Line number where panic happened */
	X   /* Find out where we should put temporary files */
	X   if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL ) 
	X      tmpdir = getenv( "TMP" );
	X   if( tmpdir != (char *) NULL ) {
	X      /* Use temporary directory if available */
	X      (void) strcpy( tmpfile, tmpdir );
	X      (void) strcat( tmpfile, "/" );
	X   } else *tmpfile = '\0';
	X   /* Get a unique pipe file name */
	X   (void) strcat( tmpfile, uniquepipe() );
	X   if( (lineno = setjmp( panic )) != 0 ) {
	X      /* An error has occurred, so clean up */
	X      int E = errno;
	X#ifdef	DEMO
	X      fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
	X#endif	DEMO
	X      if( p != (FILE *) NULL ) (void) fclose( p );
	X      resetpipe( pipefd );
	X      errno = E;
	X      return( (FILE *) NULL );
	X   }
	X   if( strcmp( type, "w" ) == 0 ) {
	X      /* for write style pipe, pclose handles program execution */
	X      if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
	X	 pipefd = fileno( p );
	X	 pipetype[ pipefd ] = WRITEIT;
	X	 pipename[ pipefd ] = strsave( tmpfile );
	X	 prgname[ pipefd ]  = strsave( prg );
	X	 if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
	X      }
	X   } else if( strcmp( type, "r" ) == 0 ) {
	X      /* read pipe must create tmp file, set up stdout to point to the temp
	X      * file, and run the program.  note that if the pipe file cannot be
	X      * opened, it'll return a condition indicating pipe failure, which is
	X      * fine.
	X      */
	X      if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
	X	 int ostdout;
	X	 pipefd = fileno( p );
	X	 pipetype[ pipefd ]= READIT;
	X	 if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL ) 
	X	    longjmp( panic, __LINE__ );
	X	 /* Redirect stdin for the new command */
	X	 ostdout = dup( fileno( stdout ) );
	X	 if( dup2( fileno( stdout ), pipefd ) < 0 ) {
	X	    int E = errno;
	X	    (void) dup2( fileno( stdout ), ostdout );
	X	    errno = E;
	X	    longjmp( panic, __LINE__ );
	X	 }
	X	 if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
	X	 if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
	X	 if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
	X	 if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
	X      }
	X   } else {
	X      /* screwy call or unsupported type */
	X      errno = EINVFNC;
	X      longjmp( panic, __LINE__ );
	X   }
	X   return( p );
	X}
	X
	X/* close a pipe */
	X
	Xint
	Xpclose( p )
	XFILE *p;
	X{
	X   int pipefd = -1;		/* Fildes where pipe is opened */
	X   int ostdout;			/* Where our stdout points now */
	X   int ostdin;			/* Where our stdin points now */
	X   jmp_buf panic;		/* Context to return to if error */
	X   int lineno;			/* Line number where panic happened */
	X   if( (lineno = setjmp( panic )) != 0 ) {
	X      /* An error has occurred, so clean up and return */
	X      int E = errno;
	X#ifdef	DEMO
	X      fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
	X#endif	DEMO
	X      if( p != (FILE *) NULL ) (void) fclose( p );
	X      resetpipe( pipefd );
	X      errno = E;
	X      return( -1 );
	X   }
	X   pipefd = fileno( p );
	X   if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
	X   switch( pipetype[ pipefd ] ) {
	X      case WRITEIT:
	X	 /* open the temp file again as read, redirect stdin from that
	X	  * file, run the program, then clean up.
	X	  */
	X      if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL ) 
	X	 longjmp( panic, __LINE__ );
	X      ostdin = dup( fileno( stdin ));
	X      if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
	X      if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
	X      if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
	X      if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
	X      resetpipe( pipefd );
	X      break;
	X   case READIT:
	X      /* close the temp file and remove it */
	X      resetpipe( pipefd );
	X      break;
	X   default:
	X      errno = EINVFNC;
	X      longjmp( panic, __LINE__ );
	X      /*NOTREACHED*/
	X   }
	X   return( 0 );
	X}
	X
	X#ifdef	DEMO
	Xint
	Xmain( argc, argv )
	Xint argc;
	Xchar **argv;
	X{
	X   FILE *pipe;
	X   char buf[ BUFSIZ ];
	X   int n;
	X   *buf = '\0';
	X   for( n = 1; n < argc; ++n ) {
	X      (void) strcat( buf, argv[ n ] );
	X      (void) strcat( buf, " " );
	X   }
	X   if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
	X      while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL ) 
	X	 (void) fputs( buf, stdout );
	X      if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
	X   } else fprintf( stderr, "it didn't work!\n" );
	X   exit( 0 );
	X   /*NOTREACHED*/
	X}
	X#endif	DEMO
SHAR_EOF
if test 9895 -ne "`wc -c < 'popen.c'`"
then
	echo shar: "error transmitting 'popen.c'" '(should have been 9895 characters)'
fi
fi
echo shar: "extracting 'popen.h'" '(67 characters)'
if test -f 'popen.h'
then
	echo shar: "will not over-write existing file 'popen.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'popen.h'
	Xextern FILE *popen( char *, char * );
	Xextern int pclose( FILE * );
SHAR_EOF
if test 67 -ne "`wc -c < 'popen.h'`"
then
	echo shar: "error transmitting 'popen.h'" '(should have been 67 characters)'
fi
fi
echo shar: "extracting 'turboc.cfg'" '(76 characters)'
if test -f 'turboc.cfg'
then
	echo shar: "will not over-write existing file 'turboc.cfg'"
else
sed 's/^	X//' << \SHAR_EOF > 'turboc.cfg'
	X-LC:\TURBOC\LIB -IC:\TURBOC\INCLUDE -IC:\TURBOC\INCLUDE\SYS -ms -DTURBOC -M
SHAR_EOF
if test 76 -ne "`wc -c < 'turboc.cfg'`"
then
	echo shar: "error transmitting 'turboc.cfg'" '(should have been 76 characters)'
fi
fi
exit 0
#	End of shell archive



More information about the Comp.sources.misc mailing list