(Fcommandp): Add parens to clarify.
[bpt/emacs.git] / src / casefiddle.c
index ae48880..0e9e1ba 100644 (file)
@@ -1,12 +1,12 @@
 /* GNU Emacs case conversion functions.
-   Copyright (C) 1985,94,97,98,99, 2001, 2002, 2004
-   Free Software Foundation, Inc.
+   Copyright (C) 1985, 1994, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
+                 2005, 2006, 2007 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 
 #include <config.h>
@@ -45,104 +45,73 @@ casify_object (flag, obj)
   if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1]))
     Fset_case_table (current_buffer->downcase_table);
 
-  while (1)
+  if (INTEGERP (obj))
     {
-      if (INTEGERP (obj))
+      int flagbits = (CHAR_ALT | CHAR_SUPER | CHAR_HYPER
+                     | CHAR_SHIFT | CHAR_CTL | CHAR_META);
+      int flags = XINT (obj) & flagbits;
+
+      /* If the character has higher bits set
+        above the flags, return it unchanged.
+        It is not a real character.  */
+      if ((unsigned) XFASTINT (obj) > (unsigned) flagbits)
+       return obj;
+
+      c = DOWNCASE (XFASTINT (obj) & ~flagbits);
+      if (inword)
+       XSETFASTINT (obj, c | flags);
+      else if (c == (XFASTINT (obj) & ~flagbits))
        {
-         int flagbits = (CHAR_ALT | CHAR_SUPER | CHAR_HYPER
-                         | CHAR_SHIFT | CHAR_CTL | CHAR_META);
-         int flags = XINT (obj) & flagbits;
-
-         /* If the character has higher bits set
-            above the flags, return it unchanged.
-            It is not a real character.  */
-         if ((unsigned) XFASTINT (obj) > (unsigned) flagbits)
-           return obj;
-
-         c = DOWNCASE (XFASTINT (obj) & ~flagbits);
-         if (inword)
-           XSETFASTINT (obj, c | flags);
-         else if (c == (XFASTINT (obj) & ~flagbits))
-           {
-             c = UPCASE1 ((XFASTINT (obj) & ~flagbits));
-             XSETFASTINT (obj, c | flags);
-           }
-         return obj;
+         c = UPCASE1 ((XFASTINT (obj) & ~flagbits));
+         XSETFASTINT (obj, c | flags);
        }
+      return obj;
+    }
 
