Category : C Source Code
Archive   : PATCH12.ZIP
Filename : POPEN.C

 
Output of file : POPEN.C contained in archive : PATCH12.ZIP
/* popen/pclose:
*
* simple MS-DOS piping scheme to imitate UNIX pipes
*
* $Log: popen.c,v $
* Revision 1.0.1 90/07/15 14:05:00 aas
* fix assumption of trailing "/" in popen()
*
* Revision 1.0.0 88/08/03 20:08:00 ???
* original distribution: author unknown
* found on simtel20 as pd1:popen.arc
*
*/

#include
#include
#include
#include
#include
#include
#include

#include "popen.h"

extern char *getenv( char * );

#ifndef _NFILE
# define _NFILE OPEN_MAX /* Number of open files */
#endif _NFILE

#define READIT 1 /* Read pipe */
#define WRITEIT 2 /* Write pipe */

static char *prgname[ _NFILE ]; /* program name if write pipe */
static int pipetype[ _NFILE ]; /* 1=read 2=write */
static char *pipename[ _NFILE ]; /* pipe file name */

/*
*------------------------------------------------------------------------
* stoupper: Convert string to uppercase (in place)
*------------------------------------------------------------------------
*/

static void
stoupper( s )
char *s;
{
int c;
for( ; (c = *s) != '\0'; ++s ) {
if( islower( c ) ) *s = _toupper( c );
}
}

/*
*------------------------------------------------------------------------
* strsave: Copy string into malloc'ed memory and return address
*------------------------------------------------------------------------
*/

static char *
strsave( s )
char *s;
{
char *sp = malloc( strlen( s ) + 1 );
if( sp != (char *) NULL ) (void) strcpy( sp, s );
return( sp );
}

/*
*------------------------------------------------------------------------
* strfree: Returm strsave'd string memory
*------------------------------------------------------------------------
*/

static void
strfree( s )
char *s;
{
if( s != (char *) NULL ) free( s );
}

/*
*------------------------------------------------------------------------
* run: Execute command via SHELL or COMSPEC
*------------------------------------------------------------------------
*/

static int
run( command )
char *command;
{
jmp_buf panic; /* How to recover from errors */
int lineno; /* Line number where panic happened */
char *shell; /* Command processor */
char *s = (char *) NULL; /* Holds the command */
int s_is_malloced = 0; /* True if need to free 's' */
static char *command_com = "COMMAND.COM";
int status; /* Return codes */
char *shellpath; /* Full command processor path */
char *bp; /* Generic string pointer */
static char dash_c[ 3 ] = { '?', 'c', '\0' };
if( (lineno = setjmp( panic )) != 0 ) {
int E = errno;
#ifdef DEMO
fprintf( stderr, "RUN panic on line %d: %d\n", lineno, E );
#endif DEMO
if( s_is_malloced && (s != (char *) NULL) ) strfree( s );
errno = E;
return( -1 );
}
if( (s = strsave( command )) == (char *) NULL ) longjmp( panic, __LINE__ );
/* Determine the command processor */
if( ((shell = getenv( "SHELL" )) == (char *) NULL) &&
((shell = getenv( "COMSPEC" )) == (char *) NULL) ) shell = command_com;
stoupper( shell );
shellpath = shell;
/* Strip off any leading backslash directories */
shell = strrchr( shellpath, '\\' );
if( shell != (char *) NULL ) ++shell;
else shell = shellpath;
/* Strip off any leading slash directories */
bp = strrchr( shell, '/' );
if( bp != (char *) NULL ) shell = ++bp;
if( strcmp( shell, command_com ) != 0 ) {
/* MKS Shell needs quoted argument */
char *bp;
if( (bp = s = malloc( strlen( command ) + 3 )) == (char *) NULL )
longjmp( panic, __LINE__ );
*bp++ = '\'';
while( (*bp++ = *command++) != '\0' );
*(bp - 1) = '\'';
*bp = '\0';
s_is_malloced = 1;
} else s = command;
dash_c[ 0 ] = getswitch();
/* Run the program */
#ifdef DEMO
fprintf( stderr, "Running: (%s) %s %s %s\n", shellpath, shell, dash_c, s );
#endif DEMO
status = spawnl( P_WAIT, shellpath, shell, dash_c, s, (char *) NULL );
if( s_is_malloced ) free( s );
return( status );
}

/*
*------------------------------------------------------------------------
* uniquepipe: returns a unique file name
*------------------------------------------------------------------------
*/

static char *
uniquepipe()
{
static char name[ 14 ];
static short int num = 0;
(void) sprintf( name, "pipe%04d.tmp", num++ );
return( name );
}

/*
*------------------------------------------------------------------------
* resetpipe: Private routine to cancel a pipe
*------------------------------------------------------------------------
*/

static void
resetpipe( fd )
int fd;
{
char *bp;
if( (fd >= 0) && (fd < _NFILE) ) {
pipetype[ fd ] = 0;
if( (bp = pipename[ fd ]) != (char *) NULL ) {
(void) unlink( bp );
strfree( bp );
pipename[ fd ] = (char *) NULL;
}
if( (bp = prgname[ fd ]) != (char *) NULL ) {
strfree( bp );
prgname[ fd ] = (char *) NULL;
}
}
}

/*
*------------------------------------------------------------------------
* popen: open a pipe
*------------------------------------------------------------------------
*/

