/* * 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 ) * 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 ) * 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))) { // FIXME: Localize ConErrPrintf(_T("%s was unexpected.\n"), 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) { // FIXME: Localize ConErrPuts(_T("Invalid attempt to call batch label outside of batch script.\n")); 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 */