--- origsrc/cygutils-1.3.4/src/cygstart/cygstart.c 2009-04-22 11:30:26.000000000 +0900 +++ src/cygutils-1.3.4/src/cygstart/cygstart.c 2009-04-27 23:45:47.578125000 +0900 @@ -25,6 +25,9 @@ #endif #include "common.h" +#include +#include +#include #include /* The official name of this program (e.g., no `g' prefix). */ @@ -60,10 +63,12 @@ SF_WAIT = 1 << 1, } StartFlags; -static int cygStart(const char *aPath, const char *action, const char *args, - const char *workDir, int show, StartFlags startFlags); -static int winStart(const char *aPath, const char *action, const char *args, - const char *workDir, int show, StartFlags startFlags); +static int cygStart(const char *aPath, const wchar_t *action, + const wchar_t *args, const char *workDir, + int show, StartFlags startFlags); +static int winStart(const wchar_t *aPath, const wchar_t *action, + const wchar_t *args, const wchar_t *workDir, + int show, StartFlags startFlags); static char *startError(int err); static const char *getVersion(void); static void printTopDescription(FILE *f, char *name); @@ -73,6 +78,26 @@ static void version(poptContext optCon, FILE *f, char *name); static void license(poptContext optCon, FILE *f, char *name); +static size_t mbstowcs_noerr(wchar_t *wcs, const char *mbs, size_t n) +{ + size_t wcsLen = mbstowcs(wcs, mbs, n); + if (wcsLen == (size_t) -1) { + fprintf(stderr, "%s: multibyte to wide string conversion error\n", + program_name); + exit(1); + } + return wcsLen; +} + +static wchar_t *mbstowcs_dup(const char *mbs) +{ + size_t len = strlen(mbs); + wchar_t *wcs = (wchar_t *) malloc(sizeof(wchar_t) * (len + 1)); + size_t wcsLen = mbstowcs_noerr(wcs, mbs, len); + wcs[wcsLen] = L'\0'; + return wcs; +} + int main(int argc, const char **argv) { poptContext optCon; @@ -80,15 +105,17 @@ const char **rest; int rc; int ret; - char *action = NULL; + wchar_t *action = NULL; char *file = NULL; size_t argLength; const char **tmp; - char *args = NULL; + wchar_t *args = NULL; char *workDir = NULL; int show = SW_SHOWNORMAL; StartFlags startFlags = SF_NONE; + setlocale(LC_ALL, ""); + /* Action options */ struct poptOption actionOptionsTable[] = { { "action", 'a', POPT_ARG_STRING, NULL, 'a', \ @@ -257,7 +284,7 @@ /* Action options */ case 'a': if (arg = poptGetOptArg(optCon)) { - if ((action = strdup(arg)) == NULL ) { + if ((action = mbstowcs_dup(arg)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); @@ -265,31 +292,31 @@ } break; case 'o': - if ((action = strdup(ACTION_OPEN)) == NULL ) { + if ((action = mbstowcs_dup(ACTION_OPEN)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } break; case 'x': - if ((action = strdup(ACTION_EXPLORE)) == NULL ) { + if ((action = mbstowcs_dup(ACTION_EXPLORE)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } break; case 'e': - if ((action = strdup(ACTION_EDIT)) == NULL ) { + if ((action = mbstowcs_dup(ACTION_EDIT)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } break; case 'f': - if ((action = strdup(ACTION_FIND)) == NULL ) { + if ((action = mbstowcs_dup(ACTION_FIND)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } break; case 'p': - if ((action = strdup(ACTION_PRINT)) == NULL ) { + if ((action = mbstowcs_dup(ACTION_PRINT)) == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } @@ -385,15 +412,19 @@ while (tmp++ && *tmp) { argLength += 1 + strlen(*tmp); } - if ((args = (char *) malloc(argLength+1)) == NULL) { + if ((args = (wchar_t *) malloc(sizeof(wchar_t) * (argLength + 1))) + == NULL ) { fprintf(stderr, "%s: memory allocation error\n", argv[0]); exit(1); } - strcpy(args, *rest); + size_t argOffset = mbstowcs_noerr(args, *rest, argLength); while (rest++ && *rest) { - strcat(args, " "); - strcat(args, *rest); + args[argOffset++] = L' '; + size_t len = mbstowcs_noerr(args + argOffset, *rest, + argLength - argOffset); + argOffset += len; } + args[argOffset] = L'\0'; } /* Start it! */ @@ -413,54 +444,72 @@ return ret; } -/* Start a program, or open a file or URL, using Cygwin POSIX paths */ -static int cygStart(const char *aPath, const char *action, const char *args, - const char *workDir, int show, StartFlags startFlags) +/* ShellExecute*W is TOO SLOW when there is '\\?\' */ +static const wchar_t *skipLocalUNCPart(const wchar_t *path) { - char winPath[MAX_PATH+1]; - char winDir[MAX_PATH+1]; + size_t offset = 0; + + if (!wcsncmp(path, L"\\\\?\\", 4) && path[5] == L':') + return path + 4; + else + return path; +} + +/* Start a program, or open a file or URL, using Cygwin POSIX paths */ +static int cygStart(const char *aPath, const wchar_t *action, + const wchar_t *args, const char *workDir, + int show, StartFlags startFlags) +{ + wchar_t winPath[MAX_PATH+1]; + wchar_t winDir[MAX_PATH+1]; + const wchar_t *pWinPath; + const wchar_t *pWinDir; /* Convert file path from POSIX to Windows, unless it looks like a URL */ if (!strstr(aPath, "://")) { - cygwin_conv_to_win32_path(aPath, winPath); + cygwin_conv_path(CCP_POSIX_TO_WIN_W, aPath, winPath, sizeof(winPath)); + pWinPath = skipLocalUNCPart(winPath); } else { - strncpy(winPath, aPath, MAX_PATH); + mbstowcs(winPath, aPath, MAX_PATH); + pWinPath = winPath; } /* Convert working directory, if any, from POSIX to Windows */ if (workDir) { - cygwin_conv_to_win32_path(workDir, winDir); - return winStart(winPath, action, args, winDir, show, startFlags); + cygwin_conv_path(CCP_POSIX_TO_WIN_W, workDir, winDir, sizeof(winDir)); + pWinDir = skipLocalUNCPart(winDir); + return winStart(pWinPath, action, args, pWinDir, show, startFlags); } else { - return winStart(winPath, action, args, NULL, show, startFlags); + return winStart(pWinPath, action, args, NULL, show, startFlags); } } static void printLastError(FILE* file); /* Start a program, or open a file or URL, using Windows paths */ -static int winStart(const char *aPath, const char *action, const char *args, - const char *workDir, int show, StartFlags startFlags) +static int winStart(const wchar_t *aPath, const wchar_t *action, + const wchar_t *args, const wchar_t *workDir, + int show, StartFlags startFlags) { /* Need to sync the Windows environment */ cygwin_internal(CW_SYNC_WINENV); if (startFlags & SF_VERBOSE) { - printf("ShellExecute(NULL, \"%s\", \"%s\", \"%s\", \"%s\", %d)\n", + wprintf(L"ShellExecute(NULL, \"%ls\", \"%ls\", \"%ls\", \"%ls\", %d)\n", action, aPath, args, workDir, show); } if (!(startFlags & SF_WAIT)) { - int ret = (int) ShellExecute(NULL, action, aPath, args, workDir, show); + int ret = (int) ShellExecuteW(NULL, action, aPath, args, workDir, show); if (ret >= 32) { return 0; } else { - fprintf(stderr, "Unable to start '%s': %s\n", aPath, startError(ret)); + fwprintf(stderr, L"Unable to start '%ls': %s\n", aPath, startError(ret)); return 1; } } else { - SHELLEXECUTEINFO sei; + SHELLEXECUTEINFOW sei; memset(&sei, 0, sizeof(sei)); sei.cbSize = sizeof(sei); @@ -471,12 +520,12 @@ sei.nShow = show; sei.fMask |= SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI; - if (!ShellExecuteEx(&sei)) { + if (!ShellExecuteExW(&sei)) { if (((int) sei.hInstApp) < 32) { - fprintf(stderr, "Unable to start '%s': %s\n", aPath, startError((int) sei.hInstApp)); + fwprintf(stderr, L"Unable to start '%ls': %s\n", aPath, startError((int) sei.hInstApp)); return 1; } else { - fprintf(stderr, "Unable to start '%s': ", aPath); + fwprintf(stderr, L"Unable to start '%ls': ", aPath); printLastError(stderr); fprintf(stderr, "\n"); return 1;