2 * BATCH.C - batch file processor for CMD.EXE.
7 * ??/??/?? (Evan Jeffrey)
10 * 15 Jul 1995 (Tim Norman)
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.
17 * i have added some constants to help making changes easier.
19 * 29 Jan 1996 (Steffan Kaiser)
20 * made a few cosmetic changes
22 * 05 Feb 1996 (Tim Norman)
23 * changed to comply with new first/rest calling scheme
25 * 14 Jun 1997 (Steffen Kaiser)
26 * bug fixes. added error level expansion %?. ctrl-break handling
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.
32 * 16 Jul 1998 (John P Price <linux-guru@gcfl.net>)
33 * Seperated commands into individual files.
35 * 19 Jul 1998 (Hans B Pufal) [HBP_001]
36 * Preserve state of echo flag across batch calls.
38 * 19 Jul 1998 (Hans B Pufal) [HBP_002]
39 * Implementation of FOR command
41 * 20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
42 * added error checking after malloc calls
44 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
45 * added config.h include
47 * 02-Aug-1998 (Hans B Pufal) [HBP_003]
48 * Fixed bug in ECHO flag restoration at exit from batch file
50 * 26-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
51 * Replaced CRT io functions by Win32 io functions.
67 /* The stack of current batch contexts.
68 * NULL when no batch is active
70 LPBATCH_CONTEXT bc
= NULL
;
72 BOOL bEcho
= TRUE
; /* The echo flag */
76 /* Buffer for reading Batch file lines */
77 TCHAR textline
[BATCH_BUFFSIZE
];
81 * Returns a pointer to the n'th parameter of the current batch file.
82 * If no such parameter exists returns pointer to empty string.
83 * If no batch file is current, returns NULL
87 LPTSTR
FindArg (INT n
)
92 DebugPrintf ("FindArg: (%d)\n", n
);
101 /* Step up the strings till we reach the end */
102 /* or the one we want */
104 pp
+= _tcslen (pp
) + 1;
110 /* HBP_002 { FOR command support */
112 * Batch_params builds a parameter list in newlay allocated memory.
113 * The parameters consist of null terminated strings with a final
114 * NULL character signalling the end of the parameters.
118 LPTSTR
BatchParams (LPTSTR s1
, LPTSTR s2
)
120 LPTSTR dp
= (LPTSTR
)malloc ((_tcslen(s1
) + _tcslen(s2
) + 3) * sizeof (TCHAR
));
122 /* JPP 20-Jul-1998 added error checking */
125 error_out_of_memory();
131 s1
= stpcpy (dp
, s1
);
139 if (_istspace (*s2
) || _tcschr (_T(",;"), *s2
))
143 while (*s2
&& _tcschr (_T(" ,;"), *s2
))
148 if ((*s2
== _T('"')) || (*s2
== _T('\'')))
154 while (*s2
&& (*s2
!= st
));
170 * If a batch file is current, exits it, freeing the context block and
171 * chaining back to the previous one.
173 * If no new batch context is found, sets ECHO back ON.
175 * If the parameter is non-null or not empty, it is printed as an exit
179 VOID
ExitBatch (LPTSTR msg
)
182 DebugPrintf ("ExitBatch: (\'%s\')\n", msg
);
187 LPBATCH_CONTEXT t
= bc
;
191 CloseHandle (bc
->hBatchFile
);
192 bc
->hBatchFile
= INVALID_HANDLE_VALUE
;
198 /* HBP_002 { FOR command support */
208 /* HBP_003 { fix echo restore */
209 /* Preserve echo state across batch calls */
212 /* HBP_003 fix echo restore } */
221 ConOutPrintf ("%s\n", msg
);
226 * Start batch file execution
228 * The firstword parameter is the full filename of the batch file.
232 BOOL
Batch (LPTSTR fullname
, LPTSTR firstword
, LPTSTR param
)
236 hFile
= CreateFile (fullname
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
237 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
|
238 FILE_FLAG_SEQUENTIAL_SCAN
, NULL
);
241 DebugPrintf ("Batch: (\'%s\', \'%s\', \'%s\') hFile = %x\n",
242 fullname
, firstword
, param
, hFile
);
245 if (hFile
== INVALID_HANDLE_VALUE
)
247 ConErrPrintf (_T("Error opening batch file\n"));
251 /* HBP_002 { FOR command support */
253 /* Kill any and all FOR contexts */
254 while (bc
&& bc
->forvar
)
261 /* No curent batch file, create a new context */
262 LPBATCH_CONTEXT n
= (LPBATCH_CONTEXT
)malloc (sizeof(BATCH_CONTEXT
));
266 /* JPP 20-Jul-1998 added error checking */
267 error_out_of_memory ();
274 else if (bc
->hBatchFile
!= INVALID_HANDLE_VALUE
)
276 /* Then we are transferring to another batch */
277 CloseHandle (bc
->hBatchFile
);
278 bc
->hBatchFile
= INVALID_HANDLE_VALUE
;
282 bc
->hBatchFile
= hFile
;
283 bc
->bEcho
= bEcho
; /* Preserve echo across batch calls [HBP_001] */
286 /* HBP_002 { FOR command support */
288 bc
->forvar
= _T('\0');
290 bc
->params
= BatchParams (firstword
, param
);
298 * Read and return the next executable line form the current batch file
300 * If no batch file is current or no further executable lines are found
303 * Here we also look out for FOR bcontext structures which trigger the
304 * FOR expansion code.
306 * Set eflag to 0 if line is not to be echoed else 1
309 LPTSTR
ReadBatchLine (LPBOOL bLocalEcho
)
311 HANDLE hFind
= INVALID_HANDLE_VALUE
;
320 DebugPrintf ("ReadBatchLine ()\n");
326 if (CheckCtrlBreak (BREAK_BATCHFILE
))
333 /* HBP_002 { FOR command support */
338 /* If its a FOR context... */
341 LPTSTR sp
= bc
->forproto
; /* pointer to prototype command */
342 LPTSTR dp
= textline
; /* Place to expand protoype */
343 LPTSTR fv
= FindArg (0); /* Next list element */
345 /* End of list so... */
346 if ((fv
== NULL
) || (*fv
== _T('\0')))
348 /* just exit this context */
353 if (_tcscspn (fv
, _T("?*")) == _tcslen (fv
))
355 /* element is wild file */
356 bc
->shiftlevel
++; /* No use it and shift list */
360 /* Wild file spec, find first (or next) file name */
363 /* First already done so do next */
364 fv
= FindNextFile (hFind
, bc
->ffind
) ? bc
->ffind
->cFileName
: NULL
;
368 /* For first find, allocate a find first block */
369 if ((bc
->ffind
= (LPWIN32_FIND_DATA
)malloc (sizeof (WIN32_FIND_DATA
))) == NULL
)
371 error_out_of_memory(); /* JPP 20-Jul-1998 added error checking */
375 hFind
= FindFirstFile (fv
, bc
->ffind
);
376 fv
= !(hFind
==INVALID_HANDLE_VALUE
) ? bc
->ffind
->cFileName
: NULL
;
381 /* Null indicates no more files.. */
382 free (bc
->ffind
); /* free the buffer */
384 bc
->shiftlevel
++; /* On to next list element */
389 /* At this point, fv points to parameter string */
392 if ((*sp
== _T('%')) && (*(sp
+ 1) == bc
->forvar
))
395 dp
= stpcpy (dp
, fv
);
414 if (!FileGetString (bc
->hBatchFile
, textline
, sizeof (textline
)))
417 DebugPrintf (_T("ReadBatchLine(): Reached EOF!\n"));
419 /* End of file.... */
429 DebugPrintf (_T("ReadBatchLine(): textline: \'%s\'\n"), textline
);
432 /* Strip leading spaces and trailing space/control chars */
433 for (first
= textline
; _istspace (*first
); first
++)
436 for (ip
= first
+ _tcslen (first
) - 1; _istspace (*ip
) || _istcntrl (*ip
); ip
--)
441 /* ignore labels and empty lines */
442 if (*first
== _T(':') || *first
== 0)
445 if (*first
== _T('@'))
447 /* don't echo this line */
450 while (_istspace (*first
));