reactos/base/shell/cmd/cmd.h
Hermès Bélusca-Maïto 37bda06eed
[CMD] CALL: Fix the implementation of the CALL command, make it more compatible with Windows' CMD.
- Fail if no parameter is provided.

- The "CALL :label args..." syntax is available only when command extensions
  are enabled. Fail if this syntax is used outside of a batch context.

- Reparse the CALL command parameter with the command parser, in order
  to accurately parse and interpret it as a possible command (including
  escape carets, etc...) and not duplicate the logic.
  ** CURRENT Windows' CMD-compatibility LIMITATION ** (may be lifted in
  a "ROS-specific" running mode of CMD): only allow standard commands to
  be specified as parameter of the CALL command.

  This reparsing behaviour can be observed in Windows' CMD, by dumping
  the interpreted commands after enabling the cmd!fDumpParse flag from
  a debugger (using public symbols).

- When reparsing, we should tell the parser to NOT ignore lines that
  start with a colon, because in this situation these are to be
  considered as valid "commands" (for parsing "CALL :label").

  * For Windows' CMD-compatibility, the remaining escape carets need to
    be doubled again so that, after the new parser step, they are escaped
    back to their original form. But then we also need to do it the "buggy"
    way à la Windows, where carets in quotes are doubled either! However
    when being re-parsed, since they are in quotes they remain doubled!!
    (see "Phase 6" in https://stackoverflow.com/a/4095133/13530036 ).

  * A MSCMD_CALL_QUIRKS define allows to disable this buggy behaviour,
    and instead tell the parser to not not interpret the escape carets.

- When initializing a new batch context when the "CALL :label" syntax is
  used, ensure that we reuse the same batch file position pointer as its
  parent, so as to have correct call label ordering behaviour.

  That is,

  :label
  ECHO hi
  CALL :label
  :label
  ECHO bye

  should display:

  hi
  bye
  bye

  i.e., the CALL calls the second label instead of the first one (and
  thus entering into an infinite loop).

  Finally, the "CALL :label" syntax strips the first ':' away, so, as a
  side-effect, the command "CALL :EOF" fails (otherwise it would perform
  a "GOTO :EOF" and succeeds), while "CALL ::EOF" succeeds.

Fixes some cmd_winetests.
2020-09-27 19:05:23 +02:00

518 lines
11 KiB
C

/*
* CMD.H - header file for the modules in CMD.EXE
*
*
* History:
*
* 7-15-95 Tim Norman
* started
*
* 06/29/98 (Rob Lake)
* Moved error messages in here
*
* 07/12/98 (Rob Lake)
* Moved more error messages here.
*
* 30-Jul-1998 (John P Price <linux-guru@gcfl.net>)
* Added compile date to version.
*
* 26-Feb-1999 (Eric Kohl)
* Introduced a new version string.
* Thanks to Emanuele Aliberti!
*/
#pragma once
#include <config.h>
#include "cmdver.h"
#include "cmddbg.h"
/* Version of the Command Extensions */
#define CMDEXTVERSION 2
#define BREAK_BATCHFILE 1
#define BREAK_OUTOFBATCH 2 /* aka. BREAK_ENDOFBATCHFILES */
#define BREAK_INPUT 3
#define BREAK_IGNORE 4
/* define some error messages */
#define D_ON _T("on")
#define D_OFF _T("off")
/* command line buffer length */
#define CMDLINE_LENGTH 8192
/* 16k = max buffer size */
#define BUFF_SIZE 16384
/* Global variables */
extern LPTSTR lpOriginalEnvironment;
extern WORD wColor;
extern WORD wDefColor;
extern BOOL bCtrlBreak;
extern BOOL bIgnoreEcho;
extern BOOL bExit;
extern BOOL bDisableBatchEcho;
extern BOOL bEnableExtensions;
extern BOOL bDelayedExpansion;
extern INT nErrorLevel;
/* Prototypes for ALIAS.C */
VOID ExpandAlias (LPTSTR, INT);
INT CommandAlias (LPTSTR);
/* Prototypes for ASSOC.C */
INT CommandAssoc (LPTSTR);
/* Prototypes for BEEP.C */
INT cmd_beep (LPTSTR);
/* Prototypes for CALL.C */
INT cmd_call (LPTSTR);
/* Prototypes for CHOICE.C */
INT CommandChoice (LPTSTR);
/* Prototypes for CLS.C */
INT cmd_cls (LPTSTR);
/* Prototypes for CMD.C */
INT ConvertULargeInteger(ULONGLONG num, LPTSTR des, UINT len, BOOL bPutSeparator);
HANDLE RunFile(DWORD, LPTSTR, LPTSTR, LPTSTR, INT);
INT ParseCommandLine(LPTSTR);
struct _PARSED_COMMAND;
INT
ExecuteCommand(
IN struct _PARSED_COMMAND *Cmd);
INT
ExecuteCommandWithEcho(
IN struct _PARSED_COMMAND *Cmd);
LPCTSTR GetEnvVarOrSpecial ( LPCTSTR varName );
VOID AddBreakHandler (VOID);
VOID RemoveBreakHandler (VOID);
BOOL
SubstituteVar(
IN PCTSTR Src,
OUT size_t* SrcIncLen, // VarNameLen
OUT PTCHAR Dest,
IN PTCHAR DestEnd,
OUT size_t* DestIncLen,
IN TCHAR Delim);
BOOL
SubstituteVars(
IN PCTSTR Src,
OUT PTSTR Dest,
IN TCHAR Delim);
BOOL
SubstituteForVars(
IN PCTSTR Src,
OUT PTSTR Dest);
PTSTR
DoDelayedExpansion(
IN PCTSTR Line);
INT DoCommand(LPTSTR first, LPTSTR rest, struct _PARSED_COMMAND *Cmd);
BOOL ReadLine(TCHAR *commandline, BOOL bMore);
extern HANDLE CMD_ModuleHandle;
/* Prototypes for CMDINPUT.C */
BOOL ReadCommand (LPTSTR, INT);
extern TCHAR AutoCompletionChar;
extern TCHAR PathCompletionChar;
#define IS_COMPLETION_DISABLED(CompletionCtrl) \
((CompletionCtrl) == 0x00 || (CompletionCtrl) == 0x0D || (CompletionCtrl) >= 0x20)
/* Prototypes for CMDTABLE.C */
#define CMD_SPECIAL 1
#define CMD_BATCHONLY 2
#define CMD_HIDE 4
typedef struct tagCOMMAND
{
LPTSTR name;
INT flags;
INT (*func)(LPTSTR);
} COMMAND, *LPCOMMAND;
extern COMMAND cmds[]; /* The internal command table */
VOID PrintCommandList (VOID);
LPCTSTR GetParsedEnvVar ( LPCTSTR varName, UINT* varNameLen, BOOL ModeSetA );
/* Prototypes for CTTY.C */
#ifdef INCLUDE_CMD_CTTY
INT cmd_ctty(LPTSTR);
#endif
/* Prototypes for COLOR.C */
INT CommandColor(LPTSTR);
/* Prototypes for CONSOLE.C */
#include "console.h"
/* Prototypes for COPY.C */
INT cmd_copy (LPTSTR);
/* Prototypes for DATE.C */
INT cmd_date (LPTSTR);
/* Prototypes for DEL.C */
INT CommandDelete (LPTSTR);
/* Prototypes for DELAY.C */
INT CommandDelay (LPTSTR);
/* Prototypes for DIR.C */
INT FormatDate (TCHAR *, LPSYSTEMTIME, BOOL);
INT FormatTime (TCHAR *, LPSYSTEMTIME);
INT CommandDir (LPTSTR);
/* Prototypes for DIRSTACK.C */
VOID InitDirectoryStack (VOID);
VOID DestroyDirectoryStack (VOID);
INT GetDirectoryStackDepth (VOID);
INT CommandPushd (LPTSTR);
INT CommandPopd (LPTSTR);
INT CommandDirs (LPTSTR);
/* Prototypes for ECHO.C */
BOOL OnOffCommand(LPTSTR param, LPBOOL flag, INT message);
INT CommandEcho (LPTSTR);
INT CommandEchos (LPTSTR);
INT CommandEchoerr (LPTSTR);
INT CommandEchoserr (LPTSTR);
/* Prototypes for ERROR.C */
VOID
ErrorMessage(
IN DWORD dwErrorCode,
IN PCTSTR szFormat OPTIONAL,
...);
VOID error_no_pipe(VOID);
VOID error_bad_command(PCTSTR s);
VOID error_invalid_drive(VOID);
VOID error_req_param_missing(VOID);
VOID error_sfile_not_found(PCTSTR s);
VOID error_file_not_found(VOID);
VOID error_path_not_found(VOID);
VOID error_too_many_parameters(PCTSTR s);
VOID error_parameter_format(TCHAR ch);
VOID error_invalid_switch(TCHAR ch);
VOID error_invalid_parameter_format(PCTSTR s);
VOID error_out_of_memory(VOID);
VOID error_syntax(PCTSTR s);
VOID msg_pause(VOID);
/* Prototypes for FILECOMP.C */
#ifdef FEATURE_UNIX_FILENAME_COMPLETION
VOID CompleteFilename (LPTSTR, UINT);
INT ShowCompletionMatches (LPTSTR, INT);
#endif
#ifdef FEATURE_4NT_FILENAME_COMPLETION
VOID CompleteFilename (LPTSTR, BOOL, LPTSTR, UINT);
#endif
/* Prototypes for FOR.C */
#define FOR_DIRS 1 /* /D */
#define FOR_F 2 /* /F */
#define FOR_LOOP 4 /* /L */
#define FOR_RECURSIVE 8 /* /R */
INT cmd_for (LPTSTR);
INT ExecuteFor(struct _PARSED_COMMAND *Cmd);
/* Prototypes for FREE.C */
INT CommandFree (LPTSTR);
/* Prototypes for GOTO.C */
INT cmd_goto (LPTSTR);
/* Prototypes for HISTORY.C */
#ifdef FEATURE_HISTORY
LPCTSTR PeekHistory(INT);
VOID History(INT, LPTSTR);/*add entries browse history*/
VOID History_move_to_bottom(VOID);/*F3*/
VOID InitHistory(VOID);
VOID CleanHistory(VOID);
VOID History_del_current_entry(LPTSTR str);/*CTRL-D*/
INT CommandHistory(LPTSTR param);
#endif
/* Prototypes for IF.C */
#define IFFLAG_NEGATE 1 /* NOT */
#define IFFLAG_IGNORECASE 2 /* /I - Extended */
typedef enum _IF_OPERATOR
{
/** Unary operators **/
/* Standard */
IF_ERRORLEVEL, IF_EXIST,
/* Extended */
IF_CMDEXTVERSION, IF_DEFINED,
/** Binary operators **/
/* Standard */
IF_STRINGEQ, /* == */
/* Extended */
IF_EQU, IF_NEQ, IF_LSS, IF_LEQ, IF_GTR, IF_GEQ
} IF_OPERATOR;
INT ExecuteIf(struct _PARSED_COMMAND *Cmd);
/* Prototypes for INTERNAL.C */
VOID InitLastPath (VOID);
VOID FreeLastPath (VOID);
INT cmd_chdir (LPTSTR);
INT cmd_mkdir (LPTSTR);
INT cmd_rmdir (LPTSTR);
INT CommandExit (LPTSTR);
INT CommandRem (LPTSTR);
INT CommandShowCommands (LPTSTR);
/* Prototypes for LOCALE.C */
extern TCHAR cDateSeparator;
extern INT nDateFormat;
extern TCHAR cTimeSeparator;
extern INT nTimeFormat;
extern TCHAR cThousandSeparator;
extern TCHAR cDecimalSeparator;
extern INT nNumberGroups;
VOID InitLocale (VOID);
LPTSTR GetDateString (VOID);
LPTSTR GetTimeString (VOID);
/* Prototypes for MEMORY.C */
INT CommandMemory (LPTSTR);
/* Prototypes for MKLINK.C */
INT cmd_mklink(LPTSTR);
/* Prototypes for MISC.C */
INT
GetRootPath(
IN LPCTSTR InPath,
OUT LPTSTR OutPath,
IN INT size);
BOOL SetRootPath(TCHAR *oldpath,TCHAR *InPath);
TCHAR cgetchar (VOID);
BOOL CheckCtrlBreak (INT);
BOOL add_entry (LPINT ac, LPTSTR **arg, LPCTSTR entry);
LPTSTR *split (LPTSTR, LPINT, BOOL, BOOL);
LPTSTR *splitspace (LPTSTR, LPINT);
VOID freep (LPTSTR *);
LPTSTR _stpcpy (LPTSTR, LPCTSTR);
VOID StripQuotes(LPTSTR);
BOOL IsValidPathName(IN LPCTSTR pszPath);
BOOL IsExistingFile(IN LPCTSTR pszPath);
BOOL IsExistingDirectory(IN LPCTSTR pszPath);
VOID GetPathCase(TCHAR *, TCHAR *);
#define PROMPT_NO 0
#define PROMPT_YES 1
#define PROMPT_ALL 2
#define PROMPT_BREAK 3
BOOL __stdcall PagePrompt(PCON_PAGER Pager, DWORD Done, DWORD Total);
INT FilePromptYN (UINT);
INT FilePromptYNA (UINT);
/* Prototypes for MOVE.C */
INT cmd_move (LPTSTR);
/* Prototypes for MSGBOX.C */
INT CommandMsgbox (LPTSTR);
/* Prototypes from PARSER.C */
/* These three characters act like spaces to the parser in most contexts */
#define STANDARD_SEPS _T(",;=")
typedef enum _COMMAND_TYPE
{
/* Standard command */
C_COMMAND,
/* Quiet operator */
C_QUIET,
/* Parenthesized block */
C_BLOCK,
/* Operators */
C_MULTI, C_OR, C_AND, C_PIPE,
/* Special parsed commands */
C_FOR, C_IF, C_REM
} COMMAND_TYPE;
typedef struct _PARSED_COMMAND
{
/*
* For IF : this is the 'main' case (the 'else' is obtained via SubCmd->Next).
* For FOR: this is the list of all the subcommands in the DO.
*/
struct _PARSED_COMMAND *Subcommands;
struct _PARSED_COMMAND *Next; // Next command(s) in the chain.
struct _REDIRECTION *Redirections;
COMMAND_TYPE Type;
union
{
struct
{
PTSTR Rest;
TCHAR First[];
} Command;
struct
{
BYTE Switches;
TCHAR Variable;
PTSTR Params;
PTSTR List;
struct _FOR_CONTEXT *Context;
} For;
struct
{
BYTE Flags;
IF_OPERATOR Operator;
PTSTR LeftArg;
PTSTR RightArg;
} If;
};
} PARSED_COMMAND;
PARSED_COMMAND*
ParseCommand(
IN PCTSTR Line);
VOID
DumpCommand(
IN PARSED_COMMAND* Cmd,
IN ULONG SpacePad);
VOID
EchoCommand(
IN PARSED_COMMAND* Cmd);
PTCHAR
UnparseCommand(
IN PARSED_COMMAND* Cmd,
OUT PTCHAR Out,
IN PTCHAR OutEnd);
VOID
FreeCommand(
IN OUT PARSED_COMMAND* Cmd);
VOID ParseErrorEx(IN PCTSTR s);
extern BOOL bParseError;
extern TCHAR ParseLine[CMDLINE_LENGTH];
extern BOOL bIgnoreParserComments;
extern BOOL bHandleContinuations;
/* Prototypes from PATH.C */
INT cmd_path (LPTSTR);
/* Prototypes from PROMPT.C */
VOID InitPrompt (VOID);
VOID PrintPrompt (VOID);
INT cmd_prompt (LPTSTR);
/* Prototypes for REDIR.C */
HANDLE GetHandle(UINT Number);
VOID SetHandle(UINT Number, HANDLE Handle);
typedef enum _REDIR_MODE
{
REDIR_READ = 0,
REDIR_WRITE = 1,
REDIR_APPEND = 2
} REDIR_MODE;
typedef struct _REDIRECTION
{
struct _REDIRECTION *Next;
HANDLE OldHandle;
BYTE Number;
REDIR_MODE Mode;
TCHAR Filename[];
} REDIRECTION;
BOOL PerformRedirection(REDIRECTION *);
VOID UndoRedirection(REDIRECTION *, REDIRECTION *End);
INT GetRedirection(LPTSTR, REDIRECTION **);
VOID FreeRedirection(REDIRECTION *);
/* Prototypes for REN.C */
INT cmd_rename (LPTSTR);
/* Prototypes for REN.C */
INT cmd_replace (LPTSTR);
/* Prototypes for SCREEN.C */
INT CommandScreen (LPTSTR);
/* Prototypes for SET.C */
INT cmd_set (LPTSTR);
/* Prototypes for SETLOCAL.C */
LPTSTR DuplicateEnvironment(VOID);
INT cmd_setlocal (LPTSTR);
INT cmd_endlocal (LPTSTR);
/* Prototypes for START.C */
INT cmd_start (LPTSTR);
/* Prototypes for STRTOCLR.C */
BOOL StringToColor (LPWORD, LPTSTR *);
/* Prototypes for TIME.C */
INT cmd_time (LPTSTR);
/* Prototypes for TIMER.C */
INT CommandTimer (LPTSTR param);
/* Prototypes for TITLE.C */
INT cmd_title (LPTSTR);
/* Prototypes for TYPE.C */
INT cmd_type (LPTSTR);
/* Prototypes for VER.C */
VOID InitOSVersion(VOID);
VOID PrintOSVersion(VOID);
INT cmd_ver (LPTSTR);
/* Prototypes for VERIFY.C */
INT cmd_verify (LPTSTR);
/* Prototypes for VOL.C */
INT cmd_vol (LPTSTR);
/* Prototypes for WHERE.C */
BOOL SearchForExecutable (LPCTSTR, LPTSTR);
/* Prototypes for WINDOW.C */
INT CommandActivate (LPTSTR);
INT CommandWindow (LPTSTR);
/* The MSDOS Batch Commands [MS-DOS 5.0 User's Guide and Reference p359] */
int cmd_if(TCHAR *);
int cmd_pause(TCHAR *);
int cmd_shift(TCHAR *);