update for HEAD-2003091401
[reactos.git] / subsys / system / cmd / for.c
1 /*
2  *  FOR.C - for 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  *        Seperated commands into individual files.
12  *
13  *    19-Jul-1998 (Hans B Pufal)
14  *        Implementation of FOR.
15  *
16  *    27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
17  *        Added config.h include.
18  *
19  *    20-Jan-1999 (Eric Kohl)
20  *        Unicode and redirection safe!
21  *
22  *    01-Sep-1999 (Eric Kohl)
23  *        Added help text.
24  *    
25  *    23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.se>)
26  *        Implemented preservation of echo flag. Some other for related
27  *        code in other files fixed, too.
28  */
29
30 #include "config.h"
31
32 #include <windows.h>
33 #include <tchar.h>
34 #include <string.h>
35 #include <stdlib.h>
36 #include <ctype.h>
37
38 #include "cmd.h"
39 #include "batch.h"
40
41
42 /*
43  * Perform FOR command.
44  *
45  * First check syntax is correct : FOR %v IN ( <list> ) DO <command>
46  *   v must be alphabetic, <command> must not be empty.
47  *
48  * If all is correct build a new bcontext structure which preserves
49  *   the necessary information so that readbatchline can expand
50  *   each the command prototype for each list element.
51  *
52  * You might look on a FOR as being a called batch file with one line
53  *   per list element.
54  */
55
56 INT cmd_for (LPTSTR cmd, LPTSTR param)
57 {
58         LPBATCH_CONTEXT lpNew;
59         LPTSTR pp;
60         TCHAR  var;
61
62 #ifdef _DEBUG
63         DebugPrintf (_T("cmd_for (\'%s\', \'%s\'\n"), cmd, param);
64 #endif
65
66         if (!_tcsncmp (param, _T("/?"), 2))
67         {
68                 ConOutPuts (_T("Runs a specified command for each file in a set of files\n"
69                                "\n"
70                                "FOR %variable IN (set) DO command [parameters]\n"
71                                "\n"
72                                "  %variable  Specifies a replaceable parameter.\n"
73                                "  (set)      Specifies a set of one or more files. Wildcards may be used.\n"
74                                "  command    Specifies the command to carry out for each file.\n"
75                                "  parameters Specifies parameters or switches for the specified command.\n"
76                                "\n"
77                                "To user the FOR comamnd in a batch program, specify %%variable instead of\n"
78                                "%variable."));
79                 return 0;
80         }
81
82         /* Check that first element is % then an alpha char followed by space */
83         if ((*param != _T('%')) || !_istalpha (*(param + 1)) || !_istspace (*(param + 2)))
84         {
85                 error_syntax (_T("bad variable specification."));
86                 return 1;
87         }
88
89         param++;
90         var = *param++;               /* Save FOR var name */
91
92         while (_istspace (*param))
93                 param++;
94
95         /* Check next element is 'IN' */
96         if ((_tcsnicmp (param, _T("in"), 2) != 0) || !_istspace (*(param + 2)))
97         {
98                 error_syntax (_T("'in' missing in for statement."));
99                 return 1;
100         }
101
102         param += 2;
103         while (_istspace (*param))
104                 param++;
105
106         /* Folowed by a '(', find also matching ')' */
107         if ((*param != _T('(')) || (NULL == (pp = _tcsrchr (param, _T(')')))))
108         {
109                 error_syntax (_T("no brackets found."));
110                 return 1;
111         }
112
113         *pp++ = _T('\0');
114         param++;                /* param now points at null terminated list */
115
116         while (_istspace (*pp))
117                 pp++;
118
119         /* Check DO follows */
120         if ((_tcsnicmp (pp, _T("do"), 2) != 0) || !_istspace (*(pp + 2)))
121         {
122                 error_syntax (_T("'do' missing."));
123                 return 1;
124         }
125
126         pp += 2;
127         while (_istspace (*pp))
128                 pp++;
129
130         /* Check that command tail is not empty */
131         if (*pp == _T('\0'))
132         {
133                 error_syntax (_T("no command after 'do'."));
134                 return 1;
135         }
136
137         /* OK all is correct, build a bcontext.... */
138         lpNew = (LPBATCH_CONTEXT)malloc (sizeof (BATCH_CONTEXT));
139
140         lpNew->prev = bc;
141         bc = lpNew;
142
143         bc->hBatchFile = INVALID_HANDLE_VALUE;
144         bc->ffind = NULL;
145         bc->params = BatchParams (_T(""), param); /* Split out list */
146         bc->shiftlevel = 0;
147         bc->forvar = var;
148         bc->forproto = _tcsdup (pp);
149         if (bc->prev)
150                 bc->bEcho = bc->prev->bEcho;
151         else
152                 bc->bEcho = bEcho;
153
154         return 0;
155 }
156
157 /* EOF */