diff options
Diffstat (limited to 'win/winMain.c')
-rw-r--r-- | win/winMain.c | 300 |
1 files changed, 200 insertions, 100 deletions
diff --git a/win/winMain.c b/win/winMain.c index 01a5e23..62bcbd8 100644 --- a/win/winMain.c +++ b/win/winMain.c @@ -1,29 +1,29 @@ /* * winMain.c -- * - * Main entry point for wish and other Tk-based applications. + * Provides a default version of the main program and Tcl_AppInit + * procedure for wish and other Tk-based applications. * - * Copyright (c) 1995-1997 Sun Microsystems, Inc. - * Copyright (c) 1998-1999 by Scriptics Corporation. + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 Scriptics Corporation. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ -#include "tkInt.h" +#include "tk.h" #define WIN32_LEAN_AND_MEAN #include <windows.h> #undef WIN32_LEAN_AND_MEAN #include <locale.h> +#include <stdlib.h> +#include <tchar.h> #if defined(__GNUC__) int _CRT_glob = 0; #endif /* __GNUC__ */ -/* - * The following declarations refer to internal Tk routines. These interfaces - * are available for use, but are not supported. - */ #ifdef TK_TEST extern Tcl_PackageInitProc Tktest_Init; #endif /* TK_TEST */ @@ -34,12 +34,14 @@ extern Tcl_PackageInitProc Dde_Init; extern Tcl_PackageInitProc Dde_SafeInit; #endif +#ifdef TCL_BROKEN_MAINARGS +static void setargv(int *argcPtr, TCHAR ***argvPtr); +#endif + /* * Forward declarations for procedures defined later in this file: */ -static void WishPanic(CONST char *format, ...); - static BOOL consoleRequired = TRUE; /* @@ -51,7 +53,10 @@ static BOOL consoleRequired = TRUE; #ifndef TK_LOCAL_APPINIT #define TK_LOCAL_APPINIT Tcl_AppInit #endif -extern int TK_LOCAL_APPINIT(Tcl_Interp *interp); +#ifndef MODULE_SCOPE +# define MODULE_SCOPE extern +#endif +MODULE_SCOPE int TK_LOCAL_APPINIT(Tcl_Interp *interp); /* * The following #if block allows you to change how Tcl finds the startup @@ -60,13 +65,17 @@ extern int TK_LOCAL_APPINIT(Tcl_Interp *interp); */ #ifdef TK_LOCAL_MAIN_HOOK -extern int TK_LOCAL_MAIN_HOOK(int *argc, char ***argv); +MODULE_SCOPE int TK_LOCAL_MAIN_HOOK(int *argc, TCHAR ***argv); #endif + +/* Make sure the stubbed variants of those are never used. */ +#undef Tcl_ObjSetVar2 +#undef Tcl_NewStringObj /* *---------------------------------------------------------------------- * - * WinMain -- + * _tWinMain -- * * Main entry point from Windows. * @@ -80,17 +89,23 @@ extern int TK_LOCAL_MAIN_HOOK(int *argc, char ***argv); */ int APIENTRY +#ifdef TCL_BROKEN_MAINARGS WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) +#else +_tWinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpszCmdLine, + int nCmdShow) +#endif { - char **argv; + TCHAR **argv; int argc; - char *p; - - Tcl_SetPanicProc(WishPanic); + TCHAR *p; /* * Create the console channels and install them as the standard channels. @@ -111,8 +126,12 @@ WinMain( * Get our args from the c-runtime. Ignore lpszCmdLine. */ +#if defined(TCL_BROKEN_MAINARGS) + setargv(&argc, &argv); +#else argc = __argc; - argv = __argv; + argv = __targv; +#endif /* * Forward slashes substituted for backslashes. @@ -129,7 +148,7 @@ WinMain( #endif Tk_Main(argc, argv, TK_LOCAL_APPINIT); - return 1; + return 0; /* Needed only to prevent compiler warning. */ } /* @@ -155,14 +174,11 @@ int Tcl_AppInit( Tcl_Interp *interp) /* Interpreter for application. */ { -#define TK_MAX_WARN_LEN 1024 - WCHAR msgString[TK_MAX_WARN_LEN + 5]; - - if (Tcl_Init(interp) == TCL_ERROR) { - goto error; + if ((Tcl_Init)(interp) == TCL_ERROR) { + return TCL_ERROR; } if (Tk_Init(interp) == TCL_ERROR) { - goto error; + return TCL_ERROR; } Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); @@ -173,26 +189,26 @@ Tcl_AppInit( if (consoleRequired) { if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) { - goto error; + return TCL_ERROR; } } #if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES if (Registry_Init(interp) == TCL_ERROR) { - goto error; + return TCL_ERROR; } - Tcl_StaticPackage(interp, "registry", Registry_Init, NULL); + Tcl_StaticPackage(interp, "registry", Registry_Init, 0); if (Dde_Init(interp) == TCL_ERROR) { - goto error; + return TCL_ERROR; } - Tcl_StaticPackage(interp, "dde", Dde_Init, NULL); + Tcl_StaticPackage(interp, "dde", Dde_Init, Dde_SafeInit); #endif #ifdef TK_TEST if (Tktest_Init(interp) == TCL_ERROR) { - goto error; + return TCL_ERROR; } - Tcl_StaticPackage(interp, "Tktest", Tktest_Init, NULL); + Tcl_StaticPackage(interp, "Tktest", Tktest_Init, 0); #endif /* TK_TEST */ /* @@ -208,7 +224,7 @@ Tcl_AppInit( */ /* - * Call Tcl_CreateCommand for application-specific commands, if they + * Call Tcl_CreateObjCommand for application-specific commands, if they * weren't already created by the init procedures called above. */ @@ -219,76 +235,16 @@ Tcl_AppInit( * specific startup file will be run under any conditions. */ - Tcl_SetVar(interp, "tcl_rcFileName", "~/wishrc.tcl", TCL_GLOBAL_ONLY); + Tcl_ObjSetVar2(interp, Tcl_NewStringObj("tcl_rcFileName", -1), NULL, + Tcl_NewStringObj("~/wishrc.tcl", -1), TCL_GLOBAL_ONLY); return TCL_OK; - -error: - MultiByteToWideChar(CP_UTF8, 0, Tcl_GetStringResult(interp), -1, - msgString, TK_MAX_WARN_LEN); - /* - * Truncate MessageBox string if it is too long to not overflow the screen - * and cause possible oversized window error. - */ - memcpy(msgString + TK_MAX_WARN_LEN, L" ...", 5 * sizeof(WCHAR)); - MessageBeep(MB_ICONEXCLAMATION); - MessageBoxW(NULL, msgString, L"Error in Wish", - MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); - ExitProcess(1); - - /* - * We won't reach this, but we need the return. - */ - - return TCL_ERROR; -} - -/* - *---------------------------------------------------------------------- - * - * WishPanic -- - * - * Display a message and exit. - * - * Results: - * None. - * - * Side effects: - * Exits the program. - * - *---------------------------------------------------------------------- - */ - -void -WishPanic( - CONST char *format, ...) -{ - va_list argList; - char buf[TK_MAX_WARN_LEN]; - WCHAR msgString[TK_MAX_WARN_LEN + 5]; - - va_start(argList, format); - vsprintf(buf, format, argList); - - MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TK_MAX_WARN_LEN); - /* - * Truncate MessageBox string if it is too long to not overflow the screen - * and cause possible oversized window error. - */ - memcpy(msgString + TK_MAX_WARN_LEN, L" ...", 5 * sizeof(WCHAR)); - MessageBeep(MB_ICONEXCLAMATION); - MessageBoxW(NULL, msgString, L"Fatal Error in Wish", - MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); -#ifdef _MSC_VER - DebugBreak(); -#endif - ExitProcess(1); } #if defined(TK_TEST) /* *---------------------------------------------------------------------- * - * main -- + * _tmain -- * * Main entry point from the console. * @@ -302,13 +258,20 @@ WishPanic( *---------------------------------------------------------------------- */ +#ifdef TCL_BROKEN_MAINARGS int main( int argc, - char **argv) + char **dummy) { - Tcl_SetPanicProc(WishPanic); - + TCHAR **argv; +#else +int +_tmain( + int argc, + TCHAR **argv) +{ +#endif /* * Set up the default locale to be standard "C" locale so parsing is * performed correctly. @@ -316,6 +279,13 @@ main( setlocale(LC_ALL, "C"); +#ifdef TCL_BROKEN_MAINARGS + /* + * Get our args from the c-runtime. Ignore argc/argv. + */ + + setargv(&argc, &argv); +#endif /* * Console emulation widget not required as this entry is from the * console subsystem, thus stdin,out,err already have end-points. @@ -323,10 +293,140 @@ main( consoleRequired = FALSE; +#ifdef TK_LOCAL_MAIN_HOOK + TK_LOCAL_MAIN_HOOK(&argc, &argv); +#endif + Tk_Main(argc, argv, Tcl_AppInit); return 0; } -#endif /* TK_TEST */ +#endif /* !__GNUC__ || TK_TEST */ + + +/* + *------------------------------------------------------------------------- + * + * setargv -- + * + * Parse the Windows command line string into argc/argv. Done here + * because we don't trust the builtin argument parser in crt0. Windows + * applications are responsible for breaking their command line into + * arguments. + * + * 2N backslashes + quote -> N backslashes + begin quoted string + * 2N + 1 backslashes + quote -> literal + * N backslashes + non-quote -> literal + * quote + quote in a quoted string -> single quote + * quote + quote not in quoted string -> empty string + * quote -> begin quoted string + * + * Results: + * Fills argcPtr with the number of arguments and argvPtr with the array + * of arguments. + * + * Side effects: + * Memory allocated. + * + *-------------------------------------------------------------------------- + */ + +#ifdef TCL_BROKEN_MAINARGS +static void +setargv( + int *argcPtr, /* Filled with number of argument strings. */ + TCHAR ***argvPtr) /* Filled with argument strings (malloc'd). */ +{ + TCHAR *cmdLine, *p, *arg, *argSpace; + TCHAR **argv; + int argc, size, inquote, copy, slashes; + + cmdLine = GetCommandLine(); + + /* + * Precompute an overly pessimistic guess at the number of arguments in + * the command line by counting non-space spans. + */ + + size = 2; + for (p = cmdLine; *p != '\0'; p++) { + if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ + size++; + while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ + p++; + } + if (*p == '\0') { + break; + } + } + } + + /* Make sure we don't call ckalloc through the (not yet initialized) stub table */ + #undef Tcl_Alloc + #undef Tcl_DbCkalloc + + argSpace = ckalloc(size * sizeof(char *) + + (_tcslen(cmdLine) * sizeof(TCHAR)) + sizeof(TCHAR)); + argv = (TCHAR **) argSpace; + argSpace += size * (sizeof(char *)/sizeof(TCHAR)); + size--; + + p = cmdLine; + for (argc = 0; argc < size; argc++) { + argv[argc] = arg = argSpace; + while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ + p++; + } + if (*p == '\0') { + break; + } + + inquote = 0; + slashes = 0; + while (1) { + copy = 1; + while (*p == '\\') { + slashes++; + p++; + } + if (*p == '"') { + if ((slashes & 1) == 0) { + copy = 0; + if ((inquote) && (p[1] == '"')) { + p++; + copy = 1; + } else { + inquote = !inquote; + } + } + slashes >>= 1; + } + + while (slashes) { + *arg = '\\'; + arg++; + slashes--; + } + + if ((*p == '\0') || (!inquote && + ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ + break; + } + if (copy != 0) { + *arg = *p; + arg++; + } + p++; + } + *arg = '\0'; + argSpace = arg + 1; + } + argv[argc] = NULL; + + *argcPtr = argc; + *argvPtr = argv; +} +#endif /* TCL_BROKEN_MAINARGS */ + /* * Local Variables: * mode: c |