home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / VCAFE.3.0A / Main.bin / MaskEngine.java < prev    next >
Text File  |  1998-12-11  |  26KB  |  617 lines

  1. /*
  2.   Engine class for support of masked input in IRAD.
  3.  
  4.   Created 3/26/98 by Paul Lancaster.
  5. */
  6.  
  7. package com.symantec.itools.swing;
  8.  
  9. import java.awt.event.KeyEvent;
  10. import java.awt.*;
  11.  
  12. public class MaskEngine {
  13.  
  14.     // These constants are used to specify the data type information needed by
  15.     // the engine to specialize mask behaviour.
  16.     public static final int texttype = 0;
  17.     public static final int numbtype = 1;
  18.     public static final int datetype = 2;
  19.     public static final int timetype = 3;
  20.  
  21.     public MaskEngine(String mask, int datatype) {  // ctor
  22.         init();
  23.         setMask(mask);
  24.         setDatatype(datatype);
  25.     }
  26.  
  27.     public MaskEngine() {  // default constructor
  28.         init();
  29.     }
  30.  
  31.     public void setMask(String mask) {
  32.         //vasu start
  33.         if(mask.trim().equals("")) return;
  34.         //vasu end
  35.         _mask = mask;
  36.         _maskLength = mask.length();
  37.  
  38.         // Analyze filter and initialize supporting data structures
  39.         _filterCount = 0;
  40.         resetMaskScan();
  41.  
  42.         // First pass: count filters and total displayable mask characters.
  43.         // Also mark first and last filter positions.
  44.         for (_maskCount = 0; 0 != getNextMaskChar(); _maskCount++) {
  45.             if (_curMaskType == filtertype) {
  46.                 _filterCount++;                // count filters
  47.                 _lastFilterPos = _curMaskPos;  // new "last" filter pos
  48.             }
  49.             if (1 == _filterCount)
  50.                 _firstFilterPos = _curMaskPos; // note first filter pos
  51.         }
  52.         if (_maskCount * _filterCount == 0)
  53.             return;  // error: no displayable characters or no filters in mask
  54.  
  55.         // Second pass: fill filter position array.
  56.         _filterPositions = new int[_filterCount];
  57.         _commandCorrections = new int[_filterCount];
  58.         resetMaskScan();
  59.         for (int i = 0, j = 0; i < _maskCount; i++) {
  60.             getNextMaskChar();
  61.             if (_curMaskType == filtertype) {
  62.                 _filterPositions[j] = _curMaskPos;
  63.                 _commandCorrections[j++] = _commandCorrection;
  64.             }
  65.         }
  66.     }
  67.  
  68.     public void   setDatatype(int datatype) { _datatype = datatype; }
  69.     public String getMask()                 { return _mask        ; }
  70.     public int    getDatatype()             { return _datatype    ; }
  71.  
  72.     /*  Called to initialize the display of the masked data.
  73.         The first parameter is the current data in the field.
  74.         The second parameter holds the string that should be displayed.
  75.         The return value is the initial caret position.
  76.     */
  77.     public int initDisplay(String data, StringBuffer newData) {
  78.         //vasu start
  79.         if (_filterCount == 0){       // no filters?
  80.             newData.append(data);
  81.             return 0;                  // return first position
  82.         }
  83.         //vasu end
  84.         int datalen = data.length();
  85.         int inpos = 0;   // track input position
  86.         boolean zerofill           = false;
  87.         boolean dataRightOfDecimal = false;
  88.         boolean maskRightOfDecimal = false;
  89.         resetMaskScan();
  90.         char c;
  91.         for (int i = 0; (c = getNextMaskChar()) != 0; i++) { // mask drives output
  92.             if (_curMaskType == filtertype) {         // we are on a filter?
  93.                 char z = zerofill ? '0' : '_';
  94.                 if (inpos < datalen) {       // consumed all data yet?
  95.                     c = data.charAt(inpos++);  // if not, get next data char
  96.                     if (numbtype == _datatype) { // special handling for numerics
  97.                         if (_decimalPoint == c) {
  98.                             c = z;
  99.                             dataRightOfDecimal = true;
  100.                             if (maskRightOfDecimal && inpos < datalen)
  101.                                 c = data.charAt(inpos++);
  102.                         } else if (dataRightOfDecimal && !maskRightOfDecimal) {
  103.                             c = z;
  104.                             inpos--;  // can not use this fractional digit yet
  105.                         } else if (!dataRightOfDecimal && maskRightOfDecimal) {
  106.                             c = z;
  107.                         while (inpos < datalen)    // scan data for dec. pt.
  108.                             if (_decimalPoint == data.charAt(inpos++)) {
  109.                                 if (inpos < datalen)
  110.                                     c = data.charAt(inpos++);
  111.                                 dataRightOfDecimal = true;
  112.                                 break;
  113.                             }
  114.                         }
  115.                     }  // if numeric field
  116.                 } else            // we have consumed all input data
  117.                 c = z;
  118.             } else if (_curMaskChar == _decimalPoint && numbtype == _datatype) {
  119.                 maskRightOfDecimal = true;
  120.                 if (0 == datalen) {  // for empty numeric fields, start zero filling
  121.                     zerofill = true;
  122.                     newData.setCharAt(newData.length() - 1, '0'); // zero units digit
  123.                 }
  124.                 else if (inpos < datalen && data.charAt(inpos) == _decimalPoint) {
  125.                     inpos++;   // skip decimal point in input
  126.                     dataRightOfDecimal = true;
  127.                 }
  128.             }
  129.             newData.append(c);
  130.         }
  131.  
  132.         // Zero units digit of empty numeric fields with no decimal.
  133.         if (numbtype == _datatype && 0 == datalen && !zerofill && _maskLength > 0)
  134.             newData.setCharAt(newData.length() - 1, '0');
  135.  
  136.         return _filterPositions[0] - _commandCorrections[0];
  137.     }
  138.  
  139.   /* This is the main workhorse method.
  140.      It is called for every key stroke corresponding to displayable
  141.      characters once editing begins.
  142.      The 1st parameter is the user keystroke event object.
  143.      The 2nd parameter is the current cursor position (zero based).
  144.      The 3rd parameter is the current text from the component.
  145.      The 4th parameter is output and is what should be displayed in the component.
  146.      The 5th and 6th parameters are the selection start and end, respectively.
  147.      The return value is the new cursor position within the "newData"
  148.      parameter (zero based), unless it is negative, in which case:
  149.      -1 means the input is inconsistent (position not in range or not on a filter.
  150.      -2 means the input keystroke is not accepted by the relevant filter.
  151.   */
  152.     public int processKey(java.awt.event.KeyEvent e, int pos, String data,
  153.                             StringBuffer newData, int selStart, int selEnd) {
  154.         newData.append(data);    // init output to input
  155.         int keyCode = e.getKeyCode();
  156.         if (!setMaskPos(pos) && !isNavKey(keyCode))
  157.             return -1;   // cursor pos not in bounds
  158.         char key = e.getKeyChar();
  159.         if (key == _decimalPoint && _datatype == numbtype) {   // decimal?
  160.  
  161.         // Move caret to first filter to the right of first decimal point
  162.         // that is to the right of current caret position.
  163.             while (getNextMaskChar() != 0)
  164.                 if (_curMaskChar == _decimalPoint)
  165.                     return nextFilterPos();
  166.             return pos;   // could not find rightward decimal point
  167.         } else if (filtertype != _curMaskType) {   // not on filter position?
  168.             if (0 == pos && 0 == selStart && selEnd > _firstFilterPos)
  169.                 setMaskPos(pos = _firstFilterPos);
  170.             else if (!isNavKey(keyCode)) {
  171.                 if (pos > _lastFilterPos)
  172.                     return -1;      // beyond last filter
  173.                 nextFilterPos();  // advance to next filter
  174.                 pos = _curMaskPos - _commandCorrection;
  175.             }
  176.         }
  177.         switch (keyCode) {   // handle control keys
  178.         case e.VK_BACK_SPACE:
  179.             if (selStart < selEnd) {  // if selected text exists
  180.                 if (pos != selStart || selEnd - selStart > 1) {
  181.                 clearSelectedText(selStart, selEnd, newData);
  182.                 return Math.max(selStart, _firstFilterPos);
  183.                 }
  184.             }
  185.             int newPos = prevFilterPos();
  186.             if (pos > 0 && newPos != -1)
  187.                 newData.setCharAt(newPos, '_');
  188.             return newPos != -1 ? newPos : pos;
  189.         case e.VK_DELETE:
  190.             if (selStart < selEnd) {   // if selected text exists
  191.                 clearSelectedText(selStart, selEnd, newData);
  192.                 return Math.max(selStart, _firstFilterPos);
  193.             }
  194.         newData.setCharAt(pos, '_');
  195.             return pos;
  196.         case e.VK_LEFT:
  197.             return prevFilterPos();
  198.         case e.VK_RIGHT:
  199.             return nextFilterPos();
  200.         case e.VK_HOME:
  201.             return _filterPositions[0] - _commandCorrections[0];
  202.         case e.VK_END:
  203.             return _filterPositions[_filterCount-1] - _commandCorrections[_filterCount-1];
  204.         }
  205.         if (matchFilter(key)) {
  206.             clearSelectedText(selStart, selEnd, newData);
  207.             if      (eShiftLower == _shiftState)
  208.                 key = Character.toLowerCase(key);
  209.             else if (eShiftUpper == _shiftState)
  210.                 key = Character.toUpperCase(key);
  211.             newData.setCharAt(pos, key);
  212.             int newpos = nextFilterPos();;  // match: advance to next filter
  213.             return newpos == -1 ? _lastFilterPos - 999 : newpos;
  214.         } else              // no match: return with no changes
  215.             return -2;
  216.     }
  217.  
  218.     public boolean stripMask(String data, StringBuffer newData) {
  219.         if (_maskLength == 0){       
  220.             newData.append(data);
  221.             return true;
  222.         }
  223.         resetMaskScan();
  224.         boolean retval = true;
  225.         for (int i = 0; getNextMaskChar() != 0; i++) {
  226.         char c = data.charAt(i);
  227.             if (_curMaskType == filtertype) {
  228.                 if (c != '_')
  229.                     newData.append(c);
  230.                 else if (isMandatory())  // empty filter position
  231.                     retval = false;        // missing mandatory data
  232.             } else if (_curMaskChar == _decimalPoint && _datatype == numbtype) {
  233.                 newData.append(_decimalPoint);
  234.             }
  235.         }
  236.         return retval;
  237.     }
  238.  
  239.     // Return true iff the engine handles the given key stroke.
  240.     public boolean isHandledKey(java.awt.event.KeyEvent e) {
  241.         if (0 == _maskLength)  // if no mask, let component handle all keys
  242.             return false;
  243.         char c = e.getKeyChar();
  244.         if (Character.isISOControl(c)) {
  245.             int k = e.getKeyCode();
  246.             switch (k) {
  247.                 case e.VK_LEFT:
  248.                 case e.VK_RIGHT:
  249.                 case e.VK_HOME:
  250.                 case e.VK_END:
  251.                 return !e.isShiftDown();
  252.             }
  253.             switch (c) {
  254.                 case e.VK_BACK_SPACE:
  255.                 case e.VK_DELETE:
  256.                 return true;
  257.                 default:
  258.                 return false;
  259.             }
  260.         }
  261.         return true;
  262.     }
  263.  
  264.     public String cut(String data, int selStart, int selEnd, StringBuffer newData) {
  265.         newData.append(data);
  266.         setMaskPos(selStart);
  267.         clearSelectedText(selStart, selEnd, newData);
  268.         return data.substring(selStart, selEnd);
  269.     }
  270.  
  271.     public int paste(String data, String pasteData, int pos, StringBuffer newData, int selStart, int selEnd) {
  272.         boolean hasSelection = selStart < selEnd;
  273.         if (hasSelection)
  274.             pos = selStart;
  275.         if (!setMaskPos(pos))
  276.             return -1;
  277.         StringBuffer sb = new StringBuffer(data);
  278.         int len = pasteData.length();
  279.         KeyEvent e = new KeyEvent(new TextField(), 0, 0, 0, 0);
  280.         String s = new String(sb.toString());
  281.         int newpos = pos;
  282.         for (int i = 0; i < len; i++) {
  283.             char c = pasteData.charAt(i);
  284.             e.setKeyChar(c);
  285.             e.setKeyCode(c);
  286.             sb = new StringBuffer();
  287.             int selstart = 0, selend = 0;
  288.             if (hasSelection && newpos >= selStart && newpos < selEnd) {
  289.                 if (i == 0) {
  290.                     selstart = selStart;
  291.                     selend = selEnd;
  292.                 } 
  293.                 else {
  294.                     selstart = newpos;
  295.                     selend = newpos + 1;
  296.                 }
  297.             }
  298.             newpos = processKey(e, newpos, s, sb, selstart, selend);
  299.             if (newpos == -1 || newpos == -2) {
  300.                 break;  // next paste character was rejected by mask
  301.             }
  302.             s = sb.toString();
  303.         }
  304.         newData.append(s);
  305.         return newpos;
  306.     }
  307.  
  308.     //fix for 68889
  309.     public String getMatchedText ( String t ) {
  310.         if ( debug ) {
  311.             System.out.println ( "Input text : " + t ) ;
  312.         }
  313.         //Initailize the return stringbuffer
  314.         StringBuffer retString = new StringBuffer ( );
  315.         
  316.         if ( t != null && t.length() > 0 ) {//there is some text
  317.         
  318.             //if mask is "", then do not do anything
  319.             String mask = getMask() ;
  320.             if ( mask.length() > 0 ) {//there is some mask
  321.                 int textCharCounter = 0;
  322.                 java.text.StringCharacterIterator maskIterator = new java.text.StringCharacterIterator( mask );
  323.                 
  324.                 //iterate for each mask character - also means that if the text provided 
  325.                 //is more the extra char will be neglected
  326.                 //used do while iteration so that the substatement is executed
  327.                 //atleast once
  328.                 do   {
  329.                 
  330.                     char textChar = '_';
  331.                     char maskChar = maskIterator.current();
  332.                     
  333.                     if ( textCharCounter < t.length () ) {//sufficient text
  334.                         //we are still within the text 
  335.                         textChar = t.charAt ( textCharCounter ) ;
  336.                         if (     isFilter  ( maskChar ) ) { //if the mask char is a filter 
  337.                             
  338.                             //    if it matches with the filter, type accept it 
  339.                             if ( matchFilter ( textChar , maskChar ) ) {
  340.                                 retString.append ( textChar );
  341.                             }
  342.                             else {
  343.                                 //    otherwise use '_'
  344.                                 retString.append ( '_' );
  345.                             
  346.                             }
  347.                             
  348.                         }
  349.                         else if (isCommand ( maskChar ) ) {//if the mask char is a command 
  350.                             //handle case conversion and escape command
  351.                             //in all these cases, the current mask is just a command
  352.                             //that is applied to the next mask filter. so get it.
  353.                             maskIterator.next();
  354.                             if ( maskChar == '>' ) {//command : convert to upper case
  355.                                 //    if it matches with the filter, type accept it 
  356.                                 if ( matchFilter ( textChar , maskIterator.current()) ) {
  357.                                     retString.append ( Character.toUpperCase( textChar ));
  358.                                 }
  359.                                 else {
  360.                                     //    otherwise use '_'
  361.                                     retString.append ( '_' );
  362.                                 }
  363.                             }
  364.                             else if ( maskChar == '<' ){//command : convert to lower case
  365.                                 //    if it matches with the filter, type accept it 
  366.                                 if ( matchFilter ( textChar , maskIterator.current()) ) {
  367.                                     retString.append ( Character.toLowerCase( textChar ));
  368.                                 }
  369.                                 else {
  370.                                     //    otherwise use '_'
  371.                                     retString.append ( '_' );
  372.                                 }
  373.                                 
  374.                             }
  375.                             else {//escape character - so append mask char as a literal
  376.                                 retString.append ( maskIterator.current() );
  377.                             }
  378.                         
  379.                         }
  380.                         else {//if the mask char is a literal
  381.                             //otherwise neglect the text char. append the masks char 
  382.                             //because it is a mask literal
  383.                             retString.append ( maskChar );
  384.                         }
  385.                     }
  386.                     else {//insufficient text - text length < mask length
  387.                         //    otherwise use '_'
  388.                         retString.append ( '_' );
  389.                             
  390.                     }
  391.                     
  392.                     textCharCounter ++;//increment text counter
  393.                 
  394.                 } while ( maskIterator.next() != maskIterator.DONE ) ;
  395.                     
  396.             } 
  397.             else {//there is no mask - append the input string as it is.
  398.                 retString.append ( t ) ;
  399.             }
  400.         }
  401.         else {//there is no text or it is null
  402.             //do nothing
  403.         }
  404.         
  405.         if ( debug ) {
  406.             System.out.println ( "Output text : " + retString ) ;
  407.         }
  408.         
  409.         return retString.toString() ;
  410.         
  411.     }
  412.  
  413.  
  414.     boolean clearSelectedText(int selStart, int selEnd, StringBuffer newData) {
  415.         if (selEnd > selStart) {  // only if selected text exists
  416.             // save mask scan state
  417.             int curMaskPos = _curMaskPos;
  418.             int nextMaskPos = _nextMaskPos;
  419.             int curMaskType = _curMaskType;
  420.             char curMaskChar = _curMaskChar;
  421.             char lastMaskChar = _lastMaskChar;
  422.             char decimalPoint = _decimalPoint;
  423.             int commandCorrection = _commandCorrection;
  424.             int shiftState = _shiftState;
  425.  
  426.             setMaskPos(selStart);
  427.             int outpos = selStart;   // track input position
  428.             char c = _curMaskChar;
  429.             while (outpos < selEnd && c != 0) {
  430.                 if (_curMaskType == filtertype)
  431.                 c = '_';
  432.                 newData.setCharAt(outpos++, c);
  433.                 c = getNextMaskChar();
  434.             }
  435.  
  436.             // restore mask scan state
  437.             _curMaskPos = curMaskPos;
  438.             _nextMaskPos = nextMaskPos;
  439.             _curMaskType = curMaskType;
  440.             _curMaskChar = curMaskChar;
  441.             _lastMaskChar = lastMaskChar;
  442.             _decimalPoint = decimalPoint;
  443.             _commandCorrection = commandCorrection;
  444.             _shiftState = shiftState;
  445.             return true;
  446.         }
  447.         return false;
  448.     }
  449.  
  450.     // Set new position in mask.  Return false iff it is out of bounds.
  451.     boolean setMaskPos(int pos) {
  452.         if (pos < 0)
  453.             return false;
  454.         resetMaskScan();
  455.         _inRange = true;
  456.         while (pos-- >= 0)
  457.             if (getNextMaskChar() == 0)
  458.                 return _inRange = false;
  459.         return true;
  460.     }
  461.  
  462.     // Returns the position in the mask of the first filter that follows the
  463.     // current position.
  464.     int nextFilterPos() {
  465.         while (getNextMaskChar() != 0)
  466.             if (_curMaskType == filtertype)
  467.                 return _curMaskPos - _commandCorrection;
  468.         return -1;
  469.     }
  470.  
  471.   // Returns the position in the mask of the filter that precedes the
  472.   // current position.  Return of -1 means no previous filter was found.
  473.     int prevFilterPos() {
  474.         int oldPos = _curMaskPos;
  475.         resetMaskScan();
  476.         int prevFilterPos = -1;
  477.         int prevCommandCorrection = 0;
  478.         while (nextFilterPos() != -1) {
  479.             if (_curMaskPos >= oldPos) { // scanned past previous filter
  480.                 if (!_inRange)
  481.                 return _curMaskPos - _commandCorrection;
  482.                 break;
  483.             }
  484.             prevFilterPos = _curMaskPos;  // save pos info on this filter
  485.             prevCommandCorrection = _commandCorrection;
  486.         }
  487.         return prevFilterPos - prevCommandCorrection;
  488.     }
  489.  
  490.     // Return true iff key is accepted by current filter
  491.     boolean matchFilter(char key) {
  492.         return matchFilter ( key , _curMaskChar ) ;
  493.     }
  494.   
  495.     // Return true iff key is accepted by current filter
  496.     boolean matchFilter(char key , char maskChar ) {
  497.         switch ( maskChar ) {
  498.             case '0':   // any digit
  499.                 return Character.isDigit(key);
  500.             case '9':   // any digit or space
  501.                 return Character.isDigit(key) || Character.isSpaceChar(key);
  502.             case '#':   // digit, space or sign
  503.                 return Character.isDigit(key) || Character.isSpaceChar(key) ||
  504.                     key == '+' || key == '-';
  505.             case 'L':   // letter
  506.             case '?':
  507.                 return Character.isLetter(key);
  508.             case 'A':   // letter or digit
  509.             case 'a':
  510.                 return Character.isLetterOrDigit(key);
  511.             case '&':   // any character
  512.             case 'C':
  513.                 //some ignorable characters cause problems while 
  514.                 //auto-repeating back-space and other keys. so filter them out.
  515.                 return ( !Character.isIdentifierIgnorable ( key ));
  516.             default:
  517.                 return false;
  518.         }
  519.     }
  520.  
  521.     // Prepare mask to be scanned from the beginning.
  522.     void resetMaskScan() {
  523.         _curMaskPos = 0;
  524.         _nextMaskPos = 0;   // set first char to get
  525.         _lastMaskChar = 0;
  526.         _commandCorrection = 0;
  527.         _curMaskType = 0;
  528.         _shiftState = eShiftNul;
  529.     }
  530.  
  531.     char getNextMaskChar() {
  532.         while (true) {        // loop through command chars
  533.             if (_nextMaskPos >= _maskLength)
  534.                 return 0;
  535.             _lastMaskChar = _curMaskChar;
  536.             _curMaskChar = _mask.charAt(_nextMaskPos++);
  537.             if (isCommand()) {
  538.                 _commandCorrection++;
  539.                 if ('<' == _curMaskChar)
  540.                     _shiftState = eShiftLower;
  541.                 else if ('>' == _curMaskChar)
  542.                     _shiftState = eShiftUpper;
  543.             } else
  544.                 break;
  545.         }
  546.         _curMaskType = literaltype;
  547.         if (_lastMaskChar != '\\' && isFilter())
  548.             _curMaskType = filtertype;
  549.         _curMaskPos = _nextMaskPos - 1;
  550.         return _curMaskChar;
  551.     }
  552.  
  553.     // Return true iff key is a cursor navigation key.
  554.     boolean isNavKey(int key) {
  555.         switch (key) {
  556.             default:
  557.                 return false;
  558.             case java.awt.event.KeyEvent.VK_LEFT:
  559.             case java.awt.event.KeyEvent.VK_RIGHT:
  560.             case java.awt.event.KeyEvent.VK_BACK_SPACE:
  561.             case java.awt.event.KeyEvent.VK_HOME:
  562.             case java.awt.event.KeyEvent.VK_END:
  563.         }
  564.         return true;
  565.     }
  566.  
  567.     boolean isFilter()    { return isFilter(_curMaskChar); }
  568.     boolean isCommand()   { return isCommand(_curMaskChar); }
  569.     boolean isMandatory() { return isMandatory(_curMaskChar); }
  570.     
  571.     //add other utility methods
  572.     boolean isFilter( char c )    { return -1 != "09#aAL?&C".indexOf( c ); }
  573.     boolean isCommand( char c )   { return -1 != "<>\\"     .indexOf( c ); }
  574.     boolean isMandatory( char c ) { return -1 != "0LA&"     .indexOf( c ); }
  575.     
  576.  
  577.  
  578.     // Called by all ctors
  579.     void init() {}
  580.  
  581.     // Variables
  582.     String  _mask             = ""      ; // current mask
  583.     int     _maskLength       = 0       ; // its length
  584.     int     _datatype         = texttype; // data type of masked field
  585.     int     _filterCount      = 0       ; // count of filters in mask
  586.     int     _maskCount        = 0       ; // count of displayable characters
  587.     int     _firstFilterPos   = 0       ;
  588.     int     _lastFilterPos    = 0       ;
  589.     int[]   _filterPositions            ; // track all filter positions
  590.     int[]   _commandCorrections         ; // track all command corrections
  591.     boolean _inRange          = true    ; // true if last mask position request is in range
  592.  
  593.     // State variables for scanning the mask
  594.     int  _curMaskPos        = 0;          // position of current mask character
  595.     int  _nextMaskPos       = 0;          // position of next mask character
  596.     int  _curMaskType       = nulltype;   // type of current mask character
  597.     char _curMaskChar       = 0;
  598.     char _lastMaskChar      = 0;
  599.     int  _commandCorrection = 0;
  600.     int  _shiftState        = eShiftNul;
  601.     char _decimalPoint      = '.';
  602.  
  603.     // Internal mask command type codes
  604.     static final int nulltype    = 0;
  605.     static final int filtertype  = 1;
  606.     static final int literaltype = 2;
  607.  
  608.     // Internal shift states
  609.     static final int eShiftNul   = 0;
  610.     static final int eShiftUpper = 1;
  611.     static final int eShiftLower = 2;
  612.         
  613.         //debug flag
  614.     private boolean          debug          = false;
  615.         
  616. }
  617.