------------------------------------------------------------------------------
--                                                                          --
--                         GNAT RUNTIME COMPONENTS                          --
--                                                                          --
--                 G N A T . S P E L L I N G _ C H E C K E R                --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--           Copyright (C) 1998-2003 Ada Core Technologies, Inc.            --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
-- for  more details.  You should have  received  a copy of the GNU General --
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
-- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
-- MA 02111-1307, USA.                                                      --
--                                                                          --
-- As a special exception,  if other files  instantiate  generics from this --
-- unit, or you link  this unit with other files  to produce an executable, --
-- this  unit  does not  by itself cause  the resulting  executable  to  be --
-- covered  by the  GNU  General  Public  License.  This exception does not --
-- however invalidate  any other reasons why  the executable file  might be --
-- covered by the  GNU Public License.                                      --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------

package body GNAT.Spelling_Checker is

   ------------------------
   -- Is_Bad_Spelling_Of --
   ------------------------

   function Is_Bad_Spelling_Of
     (Found  : String;
      Expect : String)
      return   Boolean
   is
      FN : constant Natural := Found'Length;
      FF : constant Natural := Found'First;
      FL : constant Natural := Found'Last;

      EN : constant Natural := Expect'Length;
      EF : constant Natural := Expect'First;
      EL : constant Natural := Expect'Last;

   begin
      --  If both strings null, then we consider this a match, but if one
      --  is null and the other is not, then we definitely do not match

      if FN = 0 then
         return (EN = 0);

      elsif EN = 0 then
         return False;

      --  If first character does not match, then definitely not misspelling

      elsif Found (FF) /= Expect (EF) then
         return False;

      --  Not a bad spelling if both strings are 1-2 characters long

      elsif FN < 3 and then EN < 3 then
         return False;

      --  Lengths match. Execute loop to check for a single error, single
      --  transposition or exact match (we only fall through this loop if
      --  one of these three conditions is found).

      elsif FN = EN then
         for J in 1 .. FN - 2 loop
            if Expect (EF + J) /= Found (FF + J) then

               --  If both mismatched characters are digits, then we do
               --  not consider it a misspelling (e.g. B345 is not a
               --  misspelling of B346, it is something quite different)

               if Expect (EF + J) in '0' .. '9'
                 and then Found (FF + J) in '0' .. '9'
               then
                  return False;

               elsif Expect (EF + J + 1) = Found (FF + J + 1)
                 and then Expect (EF + J + 2 .. EL) = Found (FF + J + 2 .. FL)
               then
                  return True;

               elsif Expect (EF + J) = Found (FF + J + 1)
                 and then Expect (EF + J + 1) = Found (FF + J)
                 and then Expect (EF + J + 2 .. EL) = Found (FF + J + 2 .. FL)
               then
                  return True;

               else
                  return False;
               end if;
            end if;
         end loop;

         --  At last character. Test digit case as above, otherwise we
         --  have a match since at most this last character fails to match.

         if Expect (EL) in '0' .. '9'
           and then Found (FL) in '0' .. '9'
           and then Expect (EL) /= Found (FL)
         then
            return False;
         else
            return True;
         end if;

      --  Length is 1 too short. Execute loop to check for single deletion

      elsif FN = EN - 1 then
         for J in 1 .. FN - 1 loop
            if Found (FF + J) /= Expect (EF + J) then
               return Found (FF + J .. FL) = Expect (EF + J + 1 .. EL);
            end if;
         end loop;

         --  If we fall through then the last character was missing, which
         --  we consider to be a match (e.g. found xyz, expected xyza).

         return True;

      --  Length is 1 too long. Execute loop to check for single insertion

      elsif FN = EN + 1 then
         for J in 1 .. EN - 1 loop
            if Found (FF + J) /= Expect (EF + J) then
               return Found (FF + J + 1 .. FL) = Expect (EF + J .. EL);
            end if;
         end loop;

         --  If we fall through then the last character was an additional
         --  character, which is a match (e.g. found xyza, expected xyz).

         return True;

      --  Length is completely wrong

      else
         return False;
      end if;

   end Is_Bad_Spelling_Of;

end GNAT.Spelling_Checker;
