tclAppInit.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /*
  2.  * tclAppInit.c --
  3.  *
  4.  * Provides a default version of the main program and Tcl_AppInit
  5.  * procedure for Tcl applications (without Tk).  Note that this
  6.  * program must be built in Win32 console mode to work properly.
  7.  *
  8.  * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
  9.  * Copyright (c) 1998-1999 by Scriptics Corporation.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * RCS: @(#) $Id: tclAppInit.c,v 1.11.2.3 2007/03/19 17:06:26 dgp Exp $
  15.  */
  16. #include "tcl.h"
  17. #include <windows.h>
  18. #include <locale.h>
  19. #ifdef TCL_TEST
  20. extern int Procbodytest_Init _ANSI_ARGS_((Tcl_Interp *interp));
  21. extern int Procbodytest_SafeInit _ANSI_ARGS_((Tcl_Interp *interp));
  22. extern int Tcltest_Init _ANSI_ARGS_((Tcl_Interp *interp));
  23. extern int TclObjTest_Init _ANSI_ARGS_((Tcl_Interp *interp));
  24. #ifdef TCL_THREADS
  25. extern int TclThread_Init _ANSI_ARGS_((Tcl_Interp *interp));
  26. #endif
  27. #endif /* TCL_TEST */
  28. static void setargv _ANSI_ARGS_((int *argcPtr, char ***argvPtr));
  29. static BOOL __stdcall sigHandler (DWORD fdwCtrlType);
  30. static Tcl_AsyncProc asyncExit;
  31. static void AppInitExitHandler(ClientData clientData);
  32. static char **          argvSave = NULL;
  33. static Tcl_AsyncHandler exitToken = NULL;
  34. static DWORD            exitErrorCode = 0;
  35. /*
  36.  *----------------------------------------------------------------------
  37.  *
  38.  * main --
  39.  *
  40.  * This is the main program for the application.
  41.  *
  42.  * Results:
  43.  * None: Tcl_Main never returns here, so this procedure never
  44.  * returns either.
  45.  *
  46.  * Side effects:
  47.  * Whatever the application does.
  48.  *
  49.  *----------------------------------------------------------------------
  50.  */
  51. int
  52. main(argc, argv)
  53.     int argc; /* Number of command-line arguments. */
  54.     char **argv; /* Values of command-line arguments. */
  55. {
  56.     /*
  57.      * The following #if block allows you to change the AppInit
  58.      * function by using a #define of TCL_LOCAL_APPINIT instead
  59.      * of rewriting this entire file.  The #if checks for that
  60.      * #define and uses Tcl_AppInit if it doesn't exist.
  61.      */
  62. #ifndef TCL_LOCAL_APPINIT
  63. #define TCL_LOCAL_APPINIT Tcl_AppInit
  64. #endif
  65.     extern int TCL_LOCAL_APPINIT _ANSI_ARGS_((Tcl_Interp *interp));
  66.     /*
  67.      * The following #if block allows you to change how Tcl finds the startup
  68.      * script, prime the library or encoding paths, fiddle with the argv,
  69.      * etc., without needing to rewrite Tcl_Main()
  70.      */
  71. #ifdef TCL_LOCAL_MAIN_HOOK
  72.     extern int TCL_LOCAL_MAIN_HOOK _ANSI_ARGS_((int *argc, char ***argv));
  73. #endif
  74.     char buffer[MAX_PATH +1];
  75.     char *p;
  76.     /*
  77.      * Set up the default locale to be standard "C" locale so parsing
  78.      * is performed correctly.
  79.      */
  80.     setlocale(LC_ALL, "C");
  81.     setargv(&argc, &argv);
  82.     /*
  83.      * Save this for later, so we can free it.
  84.      */
  85.     argvSave = argv;
  86.     /*
  87.      * Replace argv[0] with full pathname of executable, and forward
  88.      * slashes substituted for backslashes.
  89.      */
  90.     GetModuleFileName(NULL, buffer, sizeof(buffer));
  91.     argv[0] = buffer;
  92.     for (p = buffer; *p != ''; p++) {
  93. if (*p == '\') {
  94.     *p = '/';
  95. }
  96.     }
  97. #ifdef TCL_LOCAL_MAIN_HOOK
  98.     TCL_LOCAL_MAIN_HOOK(&argc, &argv);
  99. #endif
  100.     Tcl_Main(argc, argv, TCL_LOCAL_APPINIT);
  101.     return 0; /* Needed only to prevent compiler warning. */
  102. }
  103. /*
  104.  *----------------------------------------------------------------------
  105.  *
  106.  * Tcl_AppInit --
  107.  *
  108.  * This procedure performs application-specific initialization.
  109.  * Most applications, especially those that incorporate additional
  110.  * packages, will have their own version of this procedure.
  111.  *
  112.  * Results:
  113.  * Returns a standard Tcl completion code, and leaves an error
  114.  * message in the interp's result if an error occurs.
  115.  *
  116.  * Side effects:
  117.  * Depends on the startup script.
  118.  *
  119.  *----------------------------------------------------------------------
  120.  */
  121. int
  122. Tcl_AppInit(interp)
  123.     Tcl_Interp *interp; /* Interpreter for application. */
  124. {
  125.     if (Tcl_Init(interp) == TCL_ERROR) {
  126. return TCL_ERROR;
  127.     }
  128.     /*
  129.      * Install a signal handler to the win32 console tclsh is running in.
  130.      */
  131.     SetConsoleCtrlHandler(sigHandler, TRUE);
  132.     exitToken = Tcl_AsyncCreate(asyncExit, NULL);
  133.     /*
  134.      * This exit handler will be used to free the
  135.      * resources allocated in this file.
  136.      */
  137.     Tcl_CreateExitHandler(AppInitExitHandler, NULL);
  138. #ifdef TCL_TEST
  139.     if (Tcltest_Init(interp) == TCL_ERROR) {
  140. return TCL_ERROR;
  141.     }
  142.     Tcl_StaticPackage(interp, "Tcltest", Tcltest_Init,
  143.             (Tcl_PackageInitProc *) NULL);
  144.     if (TclObjTest_Init(interp) == TCL_ERROR) {
  145. return TCL_ERROR;
  146.     }
  147. #ifdef TCL_THREADS
  148.     if (TclThread_Init(interp) == TCL_ERROR) {
  149. return TCL_ERROR;
  150.     }
  151. #endif
  152.     if (Procbodytest_Init(interp) == TCL_ERROR) {
  153. return TCL_ERROR;
  154.     }
  155.     Tcl_StaticPackage(interp, "procbodytest", Procbodytest_Init,
  156.             Procbodytest_SafeInit);
  157. #endif /* TCL_TEST */
  158. #if defined(STATIC_BUILD) && defined(TCL_USE_STATIC_PACKAGES)
  159.     {
  160. extern Tcl_PackageInitProc Registry_Init;
  161. extern Tcl_PackageInitProc Dde_Init;
  162. if (Registry_Init(interp) == TCL_ERROR) {
  163.     return TCL_ERROR;
  164. }
  165. Tcl_StaticPackage(interp, "registry", Registry_Init, NULL);
  166. if (Dde_Init(interp) == TCL_ERROR) {
  167.     return TCL_ERROR;
  168. }
  169. Tcl_StaticPackage(interp, "dde", Dde_Init, NULL);
  170.    }
  171. #endif
  172.     /*
  173.      * Call the init procedures for included packages.  Each call should
  174.      * look like this:
  175.      *
  176.      * if (Mod_Init(interp) == TCL_ERROR) {
  177.      *     return TCL_ERROR;
  178.      * }
  179.      *
  180.      * where "Mod" is the name of the module.
  181.      */
  182.     /*
  183.      * Call Tcl_CreateCommand for application-specific commands, if
  184.      * they weren't already created by the init procedures called above.
  185.      */
  186.     /*
  187.      * Specify a user-specific startup file to invoke if the application
  188.      * is run interactively.  Typically the startup file is "~/.apprc"
  189.      * where "app" is the name of the application.  If this line is deleted
  190.      * then no user-specific startup file will be run under any conditions.
  191.      */
  192.     Tcl_SetVar(interp, "tcl_rcFileName", "~/tclshrc.tcl", TCL_GLOBAL_ONLY);
  193.     return TCL_OK;
  194. }
  195. /*
  196.  *----------------------------------------------------------------------
  197.  *
  198.  * AppInitExitHandler --
  199.  *
  200.  * This function is called to cleanup the app init resources before
  201.  * Tcl is unloaded.
  202.  *
  203.  * Results:
  204.  * None.
  205.  *
  206.  * Side effects:
  207.  * Frees the saved argv and deletes the async exit handler.
  208.  *
  209.  *----------------------------------------------------------------------
  210.  */
  211. static void
  212. AppInitExitHandler(
  213.     ClientData clientData)
  214. {
  215.     if (argvSave != NULL) {
  216.         ckfree((char *)argvSave);
  217.         argvSave = NULL;
  218.     }
  219.     if (exitToken != NULL) {
  220.         /*
  221.          * This should be safe to do even if we
  222.          * are in an async exit right now.
  223.          */
  224.         Tcl_AsyncDelete(exitToken);
  225.         exitToken = NULL;
  226.     }
  227. }
  228. /*
  229.  *-------------------------------------------------------------------------
  230.  *
  231.  * setargv --
  232.  *
  233.  * Parse the Windows command line string into argc/argv.  Done here
  234.  * because we don't trust the builtin argument parser in crt0.
  235.  * Windows applications are responsible for breaking their command
  236.  * line into arguments.
  237.  *
  238.  * 2N backslashes + quote -> N backslashes + begin quoted string
  239.  * 2N + 1 backslashes + quote -> literal
  240.  * N backslashes + non-quote -> literal
  241.  * quote + quote in a quoted string -> single quote
  242.  * quote + quote not in quoted string -> empty string
  243.  * quote -> begin quoted string
  244.  *
  245.  * Results:
  246.  * Fills argcPtr with the number of arguments and argvPtr with the
  247.  * array of arguments.
  248.  *
  249.  * Side effects:
  250.  * Memory allocated.
  251.  *
  252.  *--------------------------------------------------------------------------
  253.  */
  254. static void
  255. setargv(argcPtr, argvPtr)
  256.     int *argcPtr; /* Filled with number of argument strings. */
  257.     char ***argvPtr; /* Filled with argument strings (malloc'd). */
  258. {
  259.     char *cmdLine, *p, *arg, *argSpace;
  260.     char **argv;
  261.     int argc, size, inquote, copy, slashes;
  262.     cmdLine = GetCommandLine(); /* INTL: BUG */
  263.     /*
  264.      * Precompute an overly pessimistic guess at the number of arguments
  265.      * in the command line by counting non-space spans.
  266.      */
  267.     size = 2;
  268.     for (p = cmdLine; *p != ''; p++) {
  269. if ((*p == ' ') || (*p == 't')) { /* INTL: ISO space. */
  270.     size++;
  271.     while ((*p == ' ') || (*p == 't')) { /* INTL: ISO space. */
  272. p++;
  273.     }
  274.     if (*p == '') {
  275. break;
  276.     }
  277. }
  278.     }
  279.     argSpace = (char *) ckalloc(
  280.     (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1));
  281.     argv = (char **) argSpace;
  282.     argSpace += size * sizeof(char *);
  283.     size--;
  284.     p = cmdLine;
  285.     for (argc = 0; argc < size; argc++) {
  286. argv[argc] = arg = argSpace;
  287. while ((*p == ' ') || (*p == 't')) { /* INTL: ISO space. */
  288.     p++;
  289. }
  290. if (*p == '') {
  291.     break;
  292. }
  293. inquote = 0;
  294. slashes = 0;
  295. while (1) {
  296.     copy = 1;
  297.     while (*p == '\') {
  298. slashes++;
  299. p++;
  300.     }
  301.     if (*p == '"') {
  302. if ((slashes & 1) == 0) {
  303.     copy = 0;
  304.     if ((inquote) && (p[1] == '"')) {
  305. p++;
  306. copy = 1;
  307.     } else {
  308. inquote = !inquote;
  309.     }
  310.                 }
  311.                 slashes >>= 1;
  312.             }
  313.             while (slashes) {
  314. *arg = '\';
  315. arg++;
  316. slashes--;
  317.     }
  318.     if ((*p == '')
  319.     || (!inquote && ((*p == ' ') || (*p == 't')))) { /* INTL: ISO space. */
  320. break;
  321.     }
  322.     if (copy != 0) {
  323. *arg = *p;
  324. arg++;
  325.     }
  326.     p++;
  327.         }
  328. *arg = '';
  329. argSpace = arg + 1;
  330.     }
  331.     argv[argc] = NULL;
  332.     *argcPtr = argc;
  333.     *argvPtr = argv;
  334. }
  335. /*
  336.  *----------------------------------------------------------------------
  337.  *
  338.  * asyncExit --
  339.  *
  340.  *  The AsyncProc for the exitToken.
  341.  *
  342.  * Results:
  343.  *  doesn't actually return.
  344.  *
  345.  * Side effects:
  346.  *  tclsh cleanly exits.
  347.  *
  348.  *----------------------------------------------------------------------
  349.  */
  350. int
  351. asyncExit (ClientData clientData, Tcl_Interp *interp, int code)
  352. {
  353.     Tcl_Exit((int)exitErrorCode);
  354.     /* NOTREACHED */
  355.     return code;
  356. }
  357. /*
  358.  *----------------------------------------------------------------------
  359.  *
  360.  * sigHandler --
  361.  *
  362.  * Signal handler for the Win32 OS. Catches Ctrl+C, Ctrl+Break and
  363.  * other exits. This is needed so tclsh can do it's real clean-up
  364.  * and not an unclean crash terminate.
  365.  *
  366.  * Results:
  367.  * TRUE.
  368.  *
  369.  * Side effects:
  370.  * Effects the way the app exits from a signal. This is an
  371.  * operating system supplied thread and unsafe to call ANY
  372.  * Tcl commands except for Tcl_AsyncMark.
  373.  *
  374.  *----------------------------------------------------------------------
  375.  */
  376. BOOL __stdcall
  377. sigHandler(DWORD fdwCtrlType)
  378. {
  379.     HANDLE hStdIn;
  380.     if (!exitToken) {
  381. /* Async token must have been destroyed, punt gracefully. */
  382. return FALSE;
  383.     }
  384.     /*
  385.      * If Tcl is currently executing some bytecode or in the eventloop,
  386.      * this will cause Tcl to enter asyncExit at the next command
  387.      * boundry.
  388.      */
  389.     exitErrorCode = fdwCtrlType;
  390.     Tcl_AsyncMark(exitToken);
  391.     /*
  392.      * This will cause Tcl_Gets in Tcl_Main() to drop-out with an <EOF>
  393.      * should it be blocked on input and our Tcl_AsyncMark didn't grab
  394.      * the attention of the interpreter.
  395.      */
  396.     hStdIn = GetStdHandle(STD_INPUT_HANDLE);
  397.     if (hStdIn) {
  398. CloseHandle(hStdIn);
  399.     }
  400.     /* indicate to the OS not to call the default terminator */
  401.     return TRUE;
  402. }