xref: /reactos/base/shell/cmd/if.c (revision 0ab63f95)
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 
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 
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 
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         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 version
88          * is greater or equal to n */
89         DWORD n = _tcstoul(Right, &param, 10);
90         if (*param != _T('\0'))
91         {
92             error_syntax(Right);
93             cmd_free(Right);
94             return 1;
95         }
96         result = (CMDEXTVERSION >= n);
97     }
98     else if (bEnableExtensions && (Cmd->If.Operator == IF_DEFINED))
99     {
100         /* IF DEFINED var: check if environment variable exists */
101         result = (GetEnvVarOrSpecial(Right) != NULL);
102     }
103     else if (Cmd->If.Operator == IF_ERRORLEVEL)
104     {
105         /* IF ERRORLEVEL n: check if last exit code is greater or equal to n */
106         INT n = _tcstol(Right, &param, 10);
107         if (*param != _T('\0'))
108         {
109             error_syntax(Right);
110             cmd_free(Right);
111             return 1;
112         }
113         result = (nErrorLevel >= n);
114     }
115     else if (Cmd->If.Operator == IF_EXIST)
116     {
117         BOOL IsDir;
118         INT Size;
119         WIN32_FIND_DATA f;
120         HANDLE hFind;
121         DWORD attrs;
122 
123         /* IF EXIST filename: check if file exists (wildcards allowed) */
124         StripQuotes(Right);
125 
126         Size = _tcslen(Right);
127         IsDir = (Right[Size - 1] == '\\');
128         if (IsDir)
129             Right[Size - 1] = 0;
130 
131         hFind = FindFirstFile(Right, &f);
132         if (hFind != INVALID_HANDLE_VALUE)
133         {
134             attrs = f.dwFileAttributes;
135             FindClose(hFind);
136         }
137         else
138         {
139             /* FindFirstFile fails at the root directory. */
140             attrs = GetFileAttributes(Right);
141         }
142 
143         if (attrs == 0xFFFFFFFF)
144             result = FALSE;
145         else if (IsDir)
146             result = ((attrs & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
147         else
148             result = TRUE;
149 
150         if (IsDir)
151             Right[Size - 1] = '\\';
152     }
153     else
154     {
155         /*
156          * Do case-insensitive string comparisons if /I specified.
157          *
158          * Since both strings are user-specific, use kernel32!lstrcmp(i)
159          * instead of CRT!_tcs(i)cmp, so as to use the correct
160          * current thread locale information.
161          */
162         INT (WINAPI *StringCmp)(LPCTSTR, LPCTSTR) =
163             (Cmd->If.Flags & IFFLAG_IGNORECASE) ? lstrcmpi : lstrcmp;
164 
165         if (Cmd->If.Operator == IF_STRINGEQ)
166         {
167             /* IF str1 == str2 */
168             result = (StringCmp(Left, Right) == 0);
169         }
170         else if (bEnableExtensions)
171         {
172             result = GenericCmp(StringCmp, Left, Right);
173             switch (Cmd->If.Operator)
174             {
175             case IF_EQU: result = (result == 0); break;
176             case IF_NEQ: result = (result != 0); break;
177             case IF_LSS: result = (result <  0); break;
178             case IF_LEQ: result = (result <= 0); break;
179             case IF_GTR: result = (result >  0); break;
180             case IF_GEQ: result = (result >= 0); break;
181             }
182         }
183     }
184 
185     cmd_free(Left);
186     cmd_free(Right);
187 
188     if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0))
189     {
190         /* Full condition was true, do the command */
191         return ExecuteCommand(Cmd->Subcommands);
192     }
193     else
194     {
195         /* Full condition was false, do the "else" command if there is one */
196         return ExecuteCommand(Cmd->Subcommands->Next);
197     }
198 }
199 
200 /* EOF */
201