tkConsole.c
上传用户:kellyonhid
上传日期:2013-10-12
资源大小:932k
文件大小:17k
源码类别:

3D图形编程

开发平台:

Visual C++

  1. /* 
  2.  * tkConsole.c --
  3.  *
  4.  * This file implements a Tcl console for systems that may not
  5.  * otherwise have access to a console.  It uses the Text widget
  6.  * and provides special access via a console command.
  7.  *
  8.  * Copyright (c) 1995-1996 Sun Microsystems, Inc.
  9.  *
  10.  * See the file "license.terms" for information on usage and redistribution
  11.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12.  *
  13.  * SCCS: @(#) tkConsole.c 1.53 97/07/22 16:36:55
  14.  */
  15. #include "tkInt.h"
  16. /*
  17.  * A data structure of the following type holds information for each console
  18.  * which a handler (i.e. a Tcl command) has been defined for a particular
  19.  * top-level window.
  20.  */
  21. typedef struct ConsoleInfo {
  22.     Tcl_Interp *consoleInterp; /* Interpreter for the console. */
  23.     Tcl_Interp *interp; /* Interpreter to send console commands. */
  24. } ConsoleInfo;
  25. static Tcl_Interp *gStdoutInterp = NULL;
  26. /*
  27.  * Forward declarations for procedures defined later in this file:
  28.  *
  29.  * The first three will be used in the tk app shells...
  30.  */
  31.  
  32. void TkConsoleCreate _ANSI_ARGS_((void));
  33. int TkConsoleInit _ANSI_ARGS_((Tcl_Interp *interp));
  34. void TkConsolePrint _ANSI_ARGS_((Tcl_Interp *interp,
  35.     int devId, char *buffer, long size));
  36. static int ConsoleCmd _ANSI_ARGS_((ClientData clientData,
  37.     Tcl_Interp *interp, int argc, char **argv));
  38. static void ConsoleDeleteProc _ANSI_ARGS_((ClientData clientData));
  39. static void ConsoleEventProc _ANSI_ARGS_((ClientData clientData,
  40.     XEvent *eventPtr));
  41. static int InterpreterCmd _ANSI_ARGS_((ClientData clientData,
  42.     Tcl_Interp *interp, int argc, char **argv));
  43. static int ConsoleInput _ANSI_ARGS_((ClientData instanceData,
  44.     char *buf, int toRead, int *errorCode));
  45. static int ConsoleOutput _ANSI_ARGS_((ClientData instanceData,
  46.     char *buf, int toWrite, int *errorCode));
  47. static int ConsoleClose _ANSI_ARGS_((ClientData instanceData,
  48.     Tcl_Interp *interp));
  49. static void ConsoleWatch _ANSI_ARGS_((ClientData instanceData,
  50.     int mask));
  51. static int ConsoleHandle _ANSI_ARGS_((ClientData instanceData,
  52.     int direction, ClientData *handlePtr));
  53. /*
  54.  * This structure describes the channel type structure for file based IO:
  55.  */
  56. static Tcl_ChannelType consoleChannelType = {
  57.     "console", /* Type name. */
  58.     NULL, /* Always non-blocking.*/
  59.     ConsoleClose, /* Close proc. */
  60.     ConsoleInput, /* Input proc. */
  61.     ConsoleOutput, /* Output proc. */
  62.     NULL, /* Seek proc. */
  63.     NULL, /* Set option proc. */
  64.     NULL, /* Get option proc. */
  65.     ConsoleWatch, /* Watch for events on console. */
  66.     ConsoleHandle, /* Get a handle from the device. */
  67. };
  68. /*
  69.  *----------------------------------------------------------------------
  70.  *
  71.  * TkConsoleCreate --
  72.  *
  73.  *  Create the console channels and install them as the standard
  74.  *  channels.  All I/O will be discarded until TkConsoleInit is
  75.  *  called to attach the console to a text widget.
  76.  *
  77.  * Results:
  78.  * None.
  79.  *
  80.  * Side effects:
  81.  * Creates the console channel and installs it as the standard
  82.  * channels.
  83.  *
  84.  *----------------------------------------------------------------------
  85.  */
  86. void
  87. TkConsoleCreate()
  88. {
  89.     Tcl_Channel consoleChannel;
  90.     consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console0",
  91.     (ClientData) TCL_STDIN, TCL_READABLE);
  92.     if (consoleChannel != NULL) {
  93. Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
  94. Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
  95.     }
  96.     Tcl_SetStdChannel(consoleChannel, TCL_STDIN);
  97.     consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console1",
  98.     (ClientData) TCL_STDOUT, TCL_WRITABLE);
  99.     if (consoleChannel != NULL) {
  100. Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
  101. Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
  102.     }
  103.     Tcl_SetStdChannel(consoleChannel, TCL_STDOUT);
  104.     consoleChannel = Tcl_CreateChannel(&consoleChannelType, "console2",
  105.     (ClientData) TCL_STDERR, TCL_WRITABLE);
  106.     if (consoleChannel != NULL) {
  107. Tcl_SetChannelOption(NULL, consoleChannel, "-translation", "lf");
  108. Tcl_SetChannelOption(NULL, consoleChannel, "-buffering", "none");
  109.     }
  110.     Tcl_SetStdChannel(consoleChannel, TCL_STDERR);
  111. }
  112. /*
  113.  *----------------------------------------------------------------------
  114.  *
  115.  * TkConsoleInit --
  116.  *
  117.  * Initialize the console.  This code actually creates a new
  118.  * application and associated interpreter.  This effectivly hides
  119.  * the implementation from the main application.
  120.  *
  121.  * Results:
  122.  * None.
  123.  *
  124.  * Side effects:
  125.  * A new console it created.
  126.  *
  127.  *----------------------------------------------------------------------
  128.  */
  129. int 
  130. TkConsoleInit(interp)
  131.     Tcl_Interp *interp; /* Interpreter to use for prompting. */
  132. {
  133.     Tcl_Interp *consoleInterp;
  134.     ConsoleInfo *info;
  135.     Tk_Window mainWindow = Tk_MainWindow(interp);
  136. #ifdef MAC_TCL
  137.     static char initCmd[] = "source -rsrc {Console}";
  138. #else
  139.     static char initCmd[] = "source $tk_library/console.tcl; wm title . "Scanalyze Console"";
  140. #endif
  141.     
  142.     consoleInterp = Tcl_CreateInterp();
  143.     if (consoleInterp == NULL) {
  144. goto error;
  145.     }
  146.     
  147.     /*
  148.      * Initialized Tcl and Tk.
  149.      */
  150.     if (Tcl_Init(consoleInterp) != TCL_OK) {
  151. goto error;
  152.     }
  153.     if (Tk_Init(consoleInterp) != TCL_OK) {
  154. goto error;
  155.     }
  156.     gStdoutInterp = interp;
  157.     
  158.     /* 
  159.      * Add console commands to the interp 
  160.      */
  161.     info = (ConsoleInfo *) ckalloc(sizeof(ConsoleInfo));
  162.     info->interp = interp;
  163.     info->consoleInterp = consoleInterp;
  164.     Tcl_CreateCommand(interp, "console", ConsoleCmd, (ClientData) info,
  165.     (Tcl_CmdDeleteProc *) ConsoleDeleteProc);
  166.     Tcl_CreateCommand(consoleInterp, "consoleinterp", InterpreterCmd,
  167.     (ClientData) info, (Tcl_CmdDeleteProc *) NULL);
  168.     Tk_CreateEventHandler(mainWindow, StructureNotifyMask, ConsoleEventProc,
  169.     (ClientData) info);
  170.     Tcl_Preserve((ClientData) consoleInterp);
  171.     if (Tcl_Eval(consoleInterp, initCmd) == TCL_ERROR) {
  172. /* goto error; -- no problem for now... */
  173. printf("Eval error: %s", consoleInterp->result);
  174.     }
  175.     Tcl_Release((ClientData) consoleInterp);
  176.     return TCL_OK;
  177.     
  178.     error:
  179.     if (consoleInterp != NULL) {
  180.      Tcl_DeleteInterp(consoleInterp);
  181.     }
  182.     return TCL_ERROR;
  183. }
  184. /*
  185.  *----------------------------------------------------------------------
  186.  *
  187.  * ConsoleOutput--
  188.  *
  189.  * Writes the given output on the IO channel. Returns count of how
  190.  * many characters were actually written, and an error indication.
  191.  *
  192.  * Results:
  193.  * A count of how many characters were written is returned and an
  194.  * error indication is returned in an output argument.
  195.  *
  196.  * Side effects:
  197.  * Writes output on the actual channel.
  198.  *
  199.  *----------------------------------------------------------------------
  200.  */
  201. static int
  202. ConsoleOutput(instanceData, buf, toWrite, errorCode)
  203.     ClientData instanceData; /* Indicates which device to use. */
  204.     char *buf; /* The data buffer. */
  205.     int toWrite; /* How many bytes to write? */
  206.     int *errorCode; /* Where to store error code. */
  207. {
  208.     *errorCode = 0;
  209.     Tcl_SetErrno(0);
  210.     if (gStdoutInterp != NULL) {
  211. TkConsolePrint(gStdoutInterp, (int) instanceData, buf, toWrite);
  212.     }
  213.     
  214.     return toWrite;
  215. }
  216. /*
  217.  *----------------------------------------------------------------------
  218.  *
  219.  * ConsoleInput --
  220.  *
  221.  * Read input from the console.  Not currently implemented.
  222.  *
  223.  * Results:
  224.  * Always returns EOF.
  225.  *
  226.  * Side effects:
  227.  * None.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231. /* ARGSUSED */
  232. static int
  233. ConsoleInput(instanceData, buf, bufSize, errorCode)
  234.     ClientData instanceData; /* Unused. */
  235.     char *buf; /* Where to store data read. */
  236.     int bufSize; /* How much space is available
  237.                                          * in the buffer? */
  238.     int *errorCode; /* Where to store error code. */
  239. {
  240.     return 0; /* Always return EOF. */
  241. }
  242. /*
  243.  *----------------------------------------------------------------------
  244.  *
  245.  * ConsoleClose --
  246.  *
  247.  * Closes the IO channel.
  248.  *
  249.  * Results:
  250.  * Always returns 0 (success).
  251.  *
  252.  * Side effects:
  253.  * Frees the dummy file associated with the channel.
  254.  *
  255.  *----------------------------------------------------------------------
  256.  */
  257. /* ARGSUSED */
  258. static int
  259. ConsoleClose(instanceData, interp)
  260.     ClientData instanceData; /* Unused. */
  261.     Tcl_Interp *interp; /* Unused. */
  262. {
  263.     return 0;
  264. }
  265. /*
  266.  *----------------------------------------------------------------------
  267.  *
  268.  * ConsoleWatch --
  269.  *
  270.  * Called by the notifier to set up the console device so that
  271.  * events will be noticed. Since there are no events on the
  272.  * console, this routine just returns without doing anything.
  273.  *
  274.  * Results:
  275.  * None.
  276.  *
  277.  * Side effects:
  278.  * None.
  279.  *
  280.  *----------------------------------------------------------------------
  281.  */
  282. /* ARGSUSED */
  283. static void
  284. ConsoleWatch(instanceData, mask)
  285.     ClientData instanceData; /* Device ID for the channel. */
  286.     int mask; /* OR-ed combination of
  287.                                          * TCL_READABLE, TCL_WRITABLE and
  288.                                          * TCL_EXCEPTION, for the events
  289.                                          * we are interested in. */
  290. {
  291. }
  292. /*
  293.  *----------------------------------------------------------------------
  294.  *
  295.  * ConsoleHandle --
  296.  *
  297.  * Invoked by the generic IO layer to get a handle from a channel.
  298.  * Because console channels are not devices, this function always
  299.  * fails.
  300.  *
  301.  * Results:
  302.  * Always returns TCL_ERROR.
  303.  *
  304.  * Side effects:
  305.  * None.
  306.  *
  307.  *----------------------------------------------------------------------
  308.  */
  309. /* ARGSUSED */
  310. static int
  311. ConsoleHandle(instanceData, direction, handlePtr)
  312.     ClientData instanceData; /* Device ID for the channel. */
  313.     int direction; /* TCL_READABLE or TCL_WRITABLE to indicate
  314.  * which direction of the channel is being
  315.  * requested. */
  316.     ClientData *handlePtr; /* Where to store handle */
  317. {
  318.     return TCL_ERROR;
  319. }
  320. /*
  321.  *----------------------------------------------------------------------
  322.  *
  323.  * ConsoleCmd --
  324.  *
  325.  * The console command implements a Tcl interface to the various console
  326.  * options.
  327.  *
  328.  * Results:
  329.  * None.
  330.  *
  331.  * Side effects:
  332.  * None.
  333.  *
  334.  *----------------------------------------------------------------------
  335.  */
  336. static int
  337. ConsoleCmd(clientData, interp, argc, argv)
  338.     ClientData clientData; /* Not used. */
  339.     Tcl_Interp *interp; /* Current interpreter. */
  340.     int argc; /* Number of arguments. */
  341.     char **argv; /* Argument strings. */
  342. {
  343.     ConsoleInfo *info = (ConsoleInfo *) clientData;
  344.     char c;
  345.     int length;
  346.     int result;
  347.     Tcl_Interp *consoleInterp;
  348.     if (argc < 2) {
  349. Tcl_AppendResult(interp, "wrong # args: should be "", argv[0],
  350. " option ?arg arg ...?"", (char *) NULL);
  351. return TCL_ERROR;
  352.     }
  353.     
  354.     c = argv[1][0];
  355.     length = strlen(argv[1]);
  356.     result = TCL_OK;
  357.     consoleInterp = info->consoleInterp;
  358.     Tcl_Preserve((ClientData) consoleInterp);
  359.     if ((c == 't') && (strncmp(argv[1], "title", length)) == 0) {
  360. Tcl_DString dString;
  361. Tcl_DStringInit(&dString);
  362. Tcl_DStringAppend(&dString, "wm title . ", -1);
  363. if (argc == 3) {
  364.     Tcl_DStringAppendElement(&dString, argv[2]);
  365. }
  366. Tcl_Eval(consoleInterp, Tcl_DStringValue(&dString));
  367. Tcl_DStringFree(&dString);
  368.     } else if ((c == 'h') && (strncmp(argv[1], "hide", length)) == 0) {
  369. Tcl_Eval(info->consoleInterp, "wm withdraw .");
  370.     } else if ((c == 's') && (strncmp(argv[1], "show", length)) == 0) {
  371. Tcl_Eval(info->consoleInterp, "wm deiconify .");
  372.     } else if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
  373. if (argc == 3) {
  374.     Tcl_Eval(info->consoleInterp, argv[2]);
  375. } else {
  376.     Tcl_AppendResult(interp, "wrong # args: should be "", argv[0],
  377.     " eval command"", (char *) NULL);
  378.     return TCL_ERROR;
  379. }
  380.     } else {
  381. Tcl_AppendResult(interp, "bad option "", argv[1],
  382. "": should be hide, show, or title",
  383. (char *) NULL);
  384.         result = TCL_ERROR;
  385.     }
  386.     Tcl_Release((ClientData) consoleInterp);
  387.     return result;
  388. }
  389. /*
  390.  *----------------------------------------------------------------------
  391.  *
  392.  * InterpreterCmd --
  393.  *
  394.  * This command allows the console interp to communicate with the
  395.  * main interpreter.
  396.  *
  397.  * Results:
  398.  * None.
  399.  *
  400.  * Side effects:
  401.  * None.
  402.  *
  403.  *----------------------------------------------------------------------
  404.  */
  405. static int
  406. InterpreterCmd(clientData, interp, argc, argv)
  407.     ClientData clientData; /* Not used. */
  408.     Tcl_Interp *interp; /* Current interpreter. */
  409.     int argc; /* Number of arguments. */
  410.     char **argv; /* Argument strings. */
  411. {
  412.     ConsoleInfo *info = (ConsoleInfo *) clientData;
  413.     char c;
  414.     int length;
  415.     int result;
  416.     Tcl_Interp *otherInterp;
  417.     if (argc < 2) {
  418. Tcl_AppendResult(interp, "wrong # args: should be "", argv[0],
  419. " option ?arg arg ...?"", (char *) NULL);
  420. return TCL_ERROR;
  421.     }
  422.     
  423.     c = argv[1][0];
  424.     length = strlen(argv[1]);
  425.     otherInterp = info->interp;
  426.     Tcl_Preserve((ClientData) otherInterp);
  427.     if ((c == 'e') && (strncmp(argv[1], "eval", length)) == 0) {
  428.     result = Tcl_GlobalEval(otherInterp, argv[2]);
  429.      Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
  430.     } else if ((c == 'r') && (strncmp(argv[1], "record", length)) == 0) {
  431.     Tcl_RecordAndEval(otherInterp, argv[2], TCL_EVAL_GLOBAL);
  432. result = TCL_OK;
  433.      Tcl_AppendResult(interp, otherInterp->result, (char *) NULL);
  434.     } else {
  435. Tcl_AppendResult(interp, "bad option "", argv[1],
  436. "": should be eval or record",
  437. (char *) NULL);
  438. result = TCL_ERROR;
  439.     }
  440.     Tcl_Release((ClientData) otherInterp);
  441.     return result;
  442. }
  443. /*
  444.  *----------------------------------------------------------------------
  445.  *
  446.  * ConsoleDeleteProc --
  447.  *
  448.  * If the console command is deleted we destroy the console window
  449.  * and all associated data structures.
  450.  *
  451.  * Results:
  452.  * None.
  453.  *
  454.  * Side effects:
  455.  * A new console it created.
  456.  *
  457.  *----------------------------------------------------------------------
  458.  */
  459. void 
  460. ConsoleDeleteProc(clientData) 
  461.     ClientData clientData;
  462. {
  463.     ConsoleInfo *info = (ConsoleInfo *) clientData;
  464.     Tcl_DeleteInterp(info->consoleInterp);
  465.     info->consoleInterp = NULL;
  466. }
  467. /*
  468.  *----------------------------------------------------------------------
  469.  *
  470.  * ConsoleEventProc --
  471.  *
  472.  * This event procedure is registered on the main window of the
  473.  * slave interpreter.  If the user or a running script causes the
  474.  * main window to be destroyed, then we need to inform the console
  475.  * interpreter by invoking "tkConsoleExit".
  476.  *
  477.  * Results:
  478.  * None.
  479.  *
  480.  * Side effects:
  481.  * Invokes the "tkConsoleExit" procedure in the console interp.
  482.  *
  483.  *----------------------------------------------------------------------
  484.  */
  485. static void
  486. ConsoleEventProc(clientData, eventPtr)
  487.     ClientData clientData;
  488.     XEvent *eventPtr;
  489. {
  490.     ConsoleInfo *info = (ConsoleInfo *) clientData;
  491.     Tcl_Interp *consoleInterp;
  492.     
  493.     if (eventPtr->type == DestroyNotify) {
  494.         consoleInterp = info->consoleInterp;
  495.         /*
  496.          * It is possible that the console interpreter itself has
  497.          * already been deleted. In that case the consoleInterp
  498.          * field will be set to NULL. If the interpreter is already
  499.          * gone, we do not have to do any work here.
  500.          */
  501.         
  502.         if (consoleInterp == (Tcl_Interp *) NULL) {
  503.             return;
  504.         }
  505.         Tcl_Preserve((ClientData) consoleInterp);
  506. Tcl_Eval(consoleInterp, "tkConsoleExit");
  507.         Tcl_Release((ClientData) consoleInterp);
  508.     }
  509. }
  510. /*
  511.  *----------------------------------------------------------------------
  512.  *
  513.  * TkConsolePrint --
  514.  *
  515.  * Prints to the give text to the console.  Given the main interp
  516.  * this functions find the appropiate console interp and forwards
  517.  * the text to be added to that console.
  518.  *
  519.  * Results:
  520.  * None.
  521.  *
  522.  * Side effects:
  523.  * None.
  524.  *
  525.  *----------------------------------------------------------------------
  526.  */
  527. void
  528. TkConsolePrint(interp, devId, buffer, size)
  529.     Tcl_Interp *interp; /* Main interpreter. */
  530.     int devId; /* TCL_STDOUT for stdout, TCL_STDERR for
  531.                                  * stderr. */
  532.     char *buffer; /* Text buffer. */
  533.     long size; /* Size of text buffer. */
  534. {
  535.     Tcl_DString command, output;
  536.     Tcl_CmdInfo cmdInfo;
  537.     char *cmd;
  538.     ConsoleInfo *info;
  539.     Tcl_Interp *consoleInterp;
  540.     int result;
  541.     if (interp == NULL) {
  542. return;
  543.     }
  544.     
  545.     if (devId == TCL_STDERR) {
  546. cmd = "tkConsoleOutput stderr ";
  547.     } else {
  548. cmd = "tkConsoleOutput stdout ";
  549.     }
  550.     
  551.     result = Tcl_GetCommandInfo(interp, "console", &cmdInfo);
  552.     if (result == 0) {
  553. return;
  554.     }
  555.     info = (ConsoleInfo *) cmdInfo.clientData;
  556.     
  557.     Tcl_DStringInit(&output);
  558.     Tcl_DStringAppend(&output, buffer, size);
  559.     Tcl_DStringInit(&command);
  560.     Tcl_DStringAppend(&command, cmd, strlen(cmd));
  561.     Tcl_DStringAppendElement(&command, output.string);
  562.     consoleInterp = info->consoleInterp;
  563.     Tcl_Preserve((ClientData) consoleInterp);
  564.     Tcl_Eval(consoleInterp, command.string);
  565.     Tcl_Release((ClientData) consoleInterp);
  566.     
  567.     Tcl_DStringFree(&command);
  568.     Tcl_DStringFree(&output);
  569. }