xref: /reactos/base/shell/cmd/call.c (revision 18acf795)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  *  CALL.C - call internal batch command.
3c2c66affSColin Finck  *
4c2c66affSColin Finck  *
5c2c66affSColin Finck  *  History:
6c2c66affSColin Finck  *
7c2c66affSColin Finck  *    16 Jul 1998 (Hans B Pufal)
8c2c66affSColin Finck  *        started.
9c2c66affSColin Finck  *
10c2c66affSColin Finck  *    16 Jul 1998 (John P Price)
11c2c66affSColin Finck  *        Separated commands into individual files.
12c2c66affSColin Finck  *
13c2c66affSColin Finck  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
14c2c66affSColin Finck  *        added config.h include
15c2c66affSColin Finck  *
16c2c66affSColin Finck  *    04-Aug-1998 (Hans B Pufal)
17c2c66affSColin Finck  *        added lines to initialize for pointers (HBP004)  This fixed the
18c2c66affSColin Finck  *        lock-up that happened sometimes when calling a batch file from
19c2c66affSColin Finck  *        another batch file.
20c2c66affSColin Finck  *
21c2c66affSColin Finck  *    07-Jan-1999 (Eric Kohl)
22c2c66affSColin Finck  *        Added help text ("call /?") and cleaned up.
23c2c66affSColin Finck  *
24c2c66affSColin Finck  *    20-Jan-1999 (Eric Kohl)
25c2c66affSColin Finck  *        Unicode and redirection safe!
26c2c66affSColin Finck  *
27c2c66affSColin Finck  *    02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
28c2c66affSColin Finck  *        Remove all hardcoded strings in En.rc
29c2c66affSColin Finck  */
30c2c66affSColin Finck 
31c2c66affSColin Finck #include "precomp.h"
32c2c66affSColin Finck 
3337bda06eSHermès Bélusca-Maïto /* Enable this define for "buggy" Windows' CMD CALL-command compatibility */
3437bda06eSHermès Bélusca-Maïto #define MSCMD_CALL_QUIRKS
3537bda06eSHermès Bélusca-Maïto 
3637bda06eSHermès Bélusca-Maïto 
37c2c66affSColin Finck /*
38c2c66affSColin Finck  * Perform CALL command.
39c2c66affSColin Finck  */
cmd_call(LPTSTR param)40c2c66affSColin Finck INT cmd_call(LPTSTR param)
41c2c66affSColin Finck {
4237bda06eSHermès Bélusca-Maïto     PARSED_COMMAND* Cmd = NULL;
4337bda06eSHermès Bélusca-Maïto     BOOL bOldIgnoreParserComments;
4437bda06eSHermès Bélusca-Maïto #ifndef MSCMD_CALL_QUIRKS
4537bda06eSHermès Bélusca-Maïto     BOOL bOldHandleContinuations;
4637bda06eSHermès Bélusca-Maïto #else
4737bda06eSHermès Bélusca-Maïto     SIZE_T nNumCarets;
4837bda06eSHermès Bélusca-Maïto #endif
4937bda06eSHermès Bélusca-Maïto     PTSTR first;
50c2c66affSColin Finck 
5137bda06eSHermès Bélusca-Maïto     TRACE("cmd_call(\'%s\')\n", debugstr_aw(param));
5237bda06eSHermès Bélusca-Maïto 
53c2c66affSColin Finck     if (!_tcsncmp(param, _T("/?"), 2))
54c2c66affSColin Finck     {
55c2c66affSColin Finck         ConOutResPaging(TRUE, STRING_CALL_HELP);
56c2c66affSColin Finck         return 0;
57c2c66affSColin Finck     }
58c2c66affSColin Finck 
5937bda06eSHermès Bélusca-Maïto     /* Fail if no command or label has been provided */
6037bda06eSHermès Bélusca-Maïto     if (*param == _T('\0'))
6124ed5344SHermès Bélusca-Maïto         return (nErrorLevel = 1);
62c2c66affSColin Finck 
6337bda06eSHermès Bélusca-Maïto     /* Ignore parser comments (starting with a colon) */
6437bda06eSHermès Bélusca-Maïto     bOldIgnoreParserComments = bIgnoreParserComments;
6537bda06eSHermès Bélusca-Maïto     bIgnoreParserComments = FALSE;
66c2c66affSColin Finck 
6737bda06eSHermès Bélusca-Maïto #ifndef MSCMD_CALL_QUIRKS
6837bda06eSHermès Bélusca-Maïto     /* Disable parsing of escape carets */
6937bda06eSHermès Bélusca-Maïto     bOldHandleContinuations = bHandleContinuations;
7037bda06eSHermès Bélusca-Maïto     bHandleContinuations = FALSE;
7137bda06eSHermès Bélusca-Maïto     first = param;
7237bda06eSHermès Bélusca-Maïto #else
7337bda06eSHermès Bélusca-Maïto     /*
7437bda06eSHermès Bélusca-Maïto      * As the original escape carets have been dealt with during the first
7537bda06eSHermès Bélusca-Maïto      * command parsing step, the remaining ones need to be doubled so that
7637bda06eSHermès Bélusca-Maïto      * they can again survive the new parsing step done below.
7737bda06eSHermès Bélusca-Maïto      * But do it the Windows' CMD "buggy" way: **all** carets are doubled,
7837bda06eSHermès Bélusca-Maïto      * even those inside quotes. However, this causes carets inside quotes
7937bda06eSHermès Bélusca-Maïto      * to remain doubled after the parsing step...
8037bda06eSHermès Bélusca-Maïto      */
8137bda06eSHermès Bélusca-Maïto 
8237bda06eSHermès Bélusca-Maïto     /* Count all the carets */
8337bda06eSHermès Bélusca-Maïto     nNumCarets = 0;
8437bda06eSHermès Bélusca-Maïto     first = param;
8537bda06eSHermès Bélusca-Maïto     while (first)
86c2c66affSColin Finck     {
8737bda06eSHermès Bélusca-Maïto         first = _tcschr(first, _T('^'));
8837bda06eSHermès Bélusca-Maïto         if (first)
8937bda06eSHermès Bélusca-Maïto         {
9037bda06eSHermès Bélusca-Maïto             ++nNumCarets;
9137bda06eSHermès Bélusca-Maïto             ++first;
9237bda06eSHermès Bélusca-Maïto         }
93c2c66affSColin Finck     }
94c2c66affSColin Finck 
9537bda06eSHermès Bélusca-Maïto     /* Re-allocate a large enough parameter string if needed */
9637bda06eSHermès Bélusca-Maïto     if (nNumCarets > 0)
9737bda06eSHermès Bélusca-Maïto     {
9837bda06eSHermès Bélusca-Maïto         PTCHAR Src, Dest, End;
99c2c66affSColin Finck 
10037bda06eSHermès Bélusca-Maïto         // TODO: Improvement: Use the scratch TempBuf if the string is not too long.
10137bda06eSHermès Bélusca-Maïto         first = cmd_alloc((_tcslen(param) + nNumCarets + 1) * sizeof(TCHAR));
10237bda06eSHermès Bélusca-Maïto         if (!first)
10337bda06eSHermès Bélusca-Maïto         {
10437bda06eSHermès Bélusca-Maïto             WARN("Cannot allocate memory for new CALL parameter string!\n");
10537bda06eSHermès Bélusca-Maïto             error_out_of_memory();
10637bda06eSHermès Bélusca-Maïto             return (nErrorLevel = 1);
10737bda06eSHermès Bélusca-Maïto         }
10837bda06eSHermès Bélusca-Maïto 
10937bda06eSHermès Bélusca-Maïto         /* Copy the parameter string and double the escape carets */
11037bda06eSHermès Bélusca-Maïto         Src = param;
11137bda06eSHermès Bélusca-Maïto         Dest = first;
11237bda06eSHermès Bélusca-Maïto         while (*Src)
11337bda06eSHermès Bélusca-Maïto         {
11437bda06eSHermès Bélusca-Maïto             if (*Src != _T('^'))
11537bda06eSHermès Bélusca-Maïto             {
11637bda06eSHermès Bélusca-Maïto                 /* Copy everything before the next caret (or the end of the string) */
11737bda06eSHermès Bélusca-Maïto                 End = _tcschr(Src, _T('^'));
11837bda06eSHermès Bélusca-Maïto                 if (!End)
11937bda06eSHermès Bélusca-Maïto                     End = Src + _tcslen(Src);
12037bda06eSHermès Bélusca-Maïto                 memcpy(Dest, Src, (End - Src) * sizeof(TCHAR));
12137bda06eSHermès Bélusca-Maïto                 Dest += End - Src;
12237bda06eSHermès Bélusca-Maïto                 Src = End;
12337bda06eSHermès Bélusca-Maïto                 continue;
12437bda06eSHermès Bélusca-Maïto             }
12537bda06eSHermès Bélusca-Maïto 
12637bda06eSHermès Bélusca-Maïto             /* Copy the original caret and double it */
12737bda06eSHermès Bélusca-Maïto             *Dest++ = *Src;
12837bda06eSHermès Bélusca-Maïto             *Dest++ = *Src++;
12937bda06eSHermès Bélusca-Maïto         }
13037bda06eSHermès Bélusca-Maïto         *Dest = _T('\0');
13137bda06eSHermès Bélusca-Maïto     }
13237bda06eSHermès Bélusca-Maïto     else
13337bda06eSHermès Bélusca-Maïto     {
13437bda06eSHermès Bélusca-Maïto         first = param;
13537bda06eSHermès Bélusca-Maïto     }
13637bda06eSHermès Bélusca-Maïto #endif
13737bda06eSHermès Bélusca-Maïto 
13837bda06eSHermès Bélusca-Maïto     /*
13937bda06eSHermès Bélusca-Maïto      * Reparse the CALL parameter string as a command.
14037bda06eSHermès Bélusca-Maïto      * Note that this will trigger a second round of %-variable substitutions.
14137bda06eSHermès Bélusca-Maïto      */
14237bda06eSHermès Bélusca-Maïto     Cmd = ParseCommand(first);
14337bda06eSHermès Bélusca-Maïto 
14437bda06eSHermès Bélusca-Maïto     /* Restore the global parsing state */
14537bda06eSHermès Bélusca-Maïto #ifndef MSCMD_CALL_QUIRKS
14637bda06eSHermès Bélusca-Maïto     bHandleContinuations = bOldHandleContinuations;
14737bda06eSHermès Bélusca-Maïto #endif
14837bda06eSHermès Bélusca-Maïto     bIgnoreParserComments = bOldIgnoreParserComments;
14937bda06eSHermès Bélusca-Maïto 
15037bda06eSHermès Bélusca-Maïto     /*
15137bda06eSHermès Bélusca-Maïto      * If no command is there, yet no error occurred, this means that
15237bda06eSHermès Bélusca-Maïto      * a whitespace label was given. Do not consider this as a failure.
15337bda06eSHermès Bélusca-Maïto      */
15437bda06eSHermès Bélusca-Maïto     if (!Cmd && !bParseError)
15537bda06eSHermès Bélusca-Maïto     {
15637bda06eSHermès Bélusca-Maïto #ifdef MSCMD_CALL_QUIRKS
15737bda06eSHermès Bélusca-Maïto         if (first != param)
15837bda06eSHermès Bélusca-Maïto             cmd_free(first);
15937bda06eSHermès Bélusca-Maïto #endif
16037bda06eSHermès Bélusca-Maïto         return (nErrorLevel = 0);
16137bda06eSHermès Bélusca-Maïto     }
16237bda06eSHermès Bélusca-Maïto 
16337bda06eSHermès Bélusca-Maïto     /* Reset bParseError so as to continue running afterwards */
16437bda06eSHermès Bélusca-Maïto     bParseError = FALSE;
16537bda06eSHermès Bélusca-Maïto 
16637bda06eSHermès Bélusca-Maïto     /*
16737bda06eSHermès Bélusca-Maïto      * Otherwise, if no command is there because a parse error occurred,
16837bda06eSHermès Bélusca-Maïto      * or if this an unsupported command: not a standard one, including
16937bda06eSHermès Bélusca-Maïto      * FOR and IF, fail and bail out.
17037bda06eSHermès Bélusca-Maïto      */
17137bda06eSHermès Bélusca-Maïto     if (!Cmd || (Cmd->Type == C_FOR) || (Cmd->Type == C_IF) ||
17237bda06eSHermès Bélusca-Maïto         ((Cmd->Type != C_COMMAND) && (Cmd->Type != C_REM)))
17337bda06eSHermès Bélusca-Maïto     {
174*18acf795SKatayama Hirofumi MZ         ConErrResPrintf(STRING_ERROR_UNEXPECTED, first);
17537bda06eSHermès Bélusca-Maïto 
17637bda06eSHermès Bélusca-Maïto #ifdef MSCMD_CALL_QUIRKS
17737bda06eSHermès Bélusca-Maïto         if (first != param)
17837bda06eSHermès Bélusca-Maïto             cmd_free(first);
17937bda06eSHermès Bélusca-Maïto #endif
18037bda06eSHermès Bélusca-Maïto         if (Cmd) FreeCommand(Cmd);
18137bda06eSHermès Bélusca-Maïto         return (nErrorLevel = 1);
18237bda06eSHermès Bélusca-Maïto     }
18337bda06eSHermès Bélusca-Maïto 
18437bda06eSHermès Bélusca-Maïto #ifdef MSCMD_CALL_QUIRKS
18537bda06eSHermès Bélusca-Maïto     if (first != param)
18637bda06eSHermès Bélusca-Maïto         cmd_free(first);
18737bda06eSHermès Bélusca-Maïto #endif
18837bda06eSHermès Bélusca-Maïto 
18937bda06eSHermès Bélusca-Maïto     first = Cmd->Command.First;
19037bda06eSHermès Bélusca-Maïto     param = Cmd->Command.Rest;
19137bda06eSHermès Bélusca-Maïto 
19237bda06eSHermès Bélusca-Maïto     /* "CALL :label args ..." - Call a subroutine of the current batch file, only if extensions are enabled */
19337bda06eSHermès Bélusca-Maïto     if (bEnableExtensions && (*first == _T(':')))
194c2c66affSColin Finck     {
195d78e8029SHermès Bélusca-Maïto         INT ret;
196d78e8029SHermès Bélusca-Maïto 
19737bda06eSHermès Bélusca-Maïto         /* A batch context must be present */
19837bda06eSHermès Bélusca-Maïto         if (!bc)
19937bda06eSHermès Bélusca-Maïto         {
200*18acf795SKatayama Hirofumi MZ             ConErrResPuts(STRING_ERROR_CALL_BAD_LABEL);
20137bda06eSHermès Bélusca-Maïto             FreeCommand(Cmd);
20237bda06eSHermès Bélusca-Maïto             return (nErrorLevel = 1);
20337bda06eSHermès Bélusca-Maïto         }
204d78e8029SHermès Bélusca-Maïto 
205d78e8029SHermès Bélusca-Maïto         ret = Batch(bc->BatchFilePath, first, param, NULL);
206d78e8029SHermès Bélusca-Maïto         nErrorLevel = (ret != 0 ? ret : nErrorLevel);
20737bda06eSHermès Bélusca-Maïto     }
20837bda06eSHermès Bélusca-Maïto     else
20937bda06eSHermès Bélusca-Maïto     {
21037bda06eSHermès Bélusca-Maïto         nErrorLevel = DoCommand(first, param, NULL);
211c2c66affSColin Finck     }
212c2c66affSColin Finck 
21337bda06eSHermès Bélusca-Maïto     FreeCommand(Cmd);
214c2c66affSColin Finck     return nErrorLevel;
215c2c66affSColin Finck }
216c2c66affSColin Finck 
217c2c66affSColin Finck /* EOF */
218