1/* 2 * winMain.c -- 3 * 4 * Main entry point for wish and other Tk-based applications. 5 * 6 * Copyright (c) 1995-1997 Sun Microsystems, Inc. 7 * Copyright (c) 1998-1999 by Scriptics Corporation. 8 * 9 * See the file "license.terms" for information on usage and redistribution of 10 * this file, and for a DISCLAIMER OF ALL WARRANTIES. 11 * 12 * RCS: @(#) $Id$ 13 */ 14 15#include "tkInt.h" 16#define WIN32_LEAN_AND_MEAN 17#include <windows.h> 18#undef WIN32_LEAN_AND_MEAN 19#include <locale.h> 20 21 22/* 23 * The following declarations refer to internal Tk routines. These interfaces 24 * are available for use, but are not supported. 25 */ 26 27/* 28 * Forward declarations for procedures defined later in this file: 29 */ 30 31static void WishPanic(CONST char *format, ...); 32#ifdef TK_TEST 33extern int Tktest_Init(Tcl_Interp *interp); 34#endif /* TK_TEST */ 35 36#if defined(__CYGWIN__) 37static void setargv(int *argcPtr, char ***argvPtr); 38#endif /* __CYGWIN__ */ 39 40static BOOL consoleRequired = TRUE; 41 42/* 43 * The following #if block allows you to change the AppInit function by using 44 * a #define of TCL_LOCAL_APPINIT instead of rewriting this entire file. The 45 * #if checks for that #define and uses Tcl_AppInit if it doesn't exist. 46 */ 47 48#ifndef TK_LOCAL_APPINIT 49#define TK_LOCAL_APPINIT Tcl_AppInit 50#endif 51extern int TK_LOCAL_APPINIT(Tcl_Interp *interp); 52 53/* 54 * The following #if block allows you to change how Tcl finds the startup 55 * script, prime the library or encoding paths, fiddle with the argv, etc., 56 * without needing to rewrite Tk_Main() 57 */ 58 59#ifdef TK_LOCAL_MAIN_HOOK 60extern int TK_LOCAL_MAIN_HOOK(int *argc, char ***argv); 61#endif 62 63/* 64 *---------------------------------------------------------------------- 65 * 66 * WinMain -- 67 * 68 * Main entry point from Windows. 69 * 70 * Results: 71 * Returns false if initialization fails, otherwise it never returns. 72 * 73 * Side effects: 74 * Just about anything, since from here we call arbitrary Tcl code. 75 * 76 *---------------------------------------------------------------------- 77 */ 78 79int APIENTRY 80WinMain( 81 HINSTANCE hInstance, 82 HINSTANCE hPrevInstance, 83 LPSTR lpszCmdLine, 84 int nCmdShow) 85{ 86 char **argv; 87 int argc; 88 char *p; 89 90 Tcl_SetPanicProc(WishPanic); 91 92 /* 93 * Create the console channels and install them as the standard channels. 94 * All I/O will be discarded until Tk_CreateConsoleWindow is called to 95 * attach the console to a text widget. 96 */ 97 98 consoleRequired = TRUE; 99 100 /* 101 * Set up the default locale to be standard "C" locale so parsing is 102 * performed correctly. 103 */ 104 105 setlocale(LC_ALL, "C"); 106 107 /* 108 * Get our args from the c-runtime. Ignore lpszCmdLine. 109 */ 110 111#if defined(__CYGWIN__) 112 setargv(&argc, &argv); 113#else 114 argc = __argc; 115 argv = __argv; 116#endif 117 118 /* 119 * Forward slashes substituted for backslashes. 120 */ 121 122 for (p = argv[0]; *p != '\0'; p++) { 123 if (*p == '\\') { 124 *p = '/'; 125 } 126 } 127 128#ifdef TK_LOCAL_MAIN_HOOK 129 TK_LOCAL_MAIN_HOOK(&argc, &argv); 130#endif 131 132 Tk_Main(argc, argv, TK_LOCAL_APPINIT); 133 return 1; 134} 135 136/* 137 *---------------------------------------------------------------------- 138 * 139 * Tcl_AppInit -- 140 * 141 * This procedure performs application-specific initialization. Most 142 * applications, especially those that incorporate additional packages, 143 * will have their own version of this procedure. 144 * 145 * Results: 146 * Returns a standard Tcl completion code, and leaves an error message in 147 * the interp's result if an error occurs. 148 * 149 * Side effects: 150 * Depends on the startup script. 151 * 152 *---------------------------------------------------------------------- 153 */ 154 155int 156Tcl_AppInit( 157 Tcl_Interp *interp) /* Interpreter for application. */ 158{ 159 if (Tcl_Init(interp) == TCL_ERROR) { 160 goto error; 161 } 162 if (Tk_Init(interp) == TCL_ERROR) { 163 goto error; 164 } 165 Tcl_StaticPackage(interp, "Tk", Tk_Init, Tk_SafeInit); 166 167 /* 168 * Initialize the console only if we are running as an interactive 169 * application. 170 */ 171 172 if (consoleRequired) { 173 if (Tk_CreateConsoleWindow(interp) == TCL_ERROR) { 174 goto error; 175 } 176 } 177#if defined(STATIC_BUILD) && TCL_USE_STATIC_PACKAGES 178 { 179 extern Tcl_PackageInitProc Registry_Init; 180 extern Tcl_PackageInitProc Dde_Init; 181 182 if (Registry_Init(interp) == TCL_ERROR) { 183 return TCL_ERROR; 184 } 185 Tcl_StaticPackage(interp, "registry", Registry_Init, NULL); 186 187 if (Dde_Init(interp) == TCL_ERROR) { 188 return TCL_ERROR; 189 } 190 Tcl_StaticPackage(interp, "dde", Dde_Init, NULL); 191 } 192#endif 193 194#ifdef TK_TEST 195 if (Tktest_Init(interp) == TCL_ERROR) { 196 goto error; 197 } 198 Tcl_StaticPackage(interp, "Tktest", Tktest_Init, NULL); 199#endif /* TK_TEST */ 200 201 Tcl_SetVar(interp, "tcl_rcFileName", "~/wishrc.tcl", TCL_GLOBAL_ONLY); 202 return TCL_OK; 203 204error: 205 MessageBeep(MB_ICONEXCLAMATION); 206 MessageBox(NULL, Tcl_GetStringResult(interp), "Error in Wish", 207 MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); 208 ExitProcess(1); 209 210 /* 211 * We won't reach this, but we need the return. 212 */ 213 214 return TCL_ERROR; 215} 216 217/* 218 *---------------------------------------------------------------------- 219 * 220 * WishPanic -- 221 * 222 * Display a message and exit. 223 * 224 * Results: 225 * None. 226 * 227 * Side effects: 228 * Exits the program. 229 * 230 *---------------------------------------------------------------------- 231 */ 232 233void 234WishPanic( 235 CONST char *format, ...) 236{ 237 va_list argList; 238 char buf[1024]; 239 240 va_start(argList, format); 241 vsprintf(buf, format, argList); 242 243 MessageBeep(MB_ICONEXCLAMATION); 244 MessageBox(NULL, buf, "Fatal Error in Wish", 245 MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); 246#ifdef _MSC_VER 247 DebugBreak(); 248#endif 249 ExitProcess(1); 250} 251 252#if !defined(__GNUC__) || defined(TK_TEST) 253/* 254 *---------------------------------------------------------------------- 255 * 256 * main -- 257 * 258 * Main entry point from the console. 259 * 260 * Results: 261 * None: Tk_Main never returns here, so this procedure never returns 262 * either. 263 * 264 * Side effects: 265 * Whatever the applications does. 266 * 267 *---------------------------------------------------------------------- 268 */ 269 270int 271main( 272 int argc, 273 char **argv) 274{ 275 Tcl_SetPanicProc(WishPanic); 276 277 /* 278 * Set up the default locale to be standard "C" locale so parsing is 279 * performed correctly. 280 */ 281 282 setlocale(LC_ALL, "C"); 283 284 /* 285 * Console emulation widget not required as this entry is from the 286 * console subsystem, thus stdin,out,err already have end-points. 287 */ 288 289 consoleRequired = FALSE; 290 291 Tk_Main(argc, argv, Tcl_AppInit); 292 return 0; 293} 294#endif /* !__GNUC__ || TK_TEST */ 295 296 297/* 298 *------------------------------------------------------------------------- 299 * 300 * setargv -- 301 * 302 * Parse the Windows command line string into argc/argv. Done here 303 * because we don't trust the builtin argument parser in crt0. Windows 304 * applications are responsible for breaking their command line into 305 * arguments. 306 * 307 * 2N backslashes + quote -> N backslashes + begin quoted string 308 * 2N + 1 backslashes + quote -> literal 309 * N backslashes + non-quote -> literal 310 * quote + quote in a quoted string -> single quote 311 * quote + quote not in quoted string -> empty string 312 * quote -> begin quoted string 313 * 314 * Results: 315 * Fills argcPtr with the number of arguments and argvPtr with the array 316 * of arguments. 317 * 318 * Side effects: 319 * Memory allocated. 320 * 321 *-------------------------------------------------------------------------- 322 */ 323 324#if defined(__CYGWIN__) 325static void 326setargv( 327 int *argcPtr, /* Filled with number of argument strings. */ 328 char ***argvPtr) /* Filled with argument strings (malloc'd). */ 329{ 330 char *cmdLine, *p, *arg, *argSpace; 331 char **argv; 332 int argc, size, inquote, copy, slashes; 333 334 cmdLine = GetCommandLine(); /* INTL: BUG */ 335 336 /* 337 * Precompute an overly pessimistic guess at the number of arguments in 338 * the command line by counting non-space spans. 339 */ 340 341 size = 2; 342 for (p = cmdLine; *p != '\0'; p++) { 343 if ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ 344 size++; 345 while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ 346 p++; 347 } 348 if (*p == '\0') { 349 break; 350 } 351 } 352 } 353 argSpace = (char *) ckalloc( 354 (unsigned) (size * sizeof(char *) + strlen(cmdLine) + 1)); 355 argv = (char **) argSpace; 356 argSpace += size * sizeof(char *); 357 size--; 358 359 p = cmdLine; 360 for (argc = 0; argc < size; argc++) { 361 argv[argc] = arg = argSpace; 362 while ((*p == ' ') || (*p == '\t')) { /* INTL: ISO space. */ 363 p++; 364 } 365 if (*p == '\0') { 366 break; 367 } 368 369 inquote = 0; 370 slashes = 0; 371 while (1) { 372 copy = 1; 373 while (*p == '\\') { 374 slashes++; 375 p++; 376 } 377 if (*p == '"') { 378 if ((slashes & 1) == 0) { 379 copy = 0; 380 if ((inquote) && (p[1] == '"')) { 381 p++; 382 copy = 1; 383 } else { 384 inquote = !inquote; 385 } 386 } 387 slashes >>= 1; 388 } 389 390 while (slashes) { 391 *arg = '\\'; 392 arg++; 393 slashes--; 394 } 395 396 if ((*p == '\0') || (!inquote && 397 ((*p == ' ') || (*p == '\t')))) { /* INTL: ISO space. */ 398 break; 399 } 400 if (copy != 0) { 401 *arg = *p; 402 arg++; 403 } 404 p++; 405 } 406 *arg = '\0'; 407 argSpace = arg + 1; 408 } 409 argv[argc] = NULL; 410 411 *argcPtr = argc; 412 *argvPtr = argv; 413} 414#endif /* __CYGWIN__ */ 415 416/* 417 * Local Variables: 418 * mode: c 419 * c-basic-offset: 4 420 * fill-column: 78 421 * End: 422 */ 423