*** empty log message ***
[bpt/emacs.git] / src / casefiddle.c
CommitLineData
dcfdbac7 1/* GNU Emacs case conversion functions.
f98a8aa9 2 Copyright (C) 1985,94,97,98,99, 2001, 2002, 2004, 2005
a0ecb2ac 3 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
3b7ad313
EN
19the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20Boston, MA 02111-1307, 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);
f98a8aa9
KH
95 if (ASCII_BYTE_P (c) || (! multibyte && SINGLE_BYTE_CHAR_P (c)))
96 SSET (obj, i, c);
97 else
a0615d90 98 {
f98a8aa9
KH
99 to_len = CHAR_BYTES (c);
100 if (from_len == to_len)
101 CHAR_STRING (c, SDATA (obj) + i);
102 else
103 Faset (obj, make_number (n), make_number (c));
a0615d90 104 }
f98a8aa9
KH
105 if ((int) flag >= (int) CASE_CAPITALIZE)
106 inword = SYNTAX (c) == Sword;
107 i += to_len;
a0615d90 108 }
dcfdbac7
JB
109 return obj;
110 }
b37902c8 111 obj = wrong_type_argument (Qchar_or_string_p, obj);
dcfdbac7
JB
112 }
113}
114
115DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
fdb82f93
PJ
116 doc: /* Convert argument to upper case and return that.
117The argument may be a character or string. The result has the same type.
118The argument object is not altered--the value is a copy.
119See also `capitalize', `downcase' and `upcase-initials'. */)
120 (obj)
dcfdbac7
JB
121 Lisp_Object obj;
122{
123 return casify_object (CASE_UP, obj);
124}
125
126DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0,
fdb82f93
PJ
127 doc: /* Convert argument to lower case and return that.
128The argument may be a character or string. The result has the same type.
129The argument object is not altered--the value is a copy. */)
130 (obj)
dcfdbac7
JB
131 Lisp_Object obj;
132{
133 return casify_object (CASE_DOWN, obj);
134}
135
136DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0,
fdb82f93
PJ
137 doc: /* Convert argument to capitalized form and return that.
138This means that each word's first character is upper case
139and the rest is lower case.
140The argument may be a character or string. The result has the same type.
141The argument object is not altered--the value is a copy. */)
142 (obj)
dcfdbac7
JB
143 Lisp_Object obj;
144{
145 return casify_object (CASE_CAPITALIZE, obj);
146}
96927ba4 147
2371fad4
KH
148/* Like Fcapitalize but change only the initials. */
149
8cef1f78 150DEFUN ("upcase-initials", Fupcase_initials, Supcase_initials, 1, 1, 0,
fdb82f93
PJ
151 doc: /* Convert the initial of each word in the argument to upper case.
152Do not change the other letters of each word.
153The argument may be a character or string. The result has the same type.
154The argument object is not altered--the value is a copy. */)
155 (obj)
8cef1f78
RS
156 Lisp_Object obj;
157{
158 return casify_object (CASE_CAPITALIZE_UP, obj);
159}
dcfdbac7
JB
160\f
161/* flag is CASE_UP, CASE_DOWN or CASE_CAPITALIZE or CASE_CAPITALIZE_UP.
162 b and e specify range of buffer to operate on. */
163
dfcf069d 164void
dcfdbac7
JB
165casify_region (flag, b, e)
166 enum case_action flag;
167 Lisp_Object b, e;
168{
169 register int i;
170 register int c;
171 register int inword = flag == CASE_DOWN;
a0615d90 172 register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
2371fad4 173 int start, end;
4c7b7eab 174 int start_byte, end_byte;
66da2880 175 int changed = 0;
dcfdbac7
JB
176
177 if (EQ (b, e))
178 /* Not modifying because nothing marked */
179 return;
180
bd47bd35
RS
181 /* If the case table is flagged as modified, rescan it. */
182 if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1]))
183 Fset_case_table (current_buffer->downcase_table);
184
dcfdbac7 185 validate_region (&b, &e);
2371fad4
KH
186 start = XFASTINT (b);
187 end = XFASTINT (e);
188 modify_region (current_buffer, start, end);
189 record_change (start, end - start);
4c7b7eab
RS
190 start_byte = CHAR_TO_BYTE (start);
191 end_byte = CHAR_TO_BYTE (end);
dcfdbac7 192
66da2880 193 for (i = start_byte; i < end_byte; i++, start++)
a04538da 194 {
66da2880
KH
195 int c2;
196 c = c2 = FETCH_BYTE (i);
a0615d90
KH
197 if (multibyte && c >= 0x80)
198 /* A multibyte character can't be handled in this simple loop. */
199 break;
200 if (inword && flag != CASE_CAPITALIZE_UP)
201 c = DOWNCASE (c);
202 else if (!UPPERCASEP (c)
203 && (!inword || flag != CASE_CAPITALIZE_UP))
204 c = UPCASE1 (c);
5d19ee8a
RS
205 if (multibyte && c >= 0x80)
206 /* A multibyte result character can't be handled in this
207 simple loop. */
208 break;
a0615d90 209 FETCH_BYTE (i) = c;
66da2880
KH
210 if (c != c2)
211 changed = 1;
a0615d90 212 if ((int) flag >= (int) CASE_CAPITALIZE)
cdeb3480 213 inword = SYNTAX (c) == Sword && (inword || !SYNTAX_PREFIX (c));
a04538da 214 }
4c7b7eab 215 if (i < end_byte)
dcfdbac7 216 {
a0615d90
KH
217 /* The work is not yet finished because of a multibyte character
218 just encountered. */
4c7b7eab
RS
219 int opoint = PT;
220 int opoint_byte = PT_BYTE;
221 int c2;
a04538da 222
f98a8aa9 223 while (start < end)
a04538da 224 {
a0615d90
KH
225 if ((c = FETCH_BYTE (i)) >= 0x80)
226 c = FETCH_MULTIBYTE_CHAR (i);
227 c2 = c;
a04538da 228 if (inword && flag != CASE_CAPITALIZE_UP)
a0615d90
KH
229 c2 = DOWNCASE (c);
230 else if (!UPPERCASEP (c)
a04538da 231 && (!inword || flag != CASE_CAPITALIZE_UP))
a0615d90
KH
232 c2 = UPCASE1 (c);
233 if (c != c2)
a04538da
KH
234 {
235 int fromlen, tolen, j;
66da2880 236 unsigned char str[MAX_MULTIBYTE_LENGTH];
a04538da 237
66da2880 238 changed = 1;
a04538da 239 /* Handle the most likely case */
a0615d90
KH
240 if (c < 0400 && c2 < 0400)
241 FETCH_BYTE (i) = c2;
66da2880
KH
242 else if (fromlen = CHAR_STRING (c, str),
243 tolen = CHAR_STRING (c2, str),
a04538da
KH
244 fromlen == tolen)
245 {
5d19ee8a 246 /* Length is unchanged. */
a04538da
KH
247 for (j = 0; j < tolen; ++j)
248 FETCH_BYTE (i + j) = str[j];
249 }
250 else
f98a8aa9
KH
251 {
252 /* Replace one character with the other,
253 keeping text properties the same. */
254 replace_range_2 (start, i,
255 start + 1, i + fromlen,
256 str, 1, tolen,
257 1);
cc4ff429
KH
258 if (opoint > start)
259 opoint_byte += tolen - fromlen;
f98a8aa9 260 }
a04538da
KH
261 }
262 if ((int) flag >= (int) CASE_CAPITALIZE)
a0615d90 263 inword = SYNTAX (c2) == Sword;
66da2880 264 INC_BOTH (start, i);
a04538da 265 }
4c7b7eab 266 TEMP_SET_PT_BOTH (opoint, opoint_byte);
dcfdbac7
JB
267 }
268
66da2880
KH
269 start = XFASTINT (b);
270 if (changed)
271 {
272 signal_after_change (start, end - start, end - start);
273 update_compositions (start, end, CHECK_ALL);
274 }
dcfdbac7
JB
275}
276
277DEFUN ("upcase-region", Fupcase_region, Supcase_region, 2, 2, "r",
fdb82f93
PJ
278 doc: /* Convert the region to upper case. In programs, wants two arguments.
279These arguments specify the starting and ending character numbers of
280the region to operate on. When used as a command, the text between
281point and the mark is operated on.
282See also `capitalize-region'. */)
283 (beg, end)
8c22d56c 284 Lisp_Object beg, end;
dcfdbac7 285{
8c22d56c 286 casify_region (CASE_UP, beg, end);
dcfdbac7
JB
287 return Qnil;
288}
289
290DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 2, "r",
fdb82f93
PJ
291 doc: /* Convert the region to lower case. In programs, wants two arguments.
292These arguments specify the starting and ending character numbers of
293the region to operate on. When used as a command, the text between
294point and the mark is operated on. */)
295 (beg, end)
8c22d56c 296 Lisp_Object beg, end;
dcfdbac7 297{
8c22d56c 298 casify_region (CASE_DOWN, beg, end);
dcfdbac7
JB
299 return Qnil;
300}
301
302DEFUN ("capitalize-region", Fcapitalize_region, Scapitalize_region, 2, 2, "r",
fdb82f93
PJ
303 doc: /* Convert the region to capitalized form.
304Capitalized form means each word's first character is upper case
305and the rest of it is lower case.
306In programs, give two arguments, the starting and ending
307character positions to operate on. */)
308 (beg, end)
8c22d56c 309 Lisp_Object beg, end;
dcfdbac7 310{
8c22d56c 311 casify_region (CASE_CAPITALIZE, beg, end);
dcfdbac7
JB
312 return Qnil;
313}
314
2371fad4
KH
315/* Like Fcapitalize_region but change only the initials. */
316
8cef1f78
RS
317DEFUN ("upcase-initials-region", Fupcase_initials_region,
318 Supcase_initials_region, 2, 2, "r",
fdb82f93
PJ
319 doc: /* Upcase the initial of each word in the region.
320Subsequent letters of each word are not changed.
321In programs, give two arguments, the starting and ending
322character positions to operate on. */)
323 (beg, end)
8c22d56c 324 Lisp_Object beg, end;
8cef1f78 325{
8c22d56c 326 casify_region (CASE_CAPITALIZE_UP, beg, end);
8cef1f78
RS
327 return Qnil;
328}
dcfdbac7
JB
329\f
330Lisp_Object
34628a90 331operate_on_word (arg, newpoint)
dcfdbac7 332 Lisp_Object arg;
34628a90 333 int *newpoint;
dcfdbac7 334{
39fb55ff 335 Lisp_Object val;
34628a90 336 int farend;
2371fad4 337 int iarg;
dcfdbac7 338
b7826503 339 CHECK_NUMBER (arg);
2371fad4 340 iarg = XINT (arg);
6ec8bbd2 341 farend = scan_words (PT, iarg);
dcfdbac7 342 if (!farend)
2371fad4 343 farend = iarg > 0 ? ZV : BEGV;
dcfdbac7 344
6ec8bbd2 345 *newpoint = PT > farend ? PT : farend;
18e23fd0 346 XSETFASTINT (val, farend);
dcfdbac7
JB
347
348 return val;
349}
350
351DEFUN ("upcase-word", Fupcase_word, Supcase_word, 1, 1, "p",
fdb82f93
PJ
352 doc: /* Convert following word (or ARG words) to upper case, moving over.
353With negative argument, convert previous words but do not move.
354See also `capitalize-word'. */)
355 (arg)
dcfdbac7
JB
356 Lisp_Object arg;
357{
34628a90
RS
358 Lisp_Object beg, end;
359 int newpoint;
6ec8bbd2 360 XSETFASTINT (beg, PT);
34628a90
RS
361 end = operate_on_word (arg, &newpoint);
362 casify_region (CASE_UP, beg, end);
363 SET_PT (newpoint);
dcfdbac7
JB
364 return Qnil;
365}
366
367DEFUN ("downcase-word", Fdowncase_word, Sdowncase_word, 1, 1, "p",
fdb82f93
PJ
368 doc: /* Convert following word (or ARG words) to lower case, moving over.
369With negative argument, convert previous words but do not move. */)
370 (arg)
dcfdbac7
JB
371 Lisp_Object arg;
372{
34628a90
RS
373 Lisp_Object beg, end;
374 int newpoint;
6ec8bbd2 375 XSETFASTINT (beg, PT);
34628a90
RS
376 end = operate_on_word (arg, &newpoint);
377 casify_region (CASE_DOWN, beg, end);
378 SET_PT (newpoint);
dcfdbac7
JB
379 return Qnil;
380}
381
382DEFUN ("capitalize-word", Fcapitalize_word, Scapitalize_word, 1, 1, "p",
fdb82f93
PJ
383 doc: /* Capitalize the following word (or ARG words), moving over.
384This gives the word(s) a first character in upper case
385and the rest lower case.
386With negative argument, capitalize previous words but do not move. */)
387 (arg)
dcfdbac7
JB
388 Lisp_Object arg;
389{
34628a90
RS
390 Lisp_Object beg, end;
391 int newpoint;
6ec8bbd2 392 XSETFASTINT (beg, PT);
34628a90
RS
393 end = operate_on_word (arg, &newpoint);
394 casify_region (CASE_CAPITALIZE, beg, end);
395 SET_PT (newpoint);
dcfdbac7
JB
396 return Qnil;
397}
398\f
dfcf069d 399void
dcfdbac7
JB
400syms_of_casefiddle ()
401{
a04538da
KH
402 Qidentity = intern ("identity");
403 staticpro (&Qidentity);
dcfdbac7
JB
404 defsubr (&Supcase);
405 defsubr (&Sdowncase);
406 defsubr (&Scapitalize);
8cef1f78 407 defsubr (&Supcase_initials);
dcfdbac7
JB
408 defsubr (&Supcase_region);
409 defsubr (&Sdowncase_region);
410 defsubr (&Scapitalize_region);
8cef1f78 411 defsubr (&Supcase_initials_region);
dcfdbac7
JB
412 defsubr (&Supcase_word);
413 defsubr (&Sdowncase_word);
414 defsubr (&Scapitalize_word);
415}
416
dfcf069d 417void
dcfdbac7
JB
418keys_of_casefiddle ()
419{
420 initial_define_key (control_x_map, Ctl('U'), "upcase-region");
d427b66a 421 Fput (intern ("upcase-region"), Qdisabled, Qt);
dcfdbac7 422 initial_define_key (control_x_map, Ctl('L'), "downcase-region");
d427b66a
JB
423 Fput (intern ("downcase-region"), Qdisabled, Qt);
424
dcfdbac7
JB
425 initial_define_key (meta_map, 'u', "upcase-word");
426 initial_define_key (meta_map, 'l', "downcase-word");
427 initial_define_key (meta_map, 'c', "capitalize-word");
428}
ab5796a9
MB
429
430/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526
431 (do not change this comment) */