Commit 68b11d12 authored by Jason Edmeades's avatar Jason Edmeades Committed by Alexandre Julliard

cmd.exe: Support for DEL filename /s.

parent 67fff395
......@@ -11,7 +11,6 @@ WHAT'S INCLUDED
WHAT'S MISSING
- Command-line qualifiers for most builtin commands
- Wildcards and relative paths in COPY, MOVE and RENAME
- Set functionality in DATE, TIME, ATTRIB, LABEL
- Full internationalisation of the text (and commands?).
......@@ -26,11 +25,6 @@ US date-time format is used. Set eg "LANG=en_GB" for DD/MM/YY dates and 24-hour
times.
- Line editing and command recall doesn't work due to missing functionality in
Wine.
- DIR/S only works if no file specification is given, ie "DIR C:\TEMP /S" works
but "DIR C:\TEMP\*.C" doesn't work if a matching file exists in a lower
directory.
- Copy, rename, move, need the source and destination to be specified fully
with an absolute or relative path but no wildcards or partial filenames.
- Redirection is implemented as a command line is parsed. This means that ">"
and "<" symbols cannot appear in command arguments even within quotes.
- In many cases parsing and syntax checking is less rigorous than DOS. Thus an
......@@ -43,4 +37,3 @@ image. The Wine binary is simpler to invoke from the U**x command line or from
a GUI such as KDE, however it is not possible to invoke a second shell using the
"CMD /C filename" syntax. Conversely a Win32 application can be invoked from a
Win32 GUI such as Program Manager but that needs starting under Wine first.
......@@ -239,24 +239,32 @@ void WCMD_create_dir (void) {
* non-hidden files
*/
void WCMD_delete (char *command) {
BOOL WCMD_delete (char *command, BOOL expectDir) {
int argno = 0;
int argsProcessed = 0;
char *argN = command;
BOOL foundAny = FALSE;
/* If not recursing, clear error flag */
if (expectDir) errorlevel = 0;
/* Loop through all args */
while (argN) {
char *thisArg = WCMD_parameter (command, argno++, &argN);
char argCopy[MAX_PATH];
if (argN && argN[0] != '/') {
WIN32_FIND_DATA fd;
HANDLE hff;
char fpath[MAX_PATH];
char *p;
BOOL handleParm = TRUE;
BOOL found = FALSE;
WINE_TRACE("del: Processing arg %s (quals:%s)\n", thisArg, quals);
strcpy(argCopy, thisArg);
WINE_TRACE("del: Processing arg %s (quals:%s)\n", argCopy, quals);
argsProcessed++;
/* If filename part of parameter is * or *.*, prompt unless
......@@ -269,7 +277,7 @@ void WCMD_delete (char *command) {
char ext[MAX_PATH];
/* Convert path into actual directory spec */
GetFullPathName (thisArg, sizeof(fpath), fpath, NULL);
GetFullPathName (argCopy, sizeof(fpath), fpath, NULL);
WCMD_splitpath(fpath, drive, dir, fname, ext);
/* Only prompt for * and *.*, not *a, a*, *.a* etc */
......@@ -278,6 +286,9 @@ void WCMD_delete (char *command) {
BOOL ok;
char question[MAXSTRING];
/* Note: Flag as found, to avoid file not found message */
found = TRUE;
/* Ask for confirmation */
sprintf(question, "%s, ", fpath);
ok = WCMD_ask_confirm(question, TRUE);
......@@ -287,25 +298,28 @@ void WCMD_delete (char *command) {
}
}
hff = FindFirstFile (thisArg, &fd);
/* First, try to delete in the current directory */
hff = FindFirstFile (argCopy, &fd);
if (hff == INVALID_HANDLE_VALUE) {
WCMD_output ("%s :File Not Found\n", thisArg);
continue;
handleParm = FALSE;
} else {
found = TRUE;
}
/* Support del <dirname> by just deleting all files dirname\* */
if ((strchr(thisArg,'*') == NULL) && (strchr(thisArg,'?') == NULL)
if (handleParm && (strchr(argCopy,'*') == NULL) && (strchr(argCopy,'?') == NULL)
&& (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
char modifiedParm[MAX_PATH];
strcpy(modifiedParm, thisArg);
strcpy(modifiedParm, argCopy);
strcat(modifiedParm, "\\*");
FindClose(hff);
WCMD_delete(modifiedParm);
continue;
found = TRUE;
WCMD_delete(modifiedParm, FALSE);
} else {
} else if (handleParm) {
/* Build the filename to delete as <supplied directory>\<findfirst filename> */
strcpy (fpath, thisArg);
strcpy (fpath, argCopy);
do {
p = strrchr (fpath, '\\');
if (p != NULL) {
......@@ -399,14 +413,100 @@ void WCMD_delete (char *command) {
} while (FindNextFile(hff, &fd) != 0);
FindClose (hff);
}
/* Now recurse into all subdirectories handling the paramater in the same way */
if (strstr (quals, "/S") != NULL) {
char thisDir[MAX_PATH];
int cPos;
char drive[10];
char dir[MAX_PATH];
char fname[MAX_PATH];
char ext[MAX_PATH];
/* Convert path into actual directory spec */
GetFullPathName (argCopy, sizeof(thisDir), thisDir, NULL);
WCMD_splitpath(thisDir, drive, dir, fname, ext);
strcpy(thisDir, drive);
strcat(thisDir, dir);
cPos = strlen(thisDir);
WINE_TRACE("Searching recursively in '%s'\n", thisDir);
/* Append '*' to the directory */
thisDir[cPos] = '*';
thisDir[cPos+1] = 0x00;
hff = FindFirstFile (thisDir, &fd);
/* Remove residual '*' */
thisDir[cPos] = 0x00;
if (hff != INVALID_HANDLE_VALUE) {
DIRECTORY_STACK *allDirs = NULL;
DIRECTORY_STACK *lastEntry = NULL;
do {
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
(strcmp(fd.cFileName, "..") != 0) &&
(strcmp(fd.cFileName, ".") != 0)) {
DIRECTORY_STACK *nextDir;
char subParm[MAX_PATH];
/* Work out search parameter in sub dir */
strcpy (subParm, thisDir);
strcat (subParm, fd.cFileName);
strcat (subParm, "\\");
strcat (subParm, fname);
strcat (subParm, ext);
WINE_TRACE("Recursive, Adding to search list '%s'\n", subParm);
/* Allocate memory, add to list */
nextDir = (DIRECTORY_STACK *) HeapAlloc(GetProcessHeap(),0,sizeof(DIRECTORY_STACK));
if (allDirs == NULL) allDirs = nextDir;
if (lastEntry != NULL) lastEntry->next = nextDir;
lastEntry = nextDir;
nextDir->next = NULL;
nextDir->dirName = HeapAlloc(GetProcessHeap(),0,(strlen(subParm)+1));
strcpy(nextDir->dirName, subParm);
}
} while (FindNextFile(hff, &fd) != 0);
FindClose (hff);
/* Go through each subdir doing the delete */
while (allDirs != NULL) {
DIRECTORY_STACK *tempDir;
tempDir = allDirs->next;
found |= WCMD_delete (allDirs->dirName, FALSE);
HeapFree(GetProcessHeap(),0,allDirs->dirName);
HeapFree(GetProcessHeap(),0,allDirs);
allDirs = tempDir;
}
}
}
/* Keep running total to see if any found, and if not recursing
issue error message */
if (expectDir) {
if (!found) {
errorlevel = 1;
WCMD_output ("%s : File Not Found\n", argCopy);
}
}
foundAny |= found;
}
}
/* Handle no valid args */
if (argsProcessed == 0) {
WCMD_output ("Argument missing\n");
return;
}
return foundAny;
}
/****************************************************************************
......
......@@ -57,13 +57,6 @@ typedef enum _DISPLAYORDER
Date
} DISPLAYORDER;
typedef struct _DIRECTORY_STACK
{
struct _DIRECTORY_STACK *next;
char *dirName;
char *fileName;
} DIRECTORY_STACK;
static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *parms, int level);
static int file_total, dir_total, recurse, wide, bare, max_width, lower;
static int shortname, usernames;
......
......@@ -35,7 +35,7 @@ void WCMD_clear_screen (void);
void WCMD_color (void);
void WCMD_copy (void);
void WCMD_create_dir (void);
void WCMD_delete (char *);
BOOL WCMD_delete (char *, BOOL);
void WCMD_directory (char *);
void WCMD_echo (const char *);
void WCMD_endlocal (void);
......@@ -109,6 +109,15 @@ struct env_stack
WCHAR *strings;
};
/* Data structure to handle building lists during recursive calls */
typedef struct _DIRECTORY_STACK
{
struct _DIRECTORY_STACK *next;
char *dirName;
char *fileName;
} DIRECTORY_STACK;
#endif /* !RC_INVOKED */
/*
......
......@@ -620,7 +620,7 @@ void WCMD_process_command (char *command)
break;
case WCMD_DEL:
case WCMD_ERASE:
WCMD_delete (p);
WCMD_delete (p, TRUE);
break;
case WCMD_DIR:
WCMD_directory (p);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment