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