From 68b11d12906655bdb27053ffa14de74399620811 Mon Sep 17 00:00:00 2001 From: Jason Edmeades Date: Mon, 23 Apr 2007 23:24:38 +0100 Subject: [PATCH] cmd.exe: Support for DEL filename /s. --- programs/cmd/README | 7 --- programs/cmd/builtins.c | 128 ++++++++++++++++++++++++++++++++++----- programs/cmd/directory.c | 7 --- programs/cmd/wcmd.h | 11 +++- programs/cmd/wcmdmain.c | 2 +- 5 files changed, 125 insertions(+), 30 deletions(-) diff --git a/programs/cmd/README b/programs/cmd/README index ee1c542325e..d7d80c2dd88 100644 --- a/programs/cmd/README +++ b/programs/cmd/README @@ -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. - diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c index e7398fd74f9..4d0fd5e9e4e 100644 --- a/programs/cmd/builtins.c +++ b/programs/cmd/builtins.c @@ -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 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 \ */ - 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; } /**************************************************************************** diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c index 801d59d1205..24c7c6c6191 100644 --- a/programs/cmd/directory.c +++ b/programs/cmd/directory.c @@ -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; diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h index 8718dd608a5..76cd22b2f48 100644 --- a/programs/cmd/wcmd.h +++ b/programs/cmd/wcmd.h @@ -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 */ /* diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c index 88a827c4fe1..a74b0852f3b 100644 --- a/programs/cmd/wcmdmain.c +++ b/programs/cmd/wcmdmain.c @@ -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);