ReactOS  0.4.13-dev-257-gfabbd7c
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 
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 
315  GetFullPathName(fullname, sizeof(bc->BatchFilePath) / sizeof(TCHAR), bc->BatchFilePath, NULL);
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 batch file line */
357  if (bEcho && !bDisableBatchEcho && Cmd->Type != C_QUIET)
358  {
359  if (!bIgnoreEcho)
360  ConOutChar(_T('\n'));
361  PrintPrompt();
362  EchoCommand(Cmd);
363  ConOutChar(_T('\n'));
364  }
365 
366  bc->current = Cmd;
368  FreeCommand(Cmd);
369  }
370 
371  /* Always return the current errorlevel */
372  ret = nErrorLevel;
373 
374  TRACE ("Batch: returns TRUE\n");
375 
376  fc = saved_fc;
377  return ret;
378 }
379 
381 {
383 
384  /* Prepend the list to the batch context's list */
385  ListEnd = RedirList;
386  while (*ListEnd)
387  ListEnd = &(*ListEnd)->Next;
388  *ListEnd = bc->RedirList;
389  bc->RedirList = *RedirList;
390 
391  /* Null out the pointer so that the list will not be cleared prematurely.
392  * These redirections should persist until the batch file exits. */
393  *RedirList = NULL;
394 }
395 
396 /*
397  * Read a single line from the batch file from the current batch/memory position.
398  * Almost a copy of FileGetString with same UNICODE handling
399  */
401 {
402  LPSTR lpString;
403  INT len = 0;
404 #ifdef _UNICODE
405  lpString = cmd_alloc(nBufferLength);
406  if (!lpString)
407  {
408  WARN("Cannot allocate memory for lpString\n");
410  return FALSE;
411  }
412 #else
413  lpString = lpBuffer;
414 #endif
415  /* read all chars from memory until a '\n' is encountered */
416  if (bc->mem)
417  {
418  for (; (bc->mempos < bc->memsize && len < (nBufferLength-1)); len++)
419  {
420  lpString[len] = bc->mem[bc->mempos++];
421  if (lpString[len] == '\n' )
422  {
423  len++;
424  break;
425  }
426  }
427  }
428 
429  if (!len)
430  {
431 #ifdef _UNICODE
432  cmd_free(lpString);
433 #endif
434  return FALSE;
435  }
436 
437  lpString[len++] = '\0';
438 #ifdef _UNICODE
439  MultiByteToWideChar(OutputCodePage, 0, lpString, -1, lpBuffer, len);
440  cmd_free(lpString);
441 #endif
442  return TRUE;
443 }
444 
445 /*
446  * Read and return the next executable line form the current batch file
447  *
448  * If no batch file is current or no further executable lines are found
449  * return NULL.
450  *
451  * Set eflag to 0 if line is not to be echoed else 1
452  */
454 {
455  TRACE ("ReadBatchLine ()\n");
456 
457  /* User halt */
459  {
460  while (bc)
461  ExitBatch();
462  return NULL;
463  }
464 
465  if (!BatchGetString (textline, sizeof (textline) / sizeof (textline[0]) - 1))
466  {
467  TRACE ("ReadBatchLine(): Reached EOF!\n");
468  /* End of file.... */
469  ExitBatch();
470  return NULL;
471  }
472 
473  TRACE ("ReadBatchLine(): textline: \'%s\'\n", debugstr_aw(textline));
474 
475  if (textline[_tcslen(textline) - 1] != _T('\n'))
476  _tcscat(textline, _T("\n"));
477 
478  return textline;
479 }
480 
481 /* 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:398
#define BREAK_BATCHFILE
Definition: cmd.h:31
BOOL bIgnoreEcho
Definition: cmd.c:155
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
VOID ConOutChar(TCHAR c)
Definition: console.c:123
INT cmd_goto(LPTSTR)
Definition: goto.c:39
#define ConErrResPuts(uID)
Definition: console.h:39
#define WARN(fmt,...)
Definition: debug.h:111
VOID AddBatchRedirection(REDIRECTION **RedirList)
Definition: batch.c:380
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:391
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:56
BOOL BatchGetString(LPTSTR lpBuffer, INT nBufferLength)
Definition: batch.c:400
LPTSTR ReadBatchLine(VOID)
Definition: batch.c:453
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:461
unsigned int BOOL
Definition: ntddk_ex.h:94
char Char
Definition: bzip2.c:161
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:978
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:136
_TCHAR * _tcschr(const _TCHAR *s, _XINT c)
Definition: tcschr.h:4
#define OPEN_EXISTING
Definition: compat.h:426
_In_ LPCSTR _In_opt_ LPCSTR _In_ DWORD nBufferLength
Definition: winbase.h:3011
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
BOOL bDisableBatchEcho
Definition: cmd.c:159
LPFOR_CONTEXT fc
Definition: for.c:53
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
Definition: fileinfo.c:481
#define SetLastError(x)
Definition: compat.h:409
int ret
#define FILE_ATTRIBUTE_NORMAL
Definition: compat.h:126
#define FILE_SHARE_DELETE
Definition: nt_native.h:682
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:3635
VOID UndoRedirection(REDIRECTION *, REDIRECTION *End)
Definition: redir.c:142
#define GENERIC_READ
Definition: compat.h:124
VOID FreeCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:1015
_In_ HANDLE hFile
Definition: mswsock.h:90
VOID EchoCommand(PARSED_COMMAND *Cmd)
Definition: parser.c:811
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:904
#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:766
INT ExecuteCommand(PARSED_COMMAND *Cmd)
Definition: cmd.c:772
Definition: cmd.h:298
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 PrintPrompt(VOID)
Definition: prompt.c:109
void BatchFile2Mem(HANDLE hBatchFile)
Definition: batch.c:208
#define STRING_BATCH_ERROR
Definition: resource.h:23
struct tagBATCHCONTEXT * prev
Definition: batch.h:9