home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tcltk805.zip / tcl805s.zip / tcl8.0.5 / os2 / tclOS2Console.c < prev    next >
C/C++ Source or Header  |  2001-02-09  |  24KB  |  668 lines

  1. /*
  2.  * tclOS2Console.c --
  3.  *
  4.  *    OS/2 PM console window class definition.
  5.  *
  6.  * Copyright (c) 1994 Software Research Associates, Inc.
  7.  * Copyright (c) 1995 Sun Microsystems, Inc.
  8.  * Copyright (c) 1996-2001 Illya Vaes
  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.  
  14. #include "tclOS2Int.h"
  15. #include <string.h>
  16. #include "tclOS2Console.h"
  17.  
  18. /*
  19.  * Predefined control identifiers.
  20.  */
  21. #define IDC_EDIT    1
  22. #define MLN_USER    0xff
  23.  
  24. #define MAX(a,b)  ( (a) > (b) ? (a) : (b) )
  25.  
  26. /*
  27.  * Initial screen size.
  28.  */
  29.  
  30. #define INIT_SCREEN_CX    80
  31. #define INIT_SCREEN_CY    25
  32.  
  33. static HWND hwndEdit;        /* Handle for edit control. */
  34. #define APP_NAME "TclPM " ## TCL_VERSION
  35. static char szAppName[] = APP_NAME;
  36. static int cxFrame, cyFrame, cyCaption, cxVScroll;
  37. static Tcl_DString command;     /* Used to buffer incomplete commands. */
  38.  
  39. char cmdBuf[256];        /* Line buffer for commands */
  40. IPT insPoint;
  41.  
  42. PFNWP oldEditProc = NULL;    /* Pointer to system Edit control procedure */
  43.  
  44. /*
  45.  * Forward references for procedures defined later in this file:
  46.  */
  47.  
  48. static void             DisplayString _ANSI_ARGS_((char *str, int newline));
  49. static MRESULT EXPENTRY TerminalProc _ANSI_ARGS_((HWND, ULONG, MPARAM, MPARAM));
  50. static MRESULT EXPENTRY EditProc _ANSI_ARGS_((HWND, ULONG, MPARAM, MPARAM));
  51. static int              TerminalPutsCmd _ANSI_ARGS_((ClientData clientData,
  52.                                 Tcl_Interp *interp, int argc, char **argv));
  53.  
  54.  
  55. /*
  56.  *----------------------------------------------------------------------
  57.  *
  58.  * RegisterTerminalClass --
  59.  *
  60.  *    Creates the application class for the console window.
  61.  *
  62.  * Results:
  63.  *    None.
  64.  *
  65.  * Side effects:
  66.  *    The global window class "Tclsh" is created.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70.  
  71. BOOL
  72. RegisterTerminalClass(hab)
  73.     HAB hab;
  74. {            
  75.     return WinRegisterClass(hab, "Terminal", TerminalProc, CS_SIZEREDRAW,
  76.                             sizeof(Tcl_Interp*));
  77. }
  78.  
  79. /*
  80.  *----------------------------------------------------------------------
  81.  *
  82.  * CreateTerminal --
  83.  *
  84.  *    Creates an instance of the Tclsh console window.
  85.  *
  86.  * Results:
  87.  *    A Window handle for the newly created instance.
  88.  *
  89.  * Side effects:
  90.  *    Creates a new window instance with a pointer to the
  91.  *    interpreter stored in the window instance data.
  92.  *
  93.  *----------------------------------------------------------------------
  94.  */
  95.  
  96. HWND
  97. CreateTerminal(hab, interp)
  98.     HAB hab;
  99.     Tcl_Interp *interp;
  100. {
  101.     HPS hps;
  102.     FONTMETRICS fm;
  103.     HWND hwnd, hFrame;
  104.     ULONG flags = FCF_TITLEBAR | FCF_SYSMENU | FCF_MINMAX | FCF_SHELLPOSITION |
  105.                   FCF_SIZEBORDER | FCF_TASKLIST;
  106.  
  107.     Tcl_DStringInit(&command);
  108.     hwnd = hFrame = NULLHANDLE;
  109.     cxFrame = WinQuerySysValue(HWND_DESKTOP, SV_CXSIZEBORDER);
  110.     cyFrame = WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER);
  111.     cyCaption = WinQuerySysValue(HWND_DESKTOP, SV_CYTITLEBAR);
  112.     cxVScroll = WinQuerySysValue(HWND_DESKTOP, SV_CXVSCROLL);
  113.  
  114.     hFrame= WinCreateStdWindow(HWND_DESKTOP, 0, &flags, "Terminal",
  115.                                szAppName, 0, NULLHANDLE, 1, &hwnd);
  116.     hps = WinGetPS(HWND_DESKTOP);
  117.     if (hwnd != NULLHANDLE) {
  118.         PSZ font = "8.Courier";
  119.         WinSetPresParam(hwnd, PP_FONTNAMESIZE, strlen(font), (PVOID)font);
  120.         /* This next setting is important in TerminalProc */
  121.         WinSetWindowULong(hwnd, QWL_USER, (ULONG)interp);
  122.         if (GpiQueryFontMetrics(hps, sizeof(FONTMETRICS), &fm)) {
  123.             /* Select system font? */
  124.             WinSetWindowPos(hFrame, HWND_TOP, 0, 0,
  125.                   (fm.lAveCharWidth * INIT_SCREEN_CX)+(cxFrame * 2)+ cxVScroll,
  126.                   (fm.lMaxBaselineExt * INIT_SCREEN_CY)+cyCaption+(cyFrame * 2),
  127.                   SWP_SIZE | SWP_SHOW);
  128.             Tcl_CreateCommand(interp, "puts", TerminalPutsCmd, NULL, NULL);
  129.         }
  130.         WinReleasePS(hps);
  131.     }
  132.     return hwnd;
  133. }
  134.  
  135. /*
  136.  *----------------------------------------------------------------------
  137.  *
  138.  * TerminalProc --
  139.  *
  140.  *    Window procedure for the Tclsh "Terminal" class.
  141.  *
  142.  * Results:
  143.  *    The usual Window procedure values.
  144.  *
  145.  * Side effects:
  146.  *    On window creation, it creates an edit child window.  Most
  147.  *    of the messages are forwarded to the child.
  148.  *
  149.  *----------------------------------------------------------------------
  150.  */
  151.  
  152. static MRESULT EXPENTRY
  153. TerminalProc(hwnd, message, param1, param2)
  154.     HWND hwnd;
  155.     ULONG message;
  156.     MPARAM param1;
  157.     MPARAM param2;
  158. {
  159.     switch(message) {
  160.     case WM_CREATE: {
  161.         MLECTLDATA mleCtlData;
  162.         IPT firstPos;
  163.  
  164.         mleCtlData.cbCtlData = sizeof(mleCtlData);
  165.         mleCtlData.afIEFormat = MLFIE_CFTEXT;
  166.         /*
  167.          * Don't specify unbounded text limit by giving -1, so we don't
  168.          * groooowwwwwww the swapfile. The limit will be raised by overflows
  169.          * that don't fit into this limit; other overflows will cause silent
  170.          * deletion of that amount from the beginning.
  171.          */
  172.         mleCtlData.cchText = 1024 * 1024;   /* 1 MB */
  173.         mleCtlData.iptAnchor = 0;
  174.         mleCtlData.iptCursor = 0;
  175.         mleCtlData.cxFormat = 0;
  176.         mleCtlData.cyFormat = 0;
  177.         mleCtlData.afFormatFlags = MLFFMTRECT_MATCHWINDOW;
  178.         hwndEdit = WinCreateWindow(hwnd, WC_MLE, NULL,
  179.                                    WS_VISIBLE | MLS_HSCROLL | MLS_VSCROLL |
  180.                                    MLS_BORDER | MLS_WORDWRAP, 0, 0, 0, 0, hwnd,
  181.                                    HWND_TOP, IDC_EDIT, &mleCtlData, NULL);
  182.         oldEditProc = WinSubclassWindow(hwndEdit, EditProc);
  183.         /* Have the first prompt displayed */
  184.         insPoint = (IPT) WinSendMsg(hwndEdit, MLM_QUERYFIRSTCHAR, (MPARAM)0,
  185.                                     (MPARAM)0);
  186.         firstPos = insPoint;
  187.         DisplayString("Welcome to the Tcl shell "TCL_VERSION" for OS/2 Presentation Manager", 1);
  188.         DisplayString("% ", 0);
  189.         WinSendMsg(hwndEdit, MLM_SETFIRSTCHAR, (MPARAM)firstPos, (MPARAM)0);
  190.         /*
  191.         insPoint = (IPT)WinSendMsg(hwndEdit, MLM_CHARFROMLINE, MPFROMLONG(-1),
  192.                                    0);
  193.         */
  194. #ifdef VERBOSE
  195.         {
  196.         LONG limit = (LONG) WinSendMsg(hwndEdit, MLM_QUERYTEXTLIMIT, (MPARAM)0,
  197.                                        (MPARAM)0);
  198.         printf("MLE text limit is %d\n", limit);
  199.         fflush(stdout);
  200.         }
  201. #endif
  202.         return 0;
  203.     }
  204.  
  205.     case WM_CONTROL:
  206.         if (SHORT1FROMMP(param1) == IDC_EDIT) {
  207.             /* This is our MLE calling */
  208.             switch (SHORT2FROMMP(param1)) {
  209.             case MLN_USER: {
  210.                 int length, offset, exp;
  211.                 char *cmd;
  212.  
  213.                 /*
  214.                  * Get line containing cursor.
  215.                  */
  216.  
  217.                 /* Get line length */
  218.                 length = (int)WinSendMsg(hwndEdit, MLM_QUERYLINELENGTH,
  219.                                          MPFROMLONG(insPoint), 0);
  220.                 /* Set export buffer */
  221.                 if (!WinSendMsg(hwndEdit, MLM_SETIMPORTEXPORT, MPFROMP(cmdBuf),
  222.                                 MPFROMLONG(length))) {
  223.                     break;
  224.                 }
  225.                 /* Export the text from the MLE */
  226.                 exp = (ULONG)WinSendMsg(hwndEdit, MLM_EXPORT,
  227.                                         MPFROMP(&insPoint), MPFROMP(&length));
  228.                 cmdBuf[exp] = '\n';
  229.                 cmdBuf[exp+1] = '\0';
  230. #ifdef VERBOSE
  231.                 printf("cmdBuf [%s]\n", cmdBuf);
  232. #endif
  233.                 if (cmdBuf[0] == '%' || cmdBuf[0] == '>') {
  234.                     if (cmdBuf[1] == ' ') offset = 2;
  235.                     else offset = 1;
  236.                 } else {
  237.                     offset = 0;
  238.                 }
  239.                 cmd = Tcl_DStringAppend(&command, cmdBuf + offset, -1);
  240.                 DisplayString("", 1);
  241.                 if (Tcl_CommandComplete(cmd)) {
  242.                     Tcl_Interp* interp = (Tcl_Interp*) WinQueryWindowULong(hwnd,
  243.                                          QWL_USER);
  244.                     Tcl_RecordAndEval(interp, cmd, 0);
  245.                     Tcl_DStringFree(&command);
  246.                     if (interp->result != NULL && *interp->result != '\0') {
  247.                         DisplayString(interp->result, 1);
  248.                     }
  249.                     DisplayString("% ", 0);
  250.                 } else {
  251.                     DisplayString("> ", 0);
  252.                 }
  253.                 break;
  254.             }
  255.  
  256.             case MLN_TEXTOVERFLOW:
  257.                 /*
  258.                  * Character(s) typed causing overflow, delete a whole block
  259.                  * of text at the beginning so the next character won't cause
  260.                  * this message again, or the amount of overflow (in param2)
  261.                  * if that's larger.
  262.                  * Return TRUE to signal that corrective action has been taken.
  263.                  */
  264. #ifdef VERBOSE
  265.                 printf("MLN_TEXTOVERFLOW %d\n", MAX(1024, LONGFROMMP(param2)));
  266.                 fflush(stdout);
  267. #endif
  268.                 WinSendMsg(hwndEdit, MLM_DELETE,
  269.                            (MPARAM) WinSendMsg(hwndEdit, MLM_CHARFROMLINE,
  270.                                            (MPARAM)0, (MPARAM)0),
  271.                            (MPARAM) MAX(1024, LONGFROMMP(param2)));
  272.                 return (MRESULT)1;
  273.  
  274.             case MLN_OVERFLOW: {
  275.                 /*
  276.                  * Some action != typing character has caused overflow, delete
  277.                  * the amount of overflow (in MLEOVERFLOW structure pointed to
  278.                  * by param2) at the beginning if this is because of a paste.
  279.                  * Return TRUE to signal that corrective action has been taken.
  280.                  */
  281.                 POVERFLOW pOverflow = (POVERFLOW) PVOIDFROMMP(param2);
  282.                 if (pOverflow->afErrInd & MLFETL_TEXTBYTES) {
  283.                     /*
  284.                      * If the overflow is larger than the text limit, increase
  285.                      * it to the overflow, so it will fit entirely. Otherwise,
  286.                      * delete the first <overflow> bytes.
  287.                      */
  288.                     IPT firstPoint;
  289.                     LONG limit = (LONG) WinSendMsg(hwndEdit, MLM_QUERYTEXTLIMIT,
  290.                                             (MPARAM)0, (MPARAM)0);
  291. #ifdef VERBOSE
  292.                     printf("MLE text limit is %d\n", limit);
  293.                     fflush(stdout);
  294. #endif
  295.                     /* limit is < 0 for unbounded, but then we can't overflow */
  296.                     if (pOverflow->nBytesOver > limit) {
  297. #ifdef VERBOSE
  298.                         printf("Increasing MLE text limit by %d to %d\n",
  299.                                pOverflow->nBytesOver,
  300.                                pOverflow->nBytesOver + limit);
  301.                         fflush(stdout);
  302. #endif
  303.                         WinSendMsg(hwndEdit, MLM_SETTEXTLIMIT,
  304.                                    (MPARAM) pOverflow->nBytesOver + limit,
  305.                                    (MPARAM)0);
  306.                     }
  307. #ifdef VERBOSE
  308.                     printf("MLN_OVERFLOW %d\n",
  309.                            MAX(1024, pOverflow->nBytesOver));
  310.                     fflush(stdout);
  311. #endif
  312.                     firstPoint = (IPT) WinSendMsg(hwndEdit, MLM_CHARFROMLINE,
  313.                                                   (MPARAM)0, (MPARAM)0);
  314.                     firstPoint = 0;
  315.                     WinSendMsg(hwndEdit, MLM_DELETE, (MPARAM)firstPoint,
  316.                                (MPARAM) MAX(1024, pOverflow->nBytesOver));
  317.                     insPoint = (IPT)WinSendMsg(hwndEdit, MLM_CHARFROMLINE,
  318.                                           (MPARAM)WinSendMsg(hwndEdit,
  319.                                                              MLM_QUERYLINECOUNT,
  320.                                                              (MPARAM)0,
  321.                                                              (MPARAM)0),
  322.                                           (MPARAM)0);
  323.                     insPoint += (int)WinSendMsg(hwndEdit, MLM_QUERYLINELENGTH,
  324.                                                 MPFROMLONG(insPoint), 0);
  325. #ifdef VERBOSE
  326.                     printf("lineCount %d\n", (long)WinSendMsg(hwndEdit,
  327.                            MLM_QUERYLINECOUNT, (MPARAM)0, (MPARAM)0));
  328.                     printf("firstPoint %d, insPoint %d\n", firstPoint,
  329.                            insPoint);
  330.                     fflush(stdout);
  331. #endif
  332.                 } else {
  333.                     /* What to do? */
  334. #ifdef VERBOSE
  335.                     printf("non-textlimit MLN_OVERFLOW %d\n",
  336.                            pOverflow->nBytesOver);
  337.                     fflush(stdout);
  338. #endif
  339.                     return (MRESULT)0;
  340.                 }
  341.                 return (MRESULT)1;
  342.             }
  343.  
  344.             case MLN_MEMERROR:
  345.                 WinMessageBox(HWND_DESKTOP, hwnd,
  346.                               "MLE says \"MLN_MEMERROR\"",
  347.                               szAppName, 0, MB_OK | MB_ERROR | MB_APPLMODAL);
  348.                 return (MRESULT)0;
  349.         }
  350.     }
  351.     break;
  352.  
  353.     case WM_CHAR: {
  354. #ifdef VERBOSE
  355.         USHORT flags= CHARMSG(&message)->fs;
  356.         USHORT charcode= CHARMSG(&message)->chr;
  357.         printf("WM_CHAR flags %x, charcode %d\n", flags, charcode);
  358. #endif
  359.         if ((CHARMSG(&message)->fs) & KC_CTRL &&
  360.             (CHARMSG(&message)->chr) == 'c') {
  361.             Tcl_Interp* interp = (Tcl_Interp*) WinQueryWindowULong(hwnd,
  362.                                  QWL_USER);
  363.             int length, exp;
  364.  
  365.             /*
  366.              * Get line containing cursor.
  367.              */
  368.  
  369.             /* Get line length */
  370.             length = (int)WinSendMsg(hwndEdit, MLM_QUERYLINELENGTH,
  371.                                      MPFROMLONG(insPoint), 0);
  372.             /* Set export buffer */
  373.             WinSendMsg(hwndEdit, MLM_SETIMPORTEXPORT, MPFROMP(cmdBuf),
  374.                             MPFROMLONG(sizeof(cmdBuf)));
  375.             /* Export the text from the MLE */
  376.             exp = (ULONG)WinSendMsg(hwndEdit, MLM_EXPORT, MPFROMP(&insPoint),
  377.                                     MPFROMP(&length));
  378.             Tcl_DStringFree(&command);
  379.             Tcl_Eval(interp, "break");
  380.             DisplayString("", 1);
  381.             DisplayString("% ", 0);
  382.         }
  383.         break;
  384.     }
  385.  
  386.     case WM_SETFOCUS:
  387.         WinSetFocus(HWND_DESKTOP, hwndEdit);
  388.         return 0;
  389.         
  390.     case WM_SIZE:
  391.         WinSetWindowPos(hwndEdit, HWND_TOP, 0, 0, SHORT1FROMMP(param2),
  392.                         SHORT2FROMMP(param2), SWP_MOVE | SWP_SIZE);
  393.         return 0;
  394.  
  395.     case WM_CLOSE:
  396.         if (WinMessageBox(HWND_DESKTOP, hwnd, "Do you really want to exit?",
  397.                           szAppName, 0, MB_YESNO|MB_ICONQUESTION|MB_APPLMODAL)
  398.             == MBID_YES) {
  399.             Tcl_Interp* interp= (Tcl_Interp*) WinQueryWindowULong(hwnd,
  400.                                                                   QWL_USER);
  401. #ifdef VERBOSE
  402.             printf("WM_CLOSE, exiting, interp %x\n", (long)interp);
  403. #endif
  404.             /*
  405.              * Rather than calling exit, invoke the "exit" command so that
  406.              * users can replace "exit" with some other command to do additional
  407.              * cleanup on exit.  The Tcl_Eval call should never return.
  408.              */
  409.  
  410.             Tcl_Eval(interp, "exit 0");
  411.         }
  412. #ifdef VERBOSE
  413.         printf("WM_CLOSE, not exiting\n");
  414. #endif
  415.         return 0 ;
  416.  
  417.     }
  418.     return WinDefWindowProc(hwnd, message, param1, param2);
  419. }
  420.  
  421. /*
  422.  *----------------------------------------------------------------------
  423.  *
  424.  * EditProc --
  425.  *
  426.  *    Edit subclass window procedure.
  427.  *
  428.  * Results:
  429.  *    The usual Window procedure values.
  430.  *
  431.  * Side effects:
  432.  *    Allows user to edit commands.  Sends a double click event to
  433.  *    the main window when the user presses enter.
  434.  *
  435.  *----------------------------------------------------------------------
  436.  */
  437.  
  438. static MRESULT EXPENTRY
  439. EditProc(hwnd, message, param1, param2)
  440.     HWND hwnd;
  441.     ULONG message;
  442.     MPARAM param1;
  443.     MPARAM param2;
  444. {
  445.     if (message == WM_CHAR && SHORT1FROMMP(param1) & KC_CHAR &&
  446.             ((USHORT)SHORT1FROMMP(param2) == '\r'
  447.              || (USHORT)SHORT1FROMMP(param2) == '\n')) {
  448. #ifdef VERBOSE
  449.         printf("short1(param1) [%x], char3(param1) [%x], char4(param1) [%x]\n",
  450.                SHORT1FROMMP(param1), CHAR3FROMMP(param1), CHAR4FROMMP(param1));
  451.         printf("short1(param2) [%x], short2(param2) [%x]\n",
  452.                SHORT1FROMMP(param2), SHORT2FROMMP(param2));
  453. #endif
  454.         WinSendMsg(WinQueryWindow(hwnd, QW_PARENT), WM_CONTROL,
  455.                    MPFROM2SHORT(IDC_EDIT,MLN_USER), (MPARAM)hwnd);
  456.         return 0 ;
  457.     } else {
  458. /*
  459. #ifdef VERBOSE
  460.         printf("Returning oldEditProc (%x, %x (%s), %x, %x)\n", hwnd,
  461.                message, message == WM_CONTROL ? "WM_CONTROL" :
  462.                (message == MLM_SETSEL ? "MLM_SETSEL" :
  463.                 (message == MLM_QUERYLINECOUNT ? "MLM_QUERYLINECOUNT" :
  464.                  (message == MLM_CHARFROMLINE ? "MLM_CHARFROMLINE" :
  465.                   (message == MLM_PASTE ? "MLM_PASTE" : "unknown")))),
  466.                param1, param2);
  467.         fflush(stdout);
  468. #endif
  469. */
  470.         return oldEditProc(hwnd, message, param1, param2);
  471.     }
  472. }
  473.  
  474. /*
  475.  *----------------------------------------------------------------------
  476.  *
  477.  * TerminalPutsCmd --
  478.  *
  479.  *    Replacement for Tcl "puts" command that writes output to the
  480.  *    terminal instead of stdout/stderr.
  481.  *
  482.  * Results:
  483.  *    A standard Tcl result.
  484.  *
  485.  * Side effects:
  486.  *    Same as Tcl_PutsCmd, except that it puts the output string
  487.  *    into the terminal if the specified file is stdout.
  488.  *
  489.  *----------------------------------------------------------------------
  490.  */
  491.  
  492. int
  493. TerminalPutsCmd(clientData, interp, argc, argv)
  494.     ClientData clientData;        /* Not used. */
  495.     Tcl_Interp *interp;            /* Current interpreter. */
  496.     int argc;                /* Number of arguments. */
  497.     char **argv;            /* Argument strings. */
  498. {
  499.     Tcl_Channel chan;                   /* The channel to puts on. */
  500.     int i;                              /* Counter. */
  501.     int newline;                        /* Add a newline at end? */
  502.     char *channelId;                    /* Name of channel for puts. */
  503.     int result;                         /* Result of puts operation. */
  504.     int mode;                           /* Mode in which channel is opened. */
  505.  
  506. #ifdef VERBOSE
  507.     printf("TerminalPutsCmd ");
  508.     fflush(stdout);
  509.     for (i=0; i<argc; i++) {
  510.        printf("[%s] ", argv[i]);
  511.     }
  512.     printf("\n");
  513.     fflush(stdout);
  514. #endif
  515.     
  516.     i = 1;
  517.     newline = 1;
  518.     if ((argc >= 2) && (strcmp(argv[1], "-nonewline") == 0)) {
  519.         newline = 0;
  520.         i++;
  521.     }
  522.     if ((i < (argc-3)) || (i >= argc)) {
  523.         Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
  524.                 " ?-nonewline? ?channelId? string\"", (char *) NULL);
  525.         return TCL_ERROR;
  526.     }
  527.  
  528.     /*
  529.      * The code below provides backwards compatibility with an old
  530.      * form of the command that is no longer recommended or documented.
  531.      */
  532.  
  533.     if (i == (argc-3)) {
  534.         if (strncmp(argv[i+2], "nonewline", strlen(argv[i+2])) != 0) {
  535.             Tcl_AppendResult(interp, "bad argument \"", argv[i+2],
  536.                 "\": should be \"nonewline\"", (char *) NULL);
  537.             return TCL_ERROR;
  538.         }
  539.         newline = 0;
  540.     }
  541.     if (i == (argc-1)) {
  542.         /* Output on console terminal */
  543.         DisplayString(argv[i], newline);
  544.     } else if ( (stricmp(Tcl_GetVar(interp, "tcl_interactive", TCL_GLOBAL_ONLY),
  545.                         "1") == 0 &&
  546.               ( (stricmp(argv[i], "stdout") == 0 ||
  547.                  stricmp(argv[i], "stderr") == 0))
  548.         ) ) {
  549.         i++;
  550.         /* Output on console terminal */
  551.         DisplayString(argv[i], newline);
  552.     } else {
  553.         /* Other channel specified, use standard (tclIOCmd) stuff */
  554.         channelId = argv[i];
  555.         i++;
  556.         chan = Tcl_GetChannel(interp, channelId, &mode);
  557.         if (chan == (Tcl_Channel) NULL) {
  558.             return TCL_ERROR;
  559.         }
  560.         if ((mode & TCL_WRITABLE) == 0) {
  561.             Tcl_AppendResult(interp, "channel \"", channelId,
  562.                     "\" wasn't opened for writing", (char *) NULL);
  563.             return TCL_ERROR;
  564.         }
  565.  
  566.         result = Tcl_Write(chan, argv[i], -1);
  567.         if (result < 0) {
  568.             goto error;
  569.         }
  570.         if (newline != 0) {
  571.             result = Tcl_Write(chan, "\n", 1);
  572.             if (result < 0) {
  573.                 goto error;
  574.             }
  575.         }
  576.     }
  577.  
  578.     return TCL_OK;
  579.  
  580. error:
  581.     Tcl_AppendResult(interp, "error writing \"", Tcl_GetChannelName(chan),
  582.             "\": ", Tcl_PosixError(interp), (char *) NULL);
  583.     return TCL_ERROR;
  584. }
  585.  
  586. /*
  587.  *----------------------------------------------------------------------
  588.  *
  589.  * DisplayString --
  590.  *
  591.  *    Insert a string into the console with an optional trailing
  592.  *    newline.
  593.  *      NOTE: the MLE control assumes the text to be in the clipboard as
  594.  *      a single contiguous data segment, which restricts the amount to
  595.  *      the maximum segment size (64K).
  596.  *
  597.  * Results:
  598.  *    None.
  599.  *
  600.  * Side effects:
  601.  *    Updates the MLE control.
  602.  *
  603.  *----------------------------------------------------------------------
  604.  */
  605.  
  606. void
  607. DisplayString(str, newline)
  608.     char *str;
  609.     int newline;
  610. {
  611.     char *p;
  612.     const char *tmp;
  613.     PVOID clipmem;
  614.     ULONG size, lineCnt;
  615. #ifdef VERBOSE
  616.     printf("DisplayString (%s,%d) (%d) (insPoint %d)\n", str, newline,
  617.            strlen(str), insPoint);
  618. #endif
  619.  
  620.     tmp = str;
  621.     for(lineCnt = 0; *tmp; tmp++) {
  622.         if(*tmp == '\n') {
  623.             lineCnt++;
  624.         }
  625.     }
  626.     if (newline) {
  627.         size  = strlen(str) + lineCnt + 3;
  628.     } else {
  629.         size  = strlen(str) + lineCnt + 1;
  630.     }
  631.     if ( (clipmem = ckalloc(size)) ) {
  632.         for (p = (char *)clipmem; *str != '\0'; p++, str++) {
  633.             if(*str == '\n') {
  634.                 *p++ = '\r';
  635.             }
  636.             *p = *str;
  637.         }
  638.         if (newline) {
  639.             *p++ = '\r';
  640.             *p++ = '\n';
  641.         }
  642.         *p = '\0';
  643. #ifdef VERBOSE
  644.         printf("    sending [%s] (size %d)\n", clipmem, size);
  645. #endif
  646.         WinSendMsg(hwndEdit, MLM_DISABLEREFRESH, (MPARAM)0, (MPARAM)0);
  647.         if (WinSendMsg(hwndEdit, MLM_SETIMPORTEXPORT, MPFROMP(clipmem),
  648.                        MPFROMLONG(size))) {
  649. #ifdef VERBOSE
  650.             ULONG imported;
  651.             printf("before MLM_IMPORT, insPoint %d, size %d\n", insPoint,
  652.                    size);
  653.             imported = (ULONG)
  654. #endif
  655.             WinSendMsg(hwndEdit, MLM_IMPORT, MPFROMP(&insPoint),
  656.                        MPFROMLONG(size));
  657. #ifdef VERBOSE
  658.             printf("MLM_IMPORT imported %d (insPoint %d, size %d)\n",
  659.                    imported, insPoint, size);
  660. #endif
  661.         }
  662.         WinSendMsg(hwndEdit, MLM_SETSEL, (MPARAM)insPoint,
  663.                    (MPARAM)insPoint);
  664.         WinSendMsg(hwndEdit, MLM_ENABLEREFRESH, (MPARAM)0, (MPARAM)0);
  665.         ckfree((char *)clipmem);
  666.     }
  667. }
  668.