mirror of
https://github.com/reactos/reactos.git
synced 2025-07-29 15:52:19 +00:00
Added Eric Kohl's port of freedos command
svn path=/trunk/; revision=324
This commit is contained in:
parent
af3d943b02
commit
9f7f2c0f72
110 changed files with 23334 additions and 252 deletions
462
rosapps/cmd/batch.c
Normal file
462
rosapps/cmd/batch.c
Normal file
|
@ -0,0 +1,462 @@
|
|||
/*
|
||||
* BATCH.C - batch file processor for CMD.EXE.
|
||||
*
|
||||
*
|
||||
* History:
|
||||
*
|
||||
* ??/??/?? (Evan Jeffrey)
|
||||
* started.
|
||||
*
|
||||
* 15 Jul 1995 (Tim Norman)
|
||||
* modes and bugfixes.
|
||||
*
|
||||
* 08 Aug 1995 (Matt Rains)
|
||||
* i have cleaned up the source code. changes now bring this
|
||||
* source into guidelines for recommended programming practice.
|
||||
*
|
||||
* i have added some constants to help making changes easier.
|
||||
*
|
||||
* 29 Jan 1996 (Steffan Kaiser)
|
||||
* made a few cosmetic changes
|
||||
*
|
||||
* 05 Feb 1996 (Tim Norman)
|
||||
* changed to comply with new first/rest calling scheme
|
||||
*
|
||||
* 14 Jun 1997 (Steffen Kaiser)
|
||||
* bug fixes. added error level expansion %?. ctrl-break handling
|
||||
*
|
||||
* 16 Jul 1998 (Hans B Pufal)
|
||||
* Totally reorganised in conjunction with COMMAND.C (cf) to
|
||||
* implement proper BATCH file nesting and other improvements.
|
||||
*
|
||||
* 16 Jul 1998 (John P Price <linux-guru@gcfl.net>)
|
||||
* Seperated commands into individual files.
|
||||
*
|
||||
* 19 Jul 1998 (Hans B Pufal) [HBP_001]
|
||||
* Preserve state of echo flag across batch calls.
|
||||
*
|
||||
* 19 Jul 1998 (Hans B Pufal) [HBP_002]
|
||||
* Implementation of FOR command
|
||||
*
|
||||
* 20-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
||||
* added error checking after malloc calls
|
||||
*
|
||||
* 27-Jul-1998 (John P Price <linux-guru@gcfl.net>)
|
||||
* added config.h include
|
||||
*
|
||||
* 02-Aug-1998 (Hans B Pufal) [HBP_003]
|
||||
* Fixed bug in ECHO flag restoration at exit from batch file
|
||||
*
|
||||
* 26-Jan-1999 (Eric Kohl <ekohl@abo.rhein-zeitung.de>)
|
||||
* Replaced CRT io functions by Win32 io functions.
|
||||
* Unicode safe!
|
||||
*/
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "cmd.h"
|
||||
#include "batch.h"
|
||||
|
||||
|
||||
/* The stack of current batch contexts.
|
||||
* NULL when no batch is active
|
||||
*/
|
||||
LPBATCH_CONTEXT bc = NULL;
|
||||
|
||||
BOOL bEcho = TRUE; /* The echo flag */
|
||||
|
||||
|
||||
|
||||
/* Buffer for reading Batch file lines */
|
||||
TCHAR textline[BATCH_BUFFSIZE];
|
||||
|
||||
|
||||
/*
|
||||
* Returns a pointer to the n'th parameter of the current batch file.
|
||||
* If no such parameter exists returns pointer to empty string.
|
||||
* If no batch file is current, returns NULL
|
||||
*
|
||||
*/
|
||||
|
||||
LPTSTR FindArg (INT n)
|
||||
{
|
||||
LPTSTR pp;
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf ("FindArg: (%d)\n", n);
|
||||
#endif
|
||||
|
||||
if (bc == NULL)
|
||||
return NULL;
|
||||
|
||||
n += bc->shiftlevel;
|
||||
pp = bc->params;
|
||||
|
||||
/* Step up the strings till we reach the end */
|
||||
/* or the one we want */
|
||||
while (*pp && n--)
|
||||
pp += _tcslen (pp) + 1;
|
||||
|
||||
return pp;
|
||||
}
|
||||
|
||||
|
||||
/* HBP_002 { FOR command support */
|
||||
/*
|
||||
* Batch_params builds a parameter list in newlay allocated memory.
|
||||
* The parameters consist of null terminated strings with a final
|
||||
* NULL character signalling the end of the parameters.
|
||||
*
|
||||
*/
|
||||
|
||||
LPTSTR BatchParams (LPTSTR s1, LPTSTR s2)
|
||||
{
|
||||
LPTSTR dp = (LPTSTR)malloc ((_tcslen(s1) + _tcslen(s2) + 3) * sizeof (TCHAR));
|
||||
|
||||
/* JPP 20-Jul-1998 added error checking */
|
||||
if (dp == NULL)
|
||||
{
|
||||
error_out_of_memory();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (s1 && *s1)
|
||||
{
|
||||
s1 = stpcpy (dp, s1);
|
||||
*s1++ = _T('\0');
|
||||
}
|
||||
else
|
||||
s1 = dp;
|
||||
|
||||
while (*s2)
|
||||
{
|
||||
if (_istspace (*s2) || _tcschr (_T(",;"), *s2))
|
||||
{
|
||||
*s1++ = _T('\0');
|
||||
s2++;
|
||||
while (*s2 && _tcschr (_T(" ,;"), *s2))
|
||||
s2++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*s2 == _T('"')) || (*s2 == _T('\'')))
|
||||
{
|
||||
TCHAR st = *s2;
|
||||
|
||||
do
|
||||
*s1++ = *s2++;
|
||||
while (*s2 && (*s2 != st));
|
||||
}
|
||||
|
||||
*s1++ = *s2++;
|
||||
}
|
||||
|
||||
*s1++ = _T('\0');
|
||||
*s1 = _T('\0');
|
||||
|
||||
return dp;
|
||||
}
|
||||
|
||||
/* HBP_002 } */
|
||||
|
||||
|
||||
/*
|
||||
* If a batch file is current, exits it, freeing the context block and
|
||||
* chaining back to the previous one.
|
||||
*
|
||||
* If no new batch context is found, sets ECHO back ON.
|
||||
*
|
||||
* If the parameter is non-null or not empty, it is printed as an exit
|
||||
* message
|
||||
*/
|
||||
|
||||
VOID ExitBatch (LPTSTR msg)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf ("ExitBatch: (\'%s\')\n", msg);
|
||||
#endif
|
||||
|
||||
if (bc)
|
||||
{
|
||||
LPBATCH_CONTEXT t = bc;
|
||||
|
||||
if (bc->hBatchFile)
|
||||
{
|
||||
CloseHandle (bc->hBatchFile);
|
||||
bc->hBatchFile = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
if (bc->params)
|
||||
free(bc->params);
|
||||
|
||||
/* HBP_002 { FOR command support */
|
||||
|
||||
if (bc->forproto)
|
||||
free(bc->forproto);
|
||||
|
||||
if (bc->ffind)
|
||||
free(bc->ffind);
|
||||
|
||||
/* HBP_002 } */
|
||||
|
||||
/* HBP_003 { fix echo restore */
|
||||
/* Preserve echo state across batch calls */
|
||||
bEcho = bc->bEcho;
|
||||
|
||||
/* HBP_003 fix echo restore } */
|
||||
|
||||
bc = bc->prev;
|
||||
free(t);
|
||||
}
|
||||
|
||||
/* HBP_001 } */
|
||||
|
||||
if (msg && *msg)
|
||||
ConOutPrintf ("%s\n", msg);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Start batch file execution
|
||||
*
|
||||
* The firstword parameter is the full filename of the batch file.
|
||||
*
|
||||
*/
|
||||
|
||||
BOOL Batch (LPTSTR fullname, LPTSTR firstword, LPTSTR param)
|
||||
{
|
||||
HANDLE hFile;
|
||||
|
||||
hFile = CreateFile (fullname, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
|
||||
FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf ("Batch: (\'%s\', \'%s\', \'%s\') hFile = %x\n",
|
||||
fullname, firstword, param, hFile);
|
||||
#endif
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ConErrPrintf (_T("Error opening batch file\n"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* HBP_002 { FOR command support */
|
||||
|
||||
/* Kill any and all FOR contexts */
|
||||
while (bc && bc->forvar)
|
||||
ExitBatch (NULL);
|
||||
|
||||
/* HBP_002 } */
|
||||
|
||||
if (bc == NULL)
|
||||
{
|
||||
/* No curent batch file, create a new context */
|
||||
LPBATCH_CONTEXT n = (LPBATCH_CONTEXT)malloc (sizeof(BATCH_CONTEXT));
|
||||
|
||||
if (n == NULL)
|
||||
{
|
||||
/* JPP 20-Jul-1998 added error checking */
|
||||
error_out_of_memory ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
n->prev = bc;
|
||||
bc = n;
|
||||
}
|
||||
else if (bc->hBatchFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
/* Then we are transferring to another batch */
|
||||
CloseHandle (bc->hBatchFile);
|
||||
bc->hBatchFile = INVALID_HANDLE_VALUE;
|
||||
free (bc->params);
|
||||
}
|
||||
|
||||
bc->hBatchFile = hFile;
|
||||
bc->bEcho = bEcho; /* Preserve echo across batch calls [HBP_001] */
|
||||
bc->shiftlevel = 0;
|
||||
|
||||
/* HBP_002 { FOR command support */
|
||||
bc->ffind = NULL;
|
||||
bc->forvar = _T('\0');
|
||||
bc->forproto = NULL;
|
||||
bc->params = BatchParams (firstword, param);
|
||||
/* HBP_002 } */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read and return the next executable line form the current batch file
|
||||
*
|
||||
* If no batch file is current or no further executable lines are found
|
||||
* return NULL.
|
||||
*
|
||||
* Here we also look out for FOR bcontext structures which trigger the
|
||||
* FOR expansion code.
|
||||
*
|
||||
* Set eflag to 0 if line is not to be echoed else 1
|
||||
*/
|
||||
|
||||
LPTSTR ReadBatchLine (LPBOOL bLocalEcho)
|
||||
{
|
||||
HANDLE hFind = INVALID_HANDLE_VALUE;
|
||||
LPTSTR first;
|
||||
LPTSTR ip;
|
||||
|
||||
/* No batch */
|
||||
if (bc == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf ("ReadBatchLine ()\n");
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* User halt */
|
||||
if (CheckCtrlBreak (BREAK_BATCHFILE))
|
||||
{
|
||||
while (bc)
|
||||
ExitBatch (NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* HBP_002 { FOR command support */
|
||||
/* No batch */
|
||||
if (bc == NULL)
|
||||
return NULL;
|
||||
|
||||
/* If its a FOR context... */
|
||||
if (bc->forvar)
|
||||
{
|
||||
LPTSTR sp = bc->forproto; /* pointer to prototype command */
|
||||
LPTSTR dp = textline; /* Place to expand protoype */
|
||||
LPTSTR fv = FindArg (0); /* Next list element */
|
||||
|
||||
/* End of list so... */
|
||||
if ((fv == NULL) || (*fv == _T('\0')))
|
||||
{
|
||||
/* just exit this context */
|
||||
ExitBatch (NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_tcscspn (fv, _T("?*")) == _tcslen (fv))
|
||||
{
|
||||
/* element is wild file */
|
||||
bc->shiftlevel++; /* No use it and shift list */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wild file spec, find first (or next) file name */
|
||||
if (bc->ffind)
|
||||
{
|
||||
/* First already done so do next */
|
||||
fv = FindNextFile (hFind, bc->ffind) ? bc->ffind->cFileName : NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For first find, allocate a find first block */
|
||||
if ((bc->ffind = (LPWIN32_FIND_DATA)malloc (sizeof (WIN32_FIND_DATA))) == NULL)
|
||||
{
|
||||
error_out_of_memory(); /* JPP 20-Jul-1998 added error checking */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hFind = FindFirstFile (fv, bc->ffind);
|
||||
fv = !(hFind==INVALID_HANDLE_VALUE) ? bc->ffind->cFileName : NULL;
|
||||
}
|
||||
|
||||
if (fv == NULL)
|
||||
{
|
||||
/* Null indicates no more files.. */
|
||||
free (bc->ffind); /* free the buffer */
|
||||
bc->ffind = NULL;
|
||||
bc->shiftlevel++; /* On to next list element */
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* At this point, fv points to parameter string */
|
||||
while (*sp)
|
||||
{
|
||||
if ((*sp == _T('%')) && (*(sp + 1) == bc->forvar))
|
||||
{
|
||||
/* replace % var */
|
||||
dp = stpcpy (dp, fv);
|
||||
sp += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Else just copy */
|
||||
*dp++ = *sp++;
|
||||
}
|
||||
}
|
||||
|
||||
*dp = _T('\0');
|
||||
|
||||
*bLocalEcho = bEcho;
|
||||
|
||||
return textline;
|
||||
}
|
||||
|
||||
/* HBP_002 } */
|
||||
|
||||
if (!FileGetString (bc->hBatchFile, textline, sizeof (textline)))
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf (_T("ReadBatchLine(): Reached EOF!\n"));
|
||||
#endif
|
||||
/* End of file.... */
|
||||
ExitBatch (NULL);
|
||||
|
||||
if (bc == NULL)
|
||||
return NULL;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
DebugPrintf (_T("ReadBatchLine(): textline: \'%s\'\n"), textline);
|
||||
#endif
|
||||
|
||||
/* Strip leading spaces and trailing space/control chars */
|
||||
for (first = textline; _istspace (*first); first++)
|
||||
;
|
||||
|
||||
for (ip = first + _tcslen (first) - 1; _istspace (*ip) || _istcntrl (*ip); ip--)
|
||||
;
|
||||
|
||||
*++ip = _T('\0');
|
||||
|
||||
/* ignore labels and empty lines */
|
||||
if (*first == _T(':') || *first == 0)
|
||||
continue;
|
||||
|
||||
if (*first == _T('@'))
|
||||
{
|
||||
/* don't echo this line */
|
||||
do
|
||||
first++;
|
||||
while (_istspace (*first));
|
||||
|
||||
*bLocalEcho = 0;
|
||||
}
|
||||
else
|
||||
*bLocalEcho = bEcho;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return first;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue