X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/7d3d343a93233bb8980990482dbee822681dcc63..c3e9438b5fde71d0464c1bd55919468880256651:/src/casefiddle.c diff --git a/src/casefiddle.c b/src/casefiddle.c index 4f1f72f6e9..02ec3f76b4 100644 --- a/src/casefiddle.c +++ b/src/casefiddle.c @@ -1,5 +1,6 @@ /* GNU Emacs case conversion functions. - Copyright (C) 1985, 1994, 1997 Free Software Foundation, Inc. + Copyright (C) 1985, 1994, 1997, 1998, 1999, 2001, 2002, 2003, 2004, + 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -15,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 @@ -25,6 +26,8 @@ Boston, MA 02111-1307, USA. */ #include "charset.h" #include "commands.h" #include "syntax.h" +#include "composite.h" +#include "keymap.h" enum case_action {CASE_UP, CASE_DOWN, CASE_CAPITALIZE, CASE_CAPITALIZE_UP}; @@ -37,7 +40,6 @@ casify_object (flag, obj) { register int i, c, len; register int inword = flag == CASE_DOWN; - Lisp_Object tem; /* If the case table is flagged as modified, rescan it. */ if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1])) @@ -47,13 +49,23 @@ casify_object (flag, obj) { if (INTEGERP (obj)) { - c = DOWNCASE (XFASTINT (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); - else if (c == XFASTINT (obj)) + XSETFASTINT (obj, c | flags); + else if (c == (XFASTINT (obj) & ~flagbits)) { - c = UPCASE1 (XFASTINT (obj)); - XSETFASTINT (obj, c); + c = UPCASE1 ((XFASTINT (obj) & ~flagbits)); + XSETFASTINT (obj, c | flags); } return obj; } @@ -61,71 +73,42 @@ casify_object (flag, obj) if (STRINGP (obj)) { int multibyte = STRING_MULTIBYTE (obj); + int n; obj = Fcopy_sequence (obj); - len = STRING_BYTES (XSTRING (obj)); + len = SBYTES (obj); - /* Scan all single-byte characters from start of string. */ - for (i = 0; i < len;) + /* I counts bytes, and N counts chars. */ + for (i = n = 0; i < len; n++) { - c = XSTRING (obj)->data[i]; + int from_len = 1, to_len = 1; + + c = SREF (obj, i); if (multibyte && c >= 0x80) - /* A multibyte character can't be handled in this - simple loop. */ - break; + 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 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; - - XSTRING (obj)->data[i] = c; - if ((int) flag >= (int) CASE_CAPITALIZE) - inword = SYNTAX (c) == Sword; - i++; - } - - /* 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, tolen, j = i, j_byte = i; - char *buf - = (char *) alloca ((len - i) * MAX_LENGTH_OF_MULTI_BYTE_FORM - + i); - unsigned char *str, workbuf[4]; - - /* Copy data already handled. */ - bcopy (XSTRING (obj)->data, buf, i); - - /* From now on, I counts bytes. */ - while (i < len) + if ((ASCII_BYTE_P (c) && from_len == 1) + || (! multibyte && SINGLE_BYTE_CHAR_P (c))) + SSET (obj, i, c); + else { - c = STRING_CHAR_AND_LENGTH (XSTRING (obj)->data + 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); - tolen = CHAR_STRING (c, workbuf, str); - bcopy (str, buf + j_byte, tolen); - i += fromlen; - j++; - j_byte += tolen; - if ((int) flag >= (int) CASE_CAPITALIZE) - inword = SYNTAX (c) == Sword; + to_len = CHAR_BYTES (c); + if (from_len == to_len) + CHAR_STRING (c, SDATA (obj) + i); + else + { + Faset (obj, make_number (n), make_number (c)); + len += to_len - from_len; + } } - obj = make_specified_string (buf, j, j_byte, - STRING_MULTIBYTE (obj)); + if ((int) flag >= (int) CASE_CAPITALIZE) + inword = SYNTAX (c) == Sword; + i += to_len; } return obj; } @@ -134,33 +117,33 @@ casify_object (flag, obj) } DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0, - "Convert argument to upper case and return that.\n\ -The argument may be a character or string. The result has the same type.\n\ -The argument object is not altered--the value is a copy.\n\ -See also `capitalize', `downcase' and `upcase-initials'.") - (obj) + doc: /* Convert argument to upper case and return that. +The argument may be a character or string. The result has the same type. +The argument object is not altered--the value is a copy. +See also `capitalize', `downcase' and `upcase-initials'. */) + (obj) Lisp_Object obj; { return casify_object (CASE_UP, obj); } DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0, - "Convert argument to lower case and return that.\n\ -The argument may be a character or string. The result has the same type.\n\ -The argument object is not altered--the value is a copy.") - (obj) + doc: /* Convert argument to lower case and return that. +The argument may be a character or string. The result has the same type. +The argument object is not altered--the value is a copy. */) + (obj) Lisp_Object obj; { return casify_object (CASE_DOWN, obj); } DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0, - "Convert argument to capitalized form and return that.\n\ -This means that each word's first character is upper case\n\ -and the rest is lower case.\n\ -The argument may be a character or string. The result has the same type.\n\ -The argument object is not altered--the value is a copy.") - (obj) + doc: /* Convert argument to capitalized form and return that. +This means that each word's first character is upper case +and the rest is lower case. +The argument may be a character or string. The result has the same type. +The argument object is not altered--the value is a copy. */) + (obj) Lisp_Object obj; { return casify_object (CASE_CAPITALIZE, obj); @@ -169,11 +152,11 @@ The argument object is not altered--the value is a copy.") /* Like Fcapitalize but change only the initials. */ DEFUN ("upcase-initials", Fupcase_initials, Supcase_initials, 1, 1, 0, - "Convert the initial of each word in the argument to upper case.\n\ -Do not change the other letters of each word.\n\ -The argument may be a character or string. The result has the same type.\n\ -The argument object is not altered--the value is a copy.") - (obj) + doc: /* Convert the initial of each word in the argument to upper case. +Do not change the other letters of each word. +The argument may be a character or string. The result has the same type. +The argument object is not altered--the value is a copy. */) + (obj) Lisp_Object obj; { return casify_object (CASE_CAPITALIZE_UP, obj); @@ -182,6 +165,7 @@ The argument object is not altered--the value is a copy.") /* flag is CASE_UP, CASE_DOWN or CASE_CAPITALIZE or CASE_CAPITALIZE_UP. b and e specify range of buffer to operate on. */ +void casify_region (flag, b, e) enum case_action flag; Lisp_Object b, e; @@ -192,7 +176,7 @@ casify_region (flag, b, e) register int multibyte = !NILP (current_buffer->enable_multibyte_characters); int start, end; int start_byte, end_byte; - Lisp_Object ch, downch, val; + int changed = 0; if (EQ (b, e)) /* Not modifying because nothing marked */ @@ -210,9 +194,10 @@ casify_region (flag, b, e) start_byte = CHAR_TO_BYTE (start); end_byte = CHAR_TO_BYTE (end); - for (i = start_byte; i < end_byte; i++) + for (i = start_byte; i < end_byte; i++, start++) { - c = FETCH_BYTE (i); + int c2; + c = c2 = FETCH_BYTE (i); if (multibyte && c >= 0x80) /* A multibyte character can't be handled in this simple loop. */ break; @@ -221,9 +206,15 @@ casify_region (flag, b, e) else if (!UPPERCASEP (c) && (!inword || flag != CASE_CAPITALIZE_UP)) c = UPCASE1 (c); + if (multibyte && c >= 0x80) + /* A multibyte result character can't be handled in this + simple loop. */ + break; FETCH_BYTE (i) = c; + if (c != c2) + changed = 1; if ((int) flag >= (int) CASE_CAPITALIZE) - inword = SYNTAX (c) == Sword; + inword = SYNTAX (c) == Sword && (inword || !SYNTAX_PREFIX (c)); } if (i < end_byte) { @@ -233,7 +224,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); @@ -246,49 +237,54 @@ casify_region (flag, b, e) if (c != c2) { int fromlen, tolen, j; - unsigned char workbuf[4], *str; + unsigned char str[MAX_MULTIBYTE_LENGTH]; + changed = 1; /* Handle the most likely case */ if (c < 0400 && c2 < 0400) FETCH_BYTE (i) = c2; - else if (fromlen = CHAR_STRING (c, workbuf, str), - tolen = CHAR_STRING (c2, workbuf, str), + else if (fromlen = CHAR_STRING (c, str), + tolen = CHAR_STRING (c2, str), fromlen == tolen) { + /* Length is unchanged. */ for (j = 0; j < tolen; ++j) FETCH_BYTE (i + j) = str[j]; } else { - error ("Can't casify letters that change length"); -#if 0 /* This is approximately what we'd like to be able to do here */ - if (tolen < fromlen) - del_range_1 (i + tolen, i + fromlen, 0); - else if (tolen > fromlen) - { - TEMP_SET_PT (i + fromlen); - insert_1 (str + fromlen, tolen - fromlen, 1, 0, 0); - } -#endif + /* 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; - INC_POS (i); + INC_BOTH (start, i); } TEMP_SET_PT_BOTH (opoint, opoint_byte); } - signal_after_change (start, end - start, end - start); + start = XFASTINT (b); + if (changed) + { + signal_after_change (start, end - start, end - start); + update_compositions (start, end, CHECK_ALL); + } } DEFUN ("upcase-region", Fupcase_region, Supcase_region, 2, 2, "r", - "Convert the region to upper case. In programs, wants two arguments.\n\ -These arguments specify the starting and ending character numbers of\n\ -the region to operate on. When used as a command, the text between\n\ -point and the mark is operated on.\n\ -See also `capitalize-region'.") - (beg, end) + doc: /* Convert the region to upper case. In programs, wants two arguments. +These arguments specify the starting and ending character numbers of +the region to operate on. When used as a command, the text between +point and the mark is operated on. +See also `capitalize-region'. */) + (beg, end) Lisp_Object beg, end; { casify_region (CASE_UP, beg, end); @@ -296,11 +292,11 @@ See also `capitalize-region'.") } DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 2, "r", - "Convert the region to lower case. In programs, wants two arguments.\n\ -These arguments specify the starting and ending character numbers of\n\ -the region to operate on. When used as a command, the text between\n\ -point and the mark is operated on.") - (beg, end) + doc: /* Convert the region to lower case. In programs, wants two arguments. +These arguments specify the starting and ending character numbers of +the region to operate on. When used as a command, the text between +point and the mark is operated on. */) + (beg, end) Lisp_Object beg, end; { casify_region (CASE_DOWN, beg, end); @@ -308,12 +304,12 @@ point and the mark is operated on.") } DEFUN ("capitalize-region", Fcapitalize_region, Scapitalize_region, 2, 2, "r", - "Convert the region to capitalized form.\n\ -Capitalized form means each word's first character is upper case\n\ -and the rest of it is lower case.\n\ -In programs, give two arguments, the starting and ending\n\ -character positions to operate on.") - (beg, end) + doc: /* Convert the region to capitalized form. +Capitalized form means each word's first character is upper case +and the rest of it is lower case. +In programs, give two arguments, the starting and ending +character positions to operate on. */) + (beg, end) Lisp_Object beg, end; { casify_region (CASE_CAPITALIZE, beg, end); @@ -324,11 +320,11 @@ character positions to operate on.") DEFUN ("upcase-initials-region", Fupcase_initials_region, Supcase_initials_region, 2, 2, "r", - "Upcase the initial of each word in the region.\n\ -Subsequent letters of each word are not changed.\n\ -In programs, give two arguments, the starting and ending\n\ -character positions to operate on.") - (beg, end) + doc: /* Upcase the initial of each word in the region. +Subsequent letters of each word are not changed. +In programs, give two arguments, the starting and ending +character positions to operate on. */) + (beg, end) Lisp_Object beg, end; { casify_region (CASE_CAPITALIZE_UP, beg, end); @@ -344,7 +340,7 @@ operate_on_word (arg, newpoint) int farend; int iarg; - CHECK_NUMBER (arg, 0); + CHECK_NUMBER (arg); iarg = XINT (arg); farend = scan_words (PT, iarg); if (!farend) @@ -357,10 +353,10 @@ operate_on_word (arg, newpoint) } DEFUN ("upcase-word", Fupcase_word, Supcase_word, 1, 1, "p", - "Convert following word (or ARG words) to upper case, moving over.\n\ -With negative argument, convert previous words but do not move.\n\ -See also `capitalize-word'.") - (arg) + doc: /* Convert following word (or ARG words) to upper case, moving over. +With negative argument, convert previous words but do not move. +See also `capitalize-word'. */) + (arg) Lisp_Object arg; { Lisp_Object beg, end; @@ -373,9 +369,9 @@ See also `capitalize-word'.") } DEFUN ("downcase-word", Fdowncase_word, Sdowncase_word, 1, 1, "p", - "Convert following word (or ARG words) to lower case, moving over.\n\ -With negative argument, convert previous words but do not move.") - (arg) + doc: /* Convert following word (or ARG words) to lower case, moving over. +With negative argument, convert previous words but do not move. */) + (arg) Lisp_Object arg; { Lisp_Object beg, end; @@ -388,11 +384,11 @@ With negative argument, convert previous words but do not move.") } DEFUN ("capitalize-word", Fcapitalize_word, Scapitalize_word, 1, 1, "p", - "Capitalize the following word (or ARG words), moving over.\n\ -This gives the word(s) a first character in upper case\n\ -and the rest lower case.\n\ -With negative argument, capitalize previous words but do not move.") - (arg) + doc: /* Capitalize the following word (or ARG words), moving over. +This gives the word(s) a first character in upper case +and the rest lower case. +With negative argument, capitalize previous words but do not move. */) + (arg) Lisp_Object arg; { Lisp_Object beg, end; @@ -404,6 +400,7 @@ With negative argument, capitalize previous words but do not move.") return Qnil; } +void syms_of_casefiddle () { Qidentity = intern ("identity"); @@ -421,6 +418,7 @@ syms_of_casefiddle () defsubr (&Scapitalize_word); } +void keys_of_casefiddle () { initial_define_key (control_x_map, Ctl('U'), "upcase-region"); @@ -432,3 +430,6 @@ keys_of_casefiddle () initial_define_key (meta_map, 'l', "downcase-word"); initial_define_key (meta_map, 'c', "capitalize-word"); } + +/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526 + (do not change this comment) */