home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mnth0107.zip / Anderson / source / edit.c next >
C/C++ Source or Header  |  1992-02-27  |  34KB  |  814 lines

  1. /*
  2.  *  EDIT.C -- A Simple Programmer's Editor Using MLE
  3.  *  
  4.  *  Programmer: Brian R. Anderson
  5.  *  Date: January 1992
  6.  *
  7.  */
  8.  
  9. #define INCL_WINHELP
  10. #define INCL_WIN
  11. #define INCL_GPI
  12. #define INCL_DOS
  13. #include <os2.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. #include "edit.h"
  18. #include "efile.h"
  19. #include "edlg.h"
  20.  
  21. /* custom messages, etc. */
  22. #define WM_ARGS (WM_USER + 0)
  23. #define WM_CLEANFILE (WM_USER + 1)
  24. #define ID_MLE 13   /* my lucky number! */
  25. #define ID_UPDATE 14
  26. #define TAB 3
  27.  
  28. /* local function prototypes */
  29. MRESULT EXPENTRY ClientWndProc (HWND, USHORT, MPARAM, MPARAM);
  30. MRESULT EXPENTRY TabWndProc (HWND, USHORT, MPARAM, MPARAM);
  31. VOID SetPtrArrow (VOID);
  32. VOID SetPtrWait (VOID);
  33.  
  34. /* global variables */
  35. HAB hab;   /* anchor block handle */
  36. HELPINIT hmiHelpData;   /* Help initialization structure*/
  37. HWND hwndHelpInstance;   /* Handle to Help window        */
  38. char szFileName[80];   /* current filename */
  39. BOOL hasName = FALSE;   /* TRUE if current file has a name */ 
  40. USHORT NeedToSave = FALSE;   /* TRUE if current file is 'Dirty' */
  41. char szFind[60];   /* target string for search */
  42. char szReplace[60];   /* replacement for search/replace */
  43. char szLine[20];   /* line number to go to */
  44. PFNWP pfMLE;   /* original MLE window procedure: subclassed to TabWndProc */
  45.  
  46.  
  47. int main (int argc, char *argv[])
  48. {
  49.    static CHAR  szClientClass[] = "Edit";
  50.    static ULONG flFrameFlags = FCF_TITLEBAR      | FCF_SYSMENU |
  51.                                FCF_SIZEBORDER    | FCF_MINMAX  |
  52.                                FCF_SHELLPOSITION | FCF_TASKLIST |
  53.                                FCF_MENU | FCF_ACCELTABLE | FCF_ICON;
  54.    HMQ hmq;
  55.    HWND hwndFrame, hwndClient;
  56.    QMSG qmsg;
  57.    USHORT res;
  58.       
  59.    hab = WinInitialize (0);
  60.    hmq = WinCreateMsgQueue (hab, 0);
  61.  
  62.    WinRegisterClass (
  63.                   hab,                /* Anchor block handle            */
  64.                   szClientClass,      /* Name of class being registered */
  65.                   ClientWndProc,      /* Window procedure for class     */
  66.                   CS_SIZEREDRAW,      /* Class style                    */
  67.                   0);                 /* Extra bytes to reserve         */
  68.  
  69.    /* Initialization IPF structure and create help instance */
  70.    hmiHelpData.cb = sizeof (HELPINIT);
  71.    hmiHelpData.ulReturnCode = 0L;   /* store HM return code from init. */
  72.    hmiHelpData.pszTutorialName = NULL;   /* no tutorial program */
  73.    hmiHelpData.phtHelpTable = (PVOID)(0xffff0000 | ID_EDIT);  /* table in RC */
  74.    hmiHelpData.hmodAccelActionBarModule = 0L;   /* normal action bar */
  75.    hmiHelpData.idAccelTable = 0;
  76.    hmiHelpData.idActionBar = 0;
  77.    hmiHelpData.pszHelpWindowTitle = "Edit Help";
  78.    hmiHelpData.hmodHelpTableModule = 0L;   /* help not in DLL */
  79.    hmiHelpData.usShowPanelId = 0;   /* don't display help panel IDs */
  80.    hmiHelpData.pszHelpLibraryName = "EDIT.HLP";
  81.  
  82.    hwndHelpInstance = WinCreateHelpInstance (hab, &hmiHelpData);
  83.    if (!hwndHelpInstance) {
  84.       WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
  85.          "Help Not Available", "Help Creation Error", 0,
  86.           MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  87.    }
  88.    else {
  89.       if (hmiHelpData.ulReturnCode) {
  90.          WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
  91.             "Help Terminated Due to Error", "Help Creation Error", 0,
  92.             MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  93.          WinDestroyHelpInstance(hwndHelpInstance);
  94.       }
  95.    }
  96.  
  97.    hwndFrame = WinCreateStdWindow (
  98.                   HWND_DESKTOP,       /* Parent window handle            */
  99.                   WS_VISIBLE,         /* Style of frame window           */
  100.                   &flFrameFlags,      /* Pointer to control data         */
  101.                   szClientClass,      /* Client window class name        */
  102.                   NULL,               /* Title bar text                  */
  103.                   0L,                 /* Style of client window          */
  104.                   0,                  /* Module handle for resources     */
  105.                   ID_EDIT,            /* ID of resources                 */
  106.                   &hwndClient);       /* Pointer to client window handle */
  107.  
  108.    WinStartTimer (hab, hwndClient, ID_UPDATE, 200);   /* 1/5 second */
  109.    
  110.    if (argc > 1) {
  111.       strcpy (szFileName, argv[1]);
  112.       WinSendMsg (hwndClient, WM_ARGS, (MPARAM) 0L, (MPARAM) 0L);
  113.    }
  114.  
  115.    if (hwndHelpInstance) 
  116.       WinAssociateHelpInstance (hwndHelpInstance, hwndFrame);
  117.  
  118.    for (;;) {   
  119.       while (WinGetMsg (hab, &qmsg, NULL, 0, 0))
  120.          WinDispatchMsg (hab, &qmsg);
  121.  
  122.       if (NeedToSave) {
  123.          res = WinMessageBox (HWND_DESKTOP, hwndClient,
  124.                               "Save before exit?", "End Session", 0,
  125.                               MB_YESNOCANCEL | MB_ICONQUESTION | MB_MOVEABLE);
  126.                         
  127.          if (res == MBID_YES) {
  128.             WinSendMsg (hwndClient, WM_COMMAND, 
  129.                MPFROM2SHORT (IDM_SAVE, 0), (MPARAM) 0L);
  130.             break;
  131.          }
  132.          else if (res == MBID_NO)
  133.             break;
  134.          else   /* res == MBID_CANCEL */
  135.             WinCancelShutdown (hmq, TRUE);
  136.       }
  137.       else
  138.          break;   /* terminate */
  139.    }                                     
  140.  
  141.    if (hwndHelpInstance) 
  142.       WinDestroyHelpInstance (hwndHelpInstance);
  143.    WinStopTimer (hab, hwndClient, ID_UPDATE);
  144.    WinDestroyWindow (hwndFrame);
  145.    WinDestroyMsgQueue (hmq);
  146.    WinTerminate (hab);
  147.    return 0;
  148. }
  149.  
  150.  
  151. /* main window procedure for application */
  152. MRESULT EXPENTRY ClientWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  153. {
  154.    HDC hdc;   /* device context */
  155.    LONG lHRes, lVRes;   /* device resolution */
  156.    HPS hps;   /* presentation space */
  157.    RECTL rcl;   /* rectangle drawing coordinates */
  158.    PSWP pswp;   /* set window position structure */
  159.    static HWND hwndFrame, hwndClient, hwndMenu, hwndMLE;   /* window handles */
  160.    static USHORT cyClient, cxClient;   /* size of edit window */
  161.    LONG selmin, selmax;   /* text selected for deletion */
  162.    SHORT undoable;   /* TRUE if last operation can be undone */
  163.    static BOOL undone = FALSE;   /* allows for redo immediately after undo */
  164.    CHAR str[60];   /* character string for output messages */
  165.    USHORT newline, newcolumn;   /* latest cursor position -- changed? */
  166.    static USHORT line, column;   /* current cursor position */
  167.    USHORT usfInfo;   /* flags for query clipboard information */
  168.    static USHORT menuheight;   /* height of standard window */
  169.    PCHAR buffer;   /* buffer for file I/O */
  170.    LONG bufferlen;   /* number of characters read into buffer */
  171.    FATTRS fattrs;   /* font attributes -- try to change to monospaced */
  172.    FONTMETRICS *pfm;   /* find a monospaced system font */
  173.    LONG lNumberFonts, lRequestFonts;   /* look for 10 point font */
  174.    USHORT res;   /* response from dialog or message box */
  175.    static USHORT resNew;   /* result of IDM_NEW (allows Cancel) */
  176.    BOOL first;   /* set to TRUE if replace dialog called for first time */
  177.    MLE_SEARCHDATA SearchData;   /* used is MLM_SEARCH message */
  178.    LONG goline, gochar;   /* go to line specified by user */
  179.    POINTS ps;   /* simulate mouse click to place cursor on specified line */
  180.    int i;   /* simple loop counter */
  181.             
  182.    switch (msg) {
  183.       case WM_CREATE:
  184.          hwndClient = hwnd;
  185.          hwndFrame = WinQueryWindow (hwnd, QW_PARENT, FALSE);
  186.          hwndMenu = WinWindowFromID (hwndFrame, FID_MENU);
  187.          menuheight = (USHORT) WinQuerySysValue (HWND_DESKTOP, SV_CYMENU);
  188.          WinSetWindowText (hwndFrame, "EDIT");
  189.             
  190.          hwndMLE = WinCreateWindow (
  191.             hwndClient,
  192.             WC_MLE, 
  193.             "", 
  194.             WS_VISIBLE | MLS_HSCROLL | MLS_VSCROLL | MLS_BORDER,
  195.             0, 0, 0, 0,   /* will set size & position later */
  196.             hwndClient,
  197.             HWND_TOP,
  198.             ID_MLE,
  199.             NULL, NULL);
  200.  
  201.          /* subclass to intercept tabs (convert to spaces) */
  202.          pfMLE = WinSubclassWindow (hwndMLE, TabWndProc);
  203.          
  204.          /* override v2.x MLE colors */
  205.          WinSendMsg (hwndMLE, MLM_SETTEXTCOLOR, 
  206.             MPFROMLONG (CLR_DEFAULT), 0L);
  207.          WinSendMsg (hwndMLE, MLM_SETBACKCOLOR, 
  208.             MPFROMLONG (CLR_BACKGROUND), 0L);
  209.    
  210.          /* try to switch to System Monospaced 10-point font */                     
  211.          hps = WinGetPS (hwndMLE);
  212.          hdc = GpiQueryDevice (hps);
  213.          DevQueryCaps (hdc, CAPS_HORIZONTAL_FONT_RES, 1L, &lHRes);
  214.          DevQueryCaps (hdc, CAPS_VERTICAL_FONT_RES, 1L, &lVRes);
  215.          lRequestFonts = 0L;
  216.          lNumberFonts = GpiQueryFonts (hps, QF_PUBLIC, "System Monospaced",
  217.                            &lRequestFonts, 0L, NULL);
  218.          pfm = malloc ((SHORT) lNumberFonts * sizeof (FONTMETRICS));
  219.          GpiQueryFonts (hps, QF_PUBLIC, "System Monospaced",  
  220.             &lNumberFonts, (LONG) sizeof (FONTMETRICS), pfm);
  221.  
  222.          for (i = 0; i < (int)lNumberFonts; i++) {
  223.             if (pfm[i].sXDeviceRes == (SHORT)lHRes &&   /* does font... */
  224.                 pfm[i].sYDeviceRes == (SHORT)lVRes &&   /* match device? */
  225.                 pfm[i].sNominalPointSize == 100) {   /* 10 point? */
  226.                WinSendMsg (hwndMLE, MLM_QUERYFONT, 
  227.                   MPFROMP (&fattrs), (MPARAM) 0L);
  228.                fattrs.lMatch = pfm[i].lMatch;
  229.                strcpy (fattrs.szFacename, "System Monospaced"); 
  230.                WinSendMsg (hwndMLE, MLM_SETFONT, 
  231.                   MPFROMP (&fattrs), (MPARAM) 0L);
  232.                break;   /* exit for loop */
  233.             }
  234.          }
  235.          free (pfm);
  236.          WinReleasePS (hps);                     
  237.          
  238.          /* set up some MLE parameters */
  239.          WinSendMsg (hwndMLE, MLM_SETTEXTLIMIT, 
  240.             MPFROMLONG (65535L), (MPARAM) 0L);
  241.                      
  242.          WinSendMsg (hwndMLE, MLM_SETTABSTOP, 
  243.             MPFROMSHORT (64), (MPARAM) 0L);
  244.                      
  245.          WinSendMsg (hwndMLE, MLM_FORMAT, 
  246.             MPFROMSHORT (MLFIE_CFTEXT), (MPARAM) 0L);
  247.  
  248.          WinSendMsg (hwndMLE, MLM_RESETUNDO, (MPARAM) 0L, (MPARAM) 0L);
  249.          WinSetFocus (HWND_DESKTOP, hwndMLE);
  250.          return 0;
  251.  
  252.       case WM_MINMAXFRAME:
  253.          pswp = PVOIDFROMMP (mp1);
  254.          if (pswp->fs & SWP_MINIMIZE) 
  255.             WinSetWindowText (hwndFrame, "EDIT");
  256.          else {
  257.             if (hasName) {
  258.                sprintf (str, "EDIT -- %s", szFileName);            
  259.                WinSetWindowText (hwndFrame, str);
  260.             }
  261.          }
  262.          return 0;
  263.          
  264.       case WM_INITMENU:
  265.          if (SHORT1FROMMP (mp1) == IDM_EDIT) {
  266.             /* enable Cut, Copy, or Delete only if text selected */
  267.             selmin = LONGFROMMR (WinSendMsg (hwndMLE, MLM_QUERYSEL, 
  268.                                     (MPARAM) MLFQS_MINSEL, (MPARAM) 0L));
  269.             selmax = LONGFROMMR (WinSendMsg (hwndMLE, MLM_QUERYSEL, 
  270.                                     (MPARAM) MLFQS_MAXSEL, (MPARAM) 0L));
  271.             WinSendMsg (hwndMenu, MM_SETITEMATTR,
  272.                MPFROM2SHORT (IDM_CUT, TRUE),
  273.                MPFROM2SHORT (MIA_DISABLED, 
  274.                (selmin == selmax) ? MIA_DISABLED : 0));
  275.             WinSendMsg (hwndMenu, MM_SETITEMATTR,
  276.                MPFROM2SHORT (IDM_COPY, TRUE),
  277.                MPFROM2SHORT (MIA_DISABLED, 
  278.                (selmin == selmax) ? MIA_DISABLED : 0));
  279.             WinSendMsg (hwndMenu, MM_SETITEMATTR,
  280.                MPFROM2SHORT (IDM_DELETE, TRUE),
  281.                MPFROM2SHORT (MIA_DISABLED, 
  282.                (selmin == selmax) ? MIA_DISABLED : 0));
  283.                   
  284.             /* enable Paste only if data available in Clipboard */
  285.             WinSendMsg (hwndMenu, MM_SETITEMATTR,
  286.                MPFROM2SHORT (IDM_PASTE, TRUE),
  287.                MPFROM2SHORT (MIA_DISABLED,
  288.                WinQueryClipbrdFmtInfo (hab, CF_TEXT, &usfInfo)
  289.                ? 0 : MIA_DISABLED));
  290.                      
  291.             /* enable Undo only if operation may be undone */
  292.             undoable = SHORT1FROMMR (WinSendMsg (hwndMLE, MLM_QUERYUNDO, 
  293.                                         (MPARAM) 0L, (MPARAM) 0L));
  294.             WinSendMsg (hwndMenu, MM_SETITEMATTR,
  295.                MPFROM2SHORT (IDM_UNDO, TRUE),
  296.                MPFROM2SHORT (MIA_DISABLED, (undoable || undone) 
  297.                                            ? 0 : MIA_DISABLED)); 
  298.          }
  299.          return 0;
  300.  
  301.       case WM_TIMER:
  302.          if (SHORT1FROMMP (mp1) == ID_UPDATE) {
  303.             /* determine position (line/column) of text cursor (caret) */
  304.             selmin = LONGFROMMR (WinSendMsg (hwndMLE, MLM_QUERYSEL, 
  305.                                     (MPARAM) MLFQS_MINSEL, (MPARAM) 0L));
  306.             newline = (int) LONGFROMMR (WinSendMsg (hwndMLE, 
  307.                                            MLM_LINEFROMCHAR,
  308.                                            MPFROMLONG (selmin), 
  309.                                            (MPARAM) 0L));
  310.             newcolumn = (int) (selmin - LONGFROMMR (WinSendMsg (hwndMLE, 
  311.                                            MLM_CHARFROMLINE,
  312.                                            MPFROMLONG ((long) newline), 
  313.                                            (MPARAM) 0L)));
  314.          
  315.             /* update on screen only if line or column changed */
  316.             if (newline != line || newcolumn != column) {
  317.                line = newline;   column = newcolumn;
  318.                WinInvalidateRect (hwnd, NULL, FALSE);
  319.             }
  320.          }
  321.          return 0;
  322.  
  323.       case WM_CONTROL:
  324.          switch (SHORT2FROMMP (mp1)) {
  325.             case MLN_OVERFLOW:
  326.                if (SHORT1FROMMP (mp1) == ID_MLE) {
  327.                   WinMessageBox (HWND_DESKTOP, hwnd, 
  328.                      "File too large -- 64K limit exceeded.",
  329.                      "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  330.                }
  331.                return 0;
  332.  
  333.             case MLN_CHANGE:
  334.                if (SHORT1FROMMP (mp1) == ID_MLE) {
  335.                   NeedToSave = TRUE;
  336.                   undone = FALSE;
  337.                }
  338.                return 0;
  339.             
  340.             default:
  341.                break;
  342.          }
  343.          break;
  344.     
  345.       case WM_CLEANFILE:
  346.          WinSendMsg (hwndMLE, MLM_RESETUNDO, (MPARAM) 0L, (MPARAM) 0L);
  347.          NeedToSave = FALSE;
  348.          return 0;
  349.       
  350.       case WM_ARGS:
  351.          /* read file into buffer */            
  352.          bufferlen = ReadFile (szFileName, &buffer);             
  353.          if (bufferlen == CANTREAD) {             
  354.             WinMessageBox (HWND_DESKTOP, hwnd, 
  355.                "Specified file does not exist.",
  356.                "New File", 0, MB_OK | MB_ICONASTERISK | MB_MOVEABLE);
  357.             hasName = TRUE;
  358.             sprintf (str, "EDIT -- %s", szFileName);            
  359.             WinSetWindowText (hwndFrame, str);             
  360.             NeedToSave = TRUE;
  361.          }             
  362.          else if (bufferlen == TOOLONG) {              
  363.             WinMessageBox (HWND_DESKTOP, hwnd, 
  364.                "File too large -- 64K limit exceeded.",
  365.                "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  366.             WinSetWindowText (hwndFrame, "EDIT");
  367.          }             
  368.          else if (bufferlen == NOMEMORY) {            
  369.             WinMessageBox (HWND_DESKTOP, hwnd, 
  370.                "Cannot allocate memory.",
  371.                "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  372.             WinSendMsg (hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  373.          }             
  374.          else {    /* normal */
  375.             /* transfer buffer to MLE */
  376.             WinSendMsg (hwndMLE, MLM_SETIMPORTEXPORT,
  377.                MPFROMP (buffer),
  378.                MPFROMSHORT ((USHORT)bufferlen));            
  379.                 selmin = 0L;
  380.             WinSendMsg (hwndMLE, MLM_IMPORT,
  381.                MPFROMP (&selmin), MPFROMLONG (bufferlen));            
  382.                 /* free buffer */
  383.             Release (buffer);    
  384.             hasName = TRUE;
  385.             sprintf (str, "EDIT -- %s", szFileName);            
  386.             WinSetWindowText (hwndFrame, str);             
  387.             WinPostMsg (hwnd, WM_CLEANFILE, (MPARAM) 0L, (MPARAM) 0L);
  388.          }             
  389.          return 0;
  390.  
  391.       case WM_COMMAND:
  392.          switch (SHORT1FROMMP (mp1)) {
  393.             case IDM_NEW:
  394.                if (NeedToSave) {
  395.                    res = WinMessageBox (HWND_DESKTOP, hwnd,
  396.                             "Save current file?", "New", 0,
  397.                              MB_YESNOCANCEL | MB_ICONQUESTION | MB_MOVEABLE);
  398.                                 
  399.                   if (res == MBID_YES) {
  400.                      WinSendMsg (hwnd, WM_COMMAND, 
  401.                         MPFROM2SHORT (IDM_SAVE, 0), (MPARAM) 0L);
  402.                   }
  403.                   else if (res == MBID_CANCEL) {
  404.                      resNew = MBID_CANCEL;
  405.                      return 0;
  406.                   }
  407.                }
  408.                SetPtrWait();
  409.                   
  410.                /* empty MLE */
  411.                selmin = 0L;
  412.                selmax = LONGFROMMR (WinSendMsg (hwndMLE, MLM_QUERYTEXTLENGTH,
  413.                                        (MPARAM) 0L, (MPARAM) 0L));
  414.                WinSendMsg (hwndMLE, MLM_DELETE, 
  415.                   MPFROMLONG (selmin), MPFROMLONG (selmax));
  416.                            
  417.                hasName = FALSE;
  418.                WinSetWindowText (hwndFrame, "EDIT");
  419.                WinPostMsg (hwnd, WM_CLEANFILE, (MPARAM) 0L, (MPARAM) 0L);
  420.                
  421.                SetPtrArrow();
  422.                resNew = MBID_OK;
  423.                return 0;
  424.                
  425.             case IDM_OPEN:
  426.                WinSendMsg (hwnd, WM_COMMAND, 
  427.                   MPFROMSHORT (IDM_NEW), (MPARAM) 0L);
  428.                if (resNew == MBID_CANCEL)
  429.                   return 0;
  430.                   
  431.                if (WinDlgBox (HWND_DESKTOP, hwnd, OpenDlgProc,
  432.                       0, IDD_OPEN, NULL)) {
  433.                               
  434.                   SetPtrWait();
  435.                      
  436.                   /* user selected a (valid) file to open */
  437.                   /* read file into buffer */
  438.                   bufferlen = ReadFile (szFileName, &buffer);
  439.                   
  440.                   SetPtrArrow();
  441.                      
  442.                   if (bufferlen == CANTREAD) {
  443.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  444.                         "Specified file does not exist.",
  445.                         "New File", 0, MB_OK | MB_ICONASTERISK | MB_MOVEABLE);
  446.                      hasName = TRUE;
  447.                      sprintf (str, "EDIT -- %s", szFileName);            
  448.                      WinSetWindowText (hwndFrame, str);             
  449.                      NeedToSave = TRUE;
  450.                   }
  451.                   else if (bufferlen == TOOLONG) {
  452.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  453.                         "File too large -- 64K limit exceeded.",
  454.                         "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  455.                      WinSetWindowText (hwndFrame, "EDIT");
  456.                      NeedToSave = FALSE;
  457.                   }
  458.                   else if (bufferlen == NOMEMORY) {
  459.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  460.                         "Cannot allocate memory.",
  461.                         "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  462.                      WinSendMsg (hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  463.                   }
  464.                   else {   /* normal */
  465.                      SetPtrWait();
  466.                         
  467.                      /* transfer buffer to MLE */
  468.                      WinSendMsg (hwndMLE, MLM_SETIMPORTEXPORT, 
  469.                         MPFROMP (buffer), MPFROMSHORT ((USHORT)bufferlen));
  470.                      selmin = 0L;            
  471.                      WinSendMsg (hwndMLE, MLM_IMPORT, 
  472.                         MPFROMP (&selmin), MPFROMLONG (bufferlen));
  473.                      /* free buffer */
  474.                      Release (buffer);
  475.                      hasName = TRUE;
  476.                      sprintf (str, "EDIT -- %s", szFileName);
  477.                      WinSetWindowText (hwndFrame, str);
  478.                      WinPostMsg (hwnd, WM_CLEANFILE, (MPARAM) 0L, (MPARAM) 0L);
  479.                      
  480.                      SetPtrArrow();
  481.                   }
  482.                } 
  483.                return 0;
  484.        
  485.             case IDM_SAVE:
  486.                if (hasName) {
  487.                   /* determine amount of text in MLE */
  488.                   bufferlen = LONGFROMMR (WinSendMsg (hwndMLE, 
  489.                                              MLM_QUERYFORMATTEXTLENGTH, 
  490.                                              (MPARAM) 0L, MPFROMLONG (-1L)));
  491.                                     
  492.                   /* allocate space for buffer */
  493.                   if (NOMEMORY == MakeWriteBuffer (bufferlen, &buffer)) {
  494.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  495.                         "Cannot allocate memory.",
  496.                         "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  497.                      WinSendMsg (hwnd, WM_QUIT, (MPARAM) 0L, (MPARAM) 0L);
  498.                   }
  499.                   SetPtrWait();
  500.                      
  501.                   /* transfer text from MLE to buffer */
  502.                   WinSendMsg (hwndMLE, MLM_SETIMPORTEXPORT, 
  503.                      MPFROMP (buffer), 
  504.                      MPFROMSHORT ((USHORT)bufferlen));
  505.                   selmin = 0L;   selmax = bufferlen;
  506.                   WinSendMsg (hwndMLE, MLM_EXPORT, 
  507.                      MPFROMP (&selmin), MPFROMP (&selmax));
  508.  
  509.                   /* write to file */
  510.                   if (CANTWRITE == WriteFile (szFileName, bufferlen, buffer)) {
  511.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  512.                         "Unable to write to file.",
  513.                         "Error", 0, MB_OK | MB_ICONHAND | MB_MOVEABLE);
  514.                   }
  515.                               
  516.                   /* deallocate buffer */
  517.                   Release (buffer);
  518.                   WinPostMsg (hwnd, WM_CLEANFILE, (MPARAM) 0L, (MPARAM) 0L);
  519.                   
  520.                   SetPtrArrow();
  521.                }
  522.                else {
  523.                   WinSendMsg (hwnd, WM_COMMAND, 
  524.                      MPFROM2SHORT (IDM_SAVEAS, 0), (MPARAM) 0L);
  525.                } 
  526.                return 0;
  527.                
  528.             case IDM_SAVEAS:
  529.                if (WinDlgBox (HWND_DESKTOP, hwnd, SaveasDlgProc,
  530.                       0, IDD_SAVEAS, NULL)) {
  531.                   hasName = TRUE;
  532.                   sprintf (str, "EDIT -- %s", szFileName);
  533.                   WinSetWindowText (hwndFrame, str);
  534.                   WinSendMsg (hwnd, WM_COMMAND, 
  535.                      MPFROM2SHORT (IDM_SAVE, 0), (MPARAM) 0L);
  536.                }
  537.                return 0;
  538.             
  539.             case IDM_EXIT:
  540.                WinSendMsg (hwnd, WM_CLOSE, (MPARAM) 0L, (MPARAM) 0L);
  541.                return 0;
  542.                
  543.             case IDM_UNDO:
  544.                WinSendMsg (hwndMLE, MLM_UNDO, (MPARAM) 0L, (MPARAM) 0L);
  545.                undone = TRUE;
  546.                return 0;
  547.                
  548.             case IDM_CUT:
  549.                WinSendMsg (hwndMLE, MLM_CUT, (MPARAM) 0L, (MPARAM) 0L);
  550.                return 0;
  551.             
  552.             case IDM_COPY:
  553.                WinSendMsg (hwndMLE, MLM_COPY, (MPARAM) 0L, (MPARAM) 0L);
  554.                return 0;
  555.                
  556.             case IDM_PASTE:
  557.                WinSendMsg (hwndMLE, MLM_PASTE, (MPARAM) 0L, (MPARAM) 0L);
  558.                return 0;
  559.                
  560.             case IDM_DELETE:
  561.                WinSendMsg (hwndMLE, MLM_CLEAR, (MPARAM) 0L, (MPARAM) 0L);
  562.                return 0;  
  563.             
  564.             case IDM_FIND:
  565.                if (DID_OK == WinDlgBox (HWND_DESKTOP, hwnd, FindDlgProc,
  566.                                 0, IDD_FIND, NULL)) {
  567.                   SetPtrWait();
  568.       
  569.                   SearchData.cb = sizeof (MLE_SEARCHDATA);
  570.                   SearchData.pchFind = szFind;
  571.                   SearchData.cchFind = strlen (szFind);
  572.                   SearchData.iptStart = (-1L);
  573.                   SearchData.iptStop = (-1L);
  574.       
  575.                   res = SHORT1FROMMR (WinSendMsg (hwndMLE, MLM_SEARCH, 
  576.                                           MPFROMLONG (MLFSEARCH_SELECTMATCH),
  577.                                           MPFROMP (&SearchData)));
  578.       
  579.                   SetPtrArrow();
  580.       
  581.                   if (!res) {
  582.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  583.                         "Search string not found.", "Find", 0, 
  584.                         MB_OK | MB_ICONASTERISK | MB_MOVEABLE);
  585.                   }
  586.                }
  587.                return 0;
  588.                
  589.             case IDM_REPLACE:
  590.                first = TRUE;
  591.                res = WinDlgBox (HWND_DESKTOP, hwnd, ReplaceDlgProc,
  592.                         0, IDD_REPLACE, (PVOID)(&first));
  593.                first = FALSE;
  594.                for (;;) {
  595.                   if (res == DID_CANCEL)
  596.                      break;
  597.                   else if (res == DID_OK) {                                   
  598.                      SetPtrWait();
  599.                         
  600.                      SearchData.cb = sizeof (MLE_SEARCHDATA);
  601.                      SearchData.pchFind = szFind;
  602.                      SearchData.cchFind = strlen (szFind);
  603.                      SearchData.iptStart = (-1L);
  604.                      SearchData.iptStop = (-1L);
  605.                      
  606.                      res = SHORT1FROMMR (WinSendMsg (hwndMLE, MLM_SEARCH, 
  607.                                             MPFROMLONG (MLFSEARCH_SELECTMATCH),
  608.                                             MPFROMP (&SearchData)));
  609.                                        
  610.                      SetPtrArrow();
  611.                         
  612.                      if (!res) {                  
  613.                         WinMessageBox (HWND_DESKTOP, hwnd, 
  614.                            "Search string not found.", "Replace", 0,
  615.                             MB_OK | MB_ICONASTERISK | MB_MOVEABLE);
  616.                         break;   /* exit search/replace */
  617.                      }
  618.                   }
  619.                   else if (res == DID_DOREPLACE)
  620.                      WinSendMsg (hwndMLE, MLM_INSERT, 
  621.                         MPFROMP (szReplace), (MPARAM) 0L);
  622.                   else if (res == DID_REPLACEALL) {
  623.                      SetPtrWait();
  624.                         
  625.                      WinSendMsg (hwndMLE, MLM_INSERT, 
  626.                         MPFROMP (szReplace), (MPARAM) 0L);
  627.                                  
  628.                      SearchData.cb = sizeof (MLE_SEARCHDATA);
  629.                      SearchData.pchFind = szFind;
  630.                      SearchData.cchFind = strlen (szFind);
  631.                      SearchData.pchReplace = szReplace;
  632.                      SearchData.cchReplace = strlen (szReplace);
  633.                      SearchData.iptStart = (-1L);
  634.                      SearchData.iptStop = (-1L);
  635.                      WinSendMsg (hwndMLE, MLM_SEARCH, 
  636.                         MPFROMLONG (MLFSEARCH_CHANGEALL), 
  637.                         MPFROMP (&SearchData));
  638.                                  
  639.                      SetPtrArrow();
  640.                         
  641.                      WinMessageBox (HWND_DESKTOP, hwnd, 
  642.                         "All occurrences replaced.", "Replace", 0,
  643.                         MB_OK | MB_ICONASTERISK | MB_MOVEABLE);
  644.                      break;   /* exit search/replace */
  645.                   }
  646.                   else
  647.                      break;   /* exit search/replace */
  648.                      
  649.                   res = WinDlgBox (HWND_DESKTOP, hwnd, ReplaceDlgProc,
  650.                            0, IDD_REPLACE, (PVOID)(&first));
  651.                }
  652.                return 0;
  653.  
  654.             case IDM_GO:
  655.                   res = WinDlgBox (HWND_DESKTOP, hwnd, GoLnDlgProc,
  656.                            0, IDD_GOLINE, NULL);
  657.                   if (res == MBID_OK) {
  658.                      if (sscanf (szLine, "%ld", &goline)) {
  659.                         if (goline < 1)
  660.                            goline = 1;
  661.                         gochar = LONGFROMMR (WinSendMsg (hwndMLE, 
  662.                                                  MLM_CHARFROMLINE, 
  663.                                                  MPFROMLONG (--goline), 
  664.                                                  (MPARAM) 0L));
  665.                         WinSendMsg (hwndMLE, MLM_SETFIRSTCHAR, 
  666.                            MPFROMLONG (gochar), (MPARAM) 0L);
  667.                         ps.x = 0;   ps.y = cyClient - (2 * menuheight);
  668.                         WinSendMsg (hwndMLE, WM_BUTTON1DOWN, 
  669.                            MPFROM2SHORT (ps.x, ps.y), (MPARAM) 0L);
  670.                         WinSendMsg (hwndMLE, WM_BUTTON1UP, 
  671.                            MPFROM2SHORT (ps.x, ps.y), (MPARAM) 0L);
  672.                      }
  673.                   }
  674.                return 0;
  675.  
  676.             case IDM_HELPFORHELP:
  677.                if (hwndHelpInstance)
  678.                   WinSendMsg( hwndHelpInstance, HM_DISPLAY_HELP, 0L, 0L);
  679.                break;
  680.  
  681.             case IDM_EXTENDEDHELP:
  682.                WinPostMsg (hwndFrame, WM_SYSCOMMAND,
  683.                   MPFROM2SHORT (SC_HELPEXTENDED, 0), (MPARAM) 0L);
  684.                break;
  685.                
  686.             case IDM_KEYSHELP:
  687.                WinPostMsg (hwndFrame, WM_SYSCOMMAND,
  688.                   MPFROM2SHORT (SC_HELPKEYS, 0), (MPARAM) 0L);
  689.                break;
  690.                
  691.             case IDM_HELPINDEX:
  692.                WinPostMsg (hwndFrame, WM_SYSCOMMAND,
  693.                   MPFROM2SHORT (SC_HELPINDEX, 0), (MPARAM) 0L);
  694.                break;
  695.                
  696.             case IDM_ABOUT:
  697.                WinDlgBox (HWND_DESKTOP, hwnd, AboutDlgProc, 
  698.                   0, IDD_ABOUT, NULL);
  699.                return 0;
  700.                
  701.             default:
  702.                break;
  703.          }
  704.          break;
  705.  
  706.       case WM_SIZE:
  707.          cxClient = SHORT1FROMMP (mp2);
  708.          cyClient = SHORT2FROMMP (mp2);
  709.          
  710.          WinSetWindowPos (
  711.             hwndMLE, 
  712.             HWND_TOP, 
  713.             0, 0, 
  714.             cxClient, cyClient - menuheight, 
  715.             SWP_MOVE | SWP_SIZE);
  716.          WinSetFocus (HWND_DESKTOP, hwndMLE);
  717.          return 0;
  718.  
  719.       case WM_PAINT:
  720.          hps = WinBeginPaint (hwnd, NULL, NULL);
  721.          sprintf (str, "  Line: %-5d   Col: %-5d", line + 1, column + 1);
  722.          WinQueryWindowRect (hwnd, &rcl);
  723.          rcl.yBottom = cyClient - menuheight;
  724.          WinDrawText (hps, -1, str, &rcl, CLR_NEUTRAL, CLR_BACKGROUND,
  725.             DT_LEFT | DT_VCENTER | DT_ERASERECT);
  726.          WinEndPaint (hps);
  727.          return 0;
  728.    
  729.       case HM_QUERY_KEYS_HELP:
  730.          return ((MRESULT) IDH_KEYSHELP);
  731.          break;
  732.  
  733.       case HM_ERROR:
  734.          if ( (hwndHelpInstance && (ULONG) mp1) == HMERR_NO_MEMORY) {
  735.             WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
  736.                "Help Terminated Due to Error", "Help Error", 0,
  737.                MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  738.             WinDestroyHelpInstance(hwndHelpInstance);
  739.          }
  740.          else {
  741.             WinMessageBox (HWND_DESKTOP, HWND_DESKTOP,
  742.                "Help Error Occurred", "Help Error", 0,
  743.                MB_OK | MB_ICONEXCLAMATION | MB_MOVEABLE);
  744.          }
  745.          break;
  746.          
  747.       case WM_DESTROY:
  748.          WinDestroyWindow (hwndMLE);
  749.          return 0;
  750.    }
  751.    return WinDefWindowProc (hwnd, msg, mp1, mp2);
  752. }
  753.  
  754.  
  755. MRESULT EXPENTRY TabWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  756. {
  757.    USHORT flags, vk;   /* WM_CHAR message parameters */
  758.    long curpos;   /* current postion -- relative to top of document */
  759.    int ln, col;   /* current position -- line/column */
  760.    char str[TAB + 1];   /* insert string of spaces for tab */
  761.    int i;   /* loop counter: will insert spaces for tab */
  762.    int ts;   /* number of spaces to insert for tab */
  763.  
  764.    switch (msg) {
  765.       case WM_CHAR:
  766.          flags = SHORT1FROMMP (mp1);
  767.          vk = SHORT2FROMMP (mp2);
  768.          if (flags & KC_VIRTUALKEY && !(flags & KC_KEYUP) && vk == VK_TAB) {
  769.             /* determine position of text cursor */
  770.             curpos = LONGFROMMR (WinSendMsg (hwnd, MLM_QUERYSEL, 
  771.                                     (MPARAM) MLFQS_MINSEL, (MPARAM) 0L));
  772.             ln = (int) LONGFROMMR (WinSendMsg (hwnd, MLM_LINEFROMCHAR,
  773.                                       MPFROMLONG (curpos), (MPARAM) 0L));
  774.             col = (int) (curpos - LONGFROMMR (WinSendMsg (hwnd, 
  775.                                                  MLM_CHARFROMLINE,
  776.                                                  MPFROMLONG ((long) ln), 
  777.                                                  (MPARAM) 0L)));
  778.             ts = TAB - (col % TAB); 
  779.             for (i = 0; i < ts; i++) 
  780.                str[i] = ' ';
  781.             str[i] = '\0';
  782.             
  783.             WinSendMsg (hwnd, MLM_INSERT, MPFROMP (str), (MPARAM) 0L);
  784.             return 0;
  785.          }
  786.          else
  787.             break;
  788.  
  789.       default:
  790.          break;
  791.    }
  792.    pfMLE (hwnd, msg, mp1, mp2);
  793. }
  794.  
  795.  
  796. VOID SetPtrArrow (VOID)
  797. {
  798.    if (!WinQuerySysValue (HWND_DESKTOP, SV_MOUSEPRESENT))
  799.       WinShowPointer (HWND_DESKTOP, FALSE);
  800.  
  801.    WinSetPointer (HWND_DESKTOP,
  802.       WinQuerySysPointer (HWND_DESKTOP, SPTR_ARROW, 0));
  803. }
  804.  
  805.  
  806. VOID SetPtrWait (VOID)
  807. {
  808.    WinSetPointer (HWND_DESKTOP,
  809.       WinQuerySysPointer (HWND_DESKTOP, SPTR_WAIT, 0));
  810.  
  811.    if (!WinQuerySysValue (HWND_DESKTOP, SV_MOUSEPRESENT))
  812.       WinShowPointer (HWND_DESKTOP, TRUE);
  813. }
  814.