JAL-1807
[jalview.git] / src / com / stevesoft / pat / ReplaceRule.java
index d4f09bb..4805ed4 100755 (executable)
-//\r
-// This software is now distributed according to\r
-// the Lesser Gnu Public License.  Please see\r
-// http://www.gnu.org/copyleft/lesser.txt for\r
-// the details.\r
-//    -- Happy Computing!\r
-//\r
-package com.stevesoft.pat;\r
-\r
-import java.util.*;\r
-\r
-/** ReplaceRule is a singly linked list of Objects which describe how\r
-    to replace the matched portion of a String.  The only member method\r
-    that you absolutely need to define to use this class is apply(StringBuffer,RegRes) --\r
-    although you may want define toString1() and clone1() (if you are\r
-    unhappy with the default methods) that are needed by\r
-    the clone() or toString() methods on this class.\r
-    During the replacement process, each ReplaceRule tells the replacer\r
-    what to add to StringBuffer and uses the contents of the Regular\r
-    expression result to get the information it needs to\r
-    do this.  Here is an <a href="http://javaregex.com/code/fancy.java.html">example</a>\r
-\r
-    @see com.stevesoft.pat.NullRule\r
-    @see com.stevesoft.pat.AmpersandRule\r
-    @see com.stevesoft.pat.BackRefRule\r
-    @see com.stevesoft.pat.LeftRule\r
-    @see com.stevesoft.pat.RightRule\r
-    @see com.stevesoft.pat.StringRule\r
- */\r
-public abstract class ReplaceRule\r
-{\r
-  /** points to the next ReplaceRule in the linked list. */\r
-  protected ReplaceRule next = null;\r
-  /** This function appends to the StringBufferLike the text you want\r
-      to replaced the portion of the String last matched. */\r
-  public abstract void apply(StringBufferLike sb, RegRes r);\r
-\r
-  /** A rule describing how to clone only the current ReplaceRule,\r
-      and none of the others in this linked list.  It is called by\r
-      clone() for each item in the list. */\r
-  public Object clone1()\r
-  {\r
-    return new RuleHolder(this);\r
-  }\r
-\r
-  public final Object clone()\r
-  {\r
-    ReplaceRule x = (ReplaceRule) clone1();\r
-    ReplaceRule xsav = x;\r
-    ReplaceRule y = this;\r
-    while (y.next != null)\r
-    {\r
-      x.next = (ReplaceRule) y.next.clone1();\r
-      x.name = y.name;\r
-      x = x.next;\r
-      y = y.next;\r
-    }\r
-    return xsav;\r
-  }\r
-\r
-  static ReplaceRule add(ReplaceRule head, ReplaceRule adding)\r
-  {\r
-    if (head == null)\r
-    {\r
-      return head = adding;\r
-    }\r
-    head.addRule(adding);\r
-    return head;\r
-  }\r
-\r
-  public ReplaceRule add(ReplaceRule adding)\r
-  {\r
-    return add(this, adding);\r
-  }\r
-\r
-  /** Add another ReplaceRule to the linked list. */\r
-  public void addRule(ReplaceRule r)\r
-  {\r
-    if (next == null)\r
-    {\r
-      next = r;\r
-    }\r
-    else\r
-    {\r
-      next.addRule(r);\r
-    }\r
-  }\r
-\r
-  static Regex getvar = null;\r
-  final static Regex getv()\r
-  {\r
-    // Thanks to Michael Jimenez for pointing out the need\r
-    // to clone getvar rather than simply returning it.\r
-    // Previously this was not thread safe.\r
-    //if(getvar != null) return getvar;\r
-    if (getvar != null)\r
-    {\r
-      return (Regex) getvar.clone();\r
-    }\r
-    getvar =\r
-        new Regex(\r
-            "(?:\\\\(\\d+)|" + // ref 1\r
-            "\\$(?:" +\r
-            "(\\d+)|" + // ref 2\r
-            "(\\w+)|" + // ref 3\r
-            "([&'`])|" + // ref 4\r
-            "\\{(?:(\\d+)|" + // ref 5\r
-            "([^\n}\\\\]+))}" + // ref 6\r
-            ")|" +\r
-            "\\\\([nrbtaef])|" + // ref 7\r
-            "\\\\c([\u0000-\uFFFF])|" + // ref 8\r
-            "\\\\x([A-Fa-f0-9]{2})|" + // ref 9\r
-            "\\\\([\u0000-\uFFFF])" + // ref 10\r
-            ")");\r
-    getvar.optimize();\r
-    return getvar;\r
-  }\r
-\r
-  /** Compile a ReplaceRule using the text that would go between\r
-      the second and third /'s in a typical substitution pattern\r
-      in Perl: s/ ... / <i>The argument to ReplaceRule.perlCode</i> /.\r
-   */\r
-  public static ReplaceRule perlCode(String s)\r
-  {\r
-    //String sav_backGs = Regex.backGs;\r
-    //int sav_backGto = Regex.backGto;\r
-    try\r
-    {\r
-      int mf = 0, mt = 0;\r
-      Regex gv = getv();\r
-      ReplaceRule head = null;\r
-      Object tmp = null;\r
-      while (gv.searchFrom(s, mt))\r
-      {\r
-        int off = Regex.BackRefOffset - 1;\r
-        mf = gv.matchedFrom();\r
-        if (mf > mt)\r
-        {\r
-          head = add(head,\r
-                     new StringRule(s.substring(mt, mf)));\r
-        }\r
-        String var = null;\r
-        if ( (var = gv.stringMatched(1 + off)) != null\r
-            || (var = gv.stringMatched(2 + off)) != null\r
-            || (var = gv.stringMatched(5 + off)) != null)\r
-        {\r
-          int d = 0;\r
-          for (int i = 0; i < var.length(); i++)\r
-          {\r
-            d = 8 * d + (var.charAt(i) - '0');\r
-          }\r
-          if (var.length() == 1)\r
-          {\r
-            head = add(head, new BackRefRule(d));\r
-          }\r
-          else\r
-          {\r
-            head = new StringRule("" + (char) d);\r
-          }\r
-        }\r
-        else if (\r
-            (var = gv.stringMatched(10 + off)) != null)\r
-        {\r
-          if ("QELlUu".indexOf(var) >= 0)\r
-          {\r
-            head = add(head, new CodeRule(var.charAt(0)));\r
-          }\r
-          else\r
-          {\r
-            head = add(head, new StringRule(var));\r
-          }\r
-        }\r
-        else if (\r
-            (var = gv.stringMatched(3 + off)) != null\r
-            || (var = gv.stringMatched(4 + off)) != null\r
-            || (var = gv.stringMatched(6 + off)) != null)\r
-        {\r
-          String arg = "";\r
-          int pc;\r
-          if ( (pc = var.indexOf(':')) > 0)\r
-          {\r
-            arg = var.substring(pc + 1);\r
-            var = var.substring(0, pc);\r
-          }\r
-          if (var.equals("&") || var.equals("MATCH"))\r
-          {\r
-            head = add(head, new AmpersandRule());\r
-          }\r
-          else if (var.equals("`") || var.equals("PREMATCH"))\r
-          {\r
-            head = add(head, new LeftRule());\r
-          }\r
-          else if (var.equals("'") || var.equals("POSTMATCH"))\r
-          {\r
-            head = add(head, new RightRule());\r
-          }\r
-          else if (var.equals("WANT_MORE_TEXT"))\r
-          {\r
-            head = add(head, new WantMoreTextReplaceRule());\r
-          }\r
-          else if (var.equals("POP"))\r
-          {\r
-            head = add(head, new PopRule());\r
-          }\r
-          else if (var.startsWith("+") && (tmp = defs.get(var.substring(1))) != null)\r
-          {\r
-            if (tmp instanceof Regex)\r
-            {\r
-              head = add(head, new PushRule(var.substring(1), (Regex) tmp));\r
-            }\r
-            else if (tmp instanceof Transformer)\r
-            {\r
-              head = add(head, new PushRule(var.substring(1), (Transformer) tmp));\r
-            }\r
-            else\r
-            {\r
-              head = add(head, new StringRule("${" + var + "}"));\r
-            }\r
-          }\r
-          else if (var.startsWith("=") && (tmp = defs.get(var.substring(1))) != null)\r
-          {\r
-            if (tmp instanceof Regex)\r
-            {\r
-              head = add(head, new ChangeRule(var.substring(1), (Regex) tmp));\r
-            }\r
-            else if (tmp instanceof Transformer)\r
-            {\r
-              head = add(head,\r
-                         new ChangeRule(var.substring(1), (Transformer) tmp));\r
-            }\r
-            else\r
-            {\r
-              head = add(head, new StringRule("${" + var + "}"));\r
-            }\r
-          }\r
-          else if ( (tmp = defs.get(var)) != null)\r
-          {\r
-            if (tmp instanceof ReplaceRule)\r
-            {\r
-              ReplaceRule alt = ( (ReplaceRule) tmp).arg(arg);\r
-              if (alt == null)\r
-              {\r
-                alt = ( (ReplaceRule) tmp);\r
-              }\r
-              head = add(head, (ReplaceRule) (alt.clone()));\r
-            }\r
-          }\r
-          else // can't figure out how to transform this thing...\r
-          {\r
-            head = add(head, new StringRule("${" + var + "}"));\r
-          }\r
-        }\r
-        else if (\r
-            (var = gv.stringMatched(7 + off)) != null)\r
-        {\r
-          char c = var.charAt(0);\r
-          if (c == 'n')\r
-          {\r
-            head = add(head, new StringRule("\n"));\r
-          }\r
-          else if (c == 't')\r
-          {\r
-            head = add(head, new StringRule("\t"));\r
-          }\r
-          else if (c == 'r')\r
-          {\r
-            head = add(head, new StringRule("\r"));\r
-          }\r
-          else if (c == 'b')\r
-          {\r
-            head = add(head, new StringRule("\r"));\r
-          }\r
-          else if (c == 'a')\r
-          {\r
-            head = add(head, new StringRule("" + (char) 7));\r
-          }\r
-          else if (c == 'e')\r
-          {\r
-            head = add(head, new StringRule("" + (char) 27));\r
-          }\r
-          else if (c == 'f')\r
-          {\r
-            head = add(head, new StringRule("" + (char) 12));\r
-          }\r
-        }\r
-        else if (\r
-            (var = gv.stringMatched(8 + off)) != null)\r
-        {\r
-          char c = var.charAt(0);\r
-          if (c < Ctrl.cmap.length)\r
-          {\r
-            c = Ctrl.cmap[c];\r
-          }\r
-          head = add(head, new StringRule("" + c));\r
-        }\r
-        else if (\r
-            (var = gv.stringMatched(9 + off)) != null)\r
-        {\r
-          int d =\r
-              16 * getHexDigit(var.charAt(0)) +\r
-              getHexDigit(var.charAt(1));\r
-          head = add(head, new StringRule("" + (char) d));\r
-        }\r
-        mt = gv.matchedTo();\r
-      }\r
-      if (mt <= s.length())\r
-      {\r
-        head = add(head, new StringRule(s.substring(mt)));\r
-      }\r
-      return head;\r
-    }\r
-    finally\r
-    {\r
-      //Regex.backGs = sav_backGs;\r
-      //Regex.backGto = sav_backGto;\r
-    }\r
-  }\r
-\r
-  static Hashtable defs = new Hashtable();\r
-  public static boolean isDefined(String s)\r
-  {\r
-    return defs.get(s) != null;\r
-  }\r
-\r
-  public static void define(String s, Regex r)\r
-  {\r
-    defs.put(s, r);\r
-  }\r
-\r
-  public static void define(String s, ReplaceRule r)\r
-  {\r
-    defs.put(s, r);\r
-    r.name = s;\r
-  }\r
-\r
-  String name = getClass().getName();\r
-\r
-  public static void define(String s, Transformer t)\r
-  {\r
-    defs.put(s, t);\r
-  }\r
-\r
-  public static void undefine(String s)\r
-  {\r
-    defs.remove(s);\r
-  }\r
-\r
-  /** This tells how to convert just the current element (and none\r
-      of the other items in the linked list) to a String. This\r
-      method is called by toString() for each item in the linked\r
-      list. */\r
-  public String toString1()\r
-  {\r
-    return "${" + name + "}";\r
-  }\r
-\r
-  /** Convert to a String. */\r
-  public final String toString()\r
-  {\r
-    StringBuffer sb = new StringBuffer();\r
-    sb.append(toString1());\r
-    ReplaceRule rr = this.next;\r
-    while (rr != null)\r
-    {\r
-      sb.append(rr.toString1());\r
-      rr = rr.next;\r
-    }\r
-    return sb.toString();\r
-  }\r
-\r
-  /** Modified the behavior of a ReplaceRule by supplying\r
-      an argument.  If a ReplaceRule named "foo" is defined\r
-      and the pattern "s/x/${foo:5}/" is given to Regex.perlCode,\r
-      then the "foo" the definition of "foo" will be retrieved\r
-      and arg("5") will be called.  If the result is non-null,\r
-      that is the ReplaceRule that will be used.  If the result\r
-      is null, then the pattern works just as if it were\r
-      "s/x/${foo}/".\r
-      @see com.stevesoft.pat.Validator#arg(java.lang.String)\r
-   */\r
-  public ReplaceRule arg(String s)\r
-  {\r
-    return null;\r
-  }\r
-\r
-  static int getHexDigit(char c)\r
-  {\r
-    if (c >= '0' && c <= '9')\r
-    {\r
-      return c - '0';\r
-    }\r
-    if (c >= 'a' && c <= 'f')\r
-    {\r
-      return c - 'a' + 10;\r
-    }\r
-    return c - 'A' + 10;\r
-  }\r
-}\r
+//
+// This software is now distributed according to
+// the Lesser Gnu Public License.  Please see
+// http://www.gnu.org/copyleft/lesser.txt for
+// the details.
+//    -- Happy Computing!
+//
+package com.stevesoft.pat;
+
+import java.util.*;
+
+/**
+ * ReplaceRule is a singly linked list of Objects which describe how to replace
+ * the matched portion of a String. The only member method that you absolutely
+ * need to define to use this class is apply(StringBuffer,RegRes) -- although
+ * you may want define toString1() and clone1() (if you are unhappy with the
+ * default methods) that are needed by the clone() or toString() methods on this
+ * class. During the replacement process, each ReplaceRule tells the replacer
+ * what to add to StringBuffer and uses the contents of the Regular expression
+ * result to get the information it needs to do this. Here is an <a
+ * href="http://javaregex.com/code/fancy.java.html">example</a>
+ * 
+ * @see com.stevesoft.pat.NullRule
+ * @see com.stevesoft.pat.AmpersandRule
+ * @see com.stevesoft.pat.BackRefRule
+ * @see com.stevesoft.pat.LeftRule
+ * @see com.stevesoft.pat.RightRule
+ * @see com.stevesoft.pat.StringRule
+ */
+public abstract class ReplaceRule
+{
+  /** points to the next ReplaceRule in the linked list. */
+  protected ReplaceRule next = null;
+
+  /**
+   * This function appends to the StringBufferLike the text you want to replaced
+   * the portion of the String last matched.
+   */
+  public abstract void apply(StringBufferLike sb, RegRes r);
+
+  /**
+   * A rule describing how to clone only the current ReplaceRule, and none of
+   * the others in this linked list. It is called by clone() for each item in
+   * the list.
+   */
+  public Object clone1()
+  {
+    return new RuleHolder(this);
+  }
+
+  public final Object clone()
+  {
+    ReplaceRule x = (ReplaceRule) clone1();
+    ReplaceRule xsav = x;
+    ReplaceRule y = this;
+    while (y.next != null)
+    {
+      x.next = (ReplaceRule) y.next.clone1();
+      x.name = y.name;
+      x = x.next;
+      y = y.next;
+    }
+    return xsav;
+  }
+
+  static ReplaceRule add(ReplaceRule head, ReplaceRule adding)
+  {
+    if (head == null)
+    {
+      return head = adding;
+    }
+    head.addRule(adding);
+    return head;
+  }
+
+  public ReplaceRule add(ReplaceRule adding)
+  {
+    return add(this, adding);
+  }
+
+  /** Add another ReplaceRule to the linked list. */
+  public void addRule(ReplaceRule r)
+  {
+    if (next == null)
+    {
+      next = r;
+    }
+    else
+    {
+      next.addRule(r);
+    }
+  }
+
+  static Regex getvar = null;
+
+  private static Regex getv()
+  {
+    // Thanks to Michael Jimenez for pointing out the need
+    // to clone getvar rather than simply returning it.
+    // Previously this was not thread safe.
+    // if(getvar != null) return getvar;
+    if (getvar != null)
+    {
+      return (Regex) getvar.clone();
+    }
+    getvar = new Regex("(?:\\\\(\\d+)|" + // ref 1
+            "\\$(?:" + "(\\d+)|" + // ref 2
+            "(\\w+)|" + // ref 3
+            "([&'`])|" + // ref 4
+            "\\{(?:(\\d+)|" + // ref 5
+            "([^\n}\\\\]+))}" + // ref 6
+            ")|" + "\\\\([nrbtaef])|" + // ref 7
+            "\\\\c([\u0000-\uFFFF])|" + // ref 8
+            "\\\\x([A-Fa-f0-9]{2})|" + // ref 9
+            "\\\\([\u0000-\uFFFF])" + // ref 10
+            ")", "");
+    getvar.optimize();
+    return getvar;
+  }
+
+  /**
+   * Compile a ReplaceRule using the text that would go between the second and
+   * third /'s in a typical substitution pattern in Perl: s/ ... / <i>The
+   * argument to ReplaceRule.perlCode</i> /.
+   */
+  public static ReplaceRule perlCode(String s)
+  {
+    // String sav_backGs = Regex.backGs;
+    // int sav_backGto = Regex.backGto;
+    try
+    {
+      int mf = 0, mt = 0;
+      Regex gv = getv();
+      ReplaceRule head = null;
+      Object tmp = null;
+      while (gv.searchFrom(s, mt))
+      {
+        int off = Regex.BackRefOffset - 1;
+        mf = gv.matchedFrom();
+        if (mf > mt)
+        {
+          head = add(head, new StringRule(s.substring(mt, mf)));
+        }
+        String var = null;
+        if ((var = gv.stringMatchedI(1 + off)) != null
+                || (var = gv.stringMatchedI(2 + off)) != null
+                || (var = gv.stringMatchedI(5 + off)) != null)
+        {
+          int d = 0;
+          for (int i = 0; i < var.length(); i++)
+          {
+            d = 8 * d + (var.charAt(i) - '0');
+          }
+          if (var.length() == 1)
+          {
+            head = add(head, new BackRefRule(d));
+          }
+          else
+          {
+            head = new StringRule("" + (char) d);
+          }
+        }
+        else if ((var = gv.stringMatchedI(10 + off)) != null)
+        {
+          if ("QELlUu".indexOf(var) >= 0)
+          {
+            head = add(head, new CodeRule(var.charAt(0)));
+          }
+          else
+          {
+            head = add(head, new StringRule(var));
+          }
+        }
+        else if ((var = gv.stringMatchedI(3 + off)) != null
+                || (var = gv.stringMatchedI(4 + off)) != null
+                || (var = gv.stringMatchedI(6 + off)) != null)
+        {
+          String arg = "";
+          int pc;
+          if ((pc = var.indexOf(':')) > 0)
+          {
+            arg = var.substring(pc + 1);
+            var = var.substring(0, pc);
+          }
+          if (var.equals("&") || var.equals("MATCH"))
+          {
+            head = add(head, new AmpersandRule());
+          }
+          else if (var.equals("`") || var.equals("PREMATCH"))
+          {
+            head = add(head, new LeftRule());
+          }
+          else if (var.equals("'") || var.equals("POSTMATCH"))
+          {
+            head = add(head, new RightRule());
+          }
+          else if (var.equals("WANT_MORE_TEXT"))
+          {
+            head = add(head, new WantMoreTextReplaceRule());
+          }
+          else if (var.equals("POP"))
+          {
+            head = add(head, new PopRule());
+          }
+          else if (var.startsWith("+")
+                  && (tmp = defs.get(var.substring(1))) != null)
+          {
+            if (tmp instanceof Regex)
+            {
+              head = add(head, new PushRule(var.substring(1), (Regex) tmp));
+            }
+            else if (tmp instanceof Transformer)
+            {
+              head = add(head, new PushRule(var.substring(1),
+                      (Transformer) tmp));
+            }
+            else
+            {
+              head = add(head, new StringRule("${" + var + "}"));
+            }
+          }
+          else if (var.startsWith("=")
+                  && (tmp = defs.get(var.substring(1))) != null)
+          {
+            if (tmp instanceof Regex)
+            {
+              head = add(head,
+                      new ChangeRule(var.substring(1), (Regex) tmp));
+            }
+            else if (tmp instanceof Transformer)
+            {
+              head = add(head, new ChangeRule(var.substring(1),
+                      (Transformer) tmp));
+            }
+            else
+            {
+              head = add(head, new StringRule("${" + var + "}"));
+            }
+          }
+          else if ((tmp = defs.get(var)) != null)
+          {
+            if (tmp instanceof ReplaceRule)
+            {
+              ReplaceRule alt = ((ReplaceRule) tmp).arg(arg);
+              if (alt == null)
+              {
+                alt = ((ReplaceRule) tmp);
+              }
+              head = add(head, (ReplaceRule) (alt.clone()));
+            }
+          }
+          else
+          // can't figure out how to transform this thing...
+          {
+            head = add(head, new StringRule("${" + var + "}"));
+          }
+        }
+        else if ((var = gv.stringMatchedI(7 + off)) != null)
+        {
+          char c = var.charAt(0);
+          if (c == 'n')
+          {
+            head = add(head, new StringRule("\n"));
+          }
+          else if (c == 't')
+          {
+            head = add(head, new StringRule("\t"));
+          }
+          else if (c == 'r')
+          {
+            head = add(head, new StringRule("\r"));
+          }
+          else if (c == 'b')
+          {
+            head = add(head, new StringRule("\r"));
+          }
+          else if (c == 'a')
+          {
+            head = add(head, new StringRule("" + (char) 7));
+          }
+          else if (c == 'e')
+          {
+            head = add(head, new StringRule("" + (char) 27));
+          }
+          else if (c == 'f')
+          {
+            head = add(head, new StringRule("" + (char) 12));
+          }
+        }
+        else if ((var = gv.stringMatchedI(8 + off)) != null)
+        {
+          char c = var.charAt(0);
+          if (c < Ctrl.cmap.length)
+          {
+            c = Ctrl.cmap[c];
+          }
+          head = add(head, new StringRule("" + c));
+        }
+        else if ((var = gv.stringMatchedI(9 + off)) != null)
+        {
+          int d = 16 * getHexDigit(var.charAt(0))
+                  + getHexDigit(var.charAt(1));
+          head = add(head, new StringRule("" + (char) d));
+        }
+        mt = gv.matchedTo();
+      }
+      if (mt <= s.length())
+      {
+        head = add(head, new StringRule(s.substring(mt)));
+      }
+      return head;
+    } finally
+    {
+      // Regex.backGs = sav_backGs;
+      // Regex.backGto = sav_backGto;
+    }
+  }
+
+  static Hashtable defs = new Hashtable();
+
+  public static boolean isDefined(String s)
+  {
+    return defs.get(s) != null;
+  }
+
+  public static void define(String s, Regex r)
+  {
+    defs.put(s, r);
+  }
+
+  public static void define(String s, ReplaceRule r)
+  {
+    defs.put(s, r);
+    r.name = s;
+  }
+
+  String name = getClass().getName();
+
+  public static void define(String s, Transformer t)
+  {
+    defs.put(s, t);
+  }
+
+  public static void undefine(String s)
+  {
+    defs.remove(s);
+  }
+
+  /**
+   * This tells how to convert just the current element (and none of the other
+   * items in the linked list) to a String. This method is called by toString()
+   * for each item in the linked list.
+   */
+  public String toString1()
+  {
+    return "${" + name + "}";
+  }
+
+  /** Convert to a String. */
+  public final String toString()
+  {
+    StringBuffer sb = new StringBuffer();
+    sb.append(toString1());
+    ReplaceRule rr = this.next;
+    while (rr != null)
+    {
+      sb.append(rr.toString1());
+      rr = rr.next;
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Modified the behavior of a ReplaceRule by supplying an argument. If a
+   * ReplaceRule named "foo" is defined and the pattern "s/x/${foo:5}/" is given
+   * to Regex.perlCode, then the "foo" the definition of "foo" will be retrieved
+   * and arg("5") will be called. If the result is non-null, that is the
+   * ReplaceRule that will be used. If the result is null, then the pattern
+   * works just as if it were "s/x/${foo}/".
+   * 
+   * @see com.stevesoft.pat.Validator#arg(java.lang.String)
+   */
+  public ReplaceRule arg(String s)
+  {
+    return null;
+  }
+
+  static int getHexDigit(char c)
+  {
+    if (c >= '0' && c <= '9')
+    {
+      return c - '0';
+    }
+    if (c >= 'a' && c <= 'f')
+    {
+      return c - 'a' + 10;
+    }
+    return c - 'A' + 10;
+  }
+}