Rework batch-file processing so that 'call file.bat' doesn't return until the file has finished, allowing constructs like 'call file.bat & somethingelse' to work properly.

svn path=/trunk/; revision=39858
This commit is contained in:
Jeffrey Morlan 2009-03-03 20:06:54 +00:00
parent c933e1c643
commit 516e7fa09c
6 changed files with 83 additions and 119 deletions

View file

@ -171,8 +171,6 @@ VOID ExitBatch (LPTSTR msg)
if (bc != NULL) if (bc != NULL)
{ {
LPBATCH_CONTEXT t = bc;
if (bc->hBatchFile) if (bc->hBatchFile)
{ {
CloseHandle (bc->hBatchFile); CloseHandle (bc->hBatchFile);
@ -192,7 +190,6 @@ VOID ExitBatch (LPTSTR msg)
bEcho = bc->bEcho; bEcho = bc->bEcho;
bc = bc->prev; bc = bc->prev;
cmd_free(t);
} }
if (msg && *msg) if (msg && *msg)
@ -207,8 +204,10 @@ VOID ExitBatch (LPTSTR msg)
* *
*/ */
BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, BOOL forcenew) BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
{ {
BATCH_CONTEXT new;
HANDLE hFile; HANDLE hFile;
SetLastError(0); SetLastError(0);
hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE, NULL,
@ -227,22 +226,7 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, BOOL forcenew)
/* Kill any and all FOR contexts */ /* Kill any and all FOR contexts */
fc = NULL; fc = NULL;
if (bc == NULL || forcenew) if (bc != NULL && Cmd == bc->current)
{
/* No curent batch file, create a new context */
LPBATCH_CONTEXT n = (LPBATCH_CONTEXT)cmd_alloc (sizeof(BATCH_CONTEXT));
if (n == NULL)
{
error_out_of_memory ();
return FALSE;
}
n->prev = bc;
bc = n;
bc->RedirList = NULL;
}
else if (bc->hBatchFile != INVALID_HANDLE_VALUE)
{ {
/* Then we are transferring to another batch */ /* Then we are transferring to another batch */
CloseHandle (bc->hBatchFile); CloseHandle (bc->hBatchFile);
@ -251,6 +235,20 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, BOOL forcenew)
cmd_free (bc->params); cmd_free (bc->params);
if (bc->raw_params) if (bc->raw_params)
cmd_free (bc->raw_params); cmd_free (bc->raw_params);
AddBatchRedirection(&Cmd->Redirections);
}
else
{
/* If a batch file runs another batch file as part of a compound command
* (e.g. "x.bat & somethingelse") then the first file gets terminated. */
if (Cmd != NULL)
ExitBatch(NULL);
/* Create a new context. This function will not
* return until this context has been exited */
new.prev = bc;
bc = &new;
bc->RedirList = NULL;
} }
GetFullPathName(fullname, sizeof(bc->BatchFilePath) / sizeof(TCHAR), bc->BatchFilePath, NULL); GetFullPathName(fullname, sizeof(bc->BatchFilePath) / sizeof(TCHAR), bc->BatchFilePath, NULL);
@ -264,17 +262,42 @@ BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param, BOOL forcenew)
// //
// Allocate enough memory to hold the params and copy them over without modifications // Allocate enough memory to hold the params and copy them over without modifications
// //
bc->raw_params = (TCHAR*) cmd_alloc((_tcslen(param)+1) * sizeof(TCHAR)); bc->raw_params = cmd_dup(param);
if (bc->raw_params != NULL) if (bc->raw_params == NULL)
{
_tcscpy(bc->raw_params,param);
}
else
{ {
error_out_of_memory(); error_out_of_memory();
return FALSE; return FALSE;
} }
/* Check if this is a "CALL :label" */
if (*firstword == _T(':'))
cmd_goto(firstword);
/* If we have created a new context, don't return
* until this batch file has completed. */
while (bc == &new && !bExit)
{
Cmd = ParseCommand(NULL);
if (!Cmd)
continue;
/* JPP 19980807 */
/* Echo batch file line */
if (bEcho && Cmd->Type != C_QUIET)
{
PrintPrompt();
EchoCommand(Cmd);
ConOutChar(_T('\n'));
}
bc->current = Cmd;
ExecuteCommand(Cmd);
if (bEcho && !bIgnoreEcho && Cmd->Type != C_QUIET)
ConOutChar(_T('\n'));
FreeCommand(Cmd);
bIgnoreEcho = FALSE;
}
/* Don't print a newline for this command */ /* Don't print a newline for this command */
bIgnoreEcho = TRUE; bIgnoreEcho = TRUE;
@ -313,50 +336,34 @@ VOID AddBatchRedirection(REDIRECTION **RedirList)
LPTSTR ReadBatchLine () LPTSTR ReadBatchLine ()
{ {
LPTSTR first;
/* No batch */ /* No batch */
if (bc == NULL) if (bc == NULL)
return NULL; return NULL;
TRACE ("ReadBatchLine ()\n"); TRACE ("ReadBatchLine ()\n");
while (1) /* User halt */
if (CheckCtrlBreak (BREAK_BATCHFILE))
{ {
/* User halt */ while (bc)
if (CheckCtrlBreak (BREAK_BATCHFILE))
{
while (bc)
ExitBatch (NULL);
return NULL;
}
/* No batch */
if (bc == NULL)
return NULL;
if (!FileGetString (bc->hBatchFile, textline, sizeof (textline) / sizeof (textline[0]) - 1))
{
TRACE ("ReadBatchLine(): Reached EOF!\n");
/* End of file.... */
ExitBatch (NULL); ExitBatch (NULL);
return NULL;
if (bc == NULL)
return NULL;
continue;
}
TRACE ("ReadBatchLine(): textline: \'%s\'\n", debugstr_aw(textline));
if (textline[_tcslen(textline) - 1] != _T('\n'))
_tcscat(textline, _T("\n"));
first = textline;
break;
} }
return first; if (!FileGetString (bc->hBatchFile, textline, sizeof (textline) / sizeof (textline[0]) - 1))
{
TRACE ("ReadBatchLine(): Reached EOF!\n");
/* End of file.... */
ExitBatch (NULL);
return NULL;
}
TRACE ("ReadBatchLine(): textline: \'%s\'\n", debugstr_aw(textline));
if (textline[_tcslen(textline) - 1] != _T('\n'))
_tcscat(textline, _T("\n"));
return textline;
} }
/* EOF */ /* EOF */

