xref: /reactos/base/shell/cmd/if.c (revision e9044710)
1 /*
2  *  IF.C - if internal batch command.
3  *
4  *
5  *  History:
6  *
7  *    16 Jul 1998 (Hans B Pufal)
8  *        started.
9  *
10  *    16 Jul 1998 (John P Price)
11  *        Separated commands into individual files.
12  *
13  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
14  *        added config.h include
15  *
16  *    07-Jan-1999 (Eric Kohl)
17  *        Added help text ("if /?") and cleaned up.
18  *
19  *    21-Jan-1999 (Eric Kohl)
20  *        Unicode and redirection ready!
21  *
22  *    01-Sep-1999 (Eric Kohl)
23  *        Fixed help text.
24  *
25  *    17-Feb-2001 (ea)
26  *        IF DEFINED variable command
27  *
28  *    28-Apr-2005 (Magnus Olsen) <magnus@greatlord.com>
29  *        Remove all hardcoded strings in En.rc
30  *
31  */
32 
33 #include "precomp.h"
34 
GenericCmp(INT (WINAPI * StringCmp)(LPCTSTR,LPCTSTR),LPCTSTR Left,LPCTSTR Right)35 static INT GenericCmp(INT (WINAPI *StringCmp)(LPCTSTR, LPCTSTR),
36                       LPCTSTR Left, LPCTSTR Right)
37 {
38     TCHAR *end;
39     INT nLeft = _tcstol(Left, &end, 0);
40     if (*end == _T('\0'))
41     {
42         INT nRight = _tcstol(Right, &end, 0);
43         if (*end == _T('\0'))
44         {
45             /* both arguments are numeric */
46             return (nLeft < nRight) ? -1 : (nLeft > nRight);
47         }
48     }
49     return StringCmp(Left, Right);
50 }
51 
cmd_if(LPTSTR param)52 INT cmd_if(LPTSTR param)
53 {
54     TRACE("cmd_if(\'%s\')\n", debugstr_aw(param));
55 
56     if (!_tcsncmp (param, _T("/?"), 2))
57     {
58         ConOutResPaging(TRUE, STRING_IF_HELP1);
59         return 0;
60     }
61 
62     ParseErrorEx(param);
63     return 1;
64 }
65 
ExecuteIf(PARSED_COMMAND * Cmd)66 INT ExecuteIf(PARSED_COMMAND *Cmd)
67 {
68     INT result = FALSE; /* when set cause 'then' clause to be executed */
69     LPTSTR param;
70     LPTSTR Left = NULL, Right;
71 
72     if (Cmd->If.LeftArg)
73     {
74         Left = DoDelayedExpansion(Cmd->If.LeftArg);
75         if (!Left)
76             return 1;
77     }
78     Right = DoDelayedExpansion(Cmd->If.RightArg);
79     if (!Right)
80     {
81         if (Left) cmd_free(Left);
82         return 1;
83     }
84 
85     if (bEnableExtensions && (Cmd->If.Operator == IF_CMDEXTVERSION))
86     {
87         /* IF CMDEXTVERSION n: check if Command Extensions
88          * version is greater or equal to n. */
89         DWORD n = _tcstoul(Right, &param, 10);
90         if (*param != _T('\0'))
91         {
92             error_syntax(Right);
93             goto fail;
94         }
95         result = (CMDEXTVERSION >= n);
96     }
97     else if (bEnableExtensions && (Cmd->If.Operator == IF_DEFINED))
98     {
99         /* IF DEFINED var: check if environment variable exists */
100         result = (GetEnvVarOrSpecial(Right) != NULL);
101     }
102     else if (Cmd->If.Operator == IF_ERRORLEVEL)
103     {
104         /* IF ERRORLEVEL n: check if last exit code is greater or equal to n */
105         INT n = _tcstol(Right, &param, 10);
106         if (*param != _T('\0'))
107         {
108             error_syntax(Right);
109             goto fail;
110         }
111         result = (nErrorLevel >= n);
112     }
113     else if (Cmd->If.Operator == IF_EXIST)
114     {
115         BOOL IsDir;
116         SIZE_T Size;
117         WIN32_FIND_DATA f;
118         HANDLE hFind;
119         DWORD attrs;
120 
121         /* IF EXIST filename: check if file exists (wildcards allowed) */
122         StripQuotes(Right);
123 
124         Size = _tcslen(Right);
125         IsDir = (Right[Size - 1] == '\\');
126         if (IsDir)
127             Right[Size - 1] = 0;
128 
129         hFind = FindFirstFile(Right, &f);
130         if (hFind != INVALID_HANDLE_VALUE)
131         {
132             attrs = f.dwFileAttributes;
133             FindClose(hFind);
134         }
135         else
136         {
137             /* FindFirstFile fails at the root directory. */
138             attrs = GetFileAttributes(Right);
139         }
140 
141         if (attrs == INVALID_FILE_ATTRIBUTES)
142             result = FALSE;
143         else if (IsDir)
144             result = ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
145         else
146             result = TRUE;
147 
148         if (IsDir)
149             Right[Size - 1] = '\\';
150     }
151     else
152     {
153         /*
154          * Do case-insensitive string comparisons if /I specified.
155          *
156          * Since both strings are user-specific, use kernel32!lstrcmp(i)
157          * instead of CRT!_tcs(i)cmp, so as to use the correct
158          * current thread locale information.
159          */
160         INT (WINAPI *StringCmp)(LPCTSTR, LPCTSTR) =
161             (Cmd->If.Flags & IFFLAG_IGNORECASE) ? lstrcmpi : lstrcmp;
162 
163         if (Cmd->If.Operator == IF_STRINGEQ)
164         {
165             /* IF str1 == str2 */
166             result = (StringCmp(Left, Right) == 0);
167         }
168         else if (bEnableExtensions)
169         {
170             result = GenericCmp(StringCmp, Left, Right);
171             switch (Cmd->If.Operator)
172             {
173             case IF_EQU: result = (result == 0); break;
174             case IF_NEQ: result = (result != 0); break;
175             case IF_LSS: result = (result <  0); break;
176             case IF_LEQ: result = (result <= 0); break;
177             case IF_GTR: result = (result >  0); break;
178             case IF_GEQ: result = (result >= 0); break;
179             default: goto unknownOp;
180             }
181         }
182         else
183         {
184 unknownOp:
185             ERR("Unknown IF operator 0x%x\n", Cmd->If.Operator);
186             ASSERT(FALSE);
187             goto fail;
188         }
189     }
190 
191     if (Left) cmd_free(Left);
192     cmd_free(Right);
193 
194     if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0))
195     {
196         /* Full condition was true, do the command */
197         return ExecuteCommand(Cmd->Subcommands);
198     }
199     else
200     {
201         /* Full condition was false, do the "else" command if there is one */
202         return ExecuteCommand(Cmd->Subcommands->Next);
203     }
204 
205 fail:
206     if (Left) cmd_free(Left);
207     cmd_free(Right);
208     return 1;
209 }
210 
211 /* EOF */
212