[PATCH 2/7] [cmd] Rework parameter parsing for WCMD_Copy
Ann and Jason Edmeades
jason at edmeades.me.uk
Fri Oct 12 04:52:33 CDT 2012
This patch reworks the parameter parsing in WCMD_Copy in preparation
for adding support for various unsupported capabilities. At present,
all this does is parse the command line and build up a list of sources
and correctly handle the /a and /b flags into fields which are not
used (by this patch). Subsequent patches will use these structures
to add the concatenation support plus /a and /b support.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.winehq.org/pipermail/wine-patches/attachments/20121012/69e61410/attachment.html>
-------------- next part --------------
From 855063824118ea1b953d7cde168ed3b355e2a524 Mon Sep 17 00:00:00 2001
From: Jason Edmeades <jason at edmeades.me.uk>
Date: Mon, 8 Oct 2012 21:25:58 +0100
Subject: [PATCH 2/7] [cmd] Rework parameter parsing for WCMD_Copy
This patch reworks the parameter parsing in WCMD_Copy in preparation
for adding support for various unsupported capabilities. At present,
all this does is parse the command line and build up a list of sources
and correctly handle the /a and /b flags into fields which are not
used (by this patch). Subsequent patches will use these structures
to add the concatenation support plus /a and /b support.
---
programs/cmd/builtins.c | 221 +++++++++++++++++++++++++++++++++++++++++++++--
programs/cmd/wcmd.h | 2 +-
programs/cmd/wcmdmain.c | 2 +-
3 files changed, 214 insertions(+), 11 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index f1c356c..2f13af0 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -375,10 +375,18 @@ void WCMD_choice (const WCHAR * command) {
* 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;
- 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;
WCHAR outpath[MAX_PATH], srcpath[MAX_PATH], copycmd[4];
DWORD len;
@@ -391,14 +399,177 @@ void WCMD_copy (void) {
WCHAR fname[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) {
WCMD_output_stderr (WCMD_LoadMessage(WCMD_NOARG));
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 */
- WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(param1));
- GetFullPathNameW(param1, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
+ WINE_TRACE("Copy source (supplied): '%s'\n", wine_dbgstr_w(sourcelist->name));
+ GetFullPathNameW(sourcelist->name, sizeof(srcpath)/sizeof(WCHAR), srcpath, NULL);
if (srcpath[strlenW(srcpath) - 1] == '\\')
srcpath[strlenW(srcpath) - 1] = '\0';
@@ -420,12 +591,17 @@ void WCMD_copy (void) {
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 */
- WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(param2));
- if (param2[0] == 0x00) {
- strcpyW(param2, dotW);
+ if (destination) {
+ WINE_TRACE("Copy destination (supplied): '%s'\n", wine_dbgstr_w(destination->name));
+ strcpyW(param2, destination->name);
+ } else {
+ WINE_TRACE("Copy destination not supplied\n");
+ strcpyW(param2, dotW);
}
GetFullPathNameW(param2, sizeof(outpath)/sizeof(WCHAR), outpath, NULL);
@@ -501,14 +677,41 @@ void WCMD_copy (void) {
/* Do the copy as appropriate */
if (overwrite) {
status = CopyFileW(srcname, outname, FALSE);
- if (!status) WCMD_print_error ();
+ if (!status) {
+ WCMD_print_error ();
+ errorlevel = 1;
+ }
}
} while (FindNextFileW(hff, &fd) != 0);
FindClose (hff);
} else {
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;
}
/****************************************************************************
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index 32edc2b..529ca28 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -60,7 +60,7 @@ void WCMD_change_tty (void);
void WCMD_choice (const WCHAR *);
void WCMD_clear_screen (void);
void WCMD_color (void);
-void WCMD_copy (void);
+void WCMD_copy (WCHAR *);
void WCMD_create_dir (WCHAR *);
BOOL WCMD_delete (WCHAR *);
void WCMD_directory (WCHAR *);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index 5109ecf..7cd6bda 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -1469,7 +1469,7 @@ void WCMD_execute (const WCHAR *command, const WCHAR *redirects,
WCMD_clear_screen ();
break;
case WCMD_COPY:
- WCMD_copy ();
+ WCMD_copy (p);
break;
case WCMD_CTTY:
WCMD_change_tty ();
--
1.7.9.5
More information about the wine-patches
mailing list