diff options
Diffstat (limited to 'win/tclAppInit.c')
| -rw-r--r-- | win/tclAppInit.c | 346 | 
1 files changed, 141 insertions, 205 deletions
| diff --git a/win/tclAppInit.c b/win/tclAppInit.c index 864f59a..a6c1a67 100644 --- a/win/tclAppInit.c +++ b/win/tclAppInit.c @@ -1,40 +1,66 @@ -/*  +/*   * tclAppInit.c --   *   *	Provides a default version of the main program and Tcl_AppInit - *	procedure for Tcl applications (without Tk).  Note that this - *	program must be built in Win32 console mode to work properly. - * - * Copyright (c) 1996-1997 by Sun Microsystems, Inc. - * Copyright (c) 1998-1999 by Scriptics Corporation. + *	procedure for tclsh and other Tcl-based applications (without Tk). + *	Note that this program must be built in Win32 console mode to work + *	properly.   * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * Copyright (c) 1993 The Regents of the University of California. + * Copyright (c) 1994-1997 Sun Microsystems, Inc. + * Copyright (c) 1998-1999 Scriptics Corporation.   * - * RCS: @(#) $Id: tclAppInit.c,v 1.11 2002/12/04 03:59:17 davygrvy Exp $ + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES.   */  #include "tcl.h" +#define WIN32_LEAN_AND_MEAN  #include <windows.h> +#undef WIN32_LEAN_AND_MEAN  #include <locale.h> +#include <stdlib.h> +#include <tchar.h>  #ifdef TCL_TEST -extern int		Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -extern int		Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp)); -extern int		Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -extern int		TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp)); -#ifdef TCL_THREADS -extern int		TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp)); -#endif +extern Tcl_PackageInitProc Tcltest_Init; +extern Tcl_PackageInitProc Tcltest_SafeInit;  #endif /* TCL_TEST */ -static void		setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr)); -static BOOL __stdcall	sigHandler (DWORD fdwCtrlType); -static Tcl_AsyncProc	asyncExit; +#if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES +extern Tcl_PackageInitProc Registry_Init; +extern Tcl_PackageInitProc Dde_Init; +extern Tcl_PackageInitProc Dde_SafeInit; +#endif + +#ifdef TCL_BROKEN_MAINARGS +int _CRT_glob = 0; +static void setargv(int *argcPtr, TCHAR ***argvPtr); +#endif /* TCL_BROKEN_MAINARGS */ + +/* + * The following #if block allows you to change the AppInit function by using + * a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The + * #if checks for that #define and uses Tcl_AppInit if it does not exist. + */ + +#ifndef TCL_LOCAL_APPINIT +#define TCL_LOCAL_APPINIT Tcl_AppInit +#endif +#ifndef MODULE_SCOPE +#   define MODULE_SCOPE extern +#endif +MODULE_SCOPE int TCL_LOCAL_APPINIT(Tcl_Interp *); -Tcl_AsyncHandler	exitToken; -DWORD			exitErrorCode; +/* + * The following #if block allows you to change how Tcl finds the startup + * script, prime the library or encoding paths, fiddle with the argv, etc., + * without needing to rewrite Tcl_Main() + */ +#ifdef TCL_LOCAL_MAIN_HOOK +MODULE_SCOPE int TCL_LOCAL_MAIN_HOOK(int *argc, TCHAR ***argv); +#endif  /*   *---------------------------------------------------------------------- @@ -44,60 +70,51 @@ DWORD			exitErrorCode;   *	This is the main program for the application.   *   * Results: - *	None: Tcl_Main never returns here, so this procedure never - *	returns either. + *	None: Tcl_Main never returns here, so this procedure never returns + *	either.   *   * Side effects: - *	Whatever the application does. + *	Just about anything, since from here we call arbitrary Tcl code.   *   *----------------------------------------------------------------------   */ +#ifdef TCL_BROKEN_MAINARGS  int -main(argc, argv) -    int argc;			/* Number of command-line arguments. */ -    char **argv;		/* Values of command-line arguments. */ +main( +    int argc,			/* Number of command-line arguments. */ +    char *dummy[])		/* Not used. */ +{ +    TCHAR **argv; +#else +int +_tmain( +    int argc,			/* Number of command-line arguments. */ +    TCHAR *argv[])		/* Values of command-line arguments. */  { -    /* -     * The following #if block allows you to change the AppInit -     * function by using a #define of TCL_LOCAL_APPINIT instead -     * of rewriting this entire file.  The #if checks for that -     * #define and uses Tcl_AppInit if it doesn't exist. -     */ -     -#ifndef TCL_LOCAL_APPINIT -#define TCL_LOCAL_APPINIT Tcl_AppInit      #endif -    extern int TCL_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp)); -     +    TCHAR *p; +      /* -     * The following #if block allows you to change how Tcl finds the startup -     * script, prime the library or encoding paths, fiddle with the argv, -     * etc., without needing to rewrite Tcl_Main() +     * Set up the default locale to be standard "C" locale so parsing is +     * performed correctly.       */ -     -#ifdef TCL_LOCAL_MAIN_HOOK -    extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv)); -#endif -    char buffer[MAX_PATH +1]; -    char *p; +    setlocale(LC_ALL, "C"); + +#ifdef TCL_BROKEN_MAINARGS      /* -     * Set up the default locale to be standard "C" locale so parsing -     * is performed correctly. +     * Get our args from the c-runtime. Ignore command line.       */ -    setlocale(LC_ALL, "C");      setargv(&argc, &argv); +#endif      /* -     * Replace argv[0] with full pathname of executable, and forward -     * slashes substituted for backslashes. +     * Forward slashes substituted for backslashes.       */ -    GetModuleFileName(NULL, buffer, sizeof(buffer)); -    argv[0] = buffer; -    for (p = buffer; *p != '\0'; p++) { +    for (p = argv[0]; *p != '\0'; p++) {  	if (*p == '\\') {  	    *p = '/';  	} @@ -108,23 +125,21 @@ main(argc, argv)  #endif      Tcl_Main(argc, argv, TCL_LOCAL_APPINIT); -      return 0;			/* Needed only to prevent compiler warning. */  } -  /*   *----------------------------------------------------------------------   *   * Tcl_AppInit --   * - *	This procedure performs application-specific initialization. - *	Most applications, especially those that incorporate additional - *	packages, will have their own version of this procedure. + *	This procedure performs application-specific initialization. Most + *	applications, especially those that incorporate additional packages, + *	will have their own version of this procedure.   *   * Results: - *	Returns a standard Tcl completion code, and leaves an error - *	message in the interp's result if an error occurs. + *	Returns a standard Tcl completion code, and leaves an error message in + *	the interp's result if an error occurs.   *   * Side effects:   *	Depends on the startup script. @@ -133,81 +148,58 @@ main(argc, argv)   */  int -Tcl_AppInit(interp) -    Tcl_Interp *interp;		/* Interpreter for application. */ +Tcl_AppInit( +    Tcl_Interp *interp)		/* Interpreter for application. */  { -    if (Tcl_Init(interp) == TCL_ERROR) { +    if ((Tcl_Init)(interp) == TCL_ERROR) {  	return TCL_ERROR;      } -    /* -     * Install a signal handler to the win32 console tclsh is running in. -     */ -    SetConsoleCtrlHandler(sigHandler, TRUE);  -    exitToken = Tcl_AsyncCreate(asyncExit, NULL);  - -#ifdef TCL_TEST -    if (Tcltest_Init(interp) == TCL_ERROR) { -	return TCL_ERROR; -    } -    Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, -            (Tcl_PackageInitProc *) NULL); -    if (TclObjTest_Init(interp) == TCL_ERROR) { +#if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES +    if (Registry_Init(interp) == TCL_ERROR) {  	return TCL_ERROR;      } -#ifdef TCL_THREADS -    if (TclThread_Init(interp) == TCL_ERROR) { +    Tcl_StaticPackage(interp, "registry", Registry_Init, NULL); + +    if (Dde_Init(interp) == TCL_ERROR) {  	return TCL_ERROR;      } +    Tcl_StaticPackage(interp, "dde", Dde_Init, Dde_SafeInit);  #endif -    if (Procbodytest_Init(interp) == TCL_ERROR) { + +#ifdef TCL_TEST +    if (Tcltest_Init(interp) == TCL_ERROR) {  	return TCL_ERROR;      } -    Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init, -            Procbodytest_SafeInit); +    Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init, Tcltest_SafeInit);  #endif /* TCL_TEST */ -#if defined(STATIC_BUILD) && defined(TCL_USE_STATIC_PACKAGES) -    { -	extern Tcl_PackageInitProc Registry_Init; -	extern Tcl_PackageInitProc Dde_Init; - -	if (Registry_Init(interp) == TCL_ERROR) { -	    return TCL_ERROR; -	} -	Tcl_StaticPackage(interp, "registry", Registry_Init, NULL); - -	if (Dde_Init(interp) == TCL_ERROR) { -	    return TCL_ERROR; -	} -	Tcl_StaticPackage(interp, "dde", Dde_Init, NULL); -   } -#endif -      /* -     * Call the init procedures for included packages.  Each call should -     * look like this: +     * Call the init procedures for included packages. Each call should look +     * like this:       *       * if (Mod_Init(interp) == TCL_ERROR) {       *     return TCL_ERROR;       * }       * -     * where "Mod" is the name of the module. +     * where "Mod" is the name of the module. (Dynamically-loadable packages +     * should have the same entry-point name.)       */      /* -     * Call Tcl_CreateCommand for application-specific commands, if -     * they weren't already created by the init procedures called above. +     * Call Tcl_CreateCommand for application-specific commands, if they +     * weren't already created by the init procedures called above.       */      /* -     * Specify a user-specific startup file to invoke if the application -     * is run interactively.  Typically the startup file is "~/.apprc" -     * where "app" is the name of the application.  If this line is deleted -     * then no user-specific startup file will be run under any conditions. +     * Specify a user-specific startup file to invoke if the application is +     * run interactively. Typically the startup file is "~/.apprc" where "app" +     * is the name of the application. If this line is deleted then no +     * user-specific startup file will be run under any conditions.       */ -    Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY); +    (Tcl_ObjSetVar2)(interp, Tcl_NewStringObj("tcl_rcFileName", -1), NULL, +	    Tcl_NewStringObj("~/tclshrc.tcl", -1), TCL_GLOBAL_ONLY);      return TCL_OK;  } @@ -216,10 +208,10 @@ Tcl_AppInit(interp)   *   * 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. + *	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 @@ -229,8 +221,8 @@ Tcl_AppInit(interp)   *	quote -> begin quoted string   *   * Results: - *	Fills argcPtr with the number of arguments and argvPtr with the - *	array of arguments. + *	Fills argcPtr with the number of arguments and argvPtr with the array + *	of arguments.   *   * Side effects:   *	Memory allocated. @@ -238,20 +230,21 @@ Tcl_AppInit(interp)   *--------------------------------------------------------------------------   */ +#ifdef TCL_BROKEN_MAINARGS  static void -setargv(argcPtr, argvPtr) -    int *argcPtr;		/* Filled with number of argument strings. */ -    char ***argvPtr;		/* Filled with argument strings (malloc'd). */ +setargv( +    int *argcPtr,		/* Filled with number of argument strings. */ +    TCHAR ***argvPtr)		/* Filled with argument strings (malloc'd). */  { -    char *cmdLine, *p, *arg, *argSpace; -    char **argv; +    TCHAR *cmdLine, *p, *arg, *argSpace; +    TCHAR **argv;      int argc, size, inquote, copy, slashes; -     -    cmdLine = GetCommandLine();	/* INTL: BUG */ + +    cmdLine = GetCommandLine();      /* -     * Precompute an overly pessimistic guess at the number of arguments -     * in the command line by counting non-space spans. +     * Precompute an overly pessimistic guess at the number of arguments in +     * the command line by counting non-space spans.       */      size = 2; @@ -266,10 +259,15 @@ setargv(argcPtr, argvPtr)  	    }  	}      } -    argSpace = (char *) Tcl_Alloc( -	    (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1)); -    argv = (char **) argSpace; -    argSpace += size * sizeof(char *); + +    /* 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; @@ -299,18 +297,18 @@ setargv(argcPtr, argvPtr)  		    } else {  			inquote = !inquote;  		    } -                } -                slashes >>= 1; -            } +		} +		slashes >>= 1; +	    } -            while (slashes) { +	    while (slashes) {  		*arg = '\\';  		arg++;  		slashes--;  	    } -	    if ((*p == '\0') -		    || (!inquote && ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ +	    if ((*p == '\0') || (!inquote && +		    ((*p == ' ') || (*p == '\t')))) {	/* INTL: ISO space. */  		break;  	    }  	    if (copy != 0) { @@ -318,7 +316,7 @@ setargv(argcPtr, argvPtr)  		arg++;  	    }  	    p++; -        } +	}  	*arg = '\0';  	argSpace = arg + 1;      } @@ -327,74 +325,12 @@ setargv(argcPtr, argvPtr)      *argcPtr = argc;      *argvPtr = argv;  } - -/* - *---------------------------------------------------------------------- - * - * asyncExit -- - * - * 	The AsyncProc for the exitToken. - * - * Results: - * 	doesn't actually return. - * - * Side effects: - * 	tclsh cleanly exits. - * - *---------------------------------------------------------------------- - */ - -int -asyncExit (ClientData clientData, Tcl_Interp *interp, int code) -{ -    Tcl_Exit((int)exitErrorCode); - -    /* NOTREACHED */ -    return code; -} - +#endif /* TCL_BROKEN_MAINARGS */ +  /* - *---------------------------------------------------------------------- - * - * sigHandler -- - * - *	Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and - *	other exits. This is needed so tclsh can do it's real clean-up - *	and not an unclean crash terminate. - * - * Results: - *	TRUE. - * - * Side effects: - *	Effects the way the app exits from a signal. This is an - *	operating system supplied thread and unsafe to call ANY - *	Tcl commands except for Tcl_AsyncMark. - * - *---------------------------------------------------------------------- + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End:   */ - -BOOL __stdcall -sigHandler(DWORD fdwCtrlType) -{ -    HANDLE hStdIn; -    /* -     * If Tcl is currently executing some bytecode or in the eventloop, -     * this will cause Tcl to enter asyncExit at the next command -     * boundry. -     */ -    exitErrorCode = fdwCtrlType; -    Tcl_AsyncMark(exitToken); - -    /*  -     * This will cause Tcl_Gets in Tcl_Main() to drop-out with an <EOF>  -     * should it be blocked on input and our Tcl_AsyncMark didn't grab  -     * the attention of the interpreter.  -     */ -    hStdIn = GetStdHandle(STD_INPUT_HANDLE); -    if (hStdIn) { -	CloseHandle(hStdIn); -    } - -    /* indicate to the OS not to call the default terminator */  -    return TRUE;  -}  | 
