cmd: Rework parameter parsing for WCMD_Copy.
This commit is contained in:
parent
270163f380
commit
89b8868ae0
|
@ -375,10 +375,18 @@ void WCMD_choice (const WCHAR * command) {
|
||||||
* FIXME: Add support for a+b+c type syntax
|
* FIXME: Add support for a+b+c type syntax
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void WCMD_copy (void) {
|
void WCMD_copy(WCHAR * command) {
|
||||||
|
|
||||||
|
BOOL opt_d, opt_v, opt_n, opt_z;
|
||||||
|
WCHAR *thisparam;
|
||||||
|
int argno = 0;
|
||||||
|
WCHAR *rawarg;
|
||||||
WIN32_FIND_DATAW fd;
|
WIN32_FIND_DATAW fd;
|
||||||
HANDLE hff;
|
HANDLE hff;
|
||||||
|
int binarymode = -1; /* -1 means use the default, 1 is binary, 0 ascii */
|
||||||
|
BOOL concatnextfilename = FALSE; /* True if we have just processed a + */
|
||||||
|
BOOL anyconcats = FALSE; /* Have we found any + options */
|
||||||
|
|
||||||
BOOL force, status;
|
BOOL force, status;
|
||||||
WCHAR outpath[MAX_PATH], srcpath[MAX_PATH], copycmd[4];
|
WCHAR outpath[MAX_PATH], srcpath[MAX_PATH], copycmd[4];
|
||||||
DWORD len;
|
DWORD len;
|
||||||
|
@ -391,14 +399,177 @@ void WCMD_copy (void) {
|
||||||
WCHAR fname[MAX_PATH];
|
WCHAR fname[MAX_PATH];
|
||||||
WCHAR ext[MAX_PATH];
|
WCHAR ext[MAX_PATH];
|
||||||
|
|
||||||
|
typedef struct _COPY_FILES
|
||||||
|
{
|
||||||
|
struct _COPY_FILES *next;
|
||||||
|
BOOL concatenate;
|
||||||
|
WCHAR *name;
|
||||||
|
int binarycopy;
|
||||||
|
} COPY_FILES;
|
||||||
|
COPY_FILES *sourcelist = NULL;
|
||||||
|
COPY_FILES *lastcopyentry = NULL;
|
||||||
|
COPY_FILES *destination = NULL;
|
||||||
|
COPY_FILES *thiscopy = NULL;
|
||||||
|
COPY_FILES *prevcopy = NULL;
|
||||||
|
|
||||||
|
/* If no args supplied at all, report an error */
|
||||||
if (param1[0] == 0x00) {
|
if (param1[0] == 0x00) {
|
||||||
WCMD_output_stderr (WCMD_LoadMessage(WCMD_NOARG));
|
WCMD_output_stderr (WCMD_LoadMessage(WCMD_NOARG));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
opt_d = opt_v = opt_n = opt_z = FALSE;
|
||||||
|
|
||||||
|
/* Walk through all args, building up a list of files to process */
|
||||||
|
thisparam = WCMD_parameter(command, argno++, &rawarg, NULL, TRUE);
|
||||||
|
while (*(thisparam)) {
|
||||||
|
WCHAR *pos1, *pos2;
|
||||||
|
BOOL inquotes;
|
||||||
|
|
||||||
|
WINE_TRACE("Working on parameter '%s'\n", wine_dbgstr_w(thisparam));
|
||||||
|
|
||||||
|
/* Handle switches */
|
||||||
|
if (*thisparam == '/') {
|
||||||
|
while (*thisparam == '/') {
|
||||||
|
thisparam++;
|
||||||
|
if (toupperW(*thisparam) == 'D') {
|
||||||
|
opt_d = TRUE;
|
||||||
|
if (opt_d) WINE_FIXME("copy /D support not implemented yet\n");
|
||||||
|
} else if (toupperW(*thisparam) == 'V') {
|
||||||
|
opt_v = TRUE;
|
||||||
|
if (opt_v) WINE_FIXME("copy /V support not implemented yet\n");
|
||||||
|
} else if (toupperW(*thisparam) == 'N') {
|
||||||
|
opt_n = TRUE;
|
||||||
|
if (opt_n) WINE_FIXME("copy /N support not implemented yet\n");
|
||||||
|
} else if (toupperW(*thisparam) == 'Z') {
|
||||||
|
opt_z = TRUE;
|
||||||
|
if (opt_z) WINE_FIXME("copy /Z support not implemented yet\n");
|
||||||
|
} else if (toupperW(*thisparam) == 'A') {
|
||||||
|
if (binarymode != 0) {
|
||||||
|
binarymode = 0;
|
||||||
|
WINE_TRACE("Subsequent files will be handled as ASCII\n");
|
||||||
|
if (destination != NULL) {
|
||||||
|
WINE_TRACE("file %s will be written as ASCII\n", wine_dbgstr_w(destination->name));
|
||||||
|
destination->binarycopy = binarymode;
|
||||||
|
} else if (lastcopyentry != NULL) {
|
||||||
|
WINE_TRACE("file %s will be read as ASCII\n", wine_dbgstr_w(lastcopyentry->name));
|
||||||
|
lastcopyentry->binarycopy = binarymode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (toupperW(*thisparam) == 'B') {
|
||||||
|
if (binarymode != 1) {
|
||||||
|
binarymode = 1;
|
||||||
|
WINE_TRACE("Subsequent files will be handled as binary\n");
|
||||||
|
if (destination != NULL) {
|
||||||
|
WINE_TRACE("file %s will be written as binary\n", wine_dbgstr_w(destination->name));
|
||||||
|
destination->binarycopy = binarymode;
|
||||||
|
} else if (lastcopyentry != NULL) {
|
||||||
|
WINE_TRACE("file %s will be read as binary\n", wine_dbgstr_w(lastcopyentry->name));
|
||||||
|
lastcopyentry->binarycopy = binarymode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
WINE_FIXME("Unexpected copy switch %s\n", wine_dbgstr_w(thisparam));
|
||||||
|
}
|
||||||
|
thisparam++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This parameter was purely switches, get the next one */
|
||||||
|
thisparam = WCMD_parameter(command, argno++, &rawarg, NULL, TRUE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have found something which is not a switch. If could be anything of the form
|
||||||
|
sourcefilename (which could be destination too)
|
||||||
|
+ (when filename + filename syntex used)
|
||||||
|
sourcefilename+sourcefilename
|
||||||
|
+sourcefilename
|
||||||
|
+/b[tests show windows then ignores to end of parameter]
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (*thisparam=='+') {
|
||||||
|
if (lastcopyentry == NULL) {
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||||
|
errorlevel = 1;
|
||||||
|
goto exitreturn;
|
||||||
|
} else {
|
||||||
|
concatnextfilename = TRUE;
|
||||||
|
anyconcats = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Move to next thing to process */
|
||||||
|
thisparam++;
|
||||||
|
if (*thisparam == 0x00) thisparam = WCMD_parameter(command, argno++, &rawarg, NULL, TRUE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have found something to process - build a COPY_FILE block to store it */
|
||||||
|
thiscopy = HeapAlloc(GetProcessHeap(),0,sizeof(COPY_FILES));
|
||||||
|
if (thiscopy == NULL) goto exitreturn;
|
||||||
|
|
||||||
|
|
||||||
|
WINE_TRACE("Not a switch, but probably a filename/list %s\n", wine_dbgstr_w(thisparam));
|
||||||
|
thiscopy->concatenate = concatnextfilename;
|
||||||
|
thiscopy->binarycopy = binarymode;
|
||||||
|
thiscopy->next = NULL;
|
||||||
|
|
||||||
|
/* Time to work out the name. Allocate at least enough space (deliberately too much to
|
||||||
|
leave space to append \* to the end) , then copy in character by character. Strip off
|
||||||
|
quotes if we find them. */
|
||||||
|
len = strlenW(thisparam) + (sizeof(WCHAR) * 5); /* 5 spare characters, null + \*.* */
|
||||||
|
thiscopy->name = HeapAlloc(GetProcessHeap(),0,len*sizeof(WCHAR));
|
||||||
|
memset(thiscopy->name, 0x00, len);
|
||||||
|
|
||||||
|
pos1 = thisparam;
|
||||||
|
pos2 = thiscopy->name;
|
||||||
|
inquotes = FALSE;
|
||||||
|
while (*pos1 && (inquotes || (*pos1 != '+' && *pos1 != '/'))) {
|
||||||
|
if (*pos1 == '"') {
|
||||||
|
inquotes = !inquotes;
|
||||||
|
pos1++;
|
||||||
|
} else *pos2++ = *pos1++;
|
||||||
|
}
|
||||||
|
*pos2 = 0;
|
||||||
|
WINE_TRACE("Calculated file name %s\n", wine_dbgstr_w(thiscopy->name));
|
||||||
|
|
||||||
|
/* This is either the first source, concatenated subsequent source or destination */
|
||||||
|
if (sourcelist == NULL) {
|
||||||
|
WINE_TRACE("Adding as first source part\n");
|
||||||
|
sourcelist = thiscopy;
|
||||||
|
lastcopyentry = thiscopy;
|
||||||
|
} else if (concatnextfilename) {
|
||||||
|
WINE_TRACE("Adding to source file list to be concatenated\n");
|
||||||
|
lastcopyentry->next = thiscopy;
|
||||||
|
lastcopyentry = thiscopy;
|
||||||
|
} else if (destination == NULL) {
|
||||||
|
destination = thiscopy;
|
||||||
|
} else {
|
||||||
|
/* We have processed sources and destinations and still found more to do - invalid */
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||||
|
errorlevel = 1;
|
||||||
|
goto exitreturn;
|
||||||
|
}
|
||||||
|
concatnextfilename = FALSE;
|
||||||
|
|
||||||
|
/* We either need to process the rest of the parameter or move to the next */
|
||||||
|
if (*pos1 == '/' || *pos1 == '+') {
|
||||||
|
thisparam = pos1;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
thisparam = WCMD_parameter(command, argno++, &rawarg, NULL, TRUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure we have at least one source file */
|
||||||
|
if (!sourcelist) {
|
||||||
|
WCMD_output_stderr(WCMD_LoadMessage(WCMD_SYNTAXERR));
|
||||||
|
errorlevel = 1;
|
||||||
|
goto exitreturn;
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert source into full spec */
|
/* Convert source into full spec */
|
||||||
WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(param1));
|
WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(sourcelist->name));
|
||||||
GetFullPathNameW(param1, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
|
GetFullPathNameW(sourcelist->name, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
|
||||||
if (srcpath[strlenW(srcpath) - 1] == '\\')
|
if (srcpath[strlenW(srcpath) - 1] == '\\')
|
||||||
srcpath[strlenW(srcpath) - 1] = '\0';
|
srcpath[strlenW(srcpath) - 1] = '\0';
|
||||||
|
|
||||||
|
@ -420,12 +591,17 @@ void WCMD_copy (void) {
|
||||||
strcatW(srcpath, dir);
|
strcatW(srcpath, dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
WINE_TRACE("Copy source (calculated): path: '%s'\n", wine_dbgstr_w(srcpath));
|
WINE_TRACE("Copy source (calculated): path: '%s' (Concats: %d)\n",
|
||||||
|
wine_dbgstr_w(srcpath), anyconcats);
|
||||||
|
|
||||||
|
/* Temporarily use param2 to hold destination */
|
||||||
/* If no destination supplied, assume current directory */
|
/* If no destination supplied, assume current directory */
|
||||||
WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(param2));
|
if (destination) {
|
||||||
if (param2[0] == 0x00) {
|
WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(destination->name));
|
||||||
strcpyW(param2, dotW);
|
strcpyW(param2, destination->name);
|
||||||
|
} else {
|
||||||
|
WINE_TRACE("Copy destination not supplied\n");
|
||||||
|
strcpyW(param2, dotW);
|
||||||
}
|
}
|
||||||
|
|
||||||
GetFullPathNameW(param2, sizeof(outpath)/sizeof(WCHAR), outpath, NULL);
|
GetFullPathNameW(param2, sizeof(outpath)/sizeof(WCHAR), outpath, NULL);
|
||||||
|
@ -501,14 +677,41 @@ void WCMD_copy (void) {
|
||||||
/* Do the copy as appropriate */
|
/* Do the copy as appropriate */
|
||||||
if (overwrite) {
|
if (overwrite) {
|
||||||
status = CopyFileW(srcname, outname, FALSE);
|
status = CopyFileW(srcname, outname, FALSE);
|
||||||
if (!status) WCMD_print_error ();
|
if (!status) {
|
||||||
|
WCMD_print_error ();
|
||||||
|
errorlevel = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (FindNextFileW(hff, &fd) != 0);
|
} while (FindNextFileW(hff, &fd) != 0);
|
||||||
FindClose (hff);
|
FindClose (hff);
|
||||||
} else {
|
} else {
|
||||||
WCMD_print_error ();
|
WCMD_print_error ();
|
||||||
|
errorlevel = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We were successful! */
|
||||||
|
errorlevel = 0;
|
||||||
|
|
||||||
|
/* Exit out of the routine, freeing any remaing allocated memory */
|
||||||
|
exitreturn:
|
||||||
|
|
||||||
|
thiscopy = sourcelist;
|
||||||
|
while (thiscopy != NULL) {
|
||||||
|
prevcopy = thiscopy;
|
||||||
|
/* Free up this block*/
|
||||||
|
thiscopy = thiscopy -> next;
|
||||||
|
HeapFree(GetProcessHeap(), 0, prevcopy->name);
|
||||||
|
HeapFree(GetProcessHeap(), 0, prevcopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free up the destination memory */
|
||||||
|
if (destination) {
|
||||||
|
HeapFree(GetProcessHeap(), 0, destination->name);
|
||||||
|
HeapFree(GetProcessHeap(), 0, destination);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|
|
@ -60,7 +60,7 @@ void WCMD_change_tty (void);
|
||||||
void WCMD_choice (const WCHAR *);
|
void WCMD_choice (const WCHAR *);
|
||||||
void WCMD_clear_screen (void);
|
void WCMD_clear_screen (void);
|
||||||
void WCMD_color (void);
|
void WCMD_color (void);
|
||||||
void WCMD_copy (void);
|
void WCMD_copy (WCHAR *);
|
||||||
void WCMD_create_dir (WCHAR *);
|
void WCMD_create_dir (WCHAR *);
|
||||||
BOOL WCMD_delete (WCHAR *);
|
BOOL WCMD_delete (WCHAR *);
|
||||||
void WCMD_directory (WCHAR *);
|
void WCMD_directory (WCHAR *);
|
||||||
|
|
|
@ -1469,7 +1469,7 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
|
||||||
WCMD_clear_screen ();
|
WCMD_clear_screen ();
|
||||||
break;
|
break;
|
||||||
case WCMD_COPY:
|
case WCMD_COPY:
|
||||||
WCMD_copy ();
|
WCMD_copy (p);
|
||||||
break;
|
break;
|
||||||
case WCMD_CTTY:
|
case WCMD_CTTY:
|
||||||
WCMD_change_tty ();
|
WCMD_change_tty ();
|
||||||
|
|
Loading…
Reference in New Issue