cmd.exe: Support for DEL filename /s.
This commit is contained in:
parent
67fff3959f
commit
68b11d1290
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue