home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / M_EXT23.ZIP / FMT.C < prev    next >
C/C++ Source or Header  |  1989-08-10  |  31KB  |  1,001 lines

  1. /*****************************************************************************/
  2. /*                                                                           */
  3. /* FMT.C                                                                     */
  4. /*   Formatted edit routines for Presentation Manager.                       */
  5. /*                                                                           */
  6. /*                                                                           */
  7. /* (C) Copyright 1989  Marc Adler and Magma Systems    All Rights Reserved   */
  8. /* This source code is strictly for personal use. Commercial users must      */
  9. /* obtain a commercial license from Magma Systems.  Contact us at :          */
  10. /*   15 Bodwell Terrace, Millburn, New Jersey  07041                         */
  11. /*   (201) 912 - 0192                                                        */
  12. /*****************************************************************************/
  13.  
  14. #define INCL_WIN
  15. #define INCL_DOS
  16. #define INCL_GPI
  17. #include <os2.h>
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <malloc.h>
  21. #include <stdarg.h>
  22.  
  23. #include "fmt.h"
  24.  
  25. #define SimpleMessage(hWnd, msg)  WinMessageBox(hWnd, hWnd, \
  26.                                  (PSZ) msg, (PSZ) "Message", 0, MB_OK);
  27.  
  28. #define LCID_COURIER   1L
  29. FONTMETRICS FMCourier;
  30. FATTRS      FontAttrs;
  31. LONG        IDCourier = 0;
  32. HPS         hMyPS;
  33.  
  34. HWND hWndFrame,
  35.      hWndClient;
  36. HAB  hAB;
  37.  
  38. PFNWP  pfnOldEditWndProc = (PFN) NULL;
  39. PFNWP  pfnOldStaticWndProc = (PFN) NULL;
  40.  
  41.  
  42. MRESULT EXPENTRY ClientWndProc(HWND, USHORT, MPARAM, MPARAM);
  43. MRESULT EXPENTRY FmtDlgProc(HWND, USHORT, MPARAM, MPARAM);
  44. MRESULT EXPENTRY FmtWndProc(HWND, USHORT, MPARAM, MPARAM);
  45. MRESULT EXPENTRY MonoStaticWndProc(HWND, USHORT, MPARAM, MPARAM);
  46. void pascal EditSetCursor(HWND hWnd);
  47. extern PSZ lstrcpy(PSZ s, PSZ t);
  48.  
  49.  
  50. int pascal ValidDigit();
  51. int pascal ValidDigitSignSpace();
  52. int pascal ValidAlpha();
  53. int pascal ValidAlphaNum();
  54. int pascal ValidLogical();
  55. int pascal ValidAny();
  56. int pascal ConvertToUpper();
  57. int pascal ConvertToLower();
  58.  
  59.  
  60. typedef struct format
  61. {
  62.   ULONG fFormatFlags;
  63. #define FLD_HASPICTURE  0x0001L
  64. #define FLD_AUTONEXT    0x0002L  /* Advance to next field when all filled */
  65. #define FLD_NOECHO      0x0004L  /* Don't echo the chars (for passwds) */
  66. #define FLD_PROTECT     0x0008L  /* Can't enter data into this field   */
  67. #define FLD_IGNORE      0x0010L  /* The cursor skips over this field   */
  68. #define FLD_REQUIRED    0x0020L  /* user MUST enter data in this field */
  69. #define FLD_TOUPPER     0x0040L  /* convert characters to upper-case   */
  70. #define FLD_TOLOWER     0x0080L  /* convert characters to lower-case   */
  71. #define FLD_CENTER      0x0100L  /* center the data in the field       */
  72. #define FLD_RJUST       0x0200L  /* right justify the data in the field*/
  73. #define FLD_NUMERIC     0x0400L
  74. #define FLD_SIGNEDNUMERIC 0x0800L
  75. #define FLD_ALPHA       0x1000L
  76. #define FLD_ALPHANUMERIC 0x2000L
  77. #define FLD_LOGICAL     0x4000L
  78. #define FLD_MIXEDPICTURE 0x10000L
  79.   NPFN pfnValidChar;             /* function to validate each character*/
  80.   PSZ  szPicture;                /* picture string */
  81. } FORMAT, FAR *PFORMAT;
  82.  
  83. struct mask_to_func
  84. {
  85.   ULONG mask;
  86.   NPFN  pfnFunc;
  87. } MaskToFunc[] =
  88. {
  89.   FLD_NUMERIC,          ValidDigit,
  90.   FLD_SIGNEDNUMERIC,    ValidDigitSignSpace,
  91.   FLD_ALPHA,            ValidAlpha,
  92.   FLD_ALPHANUMERIC,     ValidAlphaNum,
  93.   FLD_LOGICAL,          ValidLogical,
  94. };
  95.  
  96. typedef struct picinfo
  97. {
  98.   NPFN pfnPicFunc;     /* validation function corresponding to the mask */
  99.   BYTE chPic;          /* the mask character */
  100. } PICINFO;
  101. extern PICINFO *CharToPicInfo(int c);
  102.  
  103. PICINFO PicInfo[] =
  104. {
  105.   ValidDigit,          '9',
  106.   ValidDigitSignSpace, '#',
  107.   ValidAlpha,          'A',
  108.   ValidLogical,        'L',
  109.   ValidAlphaNum,       'N',
  110.   ValidAny,            'X',
  111.   ConvertToUpper,      '!',
  112.   NULL,                '\0'
  113. };
  114.  
  115.  
  116. /*****************************************************************************/
  117. /* main()                                                                    */
  118. /*   Let's begin at the beginning...                                         */
  119. /*                                                                           */
  120. /*****************************************************************************/
  121. int main(void)
  122. {
  123.   HMQ   hMQ;
  124.   QMSG  qMsg;
  125.   ULONG flCreateFlags = FCF_TITLEBAR | FCF_SYSMENU | FCF_SIZEBORDER |
  126.                         FCF_MINMAX   | FCF_TASKLIST | FCF_SHELLPOSITION |
  127.                         FCF_MENU;
  128.  
  129.   PSZ  szClassName = "ClientClass";
  130.   CLASSINFO clsInfo;
  131.  
  132.   /*
  133.     Initialize the window and create the message queue
  134.   */
  135.   hAB = WinInitialize(0);
  136.   hMQ = WinCreateMsgQueue(hAB, 0);
  137.  
  138.   /*
  139.     Get the address of the default window proc for edit controls. We
  140.     will call this proc to do most of the processing for the new
  141.     formatted edit controls.
  142.   */
  143.   if (!WinQueryClassInfo(hAB, WC_ENTRYFIELD, (PCLASSINFO) &clsInfo))
  144.   {
  145.     DEBUG("Could not get class info for WC_ENTRYFIELD");
  146.     goto bye;
  147.   }
  148.   pfnOldEditWndProc = clsInfo.pfnWindowProc;
  149.  
  150.   /*
  151.     Register the main window class
  152.   */
  153.   WinRegisterClass(hAB, szClassName, ClientWndProc, 
  154.                    CS_SIZEREDRAW, sizeof(PVOID));
  155.  
  156.   if (!WinRegisterClass(hAB, "Formatted", FmtWndProc, CS_SIZEREDRAW, 
  157.                         clsInfo.cbWindowData + sizeof(PVOID)))
  158.   {
  159.     DEBUG("Could not register class Formatted");
  160.     goto bye;
  161.   }
  162.  
  163.  
  164.   /*
  165.     We have our own static class too!
  166.   */
  167.   if (!WinQueryClassInfo(hAB, WC_STATIC, (PCLASSINFO) &clsInfo))
  168.   {
  169.     DEBUG("Could not get class info for WC_STATIC");
  170.     goto bye;
  171.   }
  172.   pfnOldStaticWndProc = clsInfo.pfnWindowProc;
  173.  
  174.   if (!WinRegisterClass(hAB, "MonoStatic", MonoStaticWndProc, CS_SIZEREDRAW, 
  175.                         clsInfo.cbWindowData + sizeof(PVOID)))
  176.   {
  177.     DEBUG("Could not register class MonoStatic");
  178.     goto bye;
  179.   }
  180.  
  181.   /*
  182.     Create the main window
  183.   */
  184.   hWndFrame = WinCreateStdWindow(HWND_DESKTOP,     /* parent        */
  185.                                  WS_VISIBLE,       /* window styles */
  186.                                  &flCreateFlags,   /* frame styles  */
  187.                                  szClassName,      /* class name    */
  188.                                  (PSZ) "Fmt",      /* window title  */
  189.                                  CS_SIZEREDRAW,    /* Client style  */
  190.                                  NULL,             /* Resource ID   */
  191.                                  DLG_FORMAT,       /* frame window id */
  192.                                  &hWndClient);     /* client handle */
  193.   /*
  194.     Message Processing Loop...
  195.   */
  196.   while (WinGetMsg(hAB, &qMsg, NULL, 0, 0))
  197.   {
  198.     WinDispatchMsg(hAB, &qMsg);
  199.   }
  200.  
  201.   /*
  202.     End of the program. Destroy the window and message queue.
  203.   */
  204.   WinReleasePS(hMyPS);
  205.   WinDestroyWindow(hWndFrame);
  206. bye:
  207.   WinDestroyMsgQueue(hMQ);
  208.   WinTerminate(hAB);
  209.  
  210.   return 0;
  211. }
  212.  
  213.  
  214. /*****************************************************************************/
  215. /* ClientWndProc()                                                           */
  216. /*   Main window procedure for this app. All messages to the client window   */
  217. /* get sent here.                                                            */
  218. /*****************************************************************************/
  219. MRESULT EXPENTRY ClientWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  220. {
  221.   HPS hPS;
  222.  
  223.   switch (msg)
  224.   {
  225.     case WM_PAINT :
  226.       /*
  227.         Erase the window.
  228.       */
  229.       hPS = WinBeginPaint(hWnd, NULL, NULL);
  230.       GpiErase(hPS);
  231.       WinEndPaint(hPS);
  232.       return MRFROMSHORT(TRUE);
  233.  
  234.     case WM_COMMAND :
  235.       switch (COMMANDMSG(&msg)->cmd)
  236.       {
  237.         case ID_DLG  :
  238.           WinDlgBox(HWND_DESKTOP, hWnd, FmtDlgProc, NULL, DLG_FORMAT, NULL);
  239.           break;
  240.         case ID_EXIT :
  241.           WinPostMsg(hWnd, WM_CLOSE, 0L, 0L);
  242.           break;
  243.       }
  244.       return MRFROMSHORT(FALSE);
  245.  
  246.   } /* end switch */
  247.  
  248.   return WinDefWindowProc(hWnd, msg, mp1, mp2);
  249. }
  250.  
  251.  
  252. /*****************************************************************************/
  253. /* FmtDlgProc()                                                              */
  254. /*   Driver for the sample dialog box.                                       */
  255. /*                                                                           */
  256. /*****************************************************************************/
  257. MRESULT EXPENTRY FmtDlgProc(HWND hDlg, USHORT msg, MPARAM mp1, MPARAM mp2)
  258. {
  259.   HWND    hEdit;
  260.   struct  fldfmtinfo *pFld;
  261.   PFNWP   pfn;
  262.   PICINFO *pi;
  263.   int     i;
  264.  
  265.   switch (msg)
  266.   {
  267.     case WM_INITDLG :
  268.       /*
  269.         Get the monospaced font (Courier)
  270.       */
  271.       hMyPS = WinGetPS(hDlg);
  272.       SetMonospacedFont(hMyPS);
  273.  
  274. /*
  275.       for (i = 256;  i <= 258;  i++)
  276.         if ((hEdit = WinWindowFromID(hDlg, i)))
  277.         {
  278.           pfn = WinSubclassWindow(hEdit, MonoStaticWndProc);
  279.           if (!pfnOldStaticWndProc)
  280.             pfnOldStaticWndProc = pfn;
  281.         }
  282. */
  283.       return MRFROMSHORT(FALSE);
  284.  
  285.  
  286.     case WM_COMMAND :
  287.       switch (COMMANDMSG(&msg)->cmd)
  288.       {
  289.         case ID_OK :
  290.           WinDismissDlg(hDlg, TRUE);
  291.           return MRFROMSHORT(TRUE);
  292.         default :
  293.           break;
  294.       }
  295.       return MRFROMSHORT(TRUE);
  296.   }
  297.  
  298.   return WinDefDlgProc(hDlg, msg, mp1, mp2);
  299. }
  300.  
  301.  
  302. /*****************************************************************************/
  303. /* FmtWndProc()                                                              */
  304. /*   Window Proc for the new formatted edit control class. We will process   */
  305. /* some of the messages, but for the most part, we rely on the standard      */
  306. /* edit control window proc to handle the hard stuff.                        */
  307. /*****************************************************************************/
  308. MRESULT EXPENTRY FmtWndProc(HWND hWnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  309. {
  310.   PSZ     szFmtMask;
  311.   PSZ     szPicture = NULL;
  312.   char    buf[128], *s;
  313.   char    chFmt;
  314.   MRESULT mr;
  315.   PICINFO *pi;
  316.   HPS     hPS;
  317.   int     rc, iPos, picch, piclen;
  318.   int     incr;
  319.   int     cnt;
  320.   PFORMAT pFmt;
  321.   struct fldfmtinfo *pFld;
  322.  
  323.   switch (msg)
  324.   {
  325.     /*
  326.       WM_CREATE
  327.         We create a format information structure and associate it with
  328.       this control.
  329.     */
  330.     case WM_CREATE     :
  331.     {
  332.       PCREATESTRUCT pCr;
  333.  
  334.       /*
  335.         Get the control ID from the create-structure
  336.       */
  337.       pCr = (PCREATESTRUCT) PVOIDFROMMP(mp2);
  338.  
  339.       /*
  340.         See if we have a picture clause in the edit control's title.
  341.         If so, save the picture and set the title to NULL so that
  342.         the edit control will be initially empty.
  343.       */
  344.       if (pCr->pszText && pCr->pszText[0])
  345.       {
  346.         szPicture = pCr->pszText;
  347.         pCr->pszText = NULL;
  348.       }
  349.  
  350.       /*
  351.         Let the normal edit proc do its thing....
  352.       */
  353.       pfnOldEditWndProc(hWnd, msg, mp1, mp2);
  354.  
  355.       /*
  356.         Search the list of formatted controls for this one
  357.       */
  358.  
  359.       /*
  360.         Allocate a format structure and have the window point to it
  361.       */
  362.       pFmt = (PFORMAT) malloc(sizeof(FORMAT));
  363.       WinSetWindowPtr(hWnd, 0, (PVOID) pFmt);
  364.  
  365.       /*
  366.         Tbere is an address passed in mp1 - this signifies a char mask.
  367.       */
  368.       if (szPicture)
  369.       {
  370.         /*
  371.           Set a bit to signify that we have a character mask, and copy
  372.           the mask into some private storage area.
  373.         */
  374.         pFmt->fFormatFlags = FLD_HASPICTURE;
  375.         pFmt->szPicture = lstrcpy((PSZ) malloc(lstrlen(szPicture)+1), szPicture);
  376.  
  377.         /*
  378.           We want to display the edit control's "protected" characters,
  379.           but we don't want to display the mask characters. We copy
  380.           the mask into a character array, translating the mask chars
  381.           into blanks. If we have protected characters in the mask, then
  382.           set a bit to signify this.
  383.         */
  384.         lstrcpy((PSZ) buf, szPicture);
  385.         for (s = buf;  *s;  s++)
  386.           if (CharToPicInfo(*s))
  387.             *s = ' ';
  388.           else
  389.             pFmt->fFormatFlags |= FLD_MIXEDPICTURE;
  390.         WinSetWindowText(hWnd, (PSZ) buf);
  391.       }
  392.  
  393.       if (mp1)
  394.       {
  395.         /*
  396.           We got a bitmask instead of a character mask.
  397.           We search the mask table for this mask, and set the corresponding
  398.           character validation function.
  399.         */
  400.         struct mask_to_func *mf;
  401.         pFmt->fFormatFlags |= (long) (* (PUSHORT) mp1);
  402.         for (mf = MaskToFunc;
  403.              mf < MaskToFunc + sizeof(MaskToFunc)/sizeof(MaskToFunc[0]);  mf++)
  404.           if (pFmt->fFormatFlags & mf->mask)
  405.           {
  406.             pFmt->pfnValidChar = mf->pfnFunc;
  407.             break;
  408.           }
  409.       }
  410.  
  411.       /*
  412.         Set the cursor position to the first character
  413.       */
  414.       pfnOldEditWndProc(hWnd, EM_SETSEL, 0L, 0L);
  415.       return MRFROMSHORT(FALSE);
  416.     }
  417.  
  418.     /*---------------------------------------------------------------------*/
  419.  
  420.     /*
  421.       WM_CHAR
  422.     */
  423.     case WM_CHAR :
  424.       if ((pFmt = (PFORMAT) WinQueryWindowPtr(hWnd, 0)) == NULL)
  425.         break;
  426.  
  427.       if (CHARMSG(&msg)->fs & KC_CHAR)
  428.       {
  429.         BYTE c = (BYTE) CHARMSG(&msg)->chr;
  430.  
  431.         if (c == '\t' || c == '\n' || c == 27)
  432.           return MRFROMSHORT(FALSE);
  433.  
  434.         if (pFmt->szPicture)
  435.         {
  436.           iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  437.           piclen = strlen(pFmt->szPicture);
  438.           /*
  439.             Don't let the user type beyond the last picture char
  440.           */
  441.           if (iPos >= piclen)
  442.             return MRFROMSHORT(TRUE);
  443.  
  444.           /*
  445.             Validate the character
  446.           */
  447.           pi = CharToPicInfo(picch = pFmt->szPicture[iPos]);
  448.           if (picch == '!')
  449.             c = ConvertToUpper(c);
  450.           if (pi && pi->pfnPicFunc && (*pi->pfnPicFunc)(c) == FALSE)
  451.             return MRFROMSHORT(FormatError());
  452.  
  453.           /*
  454.             Implement overstrike mode by deleting the next character
  455.           */
  456.           pfnOldEditWndProc(hWnd, EM_SETSEL, MPFROM2SHORT(iPos, iPos+1), 0L);
  457.           pfnOldEditWndProc(hWnd, EM_CLEAR,  0L, 0L);
  458.  
  459.           /*
  460.             Let the edit win proc handle the insertion of the character
  461.           */
  462.           pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2);
  463.  
  464.           /*
  465.             Find out what position we are in
  466.           */
  467.           iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  468.  
  469. advance:
  470.           /*
  471.             If the char we typed was the last one in the picture, go back
  472.             to the left.
  473.           */
  474.           if (iPos >= piclen)
  475.           {
  476.             c = VK_LEFT;
  477.             mp1 = MPFROMSH2CH(KC_VIRTUALKEY, 1, 0);
  478.             mp2 = MPFROM2SHORT(0, VK_LEFT);
  479.             goto rightleft;
  480.           }
  481.  
  482.           /*
  483.             Figure out how many "protected" columns to skip
  484.           */
  485.           cnt = 0;
  486.           while (iPos < piclen && (picch = pFmt->szPicture[iPos]) && 
  487.                                              CharToPicInfo(picch) == NULL)
  488.             iPos++, cnt++;
  489.  
  490.           /*
  491.             Skip 'em if there is a valid column to go to
  492.           */
  493.           if (picch)
  494.             while (cnt--)
  495.             {
  496.               mp1 = MPFROMSH2CH(KC_VIRTUALKEY, 1, 0);
  497.               mp2 = MPFROM2SHORT(0, VK_RIGHT);
  498.               pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2);
  499.             }
  500.  
  501.           return MRFROMSHORT(TRUE);
  502.         }
  503.  
  504.         /*
  505.            NO MASK - we just have a validation function
  506.         */
  507.         else
  508.         {
  509.           if (pFmt->pfnValidChar && (*pFmt->pfnValidChar)(c) == FALSE)
  510.             return MRFROMSHORT(FormatError());
  511.           if (pFmt->fFormatFlags & FLD_TOUPPER)
  512.             c = toupper(c);
  513.           else if (pFmt->fFormatFlags & FLD_TOLOWER)
  514.             c = tolower(c);
  515.         }
  516.       } /* end if KC_CHAR */
  517.  
  518.  
  519.       else if (CHARMSG(&msg)->fs & KC_VIRTUALKEY)
  520.       {
  521.         BYTE c = (BYTE) CHARMSG(&msg)->vkey;
  522.  
  523.         if (c == VK_TAB || c == VK_BACKTAB || c == VK_NEWLINE || c == VK_ESC)
  524.           return MRFROMSHORT(FALSE);
  525.  
  526.         if (pFmt->szPicture)
  527.         {
  528.           iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  529.           piclen = strlen(pFmt->szPicture);
  530.           /*
  531.             Don't let the user type beyond the last picture char
  532.           */
  533.           if (iPos >= piclen)
  534.             return MRFROMSHORT(TRUE);
  535.  
  536.           switch (c)
  537.           {
  538.             case VK_LEFT  :
  539.             case VK_RIGHT :
  540.             {
  541.   rightleft:
  542.               incr = (c == VK_LEFT) ? -1 : 1;
  543.               do
  544.               {
  545.                 /* BUG - we don't know what rc is */
  546.                 rc = SHORT1FROMMR(pfnOldEditWndProc(hWnd,WM_CHAR,mp1,mp2));
  547.               } while (rc && !CharToPicInfo(pFmt->szPicture[iPos += incr]));
  548.  
  549.               EditSetCursor(hWnd);
  550.               return MRFROMSHORT(TRUE);
  551.             }
  552.  
  553.             case VK_HOME :
  554.               /*
  555.                 Pass the HOME key onto the edit control & set position to 0
  556.               */
  557.               pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2);
  558.               iPos = 0;
  559.               goto advance;
  560.  
  561.             case VK_END  :
  562.               /*
  563.                 Pass the END key onto the edit control, then get the position
  564.               */
  565.               pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2);
  566.               iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  567.  
  568.               /*
  569.                 Move left until we hit a maskable character
  570.               */
  571.               while (iPos >= piclen ||
  572.                     (picch = pFmt->szPicture[iPos]) && !CharToPicInfo(picch))
  573.               {
  574.                 mp1 = MPFROMSH2CH(KC_VIRTUALKEY, 1, 0);
  575.                 mp2 = MPFROM2SHORT(0, VK_LEFT);
  576.                 if (!pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2))
  577.                   break;
  578.                 iPos--;
  579.               }
  580.  
  581.               EditSetCursor(hWnd);
  582.               return MRFROMSHORT(TRUE);
  583.  
  584.             case VK_DELETE   :
  585.             case VK_INSERT   :
  586.             case VK_BACKSPACE:
  587.               /*
  588.                  If we have protected chars in this field, don't let the
  589.                  user delete or toggle insert mode.
  590.               */
  591.               if (pFmt->fFormatFlags & FLD_MIXEDPICTURE)
  592.                 return MRFROMSHORT(TRUE);
  593.               break;
  594.  
  595.             default :
  596.               break;
  597.               return MRFROMSHORT(FALSE);
  598.  
  599.           } /* end switch (c) */
  600.         } /* if picture */
  601.       } /* end if KC_VIRTUALKEY */
  602.       return MRFROMSHORT(TRUE);
  603.  
  604.     /*---------------------------------------------------------------------*/
  605.  
  606.     /*
  607.       WM_SETFOCUS
  608.         We intercept this to insure that the cursor is not placed
  609.       over a protected mask character.
  610.     */
  611.     case WM_SETFOCUS :
  612.       if (SHORT1FROMMP(mp2) == FALSE)   /* losing focus? */
  613.         break;
  614.  
  615.       /*
  616.         Get the window's format structure
  617.       */
  618.       if ((pFmt = (PFORMAT) WinQueryWindowPtr(hWnd, 0)) == NULL ||
  619.           !pFmt->szPicture)
  620.         break;
  621.  
  622.       /*
  623.         Let the normal edit proc do its thing for setting focus...
  624.       */
  625.       rc = pfnOldEditWndProc(hWnd, msg, mp1, mp2);
  626.  
  627.       /*
  628.         Get the current position. Move past all protected mask chars.
  629.       */
  630.       iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  631.       while ((picch = pFmt->szPicture[iPos]) && CharToPicInfo(picch) == NULL)
  632.       {
  633.         /*
  634.           We move past a mask character by simulating the user pressing
  635.           the RIGHT arrow key.
  636.         */
  637.         mp1 = MPFROMSH2CH(KC_VIRTUALKEY, 1, 0);
  638.         mp2 = MPFROM2SHORT(0, VK_RIGHT);
  639.         if (!pfnOldEditWndProc(hWnd, WM_CHAR, mp1, mp2))
  640.           break;
  641.         iPos++;
  642.       }
  643.       return MRFROMSHORT(rc);
  644.  
  645.     /*---------------------------------------------------------------------*/
  646.  
  647.     /*
  648.       WM_PAINT
  649.         We do the drawing and shadowing ourselves.
  650.     */
  651.     case WM_PAINT :
  652.     {
  653.       USHORT iLen;
  654.       HPS    hPS;
  655.       char   szText[128];
  656.       SWP    swp;
  657.       POINTL ptL;
  658.       CURSORINFO cursorInfo;
  659.  
  660.       /*
  661.         Erase the edit control
  662.       */
  663.       hPS = WinBeginPaint(hWnd, NULL, NULL);
  664.       GpiErase(hPS);
  665.       WinEndPaint(hPS);
  666.  
  667.       /*
  668.         Get the text and the coordinates of the control.
  669.       */
  670.       iLen = WinQueryWindowText(hWnd, sizeof(szText), (PCH) szText);
  671.       WinQueryWindowPos(hWnd, (PSWP) &swp);
  672.  
  673.       /*
  674.         Draw the border around the control.
  675.       */
  676.       ptL.x = swp.x;  ptL.y = swp.y;
  677.       GpiMove(hMyPS, (PPOINTL) &ptL);
  678.       ptL.x += swp.cx;
  679.       GpiLine(hMyPS, (PPOINTL) &ptL);
  680.       ptL.y += swp.cy;
  681.       GpiLine(hMyPS, (PPOINTL) &ptL);
  682.       ptL.x -= swp.cx;
  683.       GpiLine(hMyPS, (PPOINTL) &ptL);
  684.       ptL.y -= swp.cy;
  685.       GpiLine(hMyPS, (PPOINTL) &ptL);
  686.  
  687.       /*
  688.         Draw the shadow
  689.       */
  690.       ptL.x = swp.x + 4;
  691.       ptL.y = swp.y;
  692.       GpiMove(hMyPS, (PPOINTL) &ptL);
  693.  
  694.       ptL.x += swp.cx;
  695.       ptL.y -= 4;
  696.       GpiBox(hMyPS, DRO_FILL, (PPOINTL) &ptL, 0L, 0L);
  697.  
  698.       GpiMove(hMyPS, (PPOINTL) &ptL);
  699.  
  700.       ptL.x = swp.x + swp.cx;
  701.       ptL.y += swp.cy;
  702.       GpiBox(hMyPS, DRO_FILL, (PPOINTL) &ptL, 0L, 0L);
  703.  
  704.       /*
  705.         Draw the edit text in a monospaced font.
  706.       */
  707.       ptL.x = swp.x;
  708.       ptL.y = swp.y + (swp.cy - FMCourier.lMaxBaselineExt) / 2 
  709.                                            + FMCourier.lInternalLeading;
  710.       GpiCharStringAt(hMyPS, (PPOINTL) &ptL, (LONG) iLen, (PCH) szText);
  711.  
  712.       EditSetCursor(hWnd);
  713.       /*
  714.         Return FALSE to signify that we processed the message ourselves.
  715.       */
  716.       return MRFROMSHORT(FALSE);
  717.     }
  718.  
  719.     /*---------------------------------------------------------------------*/
  720.  
  721.     case WM_DESTROY :
  722.       if ((pFmt = (PFORMAT) WinQueryWindowPtr(hWnd, 0)))
  723.         free(pFmt);
  724.       break;
  725.   } /* switch */
  726.  
  727.   /*
  728.     We got a message that we weren't interested in. Let the normal edit
  729.     procedure process the message.
  730.   */
  731.   return pfnOldEditWndProc(hWnd, msg, mp1, mp2);
  732. }
  733.  
  734.  
  735. /*****************************************************************************/
  736. /* EditSetCursor()                                                           */
  737. /*   Attempts to position the editing cursor correctly within a window       */
  738. /*****************************************************************************/
  739. void pascal EditSetCursor(HWND hWnd)
  740. {
  741.   CURSORINFO cursorInfo;
  742.   SHORT      iPos;
  743.  
  744.   /*
  745.     Find out the 0-based logical position of the cursor within the edit field
  746.   */
  747.   iPos = SHORT1FROMMR(pfnOldEditWndProc(hWnd, EM_QUERYSEL, 0L, 0L));
  748.   /*
  749.     Get a copy of the cursor information
  750.   */
  751.   WinQueryCursorInfo(HWND_DESKTOP, (PCURSORINFO) &cursorInfo);
  752.   /*
  753.     The cursor is placed to the right of the current character.
  754.   */
  755.   WinCreateCursor(hWnd,
  756.           (SHORT) (iPos+1) * FMCourier.lAveCharWidth - FMCourier.lMaxCharInc,
  757.           cursorInfo.y, 0, 0, CURSOR_SETPOS, (PRECTL) NULL);
  758. }
  759.  
  760.  
  761. /*****************************************************************************/
  762. /* CharToPicInfo()                                                           */
  763. /*   Returns a pointer to the PICINFO structure associated with character c. */
  764. /*****************************************************************************/
  765. PICINFO *CharToPicInfo(c)
  766. {
  767.   PICINFO *p;
  768.  
  769.   c = toupper(c);
  770.  
  771.   for (p = PicInfo;  p->chPic && p->chPic != c;  p++)
  772.     ;
  773.   return p->chPic ? p : NULL;
  774. }
  775.  
  776. /*****************************************************************************/
  777. /*                                                                           */
  778. /*                       VALIDATION FUNCTIONS                                */
  779. /*                                                                           */
  780. /*****************************************************************************/
  781.  
  782. int pascal ValidDigit(c)
  783. {
  784.   return isdigit(c);
  785. }
  786.  
  787. int pascal ValidDigitSignSpace(c)
  788. {
  789.   return isdigit(c) || isspace(c) || c == '+' || c == '-';
  790. }
  791.  
  792. int pascal ValidAlpha(c)
  793. {
  794.   return isalpha(c);
  795. }
  796.  
  797. int pascal ValidAlphaNum(c)
  798. {
  799.   return isalnum(c);
  800. }
  801.  
  802. int pascal ValidLogical(c)
  803. {
  804.   return strchr("TtFfYyNn", c) != NULL;
  805. }
  806.  
  807. int pascal ValidAny(c)
  808. {
  809.   return TRUE;
  810. }
  811.  
  812. int pascal ConvertToUpper(c)
  813. {
  814.   return toupper(c);
  815. }
  816.  
  817.  
  818. /*****************************************************************************/
  819. /* MonoStaticWndProc()                                                       */
  820. /*   Used to "front-end" the normal behavior of a static text control so     */
  821. /* that we could print it in a mono-spaced font.                             */
  822. /*                                                                           */
  823. /*****************************************************************************/
  824. MRESULT EXPENTRY MonoStaticWndProc(HWND hWnd,USHORT msg,MPARAM mp1,MPARAM mp2)
  825. {
  826.   HPS    hPS;
  827.   POINTL ptL;
  828.   SHORT  iLen;
  829.   SWP    swp;
  830.   char   szText[128];
  831.  
  832.   switch (msg)
  833.   {
  834.     case WM_PAINT :
  835.       /*
  836.         Call Begin/EndPaint in order to satisfy PM.
  837.       */
  838.       hPS = WinBeginPaint(hWnd, NULL, NULL);
  839.       WinEndPaint(hPS);
  840.  
  841.       /*
  842.         Get the text of the static control and its position
  843.       */
  844.       iLen = WinQueryWindowText(hWnd, sizeof(szText), (PCH) szText);
  845.       WinQueryWindowPos(hWnd, (PSWP) &swp);
  846.  
  847.       /*
  848.         Write the string using our own presentation space
  849.       */
  850.       ptL.x = swp.x;  ptL.y = swp.y;
  851.       GpiCharStringAt(hMyPS, (PPOINTL) &ptL, (LONG) iLen, (PCH) szText);
  852.  
  853.       /*
  854.         Return FALSE if we processed the message ourselves
  855.       */
  856.       return MRFROMSHORT(FALSE);
  857.   }
  858.  
  859.   return pfnOldStaticWndProc(hWnd, msg, mp1, mp2);
  860. }
  861.  
  862.  
  863.  
  864. /*****************************************************************************/
  865. /* SetMonospacedFont()                                                       */
  866. /*   Sets the font of the current presentation space to a mono-spaced        */
  867. /* font. Returns TRUE if we found the font, FALSE if not.                    */
  868. /*****************************************************************************/
  869. SetMonospacedFont(hPS)
  870.   HPS hPS;
  871. {
  872.   FONTMETRICS *pMetrics;
  873.   LONG   nFonts, nRequestFonts;
  874.   int    i;
  875.   LONG   rcMatch;
  876.   ERRORID errID;
  877.   PSZ    szFont = "Courier";
  878.  
  879.   static BOOL bFirstTime = TRUE;
  880.  
  881.   /*
  882.     Load in the Courier font
  883.   */
  884.   if (bFirstTime)
  885.   {
  886.     GpiLoadFonts(hAB, (PSZ) "C:\\os2\\dll\\courier.fon");
  887.     bFirstTime = FALSE;
  888.   }
  889.  
  890.   /*
  891.     Make a dummy call to GpiQueryFonts() in order to find out how many
  892.     courier fonts are available.
  893.   */
  894.   nRequestFonts = 0L;
  895.   nFonts = GpiQueryFonts(hPS, QF_PUBLIC | QF_PRIVATE, (PSZ) szFont,
  896.                          &nRequestFonts, 0L, NULL);
  897.   if (nFonts == 0)
  898.     return FALSE;
  899.  
  900.   /*
  901.     Allocate temp space to hold the font-metrics info
  902.   */
  903.   if ((pMetrics = malloc((unsigned int) nFonts * sizeof(FONTMETRICS))) == NULL)
  904.     return FALSE;
  905.  
  906.   /*
  907.     Get the font-metric info for all Courier fonts
  908.   */
  909.   GpiQueryFonts(hPS, QF_PUBLIC | QF_PRIVATE, (PSZ) szFont, &nFonts,
  910.                                 (LONG) sizeof(FONTMETRICS), pMetrics);
  911.  
  912.   for (i = 0;  i < nFonts;  i++)
  913.   {
  914.     /*
  915.       Set up the FontAttrs structure in preparation for GpiCreateLogFont()
  916.     */
  917.     FontAttrs.usRecordLength  = sizeof(FontAttrs);
  918.     FontAttrs.fsSelection     = pMetrics[i].fsSelection;
  919.     FontAttrs.lMatch          = pMetrics[i].lMatch;
  920.     strcpy(FontAttrs.szFacename, szFont);
  921.     FontAttrs.idRegistry      = pMetrics[i].idRegistry;
  922.     FontAttrs.usCodePage      = 850;
  923.     FontAttrs.lMaxBaselineExt = pMetrics[i].lMaxBaselineExt;
  924.     FontAttrs.lAveCharWidth   = pMetrics[i].lAveCharWidth;
  925.     FontAttrs.fsType          = FATTR_TYPE_FIXED;
  926.     FontAttrs.fsFontUse       = 0;
  927.  
  928.     /*
  929.       Given the above attribures, try to find the best match in a Courier font
  930.     */
  931.     rcMatch = GpiCreateLogFont(hPS, (PSTR8) szFont,
  932.                                (LONG) ++IDCourier, (PFATTRS) &FontAttrs);
  933.     /*
  934.       We got a match if rcMatch is 2
  935.     */
  936.     if (rcMatch == 2)
  937.     {
  938.       GpiSetCharSet(hPS, IDCourier);
  939.       GpiQueryFontMetrics(hPS, (long) sizeof(FONTMETRICS), &FMCourier);
  940.       /*
  941.         If the matched font is 16x9, then let's use it.
  942.       */
  943.       if (FMCourier.lAveCharWidth == 9L 
  944.           && FMCourier.lMaxBaselineExt >= 16L)
  945.         break;
  946.     }
  947.   }
  948.  
  949.   free(pMetrics);
  950.   return (i < nFonts);
  951. }
  952.  
  953.  
  954. /*****************************************************************************/
  955. /* FormatError()                                                             */
  956. /*   Sounds a little beep when the user presses a bad key.                   */
  957. /*****************************************************************************/
  958. FormatError()
  959. {
  960.   WinAlarm(HWND_DESKTOP, WA_WARNING);
  961.   return TRUE;
  962. }
  963.  
  964.  
  965. /*****************************************************************************/
  966. /* lstrlen(), lstrcpy()                                                      */
  967. /*   Miscellaneous far-pointer routines                                      */
  968. /*****************************************************************************/
  969. int lstrlen(PSZ s)
  970. {
  971.   int len = 0;
  972.   while (*s++)
  973.     len++;
  974.   return len;
  975. }
  976.  
  977. PSZ lstrcpy(PSZ s, PSZ t)
  978. {
  979.   PSZ orig_s = s;
  980.   while (*s++ = *t++) ;
  981.   return orig_s;
  982. }
  983.  
  984.  
  985. /*****************************************************************************/
  986. /* DEBUG()                                                                   */
  987. /*   Simple diagnostic routine which displays a message box.                 */
  988. /*****************************************************************************/
  989. char szDebug[82];
  990.  
  991. DEBUG(char *fmt, ...)
  992. {
  993.   va_list arg;
  994.  
  995.   va_start(arg, fmt);
  996.   vsprintf(szDebug, fmt, arg);         /* format the message */
  997.   va_end(arg);
  998.   SimpleMessage(hWndClient, szDebug);  /* put it in a message box */
  999. }
  1000.  
  1001.