-      if (STRINGP (obj))
-       {
-         int multibyte = STRING_MULTIBYTE (obj);
-
-         obj = Fcopy_sequence (obj);
-         len = SBYTES (obj);
-
-         /* Scan all single-byte characters from start of string.  */
-         for (i = 0; i < len;)
-           {
-             c = SREF (obj, i);
-
-             if (multibyte && c >= 0x80)
-               /* A multibyte character can't be handled in this
-                   simple loop.  */
-               break;
-             if (inword && flag != CASE_CAPITALIZE_UP)
-               c = DOWNCASE (c);
-             else if (!UPPERCASEP (c)
-                      && (!inword || flag != CASE_CAPITALIZE_UP))
-               c = UPCASE1 (c);
-             /* If this char won't fit in a single-byte string.
-                fall out to the multibyte case.  */
-             if (multibyte ? ! ASCII_BYTE_P (c)
-                 : ! SINGLE_BYTE_CHAR_P (c))
-               break;
-
-             SSET (obj, i, c);
-             if ((int) flag >= (int) CASE_CAPITALIZE)
-               inword = SYNTAX (c) == Sword;
-             i++;
-           }
+  if (STRINGP (obj))
+    {
+      int multibyte = STRING_MULTIBYTE (obj);
+      int n;
 
-         /* If we didn't do the whole string as single-byte,
-            scan the rest in a more complex way.  */
-         if (i < len)
-           {
-             /* The work is not yet finished because of a multibyte
-                character just encountered.  */
-             int fromlen, j_byte = i;
-             char *buf;
-             int bufsize;
-             USE_SAFE_ALLOCA;
+      obj = Fcopy_sequence (obj);
+      len = SBYTES (obj);
 
-             bufsize = (len - i) * MAX_MULTIBYTE_LENGTH + i;
-             SAFE_ALLOCA (buf, char *, bufsize);
+      /* I counts bytes, and N counts chars.  */
+      for (i = n = 0; i < len; n++)
+       {
+         int from_len = 1, to_len = 1;
 
-             /* Copy data already handled.  */
-             bcopy (SDATA (obj), buf, i);
+         c = SREF (obj, i);
 
-             /* From now on, I counts bytes.  */
-             while (i < len)
+         if (multibyte && c >= 0x80)
+           c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i, len -i, from_len);
+         if (inword && flag != CASE_CAPITALIZE_UP)
+           c = DOWNCASE (c);
+         else if (!UPPERCASEP (c)
+                  && (!inword || flag != CASE_CAPITALIZE_UP))
+           c = UPCASE1 (c);
+         if ((ASCII_BYTE_P (c) && from_len == 1)
+             || (! multibyte && SINGLE_BYTE_CHAR_P (c)))
+           SSET (obj, i, c);
+         else
+           {
+             to_len = CHAR_BYTES (c);
+             if (from_len == to_len)
+               CHAR_STRING (c, SDATA (obj) + i);
+             else
                {
-                 c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i,
-                                             len - i, fromlen);
-                 if (inword && flag != CASE_CAPITALIZE_UP)
-                   c = DOWNCASE (c);
-                 else if (!UPPERCASEP (c)
-                          && (!inword || flag != CASE_CAPITALIZE_UP))
-                   c = UPCASE1 (c);
-                 i += fromlen;
-                 j_byte += CHAR_STRING (c, buf + j_byte);
-                 if ((int) flag >= (int) CASE_CAPITALIZE)
-                   inword = SYNTAX (c) == Sword;
+                 Faset (obj, make_number (n), make_number (c));
+                 len += to_len - from_len;
                }
-             obj = make_multibyte_string (buf, SCHARS (obj),
-                                          j_byte);
-             SAFE_FREE ();
            }
-         return obj;
+         if ((int) flag >= (int) CASE_CAPITALIZE)
+           inword = SYNTAX (c) == Sword;
+         i += to_len;
        }
-      obj = wrong_type_argument (Qchar_or_string_p, obj);
+      return obj;
     }
+
+  wrong_type_argument (Qchar_or_string_p, obj);
 }
 
 DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
@@ -218,7 +187,7 @@ casify_region (flag, b, e)
   validate_region (&b, &e);
   start = XFASTINT (b);
   end = XFASTINT (e);
-  modify_region (current_buffer, start, end);
+  modify_region (current_buffer, start, end, 0);
   record_change (start, end - start);
   start_byte = CHAR_TO_BYTE (start);
   end_byte = CHAR_TO_BYTE (end);
@@ -253,7 +222,7 @@ casify_region (flag, b, e)
       int opoint_byte = PT_BYTE;
       int c2;
 
-      while (i < end_byte)
+      while (start < end)
        {
          if ((c = FETCH_BYTE (i)) >= 0x80)
            c = FETCH_MULTIBYTE_CHAR (i);
@@ -281,12 +250,16 @@ casify_region (flag, b, e)
                    FETCH_BYTE (i + j) = str[j];
                }
              else
-               /* Replace one character with the other,
-                  keeping text properties the same.  */
-               replace_range_2 (start + 1, i + tolen,
-                                start + 2, i + tolen + fromlen,
-                                str, 1, tolen,
-                                0);
+               {
+                 /* Replace one character with the other,
+                    keeping text properties the same.  */
+                 replace_range_2 (start, i,
+                                  start + 1, i + fromlen,
+                                  str, 1, tolen,
+                                  1);
+                 if (opoint > start)
+                   opoint_byte += tolen - fromlen;
+               }
            }
          if ((int) flag >= (int) CASE_CAPITALIZE)
            inword = SYNTAX (c2) == Sword;