mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 05:15:41 +00:00
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:
parent
c933e1c643
commit
516e7fa09c
6 changed files with 83 additions and 119 deletions
|
@ -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 */
|
||||||
|
|
|
@ -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 **);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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[]);
|
||||||
|
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue