cmd: Use FormatMessage() for better internationalization support.
Francois Gouget
fgouget at free.fr
Tue Dec 6 10:40:42 CST 2011
This makes it possible to reorder the format string placeholders in message translations.
Also add a WCMD_format_string() function to mirror the WCMD_output*() ones and so all resources can use the same formatting style.
This also simplifies the padding code for the 'dir /w' command.
---
Yay. This is was the last case of a non-reorderable format string in the
po files.
programs/cmd/builtins.c | 27 +++++++-------
programs/cmd/cmd.rc | 28 +++++++-------
programs/cmd/directory.c | 59 +++++++++++-------------------
programs/cmd/wcmd.h | 1 +
programs/cmd/wcmdmain.c | 90 +++++++++++++++++++++++++++++++---------------
5 files changed, 111 insertions(+), 94 deletions(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 216a28b..ed34585 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -488,9 +488,10 @@ void WCMD_copy (void) {
else if (!overwrite) {
attribs = GetFileAttributesW(outname);
if (attribs != INVALID_FILE_ATTRIBUTES) {
- WCHAR buffer[MAXSTRING];
- wsprintfW(buffer, WCMD_LoadMessage(WCMD_OVERWRITE), outname);
- overwrite = WCMD_ask_confirm(buffer, FALSE, NULL);
+ WCHAR* question;
+ question = WCMD_format_string(WCMD_LoadMessage(WCMD_OVERWRITE), outname);
+ overwrite = WCMD_ask_confirm(question, FALSE, NULL);
+ LocalFree(question);
}
else overwrite = TRUE;
}
@@ -734,11 +735,12 @@ static BOOL WCMD_delete_one (const WCHAR *thisArg) {
/* /P means prompt for each file */
if (ok && strstrW (quals, parmP) != NULL) {
- WCHAR question[MAXSTRING];
+ WCHAR* question;
/* Ask for confirmation */
- wsprintfW(question, WCMD_LoadMessage(WCMD_DELPROMPT), fpath);
+ question = WCMD_format_string(WCMD_LoadMessage(WCMD_DELPROMPT), fpath);
ok = WCMD_ask_confirm(question, FALSE, NULL);
+ LocalFree(question);
}
/* Only proceed if ok to */
@@ -1711,14 +1713,15 @@ void WCMD_move (void)
/* Prompt if overwriting */
if (!force) {
- WCHAR question[MAXSTRING];
+ WCHAR* question;
WCHAR yesChar[10];
strcpyW(yesChar, WCMD_LoadMessage(WCMD_YES));
/* Ask for confirmation */
- wsprintfW(question, WCMD_LoadMessage(WCMD_OVERWRITE), dest);
+ question = WCMD_format_string(WCMD_LoadMessage(WCMD_OVERWRITE), dest);
ok = WCMD_ask_confirm(question, FALSE, NULL);
+ LocalFree(question);
/* So delete the destination prior to the move */
if (ok) {
@@ -2519,7 +2522,7 @@ void WCMD_type (WCHAR *command) {
errorlevel = 1;
} else {
if (writeHeaders) {
- static const WCHAR fmt[] = {'\n','%','s','\n','\n','\0'};
+ static const WCHAR fmt[] = {'\n','%','1','\n','\n','\0'};
WCMD_output(fmt, thisArg);
}
while (WCMD_ReadFile(h, buffer, sizeof(buffer)/sizeof(WCHAR) - 1, &count)) {
@@ -2866,7 +2869,6 @@ void WCMD_assoc (const WCHAR *command, BOOL assoc) {
} else {
WCHAR msgbuffer[MAXSTRING];
- WCHAR outbuffer[MAXSTRING];
/* Load the translated 'File association not found' */
if (assoc) {
@@ -2874,8 +2876,7 @@ void WCMD_assoc (const WCHAR *command, BOOL assoc) {
} else {
LoadStringW(hinst, WCMD_NOFTYPE, msgbuffer, sizeof(msgbuffer)/sizeof(WCHAR));
}
- wsprintfW(outbuffer, msgbuffer, keyValue);
- WCMD_output_asis_stderr(outbuffer);
+ WCMD_output_stderr(msgbuffer, keyValue);
errorlevel = 2;
}
@@ -2905,7 +2906,6 @@ void WCMD_assoc (const WCHAR *command, BOOL assoc) {
} else {
WCHAR msgbuffer[MAXSTRING];
- WCHAR outbuffer[MAXSTRING];
/* Load the translated 'File association not found' */
if (assoc) {
@@ -2915,8 +2915,7 @@ void WCMD_assoc (const WCHAR *command, BOOL assoc) {
LoadStringW(hinst, WCMD_NOFTYPE, msgbuffer,
sizeof(msgbuffer)/sizeof(WCHAR));
}
- wsprintfW(outbuffer, msgbuffer, keyValue);
- WCMD_output_asis_stderr(outbuffer);
+ WCMD_output_stderr(msgbuffer, keyValue);
errorlevel = 2;
}
diff --git a/programs/cmd/cmd.rc b/programs/cmd/cmd.rc
index 63ae599..7fe9d72 100644
--- a/programs/cmd/cmd.rc
+++ b/programs/cmd/cmd.rc
@@ -291,36 +291,36 @@ Enter HELP <command> for further information on any of the above commands.\n"
WCMD_CONFIRM, "Are you sure"
WCMD_YES, "#msgctxt#Yes key#Y"
WCMD_NO, "#msgctxt#No key#N"
- WCMD_NOASSOC, "File association missing for extension %s\n"
- WCMD_NOFTYPE, "No open command associated with file type '%s'\n"
- WCMD_OVERWRITE, "Overwrite %s"
+ WCMD_NOASSOC, "File association missing for extension %1\n"
+ WCMD_NOFTYPE, "No open command associated with file type '%1'\n"
+ WCMD_OVERWRITE, "Overwrite %1"
WCMD_MORESTR, "More..."
WCMD_TRUNCATEDLINE, "Line in Batch processing possibly truncated. Using:\n"
WCMD_NYI, "Not Yet Implemented\n\n"
WCMD_NOARG, "Argument missing\n"
WCMD_SYNTAXERR, "Syntax error\n"
- WCMD_FILENOTFOUND, "%s: File Not Found\n"
- WCMD_NOCMDHELP, "No help available for %s\n"
+ WCMD_FILENOTFOUND, "%1: File Not Found\n"
+ WCMD_NOCMDHELP, "No help available for %1\n"
WCMD_NOTARGET, "Target to GOTO not found\n"
- WCMD_CURRENTDATE, "Current Date is %s\n"
- WCMD_CURRENTTIME, "Current Time is %s\n"
+ WCMD_CURRENTDATE, "Current Date is %1\n"
+ WCMD_CURRENTTIME, "Current Time is %1\n"
WCMD_NEWDATE, "Enter new date: "
WCMD_NEWTIME, "Enter new time: "
- WCMD_MISSINGENV, "Environment variable %s not defined\n"
- WCMD_READFAIL, "Failed to open '%s'\n"
+ WCMD_MISSINGENV, "Environment variable %1 not defined\n"
+ WCMD_READFAIL, "Failed to open '%1'\n"
WCMD_CALLINSCRIPT, "Cannot call batch label outside of a batch script\n"
WCMD_ALL, "#msgctxt#All key#A"
- WCMD_DELPROMPT, "%s, Delete"
- WCMD_ECHOPROMPT, "Echo is %s\n"
- WCMD_VERIFYPROMPT, "Verify is %s\n"
+ WCMD_DELPROMPT, "%1, Delete"
+ WCMD_ECHOPROMPT, "Echo is %1\n"
+ WCMD_VERIFYPROMPT, "Verify is %1\n"
WCMD_VERIFYERR, "Verify must be ON or OFF\n"
WCMD_ARGERR, "Parameter error\n"
- WCMD_VOLUMEDETAIL, "Volume in drive %c is %s\nVolume Serial Number is %04x-%04x\n\n"
+ WCMD_VOLUMEDETAIL, "Volume in drive %1!c! is %2\nVolume Serial Number is %3!04x!-%4!04x!\n\n"
WCMD_VOLUMEPROMPT, "Volume label (11 characters, ENTER for none)?"
WCMD_NOPATH, "PATH not found\n"
WCMD_ANYKEY,"Press any key to continue... "
WCMD_CONSTITLE,"Wine Command Prompt"
- WCMD_VERSION,"CMD Version %s\n"
+ WCMD_VERSION,"CMD Version %1!S!\n"
WCMD_MOREPROMPT, "More? "
WCMD_LINETOOLONG, "The input line is too long.\n"
}
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c
index 7fc60a7..1134f23 100644
--- a/programs/cmd/directory.c
+++ b/programs/cmd/directory.c
@@ -254,14 +254,14 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
int concurrentDirs = 0;
BOOL done_header = FALSE;
- static const WCHAR fmtDir[] = {'%','1','0','s',' ',' ','%','8','s',' ',' ',
+ static const WCHAR fmtDir[] = {'%','1','!','1','0','s','!',' ',' ','%','2','!','8','s','!',' ',' ',
'<','D','I','R','>',' ',' ',' ',' ',' ',' ',' ',' ',' ','\0'};
- static const WCHAR fmtFile[] = {'%','1','0','s',' ',' ','%','8','s',' ',' ',
- ' ',' ','%','1','0','s',' ',' ','\0'};
- static const WCHAR fmt2[] = {'%','-','1','3','s','\0'};
- static const WCHAR fmt3[] = {'%','-','2','3','s','\0'};
- static const WCHAR fmt4[] = {'%','s','\0'};
- static const WCHAR fmt5[] = {'%','s','%','s','\0'};
+ static const WCHAR fmtFile[] = {'%','1','!','1','0','s','!',' ',' ','%','2','!','8','s','!',' ',' ',
+ ' ',' ','%','3','!','1','0','s','!',' ',' ','\0'};
+ static const WCHAR fmt2[] = {'%','1','!','-','1','3','s','!','\0'};
+ static const WCHAR fmt3[] = {'%','1','!','-','2','3','s','!','\0'};
+ static const WCHAR fmt4[] = {'%','1','\0'};
+ static const WCHAR fmt5[] = {'%','1','%','2','\0'};
dir_count = 0;
file_count = 0;
@@ -319,7 +319,7 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
if (level != 0 && (entry_count > 0)) WCMD_output_asis (newline);
if (!recurse || ((entry_count > 0) && done_header==FALSE)) {
static const WCHAR headerW[] = {'D','i','r','e','c','t','o','r','y',' ','o','f',
- ' ','%','s','\n','\n','\0'};
+ ' ','%','1','\n','\n','\0'};
WCMD_output (headerW, real_path);
done_header = TRUE;
}
@@ -391,12 +391,12 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
tmp_width = cur_width;
if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
- static const WCHAR fmt[] = {'[','%','s',']','\0'};
+ static const WCHAR fmt[] = {'[','%','1',']','\0'};
WCMD_output (fmt, (fd+i)->cFileName);
dir_count++;
tmp_width = tmp_width + strlenW((fd+i)->cFileName) + 2;
} else {
- static const WCHAR fmt[] = {'%','s','\0'};
+ static const WCHAR fmt[] = {'%','1','\0'};
WCMD_output (fmt, (fd+i)->cFileName);
tmp_width = tmp_width + strlenW((fd+i)->cFileName) ;
file_count++;
@@ -409,24 +409,9 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
if ((cur_width + widest) > max_width) {
cur_width = 0;
} else {
- int padding = cur_width - tmp_width;
- int toWrite = 0;
- WCHAR temp[101];
-
- /* Note: WCMD_output uses wvsprintf which does not allow %*
- so manually pad with spaces to appropriate width */
- strcpyW(temp, nullW);
- while (padding > 0) {
- strcatW(&temp[toWrite], space);
- toWrite++;
- if (toWrite > 99) {
- WCMD_output_asis(temp);
- toWrite = 0;
- strcpyW(temp, nullW);
- }
- padding--;
- }
- WCMD_output_asis(temp);
+ static const WCHAR padfmt[] = {'%','1','!','*','s','!','\0'};
+ static const WCHAR empty[] = {'\0'};
+ WCMD_output(padfmt, cur_width - tmp_width, empty);
}
} else if ((fd+i)->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
@@ -469,11 +454,11 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
if (!bare) {
if (file_count == 1) {
static const WCHAR fmt[] = {' ',' ',' ',' ',' ',' ',' ','1',' ','f','i','l','e',' ',
- '%','2','5','s',' ','b','y','t','e','s','\n','\0'};
+ '%','1','!','2','5','s','!',' ','b','y','t','e','s','\n','\0'};
WCMD_output (fmt, WCMD_filesize64 (byte_count.QuadPart));
}
else {
- static const WCHAR fmt[] = {'%','8','d',' ','f','i','l','e','s',' ','%','2','4','s',
+ static const WCHAR fmt[] = {'%','1','!','8','d','!',' ','f','i','l','e','s',' ','%','2','!','2','4','s','!',
' ','b','y','t','e','s','\n','\0'};
WCMD_output (fmt, file_count, WCMD_filesize64 (byte_count.QuadPart));
}
@@ -484,11 +469,11 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
if (!bare && !recurse) {
if (dir_count == 1) {
- static const WCHAR fmt[] = {'%','8','d',' ','d','i','r','e','c','t','o','r','y',
+ static const WCHAR fmt[] = {'%','1','!','8','d','!',' ','d','i','r','e','c','t','o','r','y',
' ',' ',' ',' ',' ',' ',' ',' ',' ','\0'};
WCMD_output (fmt, 1);
} else {
- static const WCHAR fmt[] = {'%','8','d',' ','d','i','r','e','c','t','o','r','i',
+ static const WCHAR fmt[] = {'%','1','!','8','d','!',' ','d','i','r','e','c','t','o','r','i',
'e','s','\0'};
WCMD_output (fmt, dir_count);
}
@@ -588,15 +573,15 @@ static void WCMD_dir_trailer(WCHAR drive) {
if (errorlevel==0 && !bare) {
if (recurse) {
static const WCHAR fmt1[] = {'\n',' ',' ',' ',' ',' ','T','o','t','a','l',' ','f','i','l','e','s',
- ' ','l','i','s','t','e','d',':','\n','%','8','d',' ','f','i','l','e',
- 's','%','2','5','s',' ','b','y','t','e','s','\n','\0'};
- static const WCHAR fmt2[] = {'%','8','d',' ','d','i','r','e','c','t','o','r','i','e','s',' ','%',
- '1','8','s',' ','b','y','t','e','s',' ','f','r','e','e','\n','\n',
+ ' ','l','i','s','t','e','d',':','\n','%','1','!','8','d','!',' ','f','i','l','e',
+ 's','%','2','!','2','5','s','!',' ','b','y','t','e','s','\n','\0'};
+ static const WCHAR fmt2[] = {'%','1','!','8','d','!',' ','d','i','r','e','c','t','o','r','i','e','s',' ','%',
+ '2','!','1','8','s','!',' ','b','y','t','e','s',' ','f','r','e','e','\n','\n',
'\0'};
WCMD_output (fmt1, file_total, WCMD_filesize64 (byte_total));
WCMD_output (fmt2, dir_total, WCMD_filesize64 (freebytes.QuadPart));
} else {
- static const WCHAR fmt[] = {' ','%','1','8','s',' ','b','y','t','e','s',' ','f','r','e','e',
+ static const WCHAR fmt[] = {' ','%','1','!','1','8','s','!',' ','b','y','t','e','s',' ','f','r','e','e',
'\n','\n','\0'};
WCMD_output (fmt, WCMD_filesize64 (freebytes.QuadPart));
}
diff --git a/programs/cmd/wcmd.h b/programs/cmd/wcmd.h
index fe16805..801c707 100644
--- a/programs/cmd/wcmd.h
+++ b/programs/cmd/wcmd.h
@@ -75,6 +75,7 @@ void WCMD_if (WCHAR *, CMD_LIST **cmdList);
void WCMD_leave_paged_mode(void);
void WCMD_more (WCHAR *);
void WCMD_move (void);
+WCHAR* WCMD_format_string (const WCHAR *format, ...);
void WCMD_output (const WCHAR *format, ...);
void WCMD_output_stderr (const WCHAR *format, ...);
void WCMD_output_asis (const WCHAR *message);
diff --git a/programs/cmd/wcmdmain.c b/programs/cmd/wcmdmain.c
index df4f9cb..cf2062a 100644
--- a/programs/cmd/wcmdmain.c
+++ b/programs/cmd/wcmdmain.c
@@ -123,19 +123,23 @@ static void WCMD_output_asis_len(const WCHAR *message, DWORD len, HANDLE device)
void WCMD_output (const WCHAR *format, ...) {
- va_list ap;
- WCHAR string[1024];
- DWORD ret;
-
- va_start(ap,format);
- ret = vsnprintfW(string, sizeof(string)/sizeof(WCHAR), format, ap);
- if( ret >= (sizeof(string)/sizeof(WCHAR))) {
- WINE_ERR("Output truncated\n" );
- ret = (sizeof(string)/sizeof(WCHAR)) - 1;
- string[ret] = '\0';
+ __ms_va_list ap;
+ WCHAR* string;
+ DWORD len;
+
+ __ms_va_start(ap,format);
+ SetLastError(NO_ERROR);
+ string = NULL;
+ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ format, 0, 0, (LPWSTR)&string, 0, &ap);
+ __ms_va_end(ap);
+ if (len == 0 && GetLastError() != NO_ERROR)
+ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(format));
+ else
+ {
+ WCMD_output_asis_len(string, len, GetStdHandle(STD_OUTPUT_HANDLE));
+ LocalFree(string);
}
- va_end(ap);
- WCMD_output_asis_len(string, ret, GetStdHandle(STD_OUTPUT_HANDLE));
}
/*******************************************************************
@@ -145,19 +149,47 @@ void WCMD_output (const WCHAR *format, ...) {
void WCMD_output_stderr (const WCHAR *format, ...) {
- va_list ap;
- WCHAR string[1024];
- DWORD ret;
-
- va_start(ap,format);
- ret = vsnprintfW(string, sizeof(string)/sizeof(WCHAR), format, ap);
- if( ret >= (sizeof(string)/sizeof(WCHAR))) {
- WINE_ERR("Output truncated\n" );
- ret = (sizeof(string)/sizeof(WCHAR)) - 1;
- string[ret] = '\0';
+ __ms_va_list ap;
+ WCHAR* string;
+ DWORD len;
+
+ __ms_va_start(ap,format);
+ SetLastError(NO_ERROR);
+ string = NULL;
+ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ format, 0, 0, (LPWSTR)&string, 0, &ap);
+ __ms_va_end(ap);
+ if (len == 0 && GetLastError() != NO_ERROR)
+ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(format));
+ else
+ {
+ WCMD_output_asis_len(string, len, GetStdHandle(STD_ERROR_HANDLE));
+ LocalFree(string);
+ }
+}
+
+/*******************************************************************
+ * WCMD_format_string - allocate a buffer and format a string
+ *
+ */
+
+WCHAR* WCMD_format_string (const WCHAR *format, ...) {
+
+ __ms_va_list ap;
+ WCHAR* string;
+ DWORD len;
+
+ __ms_va_start(ap,format);
+ SetLastError(NO_ERROR);
+ len = FormatMessageW(FORMAT_MESSAGE_FROM_STRING|FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ format, 0, 0, (LPWSTR)&string, 0, &ap);
+ __ms_va_end(ap);
+ if (len == 0 && GetLastError() != NO_ERROR) {
+ WINE_FIXME("Could not format string: le=%u, fmt=%s\n", GetLastError(), wine_dbgstr_w(format));
+ string = (WCHAR*)LocalAlloc(LMEM_FIXED, 2);
+ *string = 0;
}
- va_end(ap);
- WCMD_output_asis_len(string, ret, GetStdHandle(STD_ERROR_HANDLE));
+ return string;
}
void WCMD_enter_paged_mode(const WCHAR *msg)
@@ -2221,23 +2253,23 @@ void WCMD_free_commands(CMD_LIST *cmds) {
int wmain (int argc, WCHAR *argvW[])
{
int args;
- WCHAR *cmd = NULL;
+ WCHAR *cmd;
WCHAR string[1024];
WCHAR envvar[4];
BOOL opt_q;
int opt_t = 0;
static const WCHAR promptW[] = {'P','R','O','M','P','T','\0'};
static const WCHAR defaultpromptW[] = {'$','P','$','G','\0'};
- char ansiVersion[100];
CMD_LIST *toExecute = NULL; /* Commands left to be executed */
srand(time(NULL));
/* Pre initialize some messages */
- strcpy(ansiVersion, PACKAGE_VERSION);
- MultiByteToWideChar(CP_ACP, 0, ansiVersion, -1, string, 1024);
- wsprintfW(version_string, WCMD_LoadMessage(WCMD_VERSION), string);
strcpyW(anykey, WCMD_LoadMessage(WCMD_ANYKEY));
+ cmd = WCMD_format_string(WCMD_LoadMessage(WCMD_VERSION), PACKAGE_VERSION);
+ strcpyW(version_string, cmd);
+ LocalFree(cmd);
+ cmd = NULL;
args = argc;
opt_c = opt_k = opt_q = opt_s = FALSE;
--
1.7.7.3
More information about the wine-patches
mailing list