FILE *popen( prg, type )
char *prg; /* The command to be run */
char *type; /* "w" or "r" */
{
FILE *p = (FILE *) NULL; /* Where we open the pipe */
int ostdin; /* Where our stdin is now */
int pipefd = -1; /* fileno( p ) -- for convenience */
char tmpfile[ BUFSIZ ]; /* Holds name of pipe file */
char *tmpdir; /* Points to directory prefix of pipe */
jmp_buf panic; /* Where to go if there's an error */
int lineno; /* Line number where panic happened */
char c; /* aas */
/* Find out where we should put temporary files */
if( (tmpdir = getenv( "TMPDIR" )) == (char *) NULL )
tmpdir = getenv( "TMP" );
if( tmpdir != (char *) NULL ) {
/* Use temporary directory if available */
(void) strcpy( tmpfile, tmpdir );
if((c=tmpfile[strlen(tmpfile)-1])!='/' && c!='\\') /* aas */
(void) strcat( tmpfile, "/" );
} else *tmpfile = '\0';
/* Get a unique pipe file name */
(void) strcat( tmpfile, uniquepipe() );
if( (lineno = setjmp( panic )) != 0 ) {
/* An error has occurred, so clean up */
int E = errno;
#ifdef DEMO
fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
#endif DEMO
if( p != (FILE *) NULL ) (void) fclose( p );
resetpipe( pipefd );
errno = E;
return( (FILE *) NULL );
}
if( strcmp( type, "w" ) == 0 ) {
/* for write style pipe, pclose handles program execution */
if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
pipefd = fileno( p );
pipetype[ pipefd ] = WRITEIT;
pipename[ pipefd ] = strsave( tmpfile );
prgname[ pipefd ] = strsave( prg );
if( !pipename[ pipefd ] || !prgname[ pipefd ] ) longjmp( panic, __LINE__ );
}
} else if( strcmp( type, "r" ) == 0 ) {
/* read pipe must create tmp file, set up stdout to point to the temp
* file, and run the program. note that if the pipe file cannot be
* opened, it'll return a condition indicating pipe failure, which is
* fine.
*/
if( (p = fopen( tmpfile, "w" )) != (FILE *) NULL ) {
int ostdout;
pipefd = fileno( p );
pipetype[ pipefd ]= READIT;
if( (pipename[ pipefd ] = strsave( tmpfile )) == (char *) NULL )
longjmp( panic, __LINE__ );
/* Redirect stdin for the new command */
ostdout = dup( fileno( stdout ) );
if( dup2( fileno( stdout ), pipefd ) < 0 ) {
int E = errno;
(void) dup2( fileno( stdout ), ostdout );
errno = E;
longjmp( panic, __LINE__ );
}
if( run( prg ) != 0 ) longjmp( panic, __LINE__ );
if( dup2( fileno( stdout ), ostdout ) < 0 ) longjmp( panic, __LINE__ );
if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
if( (p = fopen( tmpfile, "r" )) == (FILE *) NULL ) longjmp( panic, __LINE__ );
}
} else {
/* screwy call or unsupported type */
errno = EINVFNC;
longjmp( panic, __LINE__ );
}
return( p );
}

/* close a pipe */

int
pclose( p )
FILE *p;
{
int pipefd = -1; /* Fildes where pipe is opened */
int ostdout; /* Where our stdout points now */
int ostdin; /* Where our stdin points now */
jmp_buf panic; /* Context to return to if error */
int lineno; /* Line number where panic happened */
if( (lineno = setjmp( panic )) != 0 ) {
/* An error has occurred, so clean up and return */
int E = errno;
#ifdef DEMO
fprintf( stderr, "POPEN panic on line %d: %d\n", lineno, E );
#endif DEMO
if( p != (FILE *) NULL ) (void) fclose( p );
resetpipe( pipefd );
errno = E;
return( -1 );
}
pipefd = fileno( p );
if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
switch( pipetype[ pipefd ] ) {
case WRITEIT:
/* open the temp file again as read, redirect stdin from that
* file, run the program, then clean up.
*/
if( (p = fopen( pipename[ pipefd ],"r" )) == (FILE *) NULL )
longjmp( panic, __LINE__ );
ostdin = dup( fileno( stdin ));
if( dup2( fileno( stdin ), fileno( p ) ) < 0 ) longjmp( panic, __LINE__ );
if( run( prgname[ pipefd ] ) != 0 ) longjmp( panic, __LINE__ );
if( dup2( fileno( stdin ), ostdin ) < 0 ) longjmp( panic, __LINE__ );
if( fclose( p ) < 0 ) longjmp( panic, __LINE__ );
resetpipe( pipefd );
break;
case READIT:
/* close the temp file and remove it */
resetpipe( pipefd );
break;
default:
errno = EINVFNC;
longjmp( panic, __LINE__ );
/*NOTREACHED*/
}
return( 0 );
}

#ifdef DEMO
int
main( argc, argv )
int argc;
char **argv;
{
FILE *pipe;
char buf[ BUFSIZ ];
int n;
*buf = '\0';
for( n = 1; n < argc; ++n ) {
(void) strcat( buf, argv[ n ] );
(void) strcat( buf, " " );
}
if( (pipe = popen( buf, "r" )) != (FILE *) NULL ) {
while( fgets( buf, sizeof( buf ), pipe ) != (char *) NULL )
(void) fputs( buf, stdout );
if( pclose( pipe ) != 0 ) fprintf( stderr, "error closing pipe!\n" );
} else fprintf( stderr, "it didn't work!\n" );
exit( 0 );
/*NOTREACHED*/
}
#endif DEMO


  3 Responses to “Category : C Source Code
Archive   : PATCH12.ZIP
Filename : POPEN.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/