📄 execnt.c
字号:
long_command[MAXLINE + 9] = 0;
assert( use_bat_file( long_command ) );
free( long_command );
}
#endif
}
// SVA - handle temp dirs with spaces in the path
static const char *getTempDir(void)
{
static char tempPath[_MAX_PATH];
static char *pTempPath=NULL;
if(pTempPath == NULL)
{
char *p;
p = getenv("TEMP");
if(p == NULL)
{
p = getenv("TMP");
}
if(p == NULL)
{
pTempPath = "\\temp";
}
else
{
GetShortPathName(p, tempPath, _MAX_PATH);
pTempPath = tempPath;
}
}
return pTempPath;
}
/*
* execcmd() - launch an async command execution
*/
void
execcmd(
char *string,
void (*func)( void *closure, int status ),
void *closure,
LIST *shell )
{
int pid;
int slot;
int raw_cmd = 0 ;
char *argv_static[ MAXARGC + 1 ]; /* +1 for NULL */
char **argv = argv_static;
char *p;
/* Check to see if we need to hack around the line-length limitation. */
/* Look for a JAMSHELL setting of "%", indicating that the command
* should be invoked directly */
if ( shell && !strcmp(shell->string,"%") && !list_next(shell) )
{
raw_cmd = 1;
shell = 0;
}
if ( !is_win95_defined )
set_is_win95();
/* Find a slot in the running commands table for this one. */
if ( is_win95 )
{
/* only synchronous spans are supported on Windows 95/98 */
slot = 0;
}
else
{
for( slot = 0; slot < MAXJOBS; slot++ )
if( !cmdtab[ slot ].pid )
break;
}
if( slot == MAXJOBS )
{
printf( "no slots for child!\n" );
exit( EXITBAD );
}
if( !cmdtab[ slot ].tempfile )
{
const char *tempdir;
DWORD procID;
tempdir = getTempDir();
// SVA - allocate 64 other just to be safe
cmdtab[ slot ].tempfile = malloc( strlen( tempdir ) + 64 );
procID = GetCurrentProcessId();
sprintf( cmdtab[ slot ].tempfile, "%s\\jam%d-%02d.bat",
tempdir, procID, slot );
}
/* Trim leading, ending white space */
while( isspace( *string ) )
++string;
/* If multi line, or too long, or JAMSHELL is set, write to bat file. */
/* Otherwise, exec directly. */
/* Frankly, if it is a single long line I don't think the */
/* command interpreter will do any better -- it will fail. */
if( shell || !raw_cmd // && use_bat_file( string )
)
{
FILE *f;
/* Write command to bat file. */
f = fopen( cmdtab[ slot ].tempfile, "w" );
fputs( string, f );
fclose( f );
string = cmdtab[ slot ].tempfile;
if( DEBUG_EXECCMD )
{
if (shell)
printf("using user-specified shell: %s", shell->string);
else
printf("Executing through .bat file\n");
}
}
else if( DEBUG_EXECCMD )
{
printf("Executing raw command directly\n");
}
/* Forumulate argv */
/* If shell was defined, be prepared for % and ! subs. */
/* Otherwise, use stock /bin/sh (on unix) or cmd.exe (on NT). */
if( shell )
{
int i;
char jobno[4];
int gotpercent = 0;
sprintf( jobno, "%d", slot + 1 );
for( i = 0; shell && i < MAXARGC; i++, shell = list_next( shell ) )
{
switch( shell->string[0] )
{
case '%': argv[i] = string; gotpercent++; break;
case '!': argv[i] = jobno; break;
default: argv[i] = shell->string;
}
if( DEBUG_EXECCMD )
printf( "argv[%d] = '%s'\n", i, argv[i] );
}
if( !gotpercent )
argv[i++] = string;
argv[i] = 0;
}
else if (raw_cmd)
{
int ignored;
argv = string_to_args(string, &ignored);
}
else
{
/* don't worry, this is ignored on Win95/98, see later.. */
argv[0] = "cmd.exe";
argv[1] = "/Q/C"; /* anything more is non-portable */
argv[2] = string;
argv[3] = 0;
}
/* Catch interrupts whenever commands are running. */
if( !cmdsrunning++ )
istat = signal( SIGINT, onintr );
/* Start the command */
/* on Win95, we only do a synchronous call */
if ( is_win95 )
{
static const char* hard_coded[] =
{
"del", "erase", "copy", "mkdir", "rmdir", "cls", "dir",
"ren", "rename", "move", 0
};
const char** keyword;
int len, spawn = 1;
int result;
for ( keyword = hard_coded; keyword[0]; keyword++ )
{
len = strlen( keyword[0] );
if ( strnicmp( string, keyword[0], len ) == 0 &&
!isalnum(string[len]) )
{
/* this is one of the hard coded symbols, use 'system' to run */
/* them.. except for "del"/"erase" */
if ( keyword - hard_coded < 2 )
result = process_del( string );
else
result = system( string );
spawn = 0;
break;
}
}
if (spawn)
{
char** args;
int num_args;
/* convert the string into an array of arguments */
/* we need to take care of double quotes !! */
args = string_to_args( string, &num_args );
if ( args )
{
#if 0
char** arg;
fprintf( stderr, "%s: ", args[0] );
arg = args+1;
while ( arg[0] )
{
fprintf( stderr, " {%s}", arg[0] );
arg++;
}
fprintf( stderr, "\n" );
#endif
result = spawnvp( P_WAIT, args[0], args );
free_args( args );
}
else
result = 1;
}
func( closure, result ? EXEC_CMD_FAIL : EXEC_CMD_OK );
return;
}
if( DEBUG_EXECCMD )
{
char **argp = argv;
printf("Executing command");
while(*argp != 0)
{
printf(" [%s]", *argp);
argp++;
}
printf("\n");
}
/* the rest is for Windows NT only */
if( ( pid = spawnvp( P_NOWAIT, argv[0], argv ) ) == -1 )
{
perror( "spawn" );
exit( EXITBAD );
}
/* Save the operation for execwait() to find. */
cmdtab[ slot ].pid = pid;
cmdtab[ slot ].func = func;
cmdtab[ slot ].closure = closure;
/* Wait until we're under the limit of concurrent commands. */
/* Don't trust globs.jobs alone. */
while( cmdsrunning >= MAXJOBS || cmdsrunning >= globs.jobs )
if( !execwait() )
break;
if (argv != argv_static)
{
free_args(argv);
}
}
/*
* execwait() - wait and drive at most one execution completion
*/
int
execwait()
{
int i;
int status, w;
int rstat;
/* Handle naive make1() which doesn't know if cmds are running. */
if( !cmdsrunning )
return 0;
if ( is_win95 )
return 0;
/* Pick up process pid and status */
while( ( w = wait( &status ) ) == -1 && errno == EINTR )
;
if( w == -1 )
{
printf( "child process(es) lost!\n" );
perror("wait");
exit( EXITBAD );
}
/* Find the process in the cmdtab. */
for( i = 0; i < MAXJOBS; i++ )
if( w == cmdtab[ i ].pid )
break;
if( i == MAXJOBS )
{
printf( "waif child found!\n" );
exit( EXITBAD );
}
/* Drive the completion */
if( !--cmdsrunning )
signal( SIGINT, istat );
if( intr )
rstat = EXEC_CMD_INTR;
else if( w == -1 || status != 0 )
rstat = EXEC_CMD_FAIL;
else
rstat = EXEC_CMD_OK;
cmdtab[ i ].pid = 0;
// SVA don't leak temp files
if(cmdtab[i].tempfile != NULL)
{
free(cmdtab[i].tempfile);
cmdtab[i].tempfile = NULL;
}
(*cmdtab[ i ].func)( cmdtab[ i ].closure, rstat );
return 1;
}
# if !defined( __BORLANDC__ )
static int
my_wait( int *status )
{
int i, num_active = 0;
DWORD exitcode, waitcode;
static HANDLE *active_handles = 0;
if (!active_handles)
active_handles = (HANDLE *)malloc(globs.jobs * sizeof(HANDLE) );
/* first see if any non-waited-for processes are dead,
* and return if so.
*/
for ( i = 0; i < globs.jobs; i++ ) {
if ( cmdtab[i].pid ) {
if ( GetExitCodeProcess((HANDLE)cmdtab[i].pid, &exitcode) ) {
if ( exitcode == STILL_ACTIVE )
active_handles[num_active++] = (HANDLE)cmdtab[i].pid;
else {
CloseHandle((HANDLE)cmdtab[i].pid);
*status = (int)((exitcode & 0xff) << 8);
return cmdtab[i].pid;
}
}
else
goto FAILED;
}
}
/* if a child exists, wait for it to die */
if ( !num_active ) {
errno = ECHILD;
return -1;
}
waitcode = WaitForMultipleObjects( num_active,
active_handles,
FALSE,
INFINITE );
if ( waitcode != WAIT_FAILED ) {
if ( waitcode >= WAIT_ABANDONED_0
&& waitcode < WAIT_ABANDONED_0 + num_active )
i = waitcode - WAIT_ABANDONED_0;
else
i = waitcode - WAIT_OBJECT_0;
if ( GetExitCodeProcess(active_handles[i], &exitcode) ) {
CloseHandle(active_handles[i]);
*status = (int)((exitcode & 0xff) << 8);
return (int)active_handles[i];
}
}
FAILED:
errno = GetLastError();
return -1;
}
# endif /* !__BORLANDC__ */
# endif /* USE_EXECNT */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -