1 /* $Id: batch.c,v 1.3 1999/10/03 22:20:32 ekohl Exp $
3 * BATCH.C - batch file processor for CMD.EXE.
8 * ??/??/?? (Evan Jeffrey)
11 * 15 Jul 1995 (Tim Norman)
14 * 08 Aug 1995 (Matt Rains)
15 * i have cleaned up the source code. changes now bring this
16 * source into guidelines for recommended programming practice.
18 * i have added some constants to help making changes easier.
20 * 29 Jan 1996 (Steffan Kaiser)
21 * made a few cosmetic changes
23 * 05 Feb 1996 (Tim Norman)
24 * changed to comply with new first/rest calling scheme
26 * 14 Jun 1997 (Steffen Kaiser)
27 * bug fixes. added error level expansion %?. ctrl-break handling
29 * 16 Jul 1998 (Hans B Pufal)
30 * Totally reorganised in conjunction with COMMAND.C (cf) to
31 * implement proper BATCH file nesting and other improvements.
33 * 16 Jul 1998 (John P Price <linux-guru@gcfl.net>)
34 * Seperated commands into individual files.
36 * 19 Jul 1998 (Hans B Pufal) [HBP_001]
37 * Preserve state of echo flag across batch calls.
39 * 19 Jul 1998 (Hans B Pufal) [HBP_002]
40 * Implementation of FOR command
42 * 20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
43 * added error checking after malloc calls
45 * 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
46 * added config.h include
48 * 02-Aug-1998 (Hans B Pufal) [HBP_003]
49 * Fixed bug in ECHO flag restoration at exit from batch file
51 * 26-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
52 * Replaced CRT io functions by Win32 io functions.
68 /* The stack of current batch contexts.
69 * NULL when no batch is active
71 LPBATCH_CONTEXT bc
= NULL
;
73 BOOL bEcho
= TRUE
; /* The echo flag */
77 /* Buffer for reading Batch file lines */
78 TCHAR textline
[BATCH_BUFFSIZE
];
82 * Returns a pointer to the n'th parameter of the current batch file.
83 * If no such parameter exists returns pointer to empty string.
84 * If no batch file is current, returns NULL
88 LPTSTR
FindArg (INT n
)
93 DebugPrintf ("FindArg: (%d)\n", n
);
102 /* Step up the strings till we reach the end */
103 /* or the one we want */
105 pp
+= _tcslen (pp
) + 1;
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
));
168 * If a batch file is current, exits it, freeing the context block and
169 * chaining back to the previous one.
171 * If no new batch context is found, sets ECHO back ON.
173 * If the parameter is non-null or not empty, it is printed as an exit
177 VOID
ExitBatch (LPTSTR msg
)
180 DebugPrintf ("ExitBatch: (\'%s\')\n", msg
);
185 LPBATCH_CONTEXT t
= bc
;
189 CloseHandle (bc
->hBatchFile
);
190 bc
->hBatchFile
= INVALID_HANDLE_VALUE
;
202 /* Preserve echo state across batch calls */
210 ConOutPrintf ("%s\n", msg
);
215 * Start batch file execution
217 * The firstword parameter is the full filename of the batch file.
221 BOOL
Batch (LPTSTR fullname
, LPTSTR firstword
, LPTSTR param
)
225 hFile
= CreateFile (fullname
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
226 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
|
227 FILE_FLAG_SEQUENTIAL_SCAN
, NULL
);
230 DebugPrintf ("Batch: (\'%s\', \'%s\', \'%s\') hFile = %x\n",
231 fullname
, firstword
, param
, hFile
);
234 if (hFile
== INVALID_HANDLE_VALUE
)
236 ConErrPrintf (_T("Error opening batch file\n"));
240 /* Kill any and all FOR contexts */
241 while (bc
&& bc
->forvar
)
246 /* No curent batch file, create a new context */
247 LPBATCH_CONTEXT n
= (LPBATCH_CONTEXT
)malloc (sizeof(BATCH_CONTEXT
));
251 error_out_of_memory ();
258 else if (bc
->hBatchFile
!= INVALID_HANDLE_VALUE
)
260 /* Then we are transferring to another batch */
261 CloseHandle (bc
->hBatchFile
);
262 bc
->hBatchFile
= INVALID_HANDLE_VALUE
;
266 bc
->hBatchFile
= hFile
;
267 bc
->bEcho
= bEcho
; /* Preserve echo across batch calls */
271 bc
->forvar
= _T('\0');
273 bc
->params
= BatchParams (firstword
, param
);
276 DebugPrintf ("Batch: returns TRUE\n");
284 * Read and return the next executable line form the current batch file
286 * If no batch file is current or no further executable lines are found
289 * Here we also look out for FOR bcontext structures which trigger the
290 * FOR expansion code.
292 * Set eflag to 0 if line is not to be echoed else 1
295 LPTSTR
ReadBatchLine (LPBOOL bLocalEcho
)
297 HANDLE hFind
= INVALID_HANDLE_VALUE
;
306 DebugPrintf ("ReadBatchLine ()\n");
312 if (CheckCtrlBreak (BREAK_BATCHFILE
))
323 /* If its a FOR context... */
326 LPTSTR sp
= bc
->forproto
; /* pointer to prototype command */
327 LPTSTR dp
= textline
; /* Place to expand protoype */
328 LPTSTR fv
= FindArg (0); /* Next list element */
330 /* End of list so... */
331 if ((fv
== NULL
) || (*fv
== _T('\0')))
333 /* just exit this context */
338 if (_tcscspn (fv
, _T("?*")) == _tcslen (fv
))
340 /* element is wild file */
341 bc
->shiftlevel
++; /* No use it and shift list */
345 /* Wild file spec, find first (or next) file name */
348 /* First already done so do next */
349 fv
= FindNextFile (hFind
, bc
->ffind
) ? bc
->ffind
->cFileName
: NULL
;
353 /* For first find, allocate a find first block */
354 if ((bc
->ffind
= (LPWIN32_FIND_DATA
)malloc (sizeof (WIN32_FIND_DATA
))) == NULL
)
356 error_out_of_memory();
360 hFind
= FindFirstFile (fv
, bc
->ffind
);
361 fv
= !(hFind
==INVALID_HANDLE_VALUE
) ? bc
->ffind
->cFileName
: NULL
;
366 /* Null indicates no more files.. */
367 free (bc
->ffind
); /* free the buffer */
369 bc
->shiftlevel
++; /* On to next list element */
374 /* At this point, fv points to parameter string */
377 if ((*sp
== _T('%')) && (*(sp
+ 1) == bc
->forvar
))
380 dp
= stpcpy (dp
, fv
);
397 if (!FileGetString (bc
->hBatchFile
, textline
, sizeof (textline
)))
400 DebugPrintf (_T("ReadBatchLine(): Reached EOF!\n"));
402 /* End of file.... */
412 DebugPrintf (_T("ReadBatchLine(): textline: \'%s\'\n"), textline
);
415 /* Strip leading spaces and trailing space/control chars */
416 for (first
= textline
; _istspace (*first
); first
++)
419 for (ip
= first
+ _tcslen (first
) - 1; _istspace (*ip
) || _istcntrl (*ip
); ip
--)
424 /* ignore labels and empty lines */
425 if (*first
== _T(':') || *first
== 0)
428 if (*first
== _T('@'))
430 /* don't echo this line */
433 while (_istspace (*first
));