ReactOS  0.4.15-dev-425-gc40b086
batch.c
Go to the documentation of this file.
1 /*
2  * BATCH.C - batch file processor for CMD.EXE.
3  *
4  *
5  * History:
6  *
7  * ??/??/?? (Evan Jeffrey)
8  * started.
9  *
10  * 15 Jul 1995 (Tim Norman)
11  * modes and bugfixes.
12  *
13  * 08 Aug 1995 (Matt Rains)
14  * i have cleaned up the source code. changes now bring this
15  * source into guidelines for recommended programming practice.
16  *
17  * i have added some constants to help making changes easier.
18  *
19  * 29 Jan 1996 (Steffan Kaiser)
20  * made a few cosmetic changes
21  *
22  * 05 Feb 1996 (Tim Norman)
23  * changed to comply with new first/rest calling scheme
24  *
25  * 14 Jun 1997 (Steffen Kaiser)
26  * bug fixes. added error level expansion %?. ctrl-break handling
27  *
28  * 16 Jul 1998 (Hans B Pufal)
29  * Totally reorganised in conjunction with COMMAND.C (cf) to
30  * implement proper BATCH file nesting and other improvements.
31  *
32  * 16 Jul 1998 (John P Price <linux-guru@gcfl.net>)
33  * Separated commands into individual files.
34  *
35  * 19 Jul 1998 (Hans B Pufal) [HBP_001]
36  * Preserve state of echo flag across batch calls.
37  *
38  * 19 Jul 1998 (Hans B Pufal) [HBP_002]
39  * Implementation of FOR command
40  *
41  * 20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
42  * added error checking after cmd_alloc calls
43  *
44  * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
45  * added config.h include
46  *
47  * 02-Aug-1998 (Hans B Pufal) [HBP_003]
48  * Fixed bug in ECHO flag restoration at exit from batch file
49  *
50  * 26-Jan-1999 Eric Kohl
51  * Replaced CRT io functions by Win32 io functions.
52  * Unicode safe!
53  *
54  * 23-Feb-2001 (Carl Nettelblad <cnettel@hem.passagen.es>)
55  * Fixes made to get "for" working.
56  *
57  * 02-Apr-2005 (Magnus Olsen <magnus@greatlord.com>)
58  * Remove all hardcoded strings in En.rc
59  */
60 
61 #include "precomp.h"
62 
63 /* The stack of current batch contexts.
64  * NULL when no batch is active
65  */
67 
68 BOOL bEcho = TRUE; /* The echo flag */
69 
70 
71 
72 /* Buffer for reading Batch file lines */
74 
75 
76 /*
77  * Returns a pointer to the n'th parameter of the current batch file.
78  * If no such parameter exists returns pointer to empty string.
79  * If no batch file is current, returns NULL
80  *
81  */
82 
83 LPTSTR FindArg(TCHAR Char, BOOL *IsParam0)
84 {
85  LPTSTR pp;
86  INT n = Char - _T('0');
87 
88  TRACE ("FindArg: (%d)\n", n);
89 
90  if (n < 0 || n > 9)
91  return NULL;
92 
93  n = bc->shiftlevel[n];
94  *IsParam0 = (n == 0);
95  pp = bc->params;
96 
97  /* Step up the strings till we reach the end */
98  /* or the one we want */
99  while (*pp && n--)
100  pp += _tcslen (pp) + 1;
101 
102  return pp;
103 }
104 
105 
106 /*
107  * Batch_params builds a parameter list in newly allocated memory.
108  * The parameters consist of null terminated strings with a final
109  * NULL character signalling the end of the parameters.
110  *
111  */
112 
114 {
115  LPTSTR dp = (LPTSTR)cmd_alloc ((_tcslen(s1) + _tcslen(s2) + 3) * sizeof (TCHAR));
116 
117  /* JPP 20-Jul-1998 added error checking */
118  if (dp == NULL)
119  {
120  WARN("Cannot allocate memory for dp!\n");
122  return NULL;
123  }
124 
125  if (s1 && *s1)
126  {
127  s1 = _stpcpy (dp, s1);
128  *s1++ = _T('\0');
129  }
130  else
131  s1 = dp;
132 
133  while (*s2)
134  {
135  BOOL inquotes = FALSE;
136 
137  /* Find next parameter */
138  while (_istspace(*s2) || (*s2 && _tcschr(_T(",;="), *s2)))
139  s2++;
140  if (!*s2)
141  break;
142 
143  /* Copy it */
144  do
145  {
146  if (!inquotes && (_istspace(*s2) || _tcschr(_T(",;="), *s2)))
147  break;
148  inquotes ^= (*s2 == _T('"'));
149  *s1++ = *s2++;
150  } while (*s2);
151  *s1++ = _T('\0');
152  }
153 
154  *s1 = _T('\0');
155 
156  return dp;
157 }
158 
159 /*
160  * free the allocated memory of a batch file
161  */
163 {
164  TRACE ("ClearBatch mem = %08x free = %d\n", bc->mem, bc->memfree);
165 
166  if (bc->mem && bc->memfree)
167  cmd_free(bc->mem);
168 
169  if (bc->raw_params)
171 
172  if (bc->params)
173  cmd_free(bc->params);
174 }
175 
176 /*
177  * If a batch file is current, exits it, freeing the context block and
178  * chaining back to the previous one.
179  *
180  * If no new batch context is found, sets ECHO back ON.
181  *
182  * If the parameter is non-null or not empty, it is printed as an exit
183  * message
184  */
185 
187 {
188  ClearBatch();
189 
190  TRACE ("ExitBatch\n");
191 
194 
195  /* Preserve echo state across batch calls */
196  bEcho = bc->bEcho;
197 
198  while (bc->setlocal)
199  cmd_endlocal(_T(""));
200 
201  bc = bc->prev;
202 }
203 
204 /*
205  * Load batch file into memory
206  *
207  */
208 void BatchFile2Mem(HANDLE hBatchFile)
209 {
210  TRACE ("BatchFile2Mem ()\n");
211 
212  bc->memsize = GetFileSize(hBatchFile, NULL);
213  bc->mem = (char *)cmd_alloc(bc->memsize+1); /* 1 extra for '\0' */
214 
215  /* if memory is available, read it in and close the file */
216  if (bc->mem != NULL)
217  {
218  TRACE ("BatchFile2Mem memory %08x - %08x\n",bc->mem,bc->memsize);
219  SetFilePointer (hBatchFile, 0, NULL, FILE_BEGIN);
220  ReadFile(hBatchFile, (LPVOID)bc->mem, bc->memsize, &bc->memsize, NULL);
221  bc->mem[bc->memsize]='\0'; /* end this, so you can dump it as a string */
222  bc->memfree=TRUE; /* this one needs to be freed */
223  }
224  else
225  {
226  bc->memsize=0; /* this will prevent mem being accessed */
227  bc->memfree=FALSE;
228  }
229  bc->mempos = 0; /* set position to the start */
230 }
231 
232 /*
233  * Start batch file execution
234  *
235  * The firstword parameter is the full filename of the batch file.
236  *
237  */
239 {
240  BATCH_CONTEXT new;
241  LPFOR_CONTEXT saved_fc;
242  INT i;
243  INT ret = 0;
244  BOOL same_fn = FALSE;
245 
246  HANDLE hFile = 0;
247  SetLastError(0);
248  if (bc && bc->mem)
249  {
250  TCHAR fpname[MAX_PATH];
251  GetFullPathName(fullname, sizeof(fpname) / sizeof(TCHAR), fpname, NULL);
252  if (_tcsicmp(bc->BatchFilePath,fpname)==0)
253  same_fn=TRUE;
254  }
255  TRACE ("Batch: (\'%s\', \'%s\', \'%s\') same_fn = %d\n",
256  debugstr_aw(fullname), debugstr_aw(firstword), debugstr_aw(param), same_fn);
257 
258  if (!same_fn)
259  {
263 
265  {
267  return 1;
268  }
269  }
270 
271  if (bc != NULL && Cmd == bc->current)
272  {
273  /* Then we are transferring to another batch */
274  ClearBatch();
275  AddBatchRedirection(&Cmd->Redirections);
276  }
277  else
278  {
279  struct _SETLOCAL *setlocal = NULL;
280 
281  if (Cmd == NULL)
282  {
283  /* This is a CALL. CALL will set errorlevel to our return value, so
284  * in order to keep the value of errorlevel unchanged in the case
285  * of calling an empty batch file, we must return that same value. */
286  ret = nErrorLevel;
287  }
288  else if (bc)
289  {
290  /* If a batch file runs another batch file as part of a compound command
291  * (e.g. "x.bat & somethingelse") then the first file gets terminated. */
292 
293  /* Get its SETLOCAL stack so it can be migrated to the new context */
294  setlocal = bc->setlocal;
295  bc->setlocal = NULL;
296  ExitBatch();
297  }
298 
299  /* Create a new context. This function will not
300  * return until this context has been exited */
301  new.prev = bc;
302  /* copy some fields in the new structure if it is the same file */
303  if (same_fn)
304  {
305  new.mem = bc->mem;
306  new.memsize = bc->memsize;
307  new.mempos = 0;
308  new.memfree = FALSE; /* don't free this, being used before this */
309  }
310  bc = &new;
311  bc->RedirList = NULL;
312  bc->setlocal = setlocal;
313  }
314 
316  /* if a new batch file, load it into memory and close the file */
317  if (!same_fn)
318  {
321  }
322 
323  bc->mempos = 0; /* goto begin of batch file */
324  bc->bEcho = bEcho; /* Preserve echo across batch calls */
325  for (i = 0; i < 10; i++)
326  bc->shiftlevel[i] = i;
327 
328  bc->params = BatchParams (firstword, param);
329  //
330  // Allocate enough memory to hold the params and copy them over without modifications
331  //
333  if (bc->raw_params == NULL)
334  {
336  return 1;
337  }
338 
339  /* Check if this is a "CALL :label" */
340  if (*firstword == _T(':'))
341  cmd_goto(firstword);
342 
343  /* If we are calling from inside a FOR, hide the FOR variables */
344  saved_fc = fc;
345  fc = NULL;
346 
347  /* If we have created a new context, don't return
348  * until this batch file has completed. */
349  while (bc == &new && !bExit)
350  {
351  Cmd = ParseCommand(NULL);
352  if (!Cmd)
353  continue;
354 
355  /* JPP 19980807 */
356  /* Echo the command and execute it */
357  bc->current = Cmd;
359  FreeCommand(Cmd);
360  }
361 
362  /* Always return the current errorlevel */
363  ret = nErrorLevel;
364 
365  TRACE ("Batch: returns TRUE\n");
366 
367  fc = saved_fc;
368  return ret;
369 }
370 
372 {
374 
375  /* Prepend the list to the batch context's list */
376  ListEnd = RedirList;
377  while (*ListEnd)
378  ListEnd = &(*ListEnd)->Next;
379  *ListEnd = bc->RedirList;
380  bc->RedirList = *RedirList;
381 
382  /* Null out the pointer so that the list will not be cleared prematurely.
383  * These redirections should persist until the batch file exits. */
384  *RedirList = NULL;
385 }
386 
387 /*
388  * Read a single line from the batch file from the current batch/memory position.
389  * Almost a copy of FileGetString with same UNICODE handling
390  */
392 {
393  LPSTR lpString;
394  INT len = 0;
395 #ifdef _UNICODE
396  lpString = cmd_alloc(nBufferLength);
397  if (!lpString)
398  {
399  WARN("Cannot allocate memory for lpString\n");
401  return FALSE;
402  }
403 #else
404  lpString = lpBuffer;
405 #endif
406  /* read all chars from memory until a '\n' is encountered */
407  if (bc->mem)
408  {
409  for (; (bc->mempos < bc->memsize && len < (nBufferLength-1)); len++)
410  {
411  lpString[len] = bc->mem[bc->mempos++];
412  if (lpString[len] == '\n' )
413  {
414  len++;
415  break;
416  }
417  }
418  }
419 
420  if (!len)
421  {
422 #ifdef _UNICODE
423  cmd_free(lpString);
424 #endif
425  return FALSE;
426  }
427 
428  lpString[len++] = '\0';
429 #ifdef _UNICODE
430  MultiByteToWideChar(OutputCodePage, 0, lpString, -1, lpBuffer, len);
431  cmd_free(lpString);
432 #endif
433  return TRUE;
434 }
435 
436 /*
437  * Read and return the next executable line form the current batch file
438  *
439  * If no batch file is current or no further executable lines are found
440  * return NULL.
441  *
442  * Set eflag to 0 if line is not to be echoed else 1
443  */
445 {
446  TRACE ("ReadBatchLine ()\n");
447 
448  /* User halt */
450  {
451  while (bc)
452  ExitBatch();
453  return NULL;
454  }
455 
456  if (!BatchGetString (textline, sizeof (textline) / sizeof (textline[0]) - 1))
457  {
458  TRACE ("ReadBatchLine(): Reached EOF!\n");
459  /* End of file.... */
460  ExitBatch();
461  return NULL;
462  }
463 
464  TRACE ("ReadBatchLine(): textline: \'%s\'\n", debugstr_aw(textline));
465 
466  if (textline[_tcslen(textline) - 1] != _T('\n'))
467  _tcscat(textline, _T("\n"));
468 
469  return textline;
470 }
471 
472 /* EOF */
INT nErrorLevel
Definition: cmd.c:157
REDIRECTION * RedirList
Definition: batch.h:19
BOOL CheckCtrlBreak(INT)
Definition: misc.c:132
struct S2 s2
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:407
#define BREAK_BATCHFILE
Definition: cmd.h:31
DWORD mempos
Definition: batch.h:12
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY ListEnd
Definition: exfuncs.h:1015
#define _tcsicmp
Definition: xmlstorage.h:205
LPBATCH_CONTEXT bc
Definition: batch.c:66
INT cmd_goto(LPTSTR)
Definition: goto.c:39
INT ExecuteCommandWithEcho(IN PARSED_COMMAND *Cmd)
Definition: cmd.c:835
#define ConErrResPuts(uID)
Definition: console.h:39
#define WARN(fmt,...)
Definition: debug.h:112
VOID AddBatchRedirection(REDIRECTION **RedirList)
Definition: batch.c:371
BOOL memfree
Definition: batch.h:13
#define debugstr_aw
Definition: precomp.h:43
GLdouble n
Definition: glext.h:7729
BOOL bEcho
Definition: batch.c:68
#define INVALID_HANDLE_VALUE
Definition: compat.h:400
INT cmd_endlocal(LPTSTR)
Definition: setlocal.c:95
LPTSTR params
Definition: batch.h:15
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
char * LPSTR
Definition: xmlstorage.h:182
int32_t INT
Definition: typedefs.h:57
BOOL BatchGetString(LPTSTR lpBuffer, INT nBufferLength)
Definition: batch.c:391
LPTSTR ReadBatchLine(VOID)
Definition: batch.c:444
CHAR * LPTSTR
Definition: xmlstorage.h:192
#define FILE_SHARE_READ
Definition: compat.h:125
DWORD WINAPI DECLSPEC_HOTPATCH SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
Definition: fileinfo.c:204
PARSED_COMMAND * current
Definition: batch.h:20
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
LPTSTR _stpcpy(LPTSTR, LPCTSTR)
Definition: misc.c:460
unsigned int BOOL
Definition: ntddk_ex.h:94
LPTSTR FindArg(TCHAR Char, BOOL *IsParam0)
Definition: batch.c:83
static TAGREF LPCWSTR LPDWORD LPVOID lpBuffer
Definition: db.cpp:173
#define pp
Definition: hlsl.yy.c:1208
char * mem
Definition: batch.h:10
size_t __cdecl _tcslen(const _TCHAR *str)
Definition: tcslen.h:9
smooth NULL
Definition: ftsmooth.c:416
#define BATCH_BUFFSIZE
Definition: batch.h:43
VOID ExitBatch(VOID)
Definition: batch.c:186
VOID error_out_of_memory(VOID)
Definition: error.c:140
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
#define OPEN_EXISTING
Definition: compat.h:435
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:3034
TCHAR textline[BATCH_BUFFSIZE]
Definition: batch.c:73
struct _SETLOCAL * setlocal
Definition: batch.h:21
VOID ClearBatch(VOID)
Definition: batch.c:162
char TCHAR
Definition: xmlstorage.h:189
#define _T(x)
Definition: vfdio.h:22
#define TRACE(s)
Definition: solgame.cpp:4
TCHAR BatchFilePath[MAX_PATH]
Definition: batch.h:14
struct S1 s1
GLfloat param
Definition: glext.h:5796
#define MAX_PATH
Definition: compat.h:26
UINT OutputCodePage
Definition: console.c:26
LPFOR_CONTEXT fc
Definition: for.c:53
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:481
#define SetLastError(x)
Definition: compat.h:418
int ret
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
const char * fullname
Definition: shader.c:1766
Definition: sacdrv.h:277
INT Batch(LPTSTR fullname, LPTSTR firstword, LPTSTR param, PARSED_COMMAND *Cmd)
Definition: batch.c:238
GLenum GLsizei len
Definition: glext.h:6722
#define GetFullPathName
Definition: winbase.h:3661
VOID UndoRedirection(REDIRECTION *, REDIRECTION *End)
Definition: redir.c:142
#define GENERIC_READ
Definition: compat.h:124
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1016
_In_ HANDLE hFile
Definition: mswsock.h:90
LPTSTR BatchParams(LPTSTR s1, LPTSTR s2)
Definition: batch.c:113
INT shiftlevel[10]
Definition: batch.h:17
#define cmd_alloc(size)
Definition: cmddbg.h:29
#define FILE_BEGIN
Definition: winbase.h:112
#define cmd_free(ptr)
Definition: cmddbg.h:31
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN CreateFile
Definition: fatprocs.h:913
#define FILE_FLAG_SEQUENTIAL_SCAN
Definition: disk.h:43
DWORD memsize
Definition: batch.h:11
#define cmd_dup(str)
Definition: cmddbg.h:32
VOID FreeRedirection(REDIRECTION *)
Definition: redir.c:153
BOOL bExit
Definition: cmd.c:152
#define MultiByteToWideChar
Definition: compat.h:100
PARSED_COMMAND * ParseCommand(LPTSTR Line)
Definition: parser.c:767
LPTSTR raw_params
Definition: batch.h:16
_TCHAR * _tcscat(_TCHAR *s, const _TCHAR *append)
Definition: tcscat.h:8
#define _istspace
Definition: tchar.h:1504
BOOL bEcho
Definition: batch.h:18
BOOL WINAPI ReadFile(IN HANDLE hFile, IN LPVOID lpBuffer, IN DWORD nNumberOfBytesToRead, OUT LPDWORD lpNumberOfBytesRead OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:123
void BatchFile2Mem(HANDLE hBatchFile)
Definition: batch.c:208
#define STRING_BATCH_ERROR
Definition: resource.h:23
struct tagBATCHCONTEXT * prev
Definition: batch.h:9