?? popen.c
字號:
/***
*popen.c - initiate a pipe and a child command
*
* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines _popen() and _pclose().
*
*******************************************************************************/
#include <cruntime.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <process.h>
#include <io.h>
#include <fcntl.h>
#include <internal.h>
#include <errno.h>
#include <msdos.h>
#include <mtdll.h>
#include <oscalls.h>
#include <tchar.h>
#include <dbgint.h>
/* size for pipe buffer
*/
#define PSIZE 1024
#define STDIN 0
#define STDOUT 1
/* definitions for table of stream pointer - process handle pairs. the table
* is created, maintained and accessed by the idtab function. _popen and
* _pclose gain access to table entries only by calling idtab. Note that the
* table is expanded as necessary (by idtab) and free table entries are reused
* (an entry is free if its stream field is NULL), but the table is never
* contracted.
*/
typedef struct {
FILE *stream;
int prochnd;
} IDpair;
/* number of entries in idpairs table
*/
#ifndef _UNICODE
unsigned __idtabsiz = 0;
#else /* _UNICODE */
extern unsigned __idtabsiz;
#endif /* _UNICODE */
/* pointer to first table entry
*/
#ifndef _UNICODE
IDpair *__idpairs = NULL;
#else /* _UNICODE */
extern IDpair *__idpairs;
#endif /* _UNICODE */
/* function to find specified table entries. also, creates and maintains
* the table.
*/
static IDpair * __cdecl idtab(FILE *);
/***
*FILE *_popen(cmdstring,type) - initiate a pipe and a child command
*
*Purpose:
* Creates a pipe and asynchronously executes a child copy of the command
* processor with cmdstring (see system()). If the type string contains
* an 'r', the calling process can read child command's standard output
* via the returned stream. If the type string contains a 'w', the calling
* process can write to the child command's standard input via the
* returned stream.
*
*Entry:
* _TSCHAR *cmdstring - command to be executed
* _TSCHAR *type - string of the form "r|w[b|t]", determines the mode
* of the returned stream (i.e., read-only vs write-only,
* binary vs text mode)
*
*Exit:
* If successful, returns a stream associated with one end of the created
* pipe (the other end of the pipe is associated with either the child
* command's standard input or standard output).
*
* If an error occurs, NULL is returned.
*
*Exceptions:
*
*******************************************************************************/
FILE * __cdecl _tpopen (
const _TSCHAR *cmdstring,
const _TSCHAR *type
)
{
int phdls[2]; /* I/O handles for pipe */
int ph_open[2]; /* flags, set if correspond phdls is open */
int i1; /* index into phdls[] */
int i2; /* index into phdls[] */
int tm = 0; /* flag indicating text or binary mode */
int stdhdl; /* either STDIN or STDOUT */
HANDLE osfhndsv1; /* used to save _osfhnd(stdhdl) */
long osfhndsv2; /* used to save _osfhnd(phdls[i2]) */
char osfilesv1; /* used to save _osfile(stdhdl) */
char osfilesv2; /* used to save _osfile(phdls[i2]) */
HANDLE oldhnd; /* used to hold OS file handle values... */
HANDLE newhnd; /* ...in calls to DuplicateHandle API */
FILE *pstream; /* stream to be associated with pipe */
HANDLE prochnd; /* handle for current process */
_TSCHAR *cmdexe; /* pathname for the command processor */
int childhnd; /* handle for child process (cmd.exe) */
IDpair *locidpair; /* pointer to IDpair table entry */
/* first check for errors in the arguments
*/
if ( (cmdstring == NULL) || (type == NULL) || ((*type != 'w') &&
(*type != _T('r'))) )
goto error1;
/* do the _pipe(). note that neither of the resulting handles will
* be inheritable.
*/
if ( *(type + 1) == _T('t') )
tm = _O_TEXT;
else if ( *(type + 1) == _T('b') )
tm = _O_BINARY;
tm |= _O_NOINHERIT;
if ( _pipe( phdls, PSIZE, tm ) == -1 )
goto error1;
/* test *type and set stdhdl, i1 and i2 accordingly.
*/
if ( *type == _T('w') ) {
stdhdl = STDIN;
i1 = 0;
i2 = 1;
}
else {
stdhdl = STDOUT;
i1 = 1;
i2 = 0;
}
/* the pipe now exists. the following steps must be carried out before
* the child process (cmd.exe) may be spawned:
*
* 1. save a non-inheritable dup of stdhdl
*
* 2. force stdhdl to be a dup of ph[i1]. close both ph[i1] and
* the original OS handle underlying stdhdl
*
* 3. associate a stdio-level stream with ph[i2].
*/
/* set flags to indicate pipe handles are open. note, these are only
* used for error recovery.
*/
ph_open[ 0 ] = ph_open[ 1 ] = 1;
/* get the process handle, it will be needed in some API calls
*/
prochnd = GetCurrentProcess();
/* MULTI-THREAD: ASSERT LOCK ON STDHDL HERE!!!!
*/
_lock_fh( stdhdl );
/* save a non-inheritable copy of stdhdl for later restoration.
*/
oldhnd = (HANDLE)_osfhnd( stdhdl );
if ( (oldhnd == INVALID_HANDLE_VALUE) ||
!DuplicateHandle( prochnd,
oldhnd,
prochnd,
&osfhndsv1,
0L,
FALSE, /* non-inheritable */
DUPLICATE_SAME_ACCESS )
) {
goto error2;
}
osfilesv1 = _osfile( stdhdl );
/* force stdhdl to an inheritable dup of phdls[i1] (i.e., force
* STDIN to the pipe read handle or STDOUT to the pipe write handle)
* and close phdls[i1] (so there won't be a stray open handle on the
* pipe after a _pclose). also, clear ph_open[i1] flag so that error
* recovery won't try to close it again.
*/
if ( !DuplicateHandle( prochnd,
(HANDLE)_osfhnd( phdls[i1] ),
prochnd,
&newhnd,
0L,
TRUE, /* inheritable */
DUPLICATE_SAME_ACCESS )
) {
goto error3;
}
(void)CloseHandle( (HANDLE)_osfhnd(stdhdl) );
_free_osfhnd( stdhdl );
_set_osfhnd( stdhdl, (long)newhnd );
_osfile( stdhdl ) = _osfile( phdls[i1] );
(void)_close( phdls[i1] );
ph_open[ i1 ] = 0;
/* associate a stream with phdls[i2]. note that if there are no
* errors, pstream is the return value to the caller.
*/
if ( (pstream = _tfdopen( phdls[i2], type )) == NULL )
goto error4;
/* MULTI-THREAD: ASSERT LOCK ON IDPAIRS HERE!!!!
*/
_mlock( _POPEN_LOCK );
/* next, set locidpair to a free entry in the idpairs table.
*/
if ( (locidpair = idtab( NULL )) == NULL )
goto error5;
/* temporarily change the osfhnd and osfile entries so that
* the child doesn't get any entries for phdls[i2].
*/
osfhndsv2 = _osfhnd( phdls[i2] );
_osfhnd( phdls[i2] ) = (long)INVALID_HANDLE_VALUE;
osfilesv2 = _osfile( phdls[i2] );
_osfile( phdls[i2] ) = 0;
/* spawn the child copy of cmd.exe. the algorithm is adapted from
* SYSTEM.C, and behaves the same way.
*/
if ( ((cmdexe = _tgetenv(_T("COMSPEC"))) == NULL) ||
(((childhnd = _tspawnl( _P_NOWAIT,
cmdexe,
cmdexe,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -