reactos/base/shell/cmd/call.c
Katayama Hirofumi MZ 18acf79551
[CMD] Prepare for localization by using resource strings (#7125)
Promote localization of cmd.exe.
JIRA issue: CORE-19680
Add some resource strings.
Use them instead of raw strings.
2024-07-11 09:12:12 +09:00

218 lines
5.7 KiB
C

/*
* CALL.C - call internal batch command.
*
*
* History:
*
* 16 Jul 1998 (Hans B Pufal)
* started.
*
* 16 Jul 1998 (John P Price)
* Separated commands into individual files.
*
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* added config.h include
*
* 04-Aug-1998 (Hans B Pufal)
* added lines to initialize for pointers (HBP004) This fixed the
* lock-up that happened sometimes when calling a batch file from
* another batch file.
*
* 07-Jan-1999 (Eric Kohl)
* Added help text ("call /?") and cleaned up.
*
* 20-Jan-1999 (Eric Kohl)
* Unicode and redirection safe!
*
* 02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
* Remove all hardcoded strings in En.rc
*/
#include "precomp.h"
/* Enable this define for "buggy" Windows' CMD CALL-command compatibility */
#define MSCMD_CALL_QUIRKS
/*
* Perform CALL command.
*/
INT cmd_call(LPTSTR param)
{
PARSED_COMMAND* Cmd = NULL;
BOOL bOldIgnoreParserComments;
#ifndef MSCMD_CALL_QUIRKS
BOOL bOldHandleContinuations;
#else
SIZE_T nNumCarets;
#endif
PTSTR first;
TRACE("cmd_call(\'%s\')\n", debugstr_aw(param));
if (!_tcsncmp(param, _T("/?"), 2))
{
ConOutResPaging(TRUE, STRING_CALL_HELP);
return 0;
}
/* Fail if no command or label has been provided */
if (*param == _T('\0'))
return (nErrorLevel = 1);
/* Ignore parser comments (starting with a colon) */
bOldIgnoreParserComments = bIgnoreParserComments;
bIgnoreParserComments = FALSE;
#ifndef MSCMD_CALL_QUIRKS
/* Disable parsing of escape carets */
bOldHandleContinuations = bHandleContinuations;
bHandleContinuations = FALSE;
first = param;
#else
/*
* As the original escape carets have been dealt with during the first
* command parsing step, the remaining ones need to be doubled so that
* they can again survive the new parsing step done below.
* But do it the Windows' CMD "buggy" way: **all** carets are doubled,
* even those inside quotes. However, this causes carets inside quotes
* to remain doubled after the parsing step...
*/
/* Count all the carets */
nNumCarets = 0;
first = param;
while (first)
{
first = _tcschr(first, _T('^'));
if (first)
{
++nNumCarets;
++first;
}
}
/* Re-allocate a large enough parameter string if needed */
if (nNumCarets > 0)
{
PTCHAR Src, Dest, End;
// TODO: Improvement: Use the scratch TempBuf if the string is not too long.
first = cmd_alloc((_tcslen(param) + nNumCarets + 1) * sizeof(TCHAR));
if (!first)
{
WARN("Cannot allocate memory for new CALL parameter string!\n");
error_out_of_memory();
return (nErrorLevel = 1);
}
/* Copy the parameter string and double the escape carets */
Src = param;
Dest = first;
while (*Src)
{
if (*Src != _T('^'))
{
/* Copy everything before the next caret (or the end of the string) */
End = _tcschr(Src, _T('^'));
if (!End)
End = Src + _tcslen(Src);
memcpy(Dest, Src, (End - Src) * sizeof(TCHAR));
Dest += End - Src;
Src = End;
continue;
}
/* Copy the original caret and double it */
*Dest++ = *Src;
*Dest++ = *Src++;
}
*Dest = _T('\0');
}
else
{
first = param;
}
#endif
/*
* Reparse the CALL parameter string as a command.
* Note that this will trigger a second round of %-variable substitutions.
*/
Cmd = ParseCommand(first);
/* Restore the global parsing state */
#ifndef MSCMD_CALL_QUIRKS
bHandleContinuations = bOldHandleContinuations;
#endif
bIgnoreParserComments = bOldIgnoreParserComments;
/*
* If no command is there, yet no error occurred, this means that
* a whitespace label was given. Do not consider this as a failure.
*/
if (!Cmd && !bParseError)
{
#ifdef MSCMD_CALL_QUIRKS
if (first != param)
cmd_free(first);
#endif
return (nErrorLevel = 0);
}
/* Reset bParseError so as to continue running afterwards */
bParseError = FALSE;
/*
* Otherwise, if no command is there because a parse error occurred,
* or if this an unsupported command: not a standard one, including
* FOR and IF, fail and bail out.
*/
if (!Cmd || (Cmd->Type == C_FOR) || (Cmd->Type == C_IF) ||
((Cmd->Type != C_COMMAND) && (Cmd->Type != C_REM)))
{
ConErrResPrintf(STRING_ERROR_UNEXPECTED, first);
#ifdef MSCMD_CALL_QUIRKS
if (first != param)
cmd_free(first);
#endif
if (Cmd) FreeCommand(Cmd);
return (nErrorLevel = 1);
}
#ifdef MSCMD_CALL_QUIRKS
if (first != param)
cmd_free(first);
#endif
first = Cmd->Command.First;
param = Cmd->Command.Rest;
/* "CALL :label args ..." - Call a subroutine of the current batch file, only if extensions are enabled */
if (bEnableExtensions && (*first == _T(':')))
{
INT ret;
/* A batch context must be present */
if (!bc)
{
ConErrResPuts(STRING_ERROR_CALL_BAD_LABEL);
FreeCommand(Cmd);
return (nErrorLevel = 1);
}
ret = Batch(bc->BatchFilePath, first, param, NULL);
nErrorLevel = (ret != 0 ? ret : nErrorLevel);
}
else
{
nErrorLevel = DoCommand(first, param, NULL);
}
FreeCommand(Cmd);
return nErrorLevel;
}
/* EOF */