View file

@ -17,6 +17,7 @@ typedef struct tagBATCHCONTEXT
INT shiftlevel; INT shiftlevel;
BOOL bEcho; /* Preserve echo flag across batch calls */ BOOL bEcho; /* Preserve echo flag across batch calls */
REDIRECTION *RedirList; REDIRECTION *RedirList;
PARSED_COMMAND *current;
} BATCH_CONTEXT, *LPBATCH_CONTEXT; } BATCH_CONTEXT, *LPBATCH_CONTEXT;
typedef struct tagFORCONTEXT typedef struct tagFORCONTEXT
@ -45,7 +46,7 @@ extern TCHAR textline[BATCH_BUFFSIZE]; /* Buffer for reading Batch file lines */
LPTSTR FindArg (INT); LPTSTR FindArg (INT);
LPTSTR BatchParams (LPTSTR, LPTSTR); LPTSTR BatchParams (LPTSTR, LPTSTR);
VOID ExitBatch (LPTSTR); VOID ExitBatch (LPTSTR);
BOOL Batch (LPTSTR, LPTSTR, LPTSTR, BOOL); BOOL Batch (LPTSTR, LPTSTR, LPTSTR, PARSED_COMMAND *);
LPTSTR ReadBatchLine(); LPTSTR ReadBatchLine();
VOID AddBatchRedirection(REDIRECTION **); VOID AddBatchRedirection(REDIRECTION **);

View file

@ -42,8 +42,6 @@
INT cmd_call (LPTSTR param) INT cmd_call (LPTSTR param)
{ {
LPBATCH_CONTEXT n = NULL;
TRACE ("cmd_call: (\'%s\')\n", debugstr_aw(param)); TRACE ("cmd_call: (\'%s\')\n", debugstr_aw(param));
if (!_tcsncmp (param, _T("/?"), 2)) if (!_tcsncmp (param, _T("/?"), 2))
{ {
@ -62,39 +60,10 @@ INT cmd_call (LPTSTR param)
while (_istspace(*param)) while (_istspace(*param))
param++; param++;
} }
if (!Batch(bc->BatchFilePath, first, param, TRUE)) return !Batch(bc->BatchFilePath, first, param, NULL);
return 1;
return cmd_goto(first);
} }
nErrorLevel = 0; return !DoCommand(param, NULL);
n = (LPBATCH_CONTEXT)cmd_alloc (sizeof (BATCH_CONTEXT));
if (n == NULL)
{
error_out_of_memory ();
return 1;
}
n->prev = bc;
bc = n;
bc->hBatchFile = INVALID_HANDLE_VALUE;
bc->params = NULL;
bc->shiftlevel = 0;
bc->RedirList = NULL;
ParseCommandLine (param);
/* Wasn't a batch file so remove conext */
if (bc->hBatchFile == INVALID_HANDLE_VALUE)
{
bc = bc->prev;
cmd_free (n);
}
return 0;
} }
/* EOF */ /* EOF */

View file

