Update years in copyright notice; nfc.
[bpt/emacs.git] / src / casefiddle.c
CommitLineData
dcfdbac7 1/* GNU Emacs case conversion functions.
0b5538bd 2 Copyright (C) 1985, 1994, 1997, 1998, 1999, 2001, 2002, 2003, 2004,
aaef169d 3 2005, 2006 Free Software Foundation, Inc.
dcfdbac7
JB
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
7c938215 9the Free Software Foundation; either version 2, or (at your option)
dcfdbac7
JB
10any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs; see the file COPYING. If not, write to
4fc5845f
LK
19the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA. */
dcfdbac7
JB
21
22
18160b98 23#include <config.h>
dcfdbac7
JB
24#include "lisp.h"
25#include "buffer.h"
a04538da 26#include "charset.h"
dcfdbac7
JB
27#include "commands.h"
28#include "syntax.h"
66da2880 29#include "composite.h"
e35f6ff7 30#include "keymap.h"
dcfdbac7
JB
31
32enum case_action {CASE_UP, CASE_DOWN, CASE_CAPITALIZE, CASE_CAPITALIZE_UP};
a04538da
KH
33
34Lisp_Object Qidentity;
dcfdbac7
JB
35\f
36Lisp_Object
37casify_object (flag, obj)
38 enum case_action flag;
39 Lisp_Object obj;
40{
41 register int i, c, len;
42 register int inword = flag == CASE_DOWN;
43
bd47bd35
RS
44 /* If the case table is flagged as modified, rescan it. */
45 if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1]))
46 Fset_case_table (current_buffer->downcase_table);
47
dcfdbac7
JB
48 while (1)
49 {
9d05e3d4 50 if (INTEGERP (obj))
dcfdbac7 51 {
e3a10b5e
KH
52 int flagbits = (CHAR_ALT | CHAR_SUPER | CHAR_HYPER
53 | CHAR_SHIFT | CHAR_CTL | CHAR_META);
54 int flags = XINT (obj) & flagbits;
55
69fe4180
RS
56 /* If the character has higher bits set
57 above the flags, return it unchanged.
58 It is not a real character. */
59 if ((unsigned) XFASTINT (obj) > (unsigned) flagbits)
60 return obj;
61
e3a10b5e 62 c = DOWNCASE (XFASTINT (obj) & ~flagbits);
5dd4d40a 63 if (inword)
e3a10b5e
KH
64 XSETFASTINT (obj, c | flags);
65 else if (c == (XFASTINT (obj) & ~flagbits))
5dd4d40a 66 {
e3a10b5e
KH
67 c = UPCASE1 ((XFASTINT (obj) & ~flagbits));
68 XSETFASTINT (obj, c | flags);
5dd4d40a 69 }
dcfdbac7
JB
70 return obj;
71 }
5245463a 72
9d05e3d4 73 if (STRINGP (obj))
dcfdbac7 74 {
5245463a 75 int multibyte = STRING_MULTIBYTE (obj);
f98a8aa9 76 int n;
a0615d90 77
dcfdbac7 78 obj = Fcopy_sequence (obj);
d5db4077 79 len = SBYTES (obj);
5245463a 80
f98a8aa9
KH
81 /* I counts bytes, and N counts chars. */
82 for (i = n = 0; i < len; n++)
dcfdbac7 83 {
f98a8aa9
KH
84 int from_len = 1, to_len = 1;
85
d5db4077 86 c = SREF (obj, i);
5245463a 87
a0615d90 88 if (multibyte && c >= 0x80)
f98a8aa9 89 c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i, len -i, from_len);
96927ba4 90 if (inword && flag != CASE_CAPITALIZE_UP)
dcfdbac7 91 c = DOWNCASE (c);
96927ba4
RS
92 else if (!UPPERCASEP (c)
93 && (!inword || flag != CASE_CAPITALIZE_UP))
dcfdbac7 94 c = UPCASE1 (c);
cac3d620
KH
95 if ((ASCII_BYTE_P (c) && from_len == 1)
96 || (! multibyte && SINGLE_BYTE_CHAR_P (c)))
f98a8aa9
KH
97 SSET (obj, i, c);
98 else
a0615d90 99 {
f98a8aa9
KH
100 to_len = CHAR_BYTES (c);
101 if (from_len == to_len)
102 CHAR_STRING (c, SDATA (obj) + i);
103 else
cac3d620
KH
104 {
105 Faset (obj, make_number (n), make_number (c));
106 len += to_len - from_len;
107 }
a0615d90 108 }
f98a8aa9
KH
109 if ((int) flag >= (int) CASE_CAPITALIZE)
110 inword = SYNTAX (c) == Sword;
111 i += to_len;
a0615d90 112 }
dcfdbac7
JB
113 return obj;
114 }
b37902c8 115 obj = wrong_type_argument (Qchar_or_string_p, obj);
dcfdbac7
JB
116 }
117}
118
119DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
fdb82f93
PJ
120 doc: /* Convert argument to upper case and return that.
121The argument may be a character or string. The result has the same type.
122The argument object is not altered--the value is a copy.
123See also `capitalize', `downcase' and `upcase-initials'. */)
124 (obj)
dcfdbac7
JB
125 Lisp_Object obj;
126{
127 return casify_object (CASE_UP, obj);
128}
129
130DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0,
fdb82f93
PJ
131 doc: /* Convert argument to lower case and return that.
132The argument may be a character or string. The result has the same type.
133The argument object is not altered--the value is a copy. */)
134 (obj)
dcfdbac7
JB
135 Lisp_Object obj;
136{
137 return casify_object (CASE_DOWN, obj);
138}
139
140DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0,
fdb82f93
PJ
141 doc: /* Convert argument to capitalized form and return that.
142This means that each word's first character is upper case
143and the rest is lower case.
144The argument may be a character or string. The result has the same type.
145The argument object is not altered--the value is a copy. */)
146 (obj)
dcfdbac7
JB
147 Lisp_Object obj;
148{
149 return casify_object (CASE_CAPITALIZE, obj);
150}
96927ba4 151
2371fad4
KH
152/* Like Fcapitalize but change only the initials. */
153
8cef1f78 154DEFUN ("upcase-initials", Fupcase_initials, Supcase_initials, 1, 1, 0,
fdb82f93
PJ
155 doc: /* Convert the initial of each word in the argument to upper case.
156Do not change the other letters of each word.
157The argument may be a character or string. The result has the same type.
158The argument object is not altered--the value is a copy. */)
159 (obj)
8cef1f78
RS
160 Lisp_Object obj;
161{
162 return casify_object (CASE_CAPITALIZE_UP, obj);
163}
dcfdbac7
JB
164\f
165/* flag is CASE_UP, CASE_DOWN or CASE_CAPITALIZE or CASE_CAPITALIZE_UP.
166 b and e specify range of buffer to operate on. */
167
dfcf069d 168void
dcfdbac7
JB
169casify_region (flag, b, e)
170 enum case_action flag;
171 Lisp_Object b, e;
172{
173 register int i;
174 register int c;
175 register int inword = flag == CASE_DOWN;
a0615d90 176 register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
2371fad4 177 int start, end;
4c7b7eab 178 int start_byte, end_byte;
66da2880 179 int changed = 0;
dcfdbac7
JB
180
181 if (EQ (b, e))
182 /* Not modifying because nothing marked */
183 return;
184
bd47bd35
RS
185 /* If the case table is flagged as modified, rescan it. */
186 if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1]))
187 Fset_case_table (current_buffer->downcase_table);
188
dcfdbac7 189 validate_region (&b, &e);
2371fad4
KH
190 start = XFASTINT (b);
191 end = XFASTINT (e);
192 modify_region (current_buffer, start, end);
193 record_change (start, end - start);
4c7b7eab
RS
194 start_byte = CHAR_TO_BYTE (start);
195 end_byte = CHAR_TO_BYTE (end);
dcfdbac7 196
66da2880 197 for (i = start_byte; i < end_byte; i++, start++)
a04538da 198 {
66da2880
KH
199 int c2;
200 c = c2 = FETCH_BYTE (i);
a0615d90
KH
201 if (multibyte && c >= 0x80)
202 /* A multibyte character can't be handled in this simple loop. */
203 break;
204 if (inword && flag != CASE_CAPITALIZE_UP)
205 c = DOWNCASE (c);
206 else if (!UPPERCASEP (c)
207 && (!inword || flag != CASE_CAPITALIZE_UP))
208 c = UPCASE1 (c);
5d19ee8a
RS
209 if (multibyte && c >= 0x80)
210 /* A multibyte result character can't be handled in this
211 simple loop. */
212 break;
a0615d90 213 FETCH_BYTE (i) = c;
66da2880
KH
214 if (c != c2)
215 changed = 1;
a0615d90 216 if ((int) flag >= (int) CASE_CAPITALIZE)
cdeb3480 217 inword = SYNTAX (c) == Sword && (inword || !SYNTAX_PREFIX (c));
a04538da 218 }
4c7b7eab 219 if (i < end_byte)
dcfdbac7 220 {
a0615d90
KH
221 /* The work is not yet finished because of a multibyte character
222 just encountered. */
4c7b7eab
RS
223 int opoint = PT;
224 int opoint_byte = PT_BYTE;
225 int c2;
a04538da 226
f98a8aa9 227 while (start < end)
a04538da 228 {
a0615d90
KH
229 if ((c = FETCH_BYTE (i)) >= 0x80)
230 c = FETCH_MULTIBYTE_CHAR (i);
231 c2 = c;
a04538da 232 if (inword && flag != CASE_CAPITALIZE_UP)
a0615d90
KH
233 c2 = DOWNCASE (c);
234 else if (!UPPERCASEP (c)
a04538da 235 && (!inword || flag != CASE_CAPITALIZE_UP))
a0615d90
KH
236 c2 = UPCASE1 (c);
237 if (c != c2)
a04538da
KH
238 {
239 int fromlen, tolen, j;
66da2880 240 unsigned char str[MAX_MULTIBYTE_LENGTH];
a04538da 241
66da2880 242 changed = 1;
a04538da 243 /* Handle the most likely case */
a0615d90
KH
244 if (c < 0400 && c2 < 0400)
245 FETCH_BYTE (i) = c2;
66da2880
KH
246 else if (fromlen = CHAR_STRING (c, str),
247 tolen = CHAR_STRING (c2, str),
a04538da
KH
248 fromlen == tolen)
249 {
5d19ee8a 250 /* Length is unchanged. */
a04538da
KH
251 for (j = 0; j < tolen; ++j)
252 FETCH_BYTE (i + j) = str[j];
253 }
254 else
f98a8aa9
KH
255 {
256 /* Replace one character with the other,
257 keeping text properties the same. */
258 replace_range_2 (start, i,
259 start + 1, i + fromlen,
260 str, 1, tolen,
261 1);
cc4ff429
KH
262 if (opoint > start)
263 opoint_byte += tolen - fromlen;
f98a8aa9 264 }
a04538da
KH
265 }
266 if ((int) flag >= (int) CASE_CAPITALIZE)
a0615d90 267 inword = SYNTAX (c2) == Sword;
66da2880 268 INC_BOTH (start, i);
a04538da 269 }
4c7b7eab 270 TEMP_SET_PT_BOTH (opoint, opoint_byte);
dcfdbac7
JB
271 }
272
66da2880
KH
273 start = XFASTINT (b);
274 if (changed)
275 {
276 signal_after_change (start, end - start, end - start);
277 update_compositions (start, end, CHECK_ALL);
278 }
dcfdbac7
JB
279}
280
281DEFUN ("upcase-region", Fupcase_region, Supcase_region, 2, 2, "r",
fdb82f93
PJ
282 doc: /* Convert the region to upper case. In programs, wants two arguments.
283These arguments specify the starting and ending character numbers of
284the region to operate on. When used as a command, the text between
285point and the mark is operated on.
286See also `capitalize-region'. */)
287 (beg, end)
8c22d56c 288 Lisp_Object beg, end;
dcfdbac7 289{
8c22d56c 290 casify_region (CASE_UP, beg, end);
dcfdbac7
JB
291 return Qnil;
292}
293
294DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 2, "r",
fdb82f93
PJ
295 doc: /* Convert the region to lower case. In programs, wants two arguments.
296These arguments specify the starting and ending character numbers of
297the region to operate on. When used as a command, the text between
298point and the mark is operated on. */)
299 (beg, end)
8c22d56c 300 Lisp_Object beg, end;
dcfdbac7 301{
8c22d56c 302 casify_region (CASE_DOWN, beg, end);
dcfdbac7
JB
303 return Qnil;
304}
305
306DEFUN ("capitalize-region", Fcapitalize_region, Scapitalize_region, 2, 2, "r",
fdb82f93
PJ
307 doc: /* Convert the region to capitalized form.
308Capitalized form means each word's first character is upper case
309and the rest of it is lower case.
310In programs, give two arguments, the starting and ending
311character positions to operate on. */)
312 (beg, end)
8c22d56c 313 Lisp_Object beg, end;
dcfdbac7 314{
8c22d56c 315 casify_region (CASE_CAPITALIZE, beg, end);
dcfdbac7
JB
316 return Qnil;
317}
318
2371fad4
KH
319/* Like Fcapitalize_region but change only the initials. */
320
8cef1f78
RS
321DEFUN ("upcase-initials-region", Fupcase_initials_region,
322 Supcase_initials_region, 2, 2, "r",
fdb82f93
PJ
323 doc: /* Upcase the initial of each word in the region.
324Subsequent letters of each word are not changed.
325In programs, give two arguments, the starting and ending
326character positions to operate on. */)
327 (beg, end)
8c22d56c 328 Lisp_Object beg, end;
8cef1f78 329{
8c22d56c 330 casify_region (CASE_CAPITALIZE_UP, beg, end);
8cef1f78
RS
331 return Qnil;
332}
dcfdbac7
JB
333\f
334Lisp_Object
34628a90 335operate_on_word (arg, newpoint)
dcfdbac7 336 Lisp_Object arg;
34628a90 337 int *newpoint;
dcfdbac7 338{
39fb55ff 339 Lisp_Object val;
34628a90 340 int farend;
2371fad4 341 int iarg;
dcfdbac7 342
b7826503 343 CHECK_NUMBER (arg);
2371fad4 344 iarg = XINT (arg);
6ec8bbd2 345 farend = scan_words (PT, iarg);
dcfdbac7 346 if (!farend)
2371fad4 347 farend = iarg > 0 ? ZV : BEGV;
dcfdbac7 348
6ec8bbd2 349 *newpoint = PT > farend ? PT : farend;
18e23fd0 350 XSETFASTINT (val, farend);
dcfdbac7
JB
351
352 return val;
353}
354
355DEFUN ("upcase-word", Fupcase_word, Supcase_word, 1, 1, "p",
fdb82f93
PJ
356 doc: /* Convert following word (or ARG words) to upper case, moving over.
357With negative argument, convert previous words but do not move.
358See also `capitalize-word'. */)
359 (arg)
dcfdbac7
JB
360 Lisp_Object arg;
361{
34628a90
RS
362 Lisp_Object beg, end;
363 int newpoint;
6ec8bbd2 364 XSETFASTINT (beg, PT);
34628a90
RS
365 end = operate_on_word (arg, &newpoint);
366 casify_region (CASE_UP, beg, end);
367 SET_PT (newpoint);
dcfdbac7
JB
368 return Qnil;
369}
370
371DEFUN ("downcase-word", Fdowncase_word, Sdowncase_word, 1, 1, "p",
fdb82f93
PJ
372 doc: /* Convert following word (or ARG words) to lower case, moving over.
373With negative argument, convert previous words but do not move. */)
374 (arg)
dcfdbac7
JB
375 Lisp_Object arg;
376{
34628a90
RS
377 Lisp_Object beg, end;
378 int newpoint;
6ec8bbd2 379 XSETFASTINT (beg, PT);
34628a90
RS
380 end = operate_on_word (arg, &newpoint);
381 casify_region (CASE_DOWN, beg, end);
382 SET_PT (newpoint);
dcfdbac7
JB
383 return Qnil;
384}
385
386DEFUN ("capitalize-word", Fcapitalize_word, Scapitalize_word, 1, 1, "p",
fdb82f93
PJ
387 doc: /* Capitalize the following word (or ARG words), moving over.
388This gives the word(s) a first character in upper case
389and the rest lower case.
390With negative argument, capitalize previous words but do not move. */)
391 (arg)
dcfdbac7
JB
392 Lisp_Object arg;
393{
34628a90
RS
394 Lisp_Object beg, end;
395 int newpoint;
6ec8bbd2 396 XSETFASTINT (beg, PT);
34628a90
RS
397 end = operate_on_word (arg, &newpoint);
398 casify_region (CASE_CAPITALIZE, beg, end);
399 SET_PT (newpoint);
dcfdbac7
JB
400 return Qnil;
401}
402\f
dfcf069d 403void
dcfdbac7
JB
404syms_of_casefiddle ()
405{
a04538da
KH
406 Qidentity = intern ("identity");
407 staticpro (&Qidentity);
dcfdbac7
JB
408 defsubr (&Supcase);
409 defsubr (&Sdowncase);
410 defsubr (&Scapitalize);
8cef1f78 411 defsubr (&Supcase_initials);
dcfdbac7
JB
412 defsubr (&Supcase_region);
413 defsubr (&Sdowncase_region);
414 defsubr (&Scapitalize_region);
8cef1f78 415 defsubr (&Supcase_initials_region);
dcfdbac7
JB
416 defsubr (&Supcase_word);
417 defsubr (&Sdowncase_word);
418 defsubr (&Scapitalize_word);
419}
420
dfcf069d 421void
dcfdbac7
JB
422keys_of_casefiddle ()
423{
424 initial_define_key (control_x_map, Ctl('U'), "upcase-region");
d427b66a 425 Fput (intern ("upcase-region"), Qdisabled, Qt);
dcfdbac7 426 initial_define_key (control_x_map, Ctl('L'), "downcase-region");
d427b66a
JB
427 Fput (intern ("downcase-region"), Qdisabled, Qt);
428
dcfdbac7
JB
429 initial_define_key (meta_map, 'u', "upcase-word");
430 initial_define_key (meta_map, 'l', "downcase-word");
431 initial_define_key (meta_map, 'c', "capitalize-word");
432}
ab5796a9
MB
433
434/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526
435 (do not change this comment) */