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