home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / c / cpicture.zip / PARAPICT.CPP next >
C/C++ Source or Header  |  1992-08-11  |  24KB  |  750 lines

  1. /*************************************************************************
  2. **           Paradox-Like Picture Field Input Processing
  3. **************************************************************************
  4. **                                                                      **
  5. **  Copyright (c) 1992  Flexible Information Systems, Inc.              **
  6. **                                                                      **
  7. **    This code may be freely used by any programmer                    **
  8. **    including royalty free inclusion in any commercial                **
  9. **    application, but any commercial rights to the source              **
  10. **    code or object files of this code is are reserved.                **
  11. **                                                                      **
  12. **    This code is supplied strictly as-is, and FIS, Inc. and the       **
  13. **    author assume no responsibility for the accuracy, use or fitness  **
  14. **    for a particular purpose                                          **
  15. **                                                                      **
  16. **                                                                      **
  17. **      Author:         Ken Vogel                                       **
  18. **      CIS Id:         74007,564                                       **
  19. **      Filename:       parapict.cpp                                    **
  20. **      Prefix:         PPIC_                                           **
  21. **      Date:           24-Mar-92                                       **
  22. **                                                                      **
  23. **      Description:    A set of recursive C++ classes which process
  24. **                      data entry with Paradox-like picture formats.
  25. **
  26. **                      The classes in this file do not actually perform
  27. **                      any keyboard or display functions, but should be
  28. **                      integrated into a data entry system.  This allows
  29. **                      them to be used in TurboVision, Windows, etc.
  30. **
  31. **                                                                      **
  32. **************************************************************************/
  33.  
  34.  
  35. #if 0
  36.     ---->>> Revision History <<<----
  37.   1 PARAPICT.CPP 18-Apr-92,14:55:12,`KEN' Paradox-like picture processing    
  38.        Not tied to any particular input system                               
  39.   2 PARAPICT.CPP 12-Jun-92,13:36:10,`KEN' Fix minor bug                      
  40.   3 PARAPICT.CPP 11-Aug-92,11:52:04,`KEN' Fix bug in \r handling             
  41.     ---->>> Revision History <<<----
  42. #endif
  43.  
  44. #include <ctype.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47.  
  48. #define Uses_parapict
  49.  
  50. #include "parapict.hpp"
  51.  
  52. void tbg_ResetOneElement (PPIC_ElementClass *element)
  53. // Reset a single element of a list of PPIC_ElementClass *
  54. {
  55.     element->ResetState();
  56. }
  57.  
  58.  
  59. //////////////////////  PPIC_ElementListClass \\\\\\\\\\\\\\\\\\\\\\\\\
  60.  
  61. PPIC_ElementListClass::PPIC_ElementListClass()
  62.                      : dElementsCPP (0)
  63.                      , dCount (0)
  64. {
  65. }
  66.  
  67. PPIC_ElementListClass::~PPIC_ElementListClass()
  68. {
  69.     PPIC_ElementClass **cursor = dElementsCPP;
  70.     while (dCount-- > 0)
  71.         delete (*cursor++);
  72.     delete dElementsCPP;
  73. }
  74.  
  75. PPIC_ElementClass *PPIC_ElementListClass::at (int index)
  76. {
  77.     return (index < dCount) ? dElementsCPP[ index ] : 0;
  78. }
  79.  
  80. void PPIC_ElementListClass::insert (PPIC_ElementClass *newElement)
  81. {
  82.     PPIC_ElementClass **NewElementsCPP = new PPIC_ElementClass *[dCount + 1];
  83.     if (dCount > 0)
  84.         memcpy (NewElementsCPP, dElementsCPP, dCount * sizeof (*dElementsCPP));
  85.     delete dElementsCPP;
  86.     dElementsCPP = NewElementsCPP;
  87.     dElementsCPP[dCount++] = newElement;
  88. }
  89.  
  90.  
  91. void PPIC_ElementListClass::forEach ( void (*actionFun)(PPIC_ElementClass *))
  92. {
  93.     for (int index = 0; index < dCount; index++)
  94.         actionFun (dElementsCPP[ index ]);
  95. }
  96.  
  97. //////////////////////  PPIC_SequenceClass \\\\\\\\\\\\\\\\\\\\\\\\\
  98.  
  99. PPIC_SequenceClass::PPIC_SequenceClass ( PPIC_ElementClass  *ElementCP)
  100.                       : dElementListCP (new PPIC_ElementListClass())
  101.                       , dCurrentEl(0)
  102. // Constructor to create a sequence class from a single element
  103. {
  104.     dElementListCP->insert (ElementCP);
  105. }
  106.  
  107. PPIC_SequenceClass::~PPIC_SequenceClass()
  108. {
  109.     delete dElementListCP;
  110. }
  111.  
  112. void PPIC_SequenceClass::AddElement (PPIC_ElementClass *ElementCP)
  113. // Add an element to a sequence class
  114. {
  115.     dElementListCP->insert (ElementCP);
  116. }
  117.  
  118.  
  119. void PPIC_SequenceClass::ResetState( void )
  120. // Reset state of entry system
  121. {
  122.     dElementListCP->forEach (tbg_ResetOneElement);
  123.     dCurrentEl = 0;
  124. }
  125.  
  126. int PPIC_SequenceClass::ProcessLetter( char    Letter
  127.                                         , PPIC_FlagsType *FlagsP
  128.                                         , Boolean IsKeypress
  129.                                         , char    *DestP
  130.                                         , int     MaxLength )
  131. {
  132.     int Result;
  133.     if (dCurrentEl >= dElementListCP->getCount())
  134.       {
  135.         *FlagsP = PPIC_cOverflow;
  136.         return 0;
  137.       }
  138.  
  139.     // Loop in case they are done
  140.     while (1)
  141.       {
  142.         PPIC_ElementClass *CurrentElP = dElementListCP->at (dCurrentEl);
  143.  
  144.         *FlagsP = 0;
  145.         Result = CurrentElP->ProcessLetter (Letter, FlagsP, IsKeypress
  146.                                            , DestP, MaxLength);
  147.         if (*FlagsP & PPIC_cOverflow)
  148.           {
  149.             if (++dCurrentEl >= dElementListCP->getCount())
  150.                 return 0;   // Keep overflow flag
  151.             continue;
  152.           }
  153.  
  154.         if (dCurrentEl < dElementListCP->getCount() - 1)
  155.             *FlagsP = 0;  // Cannot be Full if not in last element
  156.         return Result;
  157.       } // Loop over elements when done
  158. } // PPIC_SequenceClass::ProcessLetter
  159.  
  160. //////////////////////  PPIC_AlternateClass \\\\\\\\\\\\\\\\\\\\\\\\\
  161.  
  162. PPIC_AlternateClass::PPIC_AlternateClass ( PPIC_ElementClass  *ElementCP)
  163.                       : dAlternativeListCP (new PPIC_ElementListClass ())
  164.                       , dSelectedEl (-1)
  165. // Constructor to create a sequence class from a single element
  166. {
  167.     dAlternativeListCP->insert (ElementCP);
  168. }
  169.  
  170. PPIC_AlternateClass::~PPIC_AlternateClass()
  171. {
  172.     delete dAlternativeListCP;
  173. }
  174.  
  175. void PPIC_AlternateClass::AddElement (PPIC_ElementClass *ElementCP)
  176. // Add an element to a sequence class
  177. {
  178.     dAlternativeListCP->insert (ElementCP);
  179. }
  180.  
  181. void PPIC_AlternateClass::ResetState( void )
  182. // Reset state of entry system
  183. {
  184.     dAlternativeListCP->forEach (tbg_ResetOneElement);
  185.     dSelectedEl = -1;
  186. }
  187.  
  188. int PPIC_AlternateClass::ProcessLetter( char    Letter
  189.                                      , PPIC_FlagsType *FlagsP
  190.                                      , Boolean IsKeypress
  191.                                      , char    *DestP
  192.                                      , int     MaxLength )
  193. {
  194.     int Result;
  195.     PPIC_ElementClass *CurrentElP;
  196.  
  197.     if (dSelectedEl == -1)
  198.       {
  199.         for (dSelectedEl = 0; dSelectedEl < dAlternativeListCP->getCount();
  200.              dSelectedEl++)
  201.           {
  202.             CurrentElP = dAlternativeListCP->at (dSelectedEl);
  203.             Result = CurrentElP->ProcessLetter (Letter, FlagsP, IsKeypress
  204.                                                , DestP, MaxLength);
  205.             if (Result > 0)
  206.               {
  207.                 // Have a selection -- dSelectedEl is correct
  208.                 return Result;
  209.               }
  210.           }
  211.         // No-one was able to handle it
  212.         dSelectedEl = -1;
  213.         return 0;
  214.       } // Select an alternate
  215.     else
  216.       {
  217.         CurrentElP = dAlternativeListCP->at (dSelectedEl);
  218.         return CurrentElP->ProcessLetter (Letter, FlagsP, IsKeypress
  219.                                                , DestP, MaxLength);
  220.       } // Use existing selection
  221. } // PPIC_AlternateClass::ProcessLetter
  222.  
  223.  
  224. //////////////////////// PPIC_OptionalClass \\\\\\\\\\\\\\\\\\\\\\\\\\\
  225.  
  226. PPIC_OptionalClass::PPIC_OptionalClass ( PPIC_ElementClass *LeftCP
  227.                                      , PPIC_ElementClass *RightCP )
  228.                           : dLeftElementCP (LeftCP)
  229.                           , dRightElementCP (RightCP)
  230.                           , dState (PPIC_fStarting)
  231. // Construct an optional selection from two elements (first is the optional
  232. // one)
  233. {
  234. }
  235.  
  236. PPIC_OptionalClass::~PPIC_OptionalClass()
  237. {
  238.     delete dLeftElementCP;
  239.     delete dRightElementCP;
  240. }
  241.  
  242. void PPIC_OptionalClass::ResetState ()
  243. {
  244.     dLeftElementCP->ResetState();
  245.     if (dRightElementCP)
  246.         dRightElementCP->ResetState();
  247.     dState = PPIC_fStarting;
  248. }
  249.  
  250. int PPIC_OptionalClass::ProcessLetter( char    Letter
  251.                                     , PPIC_FlagsType *FlagsP
  252.                                     , Boolean IsKeypress
  253.                                     , char    *DestP
  254.                                     , int     MaxLength )
  255. {
  256.     int Result;
  257.  
  258.     if (dState == PPIC_fStarting || dState == PPIC_fLeftActive)
  259.       {
  260.         if (dState == PPIC_fStarting && Letter == '\r')
  261.           {
  262.             // Optional, so they can end it now only if right element says
  263.             // it's ok
  264.             *FlagsP = PPIC_cOverflow;
  265.             Result = 0;
  266.             // Then let the right element have a crack at it
  267.           }
  268.         else
  269.           {
  270.             // Try processing with left
  271.             Result = dLeftElementCP->ProcessLetter (Letter, FlagsP, IsKeypress
  272.                                                    , DestP, MaxLength);
  273.             if ((*FlagsP & PPIC_cOverflow)
  274.                 || (Result == 0 && dState == PPIC_fStarting))
  275.                 dState = PPIC_fRightActive;
  276.             else
  277.               {
  278.                 dState = PPIC_fLeftActive;
  279.                 return Result;
  280.               }
  281.           }
  282.       } // Check the left element
  283.  
  284.     // Only gets here if right active
  285.     if (dRightElementCP)
  286.       {
  287.         return dRightElementCP->ProcessLetter (Letter, FlagsP, IsKeypress
  288.                                           , DestP, MaxLength);
  289.       }
  290.     else
  291.       {
  292.         *FlagsP = PPIC_cOverflow;
  293.         return 0;
  294.       }
  295. } // PPIC_OptionalClass::ProcessLetter
  296.  
  297.  
  298. //////////////////// PPIC_FormatClass \\\\\\\\\\\\\\\\\\\\\\\\\\\\
  299. PPIC_FormatClass::PPIC_FormatClass (const char *FormatStrP)
  300. {
  301.     dFormatStringOP = new char [strlen (FormatStrP) + 1];
  302.     if (dFormatStringOP)
  303.         strcpy (dFormatStringOP, FormatStrP);
  304.     dCursorP = dFormatStringOP;
  305. }
  306.  
  307. void PPIC_FormatClass::~PPIC_FormatClass()
  308. {
  309.     delete dFormatStringOP;
  310. }
  311.  
  312. void PPIC_FormatClass::ResetState()
  313. {
  314.     dCursorP = dFormatStringOP;
  315. }
  316.  
  317. int PPIC_FormatClass::ProcessLetter( char    Letter
  318.                                   , PPIC_FlagsType *FlagsP
  319.                                   , Boolean IsKeypress
  320.                                   , char    *DestP
  321.                                   , int     MaxLength )
  322. {
  323.     int Result;
  324.  
  325.     if (*dCursorP == 0)
  326.       {
  327.         *FlagsP = PPIC_cOverflow;
  328.         return 0;
  329.       }
  330.     *FlagsP = 0;
  331.  
  332.     if (Letter == '\r')
  333.         return 0;
  334.  
  335.     // Process a single letter
  336.     if (*dCursorP <= PPIC_cMaxFormatChar)
  337.       {
  338.         Boolean Good = False;
  339.         // A formatting character
  340.         switch (*dCursorP)
  341.           {
  342.             case PPIC_cDigit:
  343.                 Good = Boolean (isdigit (Letter));
  344.                 break;
  345.  
  346.             case PPIC_cUpperLetter:
  347.                 Letter = toupper (Letter);
  348.             case PPIC_cLetter:
  349.                 Good = Boolean (isalpha (Letter));
  350.                 break;
  351.  
  352.             case PPIC_cUpperAny:
  353.                 Letter = toupper (Letter);
  354.             case PPIC_cAny:
  355.             default:
  356.                 Good = True;
  357.                 break;
  358.           } // Switch on cursor
  359.  
  360.         // Now process
  361.         if (!Good)
  362.             return 0;
  363.       }
  364.     else
  365.       {
  366.         // A literal -- check if it matches
  367.         if ( (!IsKeypress || Letter != ' ')
  368.              && toupper (*dCursorP) != toupper (Letter))
  369.             return 0;
  370.         Letter = *dCursorP;
  371.       }
  372.  
  373.  
  374.     // Store this letter no matter what
  375.     dCursorP++;
  376.     Result = 1;
  377.     MaxLength--;
  378.     if (IsKeypress && DestP)
  379.       {
  380.         *DestP++ = Letter;
  381.         *DestP = 0;
  382.       }
  383.  
  384.     // Check for auto expand of literals after this letter
  385.     while (MaxLength-- > 0 && *dCursorP > PPIC_cMaxFormatChar)
  386.       {
  387.         *DestP++ = *dCursorP++;
  388.         Result++;
  389.       }
  390.     *DestP = 0;
  391.  
  392.     // Check for full
  393.     if (*dCursorP == 0)
  394.         *FlagsP = PPIC_cFull;
  395.  
  396.     return Result;
  397. } // FormatClass::ProcessLetter
  398.  
  399.  
  400. //////////////////// PPIC_RepetitionClass \\\\\\\\\\\\\\\\\\\\\\\\\\\\
  401.  
  402. PPIC_RepetitionClass::PPIC_RepetitionClass (int Count
  403.                                          , PPIC_ElementClass *ElementCP)
  404.                       : dRepeatCount (Count)
  405.                       , dRepsLeft (Count)
  406.                       , dElementCP (ElementCP)
  407.                       , dInProcess (False)
  408. {
  409. }
  410.  
  411. PPIC_RepetitionClass::~PPIC_RepetitionClass()
  412. {
  413.     delete dElementCP;
  414. }
  415.  
  416. void PPIC_RepetitionClass::ResetState()
  417. {
  418.     dElementCP->ResetState();
  419.     dRepsLeft = dRepeatCount;
  420.     dInProcess = False;
  421. }
  422.  
  423.  
  424. int PPIC_RepetitionClass::ProcessLetter( char    Letter
  425.                                      , PPIC_FlagsType *FlagsP
  426.                                      , Boolean IsKeypress
  427.                                      , char    *DestP
  428.                                      , int     MaxLength )
  429. {
  430.     if (dRepsLeft == 0 || (!dInProcess && dRepsLeft == -1 && Letter == '\r') )
  431.       {
  432.         *FlagsP = PPIC_cOverflow;
  433.         return 0;
  434.       }
  435.  
  436.     int Result = dElementCP->ProcessLetter (Letter, FlagsP, IsKeypress
  437.                                            , DestP, MaxLength);
  438.     if (*FlagsP & PPIC_cOverflow)
  439.       {
  440.         if (dRepsLeft != -1)
  441.             if (--dRepsLeft == 0)
  442.                 return 0;
  443.  
  444.         dInProcess = False;
  445.         dElementCP->ResetState();
  446.         Result = dElementCP->ProcessLetter (Letter, FlagsP, IsKeypress
  447.                                           , DestP, MaxLength);
  448.       }
  449.     if (!dInProcess && Result == 0 && dRepsLeft == -1)
  450.         *FlagsP = PPIC_cOverflow;
  451.     if (Result != 0)
  452.         dInProcess = True;
  453.  
  454.     // Cannot be full unless all reps are used
  455.     if (dRepsLeft != 0)
  456.         *FlagsP &= ~PPIC_cFull;
  457.  
  458.     return Result;
  459. } // PPIC_RepetitionClass::ProcessLetter
  460.  
  461. ////////////////////////  The recursive parser \\\\\\\\\\\\\\\\\\\\\\\\\\
  462. //  parses an input picture in an element
  463.  
  464. // Get one character from the input string, process to control
  465. // codes accordingly.  Returns the next character & updates the pointer
  466. // Does NOT handle control codes!
  467. char ppic_NextChar (const char *& CursorP)
  468. {
  469.     // The character translation set.  The index into this string is the
  470.     // "internal" representation of the formatting character.
  471.     char FromCharA[] = "*[]{},#?&@!";
  472.  
  473.     char Result = *CursorP;
  474.     if (Result == 0)
  475.         return 0;
  476.  
  477.     CursorP++;
  478.  
  479.     if (Result == ';')
  480.       {
  481.         if (0 != (Result = *CursorP))
  482.             CursorP++;
  483.       }
  484.     else
  485.       {
  486.         char *SpecialP = strchr (FromCharA, Result);
  487.         if (SpecialP != 0)
  488.             Result = (char)(SpecialP - FromCharA + 1);
  489.       }
  490.     return Result;
  491. } // ppic_NextChar
  492.  
  493.  
  494. // Forward declaration for recursion
  495. PPIC_ElementClass *PPIC_Parse ( const char *&CursorP);
  496.  
  497.  
  498. PPIC_ElementClass *PPIC_ElementParse ( const char *&CursorP)
  499. // Parse an element of a picture string
  500. // PictureP is the input picture
  501. // Modifies PictureP to point to last char afer input
  502. {
  503.     PPIC_ElementClass *ResultCP;
  504.     char *StoreCursorP;
  505.     const char *BeforePeekP = CursorP;
  506.  
  507.     char NextChar = ppic_NextChar (CursorP);
  508.  
  509.     if (NextChar == 0)
  510.         return NULL;
  511.  
  512.     if (NextChar > PPIC_cMaxSpecialChar)
  513.       {
  514.         // Formatting string -- get all chars possible
  515.         // Get the length for allocation
  516.         int Length = 1;
  517.         while (ppic_NextChar (CursorP) > PPIC_cMaxSpecialChar)
  518.             Length++;
  519.         char *FormatOP = new char [Length + 1];
  520.         if (FormatOP == 0)
  521.             return 0;
  522.  
  523.         // Copy the formatting characters into this
  524.         StoreCursorP = FormatOP;
  525.         CursorP = BeforePeekP;
  526.         while ( Length--)
  527.             *StoreCursorP++ = ppic_NextChar (CursorP);
  528.         *StoreCursorP = 0;
  529.  
  530.         CursorP = CursorP;
  531.         ResultCP = new PPIC_FormatClass (FormatOP);
  532.         delete FormatOP;
  533.       } // A formatting character
  534.     else
  535.       {
  536.         char BufferA[10];
  537.         int Counter, Count;
  538.         PPIC_ElementClass *NextElementCP, *LeftCP;
  539.  
  540.         switch (NextChar)
  541.           {
  542.             case PPIC_cRepetition:
  543.                 // Get up to 5 digits
  544.                 StoreCursorP = BufferA;
  545.                 Counter = 5;
  546.                 while (Counter-- && isdigit (*CursorP))
  547.                     *StoreCursorP++ = *CursorP++;
  548.                 *StoreCursorP = 0;
  549.                 if (*BufferA == 0)
  550.                     Count = -1;
  551.                 else
  552.                   {
  553.                     Count = atoi (BufferA);
  554.                     if (Count < 0)
  555.                         Count = -1;
  556.                   }
  557.  
  558.                 // Now get the next element
  559.                 BeforePeekP = CursorP;
  560.                 NextChar = ppic_NextChar (CursorP);
  561.                 if (NextChar <= PPIC_cMaxSpecialChar)
  562.                   {
  563.                     // A complex element.  If it's an option, we only want
  564.                     // to process the beginning
  565.                     if (NextChar == PPIC_cOptionOpen)
  566.                       {
  567.                         NextElementCP = PPIC_Parse (CursorP);
  568.                         NextChar = ppic_NextChar (CursorP);
  569.                         if (NextChar != PPIC_cOptionClose)
  570.                           {
  571.                             delete NextElementCP;
  572.                             NextElementCP = 0;
  573.                             return 0;
  574.                           }
  575.                         else
  576.                           {
  577.                             NextElementCP
  578.                                 = new PPIC_OptionalClass (NextElementCP, 0);
  579.                           }
  580.                       } // Process option repetition
  581.                     else
  582.                       {
  583.                         CursorP = BeforePeekP;
  584.                         NextElementCP = PPIC_ElementParse (CursorP);
  585.                       }
  586.                   } // Have a special character
  587.                 else
  588.                   {
  589.                     // A single character
  590.                     BufferA[0] = NextChar;
  591.                     BufferA[1] = 0;
  592.                     NextElementCP = new PPIC_FormatClass (BufferA);
  593.                   }
  594.  
  595.                 if (NextElementCP == 0)
  596.                     ResultCP = 0;
  597.                 else
  598.                     ResultCP = new PPIC_RepetitionClass (Count, NextElementCP);
  599.                 break; // A repetition
  600.  
  601.             case PPIC_cOptionOpen:
  602.                 LeftCP = PPIC_Parse (CursorP);
  603.                 if (ppic_NextChar (CursorP) != PPIC_cOptionClose)
  604.                   {
  605.                     delete LeftCP;
  606.                     ResultCP = 0;
  607.                   }
  608.                 else
  609.                   {
  610.                     NextElementCP = PPIC_Parse (CursorP);
  611.                     ResultCP = new PPIC_OptionalClass (LeftCP, NextElementCP);
  612.                   }
  613.                 break;
  614.  
  615.             case PPIC_cGroupOpen:
  616.                 ResultCP = PPIC_Parse (CursorP);
  617.                 if (ppic_NextChar (CursorP) != PPIC_cGroupClose)
  618.                   {
  619.                     delete ResultCP;
  620.                     ResultCP = 0;
  621.                   }
  622.                 break;
  623.  
  624.             case PPIC_cAlternate:
  625.             case PPIC_cOptionClose:
  626.             case PPIC_cGroupClose:
  627.             default:
  628.                 CursorP = BeforePeekP;
  629.                 ResultCP = 0;
  630.                 break;
  631.           } // Switch NextChar
  632.       } // A special character
  633.  
  634.     return ResultCP;
  635. } // PPIC_ElementParse
  636.  
  637.  
  638. PPIC_ElementClass *PPIC_Parse ( const char *&CursorP)
  639. // Parse an entire picture string
  640. {
  641.     PPIC_SequenceClass *SequenceCP = 0;
  642.     PPIC_AlternateClass *AlternateCP = 0;
  643.     PPIC_ElementClass *ElementCP;
  644.     const char *BeforeP;
  645.     char NextChar;
  646.  
  647.     // Loop over the expressions we can get
  648.     while (1)
  649.       {
  650.         ElementCP = PPIC_ElementParse (CursorP);
  651.         if (ElementCP != 0 && SequenceCP != 0)
  652.           {
  653.             // Add to end of sequence
  654.             SequenceCP->AddElement (ElementCP);
  655.             ElementCP = SequenceCP;
  656.           }
  657.  
  658.         BeforeP   = CursorP;
  659.         NextChar  = ppic_NextChar (CursorP);
  660.  
  661.         if (ElementCP == 0
  662.            || NextChar == 0
  663.            || NextChar == PPIC_cOptionClose
  664.            || NextChar == PPIC_cGroupClose)
  665.           {
  666.            // The end
  667.            if (AlternateCP != 0)
  668.              {
  669.                AlternateCP->AddElement (ElementCP);
  670.                ElementCP = AlternateCP;
  671.              }
  672.            CursorP = BeforeP;
  673.            return ElementCP;
  674.           }
  675.         else if (NextChar == PPIC_cAlternate)
  676.           {
  677.             if (AlternateCP != 0)
  678.                 AlternateCP->AddElement (ElementCP);
  679.             else
  680.                 AlternateCP = new PPIC_AlternateClass (ElementCP);
  681.             // Use the element in alternate -- erase any sequence
  682.             SequenceCP = 0;
  683.           }
  684.         else
  685.           {
  686.             // A sequence of elements (if exists, we already added to end)
  687.             if (SequenceCP == 0)
  688.                 SequenceCP = new PPIC_SequenceClass (ElementCP);
  689.             CursorP    = BeforeP;
  690.           }
  691.       } // Loop over parts of expression (terminates with return)
  692. } // PPIC_Parse
  693.  
  694. PPIC_PictureClass::PPIC_PictureClass(const char *PictureP)
  695.                  : thePicture (0)
  696. {
  697.     thePicture = PPIC_Parse (PictureP);
  698.     valid = Boolean (thePicture != 0);
  699. }
  700.  
  701. PPIC_PictureClass::~PPIC_PictureClass()
  702. {
  703.     delete thePicture;
  704. }
  705.  
  706. int PPIC_PictureClass::ProcessLetter( char    Letter
  707.                                     , PPIC_FlagsType *FlagsP
  708.                                     , Boolean IsKeypress
  709.                                     , char    *DestP
  710.                                     , int     MaxLength )
  711. {
  712.     int result = 0;
  713.     if (thePicture)
  714.       {
  715.         result = thePicture->ProcessLetter ( Letter, FlagsP, IsKeypress
  716.                                                , DestP, MaxLength);
  717.  
  718.         // Overflow of outermost picture is an error (unless c/r)
  719.         if ((*FlagsP & PPIC_cOverflow) && Letter != '\r')
  720.             *FlagsP = 0;
  721.       }
  722.     return result;
  723. }
  724.  
  725.  
  726. void PPIC_PictureClass::ResetState( void )
  727. {
  728.     if (thePicture)
  729.         thePicture->ResetState();
  730. }
  731. char *PPIC_PictureClass::ReprocessString ( char *StringP
  732.                                          , PPIC_FlagsType *FlagsP)
  733. {
  734.     *FlagsP = 0;
  735.     if (thePicture)
  736.       {
  737.         thePicture->ResetState();
  738.         char *CursorP = StringP;
  739.         while (*CursorP)
  740.           {
  741.             if (!thePicture->ProcessLetter ( *CursorP, FlagsP, False, 0, 0)
  742.                || (*FlagsP & PPIC_cOverflow))
  743.                 return CursorP;
  744.             CursorP++;
  745.           }
  746.       }
  747.  
  748.     return 0;
  749. }
  750.