@ -324,7 +324,7 @@ static BOOL RunFile(LPTSTR filename)
*/ */
static BOOL static BOOL
Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest) Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest, PARSED_COMMAND *Cmd)
{ {
TCHAR *szFullName=NULL; TCHAR *szFullName=NULL;
TCHAR *first = NULL; TCHAR *first = NULL;
@ -470,7 +470,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
if (dot && (!_tcsicmp (dot, _T(".bat")) || !_tcsicmp (dot, _T(".cmd")))) if (dot && (!_tcsicmp (dot, _T(".bat")) || !_tcsicmp (dot, _T(".cmd"))))
{ {
TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest)); TRACE ("[BATCH: %s %s]\n", debugstr_aw(szFullName), debugstr_aw(rest));
Batch (szFullName, first, rest, FALSE); Batch (szFullName, first, rest, Cmd);
} }
else else
{ {
@ -568,7 +568,7 @@ Execute (LPTSTR Full, LPTSTR First, LPTSTR Rest)
*/ */
BOOL BOOL
DoCommand (LPTSTR line) DoCommand (LPTSTR line, PARSED_COMMAND *Cmd)
{ {
TCHAR *com = NULL; /* the first word in the command */ TCHAR *com = NULL; /* the first word in the command */
TCHAR *cp = NULL; TCHAR *cp = NULL;
@ -642,7 +642,7 @@ DoCommand (LPTSTR line)
/* If end of table execute ext cmd */ /* If end of table execute ext cmd */
if (cmdptr->name == NULL) if (cmdptr->name == NULL)
{ {
ret = Execute (line, com, rest); ret = Execute (line, com, rest, Cmd);
break; break;
} }
@ -866,7 +866,6 @@ ExecutePipeline(PARSED_COMMAND *Cmd)
BOOL BOOL
ExecuteCommand(PARSED_COMMAND *Cmd) ExecuteCommand(PARSED_COMMAND *Cmd)
{ {
BOOL bNewBatch = TRUE;
PARSED_COMMAND *Sub; PARSED_COMMAND *Sub;
LPTSTR ExpandedLine; LPTSTR ExpandedLine;
BOOL Success = TRUE; BOOL Success = TRUE;
@ -877,20 +876,14 @@ ExecuteCommand(PARSED_COMMAND *Cmd)
switch (Cmd->Type) switch (Cmd->Type)
{ {
case C_COMMAND: case C_COMMAND:
if(bc)
bNewBatch = FALSE;
ExpandedLine = DoDelayedExpansion(Cmd->Command.CommandLine); ExpandedLine = DoDelayedExpansion(Cmd->Command.CommandLine);
if (!ExpandedLine) if (!ExpandedLine)
{ {
Success = FALSE; Success = FALSE;
break; break;
} }
Success = DoCommand(ExpandedLine); Success = DoCommand(ExpandedLine, Cmd);
cmd_free(ExpandedLine); cmd_free(ExpandedLine);
if(bNewBatch && bc)
AddBatchRedirection(&Cmd->Redirections);
break; break;
case C_QUIET: case C_QUIET:
case C_BLOCK: case C_BLOCK:
@ -1330,7 +1323,7 @@ ReadLine (TCHAR *commandline, BOOL bMore)
LPTSTR ip; LPTSTR ip;
/* if no batch input then... */ /* if no batch input then... */
if (!(ip = ReadBatchLine())) if (bc == NULL)
{ {
if (bNoInteractive) if (bNoInteractive)
{ {
@ -1360,6 +1353,9 @@ ReadLine (TCHAR *commandline, BOOL bMore)
} }
else else
{ {
ip = ReadBatchLine();
if (!ip)
return FALSE;
bIsBatch = TRUE; bIsBatch = TRUE;
} }
@ -1378,17 +1374,8 @@ ProcessInput (BOOL bFlag)
if (!Cmd) if (!Cmd)
continue; continue;
/* JPP 19980807 */
/* Echo batch file line */
if (bIsBatch && bEcho && Cmd->Type != C_QUIET)
{
PrintPrompt ();
EchoCommand(Cmd);
ConOutChar(_T('\n'));
}
ExecuteCommand(Cmd); ExecuteCommand(Cmd);
if (bEcho && !bIgnoreEcho && (!bIsBatch || Cmd->Type != C_QUIET)) if (bEcho && !bIgnoreEcho)
ConOutChar ('\n'); ConOutChar ('\n');
FreeCommand(Cmd); FreeCommand(Cmd);
bIgnoreEcho = FALSE; bIgnoreEcho = FALSE;

View file

@ -104,7 +104,7 @@ VOID AddBreakHandler (VOID);
VOID RemoveBreakHandler (VOID); VOID RemoveBreakHandler (VOID);
BOOL SubstituteForVars(TCHAR *Src, TCHAR *Dest); BOOL SubstituteForVars(TCHAR *Src, TCHAR *Dest);
LPTSTR DoDelayedExpansion(LPTSTR Line); LPTSTR DoDelayedExpansion(LPTSTR Line);
BOOL DoCommand (LPTSTR line); BOOL DoCommand (LPTSTR line, struct _PARSED_COMMAND *Cmd);
BOOL ReadLine(TCHAR *commandline, BOOL bMore); BOOL ReadLine(TCHAR *commandline, BOOL bMore);
int cmd_main (int argc, const TCHAR *argv[]); int cmd_main (int argc, const TCHAR *argv[]);

View file

@ -707,7 +707,7 @@ INT CommandShowCommandsDetail (LPTSTR param)
LPTSTR NewCommand = cmd_alloc((_tcslen(param)+4)*sizeof(TCHAR)); LPTSTR NewCommand = cmd_alloc((_tcslen(param)+4)*sizeof(TCHAR));
_tcscpy(NewCommand, param); _tcscpy(NewCommand, param);
_tcscat(NewCommand, _T(" /?")); _tcscat(NewCommand, _T(" /?"));
DoCommand(NewCommand); DoCommand(NewCommand, NULL);
cmd_free(NewCommand); cmd_free(NewCommand);
} }
/* Else, display detailed commands list */ /* Else, display detailed commands list */