TkInterp.m
上传用户:shenzhenrh
上传日期:2013-05-12
资源大小:2904k
文件大小:12k
源码类别:

信息检索与抽取

开发平台:

Unix_Linux

  1. /* Implementation for Objective-C Tcl, Tk interpreter object
  2.    Copyright (C) 1993,1994  R. Andrew McCallum
  3.    Written by:  R. Andrew McCallum <mccallum@cs.rochester.edu>
  4.    Dept. of Computer Science, U. of Rochester, Rochester, NY  14627
  5.    This file is part of the Tcl/Objective-C interface library.
  6.    This library is free software; you can redistribute it and/or
  7.    modify it under the terms of the GNU Library General Public
  8.    License as published by the Free Software Foundation; either
  9.    version 2 of the License, or (at your option) any later version.
  10.    
  11.    This library is distributed in the hope that it will be useful,
  12.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.    Library General Public License for more details.
  15.    You should have received a copy of the GNU Library General Public
  16.    License along with this library; if not, write to the Free
  17.    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18. */ 
  19. #ifdef NeXT
  20. #include "objc-gnu2next.h"
  21. #endif
  22. #include "TkInterp.h"
  23. #if HAVE_READLINE
  24. #include <readline/readline.h>
  25. #include <readline/history.h>
  26. #endif
  27. #include <tk.h>
  28. #include "tclObjc.h"
  29. #include <misc.h>
  30. #define DEFAULT_PROMPT "Tk% "
  31. #define DEFAULT_PARTIAL_PROMPT "Tk> "
  32. #if (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 4)
  33. #define SUBDIR "tk8.4"
  34. #elif (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 3)
  35. #define SUBDIR "tk8.3"
  36. #elif (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 2)
  37. #define SUBDIR "tk8.2"
  38. #elif (TK_MAJOR_VERSION == 8) && (TK_MINOR_VERSION == 1)
  39. #define SUBDIR "tk8.1"
  40. #else
  41. #define SUBDIR "tk8.0"
  42. #endif
  43. #ifdef __CYGWIN__
  44. #include <unistd.h> // MAXPATHLEN
  45. #include <sys/cygwin.h> // cygwin_conv_to_win32_path
  46. #endif
  47. // Global variables used by the main program:
  48. static Tk_Window w; /* The main window for the application.  If
  49.  * NULL then the application no longer
  50.  * exists. */
  51. #if HAVE_READLINE
  52. int tk_iter()
  53. {
  54. #if ((TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION >= 1) || TK_MAJOR_VERSION > 4)
  55.   if (Tk_GetNumMainWindows() <= 0)
  56. #else
  57.   if (tk_NumMainWindows <= 0) 
  58. #endif
  59.     { 
  60.       rl_event_hook = 0; 
  61. #if 0
  62.       rl_end_of_line();
  63.       rl_unix_line_discard();
  64.       rl_newline();
  65.       printf("tk_iter abortingn");
  66. #endif
  67.       return 0; 
  68.     }
  69.   while (Tk_DoOneEvent(TK_ALL_EVENTS | TK_DONT_WAIT));
  70.   return 1;
  71. }
  72. #endif
  73. #if ((TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0) || TK_MAJOR_VERSION < 4)
  74. static int synchronize = 0;
  75. static char *display = NULL;
  76. #endif
  77. static const char *name = NULL;
  78. #if ! HAVE_READLINE
  79. static void Prompt _ANSI_ARGS_((Tcl_Interp *interp, int partial));
  80. #ifndef __CYGWIN__
  81. static void StdinProc _ANSI_ARGS_((ClientData clientData, int mask));
  82. #endif
  83. #endif /* ! HAVE_READLINE */
  84. #if defined(__CYGWIN__) || defined(__MINGW32__)
  85. #undef Tk_CreateFileHandler
  86. #undef Tk_DeleteFileHandler
  87. #define Tk_CreateFileHandler(a, b, c, d)
  88. #define Tk_DeleteFileHandler(a)
  89. #endif
  90. @implementation TkInterp
  91. - (const char *)checkTkLibrary
  92. {
  93.   const char *path;
  94.   extern const char *fix_tcl_path (const char *path);
  95.   if ([self checkPath: TK_LIBRARY subdirectory: NULL file: "tk.tcl"])
  96.     path = TK_LIBRARY;
  97.   else
  98.     path = [self checkPath: secondaryPath subdirectory: SUBDIR file: "tk.tcl"];
  99.   return fix_tcl_path (path);
  100. }
  101. - (const char *)preInitWithArgc: (int)argc argv: (const char **)argv
  102. {
  103.   const char *fileName;
  104.   fileName = [super preInitWithArgc:argc argv:argv];
  105.   Tcl_SetVar (interp, "tkObjc", "1", TCL_GLOBAL_ONLY);
  106.   {
  107.     const char *tclPath = [self checkTclLibrary];
  108.     if (tclPath)
  109.       Tcl_SetVar (interp, "tcl_library", (char *) tclPath, TCL_GLOBAL_ONLY);
  110.     else
  111.       abort ();
  112.   }
  113.   {
  114.     const char *tkPath = [self checkTkLibrary];
  115.     if (tkPath)
  116.       Tcl_SetVar (interp, "tk_library", (char *) tkPath, TCL_GLOBAL_ONLY);
  117.     else
  118.       abort ();
  119.   }
  120.   Tcl_SetVar (interp, "tclobjc_newTk", "0", TCL_GLOBAL_ONLY);
  121.   [self eval: "proc tkInit {} { global tclobjc_newTk; set tclobjc_newTk 1 }"];
  122.   
  123.   /*
  124.    * Initialize the Tk application and arrange to map the main window
  125.    * after the startup script has been executed, if any.  This way
  126.    * the script can withdraw the window so it isn't ever mapped
  127.    * at all.
  128.    */
  129.   if (argc)
  130.     name = argv[0];
  131.   else
  132.     name = "tkObjc";
  133. #if ((TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION == 0) || TK_MAJOR_VERSION < 4)
  134.   w = Tk_CreateMainWindow (interp, display, name, "Tk");
  135.   if (w == NULL)
  136.     {
  137.       fprintf (stderr, "%sn", interp->result);
  138.       exit (1);
  139.     }
  140.   if (synchronize)
  141.     XSynchronize (Tk_Display (w), True);
  142.   Tk_GeometryRequest(w, 200, 200);
  143. #endif
  144.   
  145.   if (Tk_Init (interp) == TCL_ERROR)
  146.     {
  147.       const char *msg = Tcl_GetVar (interp, "errorInfo", TCL_GLOBAL_ONLY);
  148.       
  149.       if (msg == NULL)
  150.         msg = interp->result;
  151.       [self error:msg];
  152.       abort ();
  153.     }
  154.   [self eval: "if {$tclobjc_newTk == 1} { source [file join $tk_library tk.tcl] }"];
  155. #if (TK_MAJOR_VERSION > 4 || (TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION >= 1))
  156.   w = Tk_MainWindow(interp);
  157.   if (w == NULL)
  158.     {
  159.       fprintf (stderr, "%sn", interp->result);
  160.       exit (1);
  161.     }
  162. #endif
  163.   return fileName;
  164. }
  165. - initWithArgc: (int)argc argv: (const char **)argv
  166. {
  167.   [super initWithArgc: argc argv: argv];
  168.   stopped = YES;
  169.   //  tclObjc_eventHook = tk_iter;  Think about this;
  170. #if HAVE_READLINE
  171.   rl_event_hook = tk_iter;
  172. #endif
  173.   fflush (stdout);
  174.   {
  175.     char buf[8];
  176.     strcpy (buf, "update");
  177.     (void) Tcl_Eval (interp, buf);
  178.   }
  179.   return self;
  180. }
  181. /* Send this to abort 'promptAndEval' loop */
  182. - (void)stop
  183. {
  184.   stopped = YES;
  185. #if HAVE_READLINE
  186.   rl_beg_of_line();
  187.   rl_kill_line();
  188.   //  rl_stuff_char(EOF);
  189.   rl_stuff_char('n');
  190. #endif
  191. }
  192. - promptAndEval
  193. #if HAVE_READLINE
  194. {
  195.   const char *cmd;
  196.   const char *line;
  197.   int result;
  198.   int gotPartial = 0;
  199.       
  200.   Tcl_DStringInit(&command);
  201.   stopped = NO;
  202. #if (TK_MAJOR_VERSION > 4 || (TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION >= 1))
  203.   while (Tk_GetNumMainWindows() > 0 && !stopped)
  204. #else
  205.   while (tk_NumMainWindows > 0 && !stopped)
  206. #endif
  207.     {
  208.       /* I could add code to do something like tcl_prompt1 */
  209.       if (gotPartial)
  210. line = readline(DEFAULT_PARTIAL_PROMPT);
  211.       else
  212. line = readline(DEFAULT_PROMPT);
  213.       if (!line)
  214. break;
  215.       add_history(line);
  216.       cmd = Tcl_DStringAppend(&command, line, -1);
  217.       free(line);
  218.       if (!Tcl_CommandComplete(cmd))
  219. {
  220.   gotPartial = 1;
  221.   continue;
  222. }
  223.       gotPartial = 0;
  224.       result = Tcl_RecordAndEval(interp, cmd, 0);
  225.       Tcl_DStringFree(&command);
  226.       if (result != TCL_OK)
  227. fprintf(stderr, "%sn", interp->result);
  228.       else
  229. printf("%sn", interp->result);
  230.     }
  231.   return self;
  232. }
  233. #else /* HAVE_READLINE */
  234. {
  235.     Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData)self);
  236.     Prompt(interp, 0);
  237.     Tcl_DStringInit(&command);
  238.     stopped = NO;
  239. #if ((TK_MAJOR_VERSION == 4 && TK_MINOR_VERSION >= 1) || TK_MAJOR_VERSION > 4)
  240.     while (Tk_GetNumMainWindows() > 0 && !stopped)
  241. #else
  242.     while (tk_NumMainWindows > 0 && !stopped)
  243. #endif
  244.       Tk_DoOneEvent(0);
  245.     printf("n");
  246.     return self;
  247. }
  248. #endif
  249. - free
  250. {
  251.   /* Call 'exit' first so that users can redefine 'exit' for their
  252.      own cleanup */
  253.   Tcl_GlobalEval(interp, "exitn");
  254.   Tcl_GlobalEval(interp, "destroy .n");
  255.   return [super free];
  256. }
  257. // Allow access to this variable so clever programmers can use Xlib to
  258. // supplement Tk. This Tk_Window is sufficient to get the Display,
  259. // visual, etc.
  260. - (Tk_Window)mainWindow
  261. {
  262.   return w;
  263. }
  264. @end
  265. #if ! HAVE_READLINE
  266. /* The following two functions modified from the Tk distribution: */
  267. /* 
  268.  * main.c --
  269.  *
  270.  * This file contains the main program for "wish", a windowing
  271.  * shell based on Tk and Tcl.  It also provides a template that
  272.  * can be used as the basis for main programs for other Tk
  273.  * applications.
  274.  *
  275.  * Copyright (c) 1990-1993 The Regents of the University of California.
  276.  * All rights reserved.
  277.  *
  278.  * Permission is hereby granted, without written agreement and without
  279.  * license or royalty fees, to use, copy, modify, and distribute this
  280.  * software and its documentation for any purpose, provided that the
  281.  * above copyright notice and the following two paragraphs appear in
  282.  * all copies of this software.
  283.  * 
  284.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  285.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  286.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  287.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  288.  *
  289.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  290.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  291.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  292.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  293.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  294.  */
  295. #ifndef __CYGWIN__
  296. /*
  297.  *----------------------------------------------------------------------
  298.  *
  299.  * StdinProc --
  300.  *
  301.  * This procedure is invoked by the event dispatcher whenever
  302.  * standard input becomes readable.  It grabs the next line of
  303.  * input characters, adds them to a command being assembled, and
  304.  * executes the command if it's complete.
  305.  *
  306.  * Results:
  307.  * None.
  308.  *
  309.  * Side effects:
  310.  * Could be almost arbitrary, depending on the command that's
  311.  * typed.
  312.  *
  313.  *----------------------------------------------------------------------
  314.  */
  315.     /* ARGSUSED */
  316. static void
  317. StdinProc(clientData, mask)
  318.     ClientData clientData;
  319.     int mask; /* Not used. */
  320. {
  321. #define BUFFER_SIZE 4000
  322.     char input[BUFFER_SIZE+1];
  323.     static int gotPartial = 0;
  324.     const char *cmd;
  325.     int code, count;
  326.     count = read(fileno(stdin), input, BUFFER_SIZE);
  327.     if (count <= 0) {
  328. if (!gotPartial) {
  329.   /***
  330.     if (tty) {
  331. Tcl_Eval(interp, "exit");
  332. exit(1);
  333.     } else {
  334. Tk_DeleteFileHandler(0);
  335.     }
  336.     ***/
  337.     [(id)clientData stop];
  338.     Tk_DeleteFileHandler(0);
  339.     return;
  340. } else {
  341.     count = 0;
  342. }
  343.     }
  344.     cmd = Tcl_DStringAppend(&(((TkInterp*)clientData)->command), input, count);
  345.     if (count != 0) {
  346. if ((input[count-1] != 'n') && (input[count-1] != ';')) {
  347.     gotPartial = 1;
  348.     goto prompt;
  349. }
  350. if (!Tcl_CommandComplete ((char *)cmd)) {
  351.     gotPartial = 1;
  352.     goto prompt;
  353. }
  354.     }
  355.     gotPartial = 0;
  356.     /*
  357.      * Disable the stdin file handler while evaluating the command;
  358.      * otherwise if the command re-enters the event loop we might
  359.      * process commands from stdin before the current command is
  360.      * finished.  Among other things, this will trash the text of the
  361.      * command being evaluated.
  362.      */
  363.     Tk_CreateFileHandler(0, 0, StdinProc, (ClientData)clientData);
  364.     code = Tcl_RecordAndEval(((TclInterp*)clientData)->interp, (char *)cmd, 0);
  365.     Tk_CreateFileHandler(0, TK_READABLE, StdinProc, (ClientData)clientData);
  366.     Tcl_DStringFree(&(((TkInterp*)clientData)->command));
  367.     if (*(((TkInterp*)clientData)->interp)->result != 0) {
  368.         /* clean this up later
  369. if (1 && (code != TCL_OK) || (tty)) */
  370.     printf("%sn", (((TclInterp*)clientData)->interp)->result);
  371.     }
  372.     /*
  373.      * Output a prompt.
  374.      */
  375.     prompt:
  376.     /* clean this up later 
  377.     if (tty) */
  378. Prompt(((TclInterp*)clientData)->interp, gotPartial);
  379. }
  380. #endif
  381. /*
  382.  *----------------------------------------------------------------------
  383.  *
  384.  * Prompt --
  385.  *
  386.  * Issue a prompt on standard output, or invoke a script
  387.  * to issue the prompt.
  388.  *
  389.  * Results:
  390.  * None.
  391.  *
  392.  * Side effects:
  393.  * A prompt gets output, and a Tcl script may be evaluated
  394.  * in interp.
  395.  *
  396.  *----------------------------------------------------------------------
  397.  */
  398. static void
  399. Prompt(interp, partial)
  400.     Tcl_Interp *interp; /* Interpreter to use for prompting. */
  401.     int partial; /* Non-zero means there already
  402.  * exists a partial command, so use
  403.  * the secondary prompt. */
  404. {
  405.   /* I could add code to do something like tcl_prompt1 */
  406.   if (partial) 
  407.     fputs(DEFAULT_PARTIAL_PROMPT, stdout);
  408.   else
  409.     fputs(DEFAULT_PROMPT, stdout);
  410.   fflush(stdout);
  411. }
  412. #endif /* ! HAVE_READLINE */