xref: /reactos/base/shell/cmd/if.c (revision c2c66aff)
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 (*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     error_syntax(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 (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 = (2 >= n);
97     }
98     else if (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 
122         /* IF EXIST filename: check if file exists (wildcards allowed) */
123         StripQuotes(Right);
124 
125         Size = _tcslen(Right);
126         IsDir = (Right[Size - 1] == '\\');
127         if (IsDir)
128             Right[Size - 1] = 0;
129 
130 
131         hFind = FindFirstFile(Right, &f);
132         if (hFind != INVALID_HANDLE_VALUE)
133         {
134             if (IsDir)
135             {
136                 result = ((f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
137             }
138             else
139             {
140                 result = TRUE;
141             }
142             FindClose(hFind);
143         }
144 
145         if (IsDir)
146             Right[Size - 1] = '\\';
147     }
148     else
149     {
150         /* Do case-insensitive string comparisons if /I specified */
151         INT (*StringCmp)(LPCTSTR, LPCTSTR) =
152             (Cmd->If.Flags & IFFLAG_IGNORECASE) ? _tcsicmp : _tcscmp;
153 
154         if (Cmd->If.Operator == IF_STRINGEQ)
155         {
156             /* IF str1 == str2 */
157             result = StringCmp(Left, Right) == 0;
158         }
159         else
160         {
161             result = GenericCmp(StringCmp, Left, Right);
162             switch (Cmd->If.Operator)
163             {
164             case IF_EQU: result = (result == 0); break;
165             case IF_NEQ: result = (result != 0); break;
166             case IF_LSS: result = (result < 0); break;
167             case IF_LEQ: result = (result <= 0); break;
168             case IF_GTR: result = (result > 0); break;
169             case IF_GEQ: result = (result >= 0); break;
170             }
171         }
172     }
173 
174     cmd_free(Left);
175     cmd_free(Right);
176 
177     if (result ^ ((Cmd->If.Flags & IFFLAG_NEGATE) != 0))
178     {
179         /* full condition was true, do the command */
180         return ExecuteCommand(Cmd->Subcommands);
181     }
182     else
183     {
184         /* full condition was false, do the "else" command if there is one */
185         if (Cmd->Subcommands->Next)
186             return ExecuteCommand(Cmd->Subcommands->Next);
187         return 0;
188     }
189 }
190 
191 /* EOF */
192