(scan_lists): Follow coding convention.
[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,
8cabe764 3 2005, 2006, 2007, 2008 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
684d6f5b 9the Free Software Foundation; either version 3, 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"
83be827a 26#include "character.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{
2422e50a 41 register int c, c1;
dcfdbac7
JB
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
0d64f689 48 if (INTEGERP (obj))
dcfdbac7 49 {
0d64f689
KH
50 int flagbits = (CHAR_ALT | CHAR_SUPER | CHAR_HYPER
51 | CHAR_SHIFT | CHAR_CTL | CHAR_META);
52 int flags = XINT (obj) & flagbits;
53 int multibyte = ! NILP (current_buffer->enable_multibyte_characters);
54
55 /* If the character has higher bits set
56 above the flags, return it unchanged.
57 It is not a real character. */
58 if ((unsigned) XFASTINT (obj) > (unsigned) flagbits)
59 return obj;
60
61 c1 = XFASTINT (obj) & ~flagbits;
62 if (! multibyte)
63 MAKE_CHAR_MULTIBYTE (c1);
64 c = DOWNCASE (c1);
65 if (inword)
66 XSETFASTINT (obj, c | flags);
67 else if (c == (XFASTINT (obj) & ~flagbits))
dcfdbac7 68 {
0d64f689
KH
69 if (! inword)
70 c = UPCASE1 (c1);
2422e50a 71 if (! multibyte)
0d64f689
KH
72 MAKE_CHAR_UNIBYTE (c);
73 XSETFASTINT (obj, c | flags);
dcfdbac7 74 }
0d64f689
KH
75 return obj;
76 }
5245463a 77
0d64f689
KH
78 if (STRINGP (obj))
79 {
80 int multibyte = STRING_MULTIBYTE (obj);
81 int i, i_byte, len;
82 int size = SCHARS (obj);
a0615d90 83
0d64f689
KH
84 obj = Fcopy_sequence (obj);
85 for (i = i_byte = 0; i < size; i++, i_byte += len)
86 {
87 if (multibyte)
88 c = STRING_CHAR_AND_LENGTH (SDATA (obj) + i_byte, 0, len);
89 else
dcfdbac7 90 {
0d64f689
KH
91 c = SREF (obj, i_byte);
92 len = 1;
93 MAKE_CHAR_MULTIBYTE (c);
94 }
95 c1 = c;
96 if (inword && flag != CASE_CAPITALIZE_UP)
97 c = DOWNCASE (c);
98 else if (!UPPERCASEP (c)
99 && (!inword || flag != CASE_CAPITALIZE_UP))
100 c = UPCASE1 (c1);
101 if ((int) flag >= (int) CASE_CAPITALIZE)
102 inword = (SYNTAX (c) == Sword);
103 if (c != c1)
104 {
105 if (! multibyte)
2422e50a 106 {
0d64f689
KH
107 MAKE_CHAR_UNIBYTE (c);
108 SSET (obj, i_byte, c);
2422e50a 109 }
0d64f689
KH
110 else if (ASCII_CHAR_P (c1) && ASCII_CHAR_P (c))
111 SSET (obj, i_byte, c);
112 else
a0615d90 113 {
0d64f689
KH
114 Faset (obj, make_number (i), make_number (c));
115 i_byte += CHAR_BYTES (c) - len;
a0615d90 116 }
a0615d90 117 }
dcfdbac7 118 }
0d64f689 119 return obj;
dcfdbac7 120 }
0d64f689
KH
121
122 wrong_type_argument (Qchar_or_string_p, obj);
dcfdbac7
JB
123}
124
125DEFUN ("upcase", Fupcase, Supcase, 1, 1, 0,
fdb82f93
PJ
126 doc: /* Convert argument to upper case and return that.
127The argument may be a character or string. The result has the same type.
128The argument object is not altered--the value is a copy.
129See also `capitalize', `downcase' and `upcase-initials'. */)
130 (obj)
dcfdbac7
JB
131 Lisp_Object obj;
132{
133 return casify_object (CASE_UP, obj);
134}
135
136DEFUN ("downcase", Fdowncase, Sdowncase, 1, 1, 0,
fdb82f93
PJ
137 doc: /* Convert argument to lower case and return that.
138The argument may be a character or string. The result has the same type.
139The argument object is not altered--the value is a copy. */)
140 (obj)
dcfdbac7
JB
141 Lisp_Object obj;
142{
143 return casify_object (CASE_DOWN, obj);
144}
145
146DEFUN ("capitalize", Fcapitalize, Scapitalize, 1, 1, 0,
fdb82f93
PJ
147 doc: /* Convert argument to capitalized form and return that.
148This means that each word's first character is upper case
149and the rest is lower case.
150The argument may be a character or string. The result has the same type.
151The argument object is not altered--the value is a copy. */)
152 (obj)
dcfdbac7
JB
153 Lisp_Object obj;
154{
155 return casify_object (CASE_CAPITALIZE, obj);
156}
96927ba4 157
2371fad4
KH
158/* Like Fcapitalize but change only the initials. */
159
8cef1f78 160DEFUN ("upcase-initials", Fupcase_initials, Supcase_initials, 1, 1, 0,
fdb82f93
PJ
161 doc: /* Convert the initial of each word in the argument to upper case.
162Do not change the other letters of each word.
163The argument may be a character or string. The result has the same type.
164The argument object is not altered--the value is a copy. */)
165 (obj)
8cef1f78
RS
166 Lisp_Object obj;
167{
168 return casify_object (CASE_CAPITALIZE_UP, obj);
169}
dcfdbac7
JB
170\f
171/* flag is CASE_UP, CASE_DOWN or CASE_CAPITALIZE or CASE_CAPITALIZE_UP.
172 b and e specify range of buffer to operate on. */
173
dfcf069d 174void
dcfdbac7
JB
175casify_region (flag, b, e)
176 enum case_action flag;
177 Lisp_Object b, e;
178{
dcfdbac7
JB
179 register int c;
180 register int inword = flag == CASE_DOWN;
a0615d90 181 register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
7927d8e3
SM
182 EMACS_INT start, end;
183 EMACS_INT start_byte, end_byte;
184 EMACS_INT first = -1, last; /* Position of first and last changes. */
185 EMACS_INT opoint = PT;
186 EMACS_INT opoint_byte = PT_BYTE;
dcfdbac7
JB
187
188 if (EQ (b, e))
189 /* Not modifying because nothing marked */
190 return;
191
bd47bd35
RS
192 /* If the case table is flagged as modified, rescan it. */
193 if (NILP (XCHAR_TABLE (current_buffer->downcase_table)->extras[1]))
194 Fset_case_table (current_buffer->downcase_table);
195
dcfdbac7 196 validate_region (&b, &e);
2371fad4
KH
197 start = XFASTINT (b);
198 end = XFASTINT (e);
3e145152 199 modify_region (current_buffer, start, end, 0);
2371fad4 200 record_change (start, end - start);
4c7b7eab
RS
201 start_byte = CHAR_TO_BYTE (start);
202 end_byte = CHAR_TO_BYTE (end);
dcfdbac7 203
2422e50a 204 while (start < end)
a04538da 205 {
2422e50a
KH
206 int c2, len;
207
208 if (multibyte)
209 {
210 c = FETCH_MULTIBYTE_CHAR (start_byte);
211 len = CHAR_BYTES (c);
212 }
213 else
214 {
215 c = FETCH_BYTE (start_byte);
216 MAKE_CHAR_MULTIBYTE (c);
217 len = 1;
218 }
219 c2 = c;
a0615d90
KH
220 if (inword && flag != CASE_CAPITALIZE_UP)
221 c = DOWNCASE (c);
222 else if (!UPPERCASEP (c)
223 && (!inword || flag != CASE_CAPITALIZE_UP))
224 c = UPCASE1 (c);
a0615d90 225 if ((int) flag >= (int) CASE_CAPITALIZE)
8f924df7 226 inword = ((SYNTAX (c) == Sword) && (inword || !SYNTAX_PREFIX (c)));
2422e50a 227 if (c != c2)
a04538da 228 {
7927d8e3
SM
229 last = start;
230 if (first < 0)
231 first = start;
232
2422e50a
KH
233 if (! multibyte)
234 {
235 MAKE_CHAR_UNIBYTE (c);
236 FETCH_BYTE (start_byte) = c;
237 }
238 else if (ASCII_CHAR_P (c2) && ASCII_CHAR_P (c))
239 FETCH_BYTE (start_byte) = c;
08588bfa 240 else
a04538da 241 {
08588bfa 242 int tolen = CHAR_BYTES (c);
2422e50a 243 int j;
66da2880 244 unsigned char str[MAX_MULTIBYTE_LENGTH];
a04538da 245
2422e50a 246 CHAR_STRING (c, str);
08588bfa
KH
247 if (len == tolen)
248 {
249 /* Length is unchanged. */
250 for (j = 0; j < len; ++j)
251 FETCH_BYTE (start_byte + j) = str[j];
252 }
253 else
254 {
255 /* Replace one character with the other,
256 keeping text properties the same. */
257 replace_range_2 (start, start_byte,
258 start + 1, start_byte + len,
259 str, 1, tolen,
260 0);
261 len = tolen;
262 }
a04538da 263 }
a04538da 264 }
2422e50a
KH
265 start++;
266 start_byte += len;
dcfdbac7
JB
267 }
268
8f924df7
KH
269 if (PT != opoint)
270 TEMP_SET_PT_BOTH (opoint, opoint_byte);
271
7927d8e3 272 if (first >= 0)
66da2880 273 {
7927d8e3
SM
274 signal_after_change (first, last + 1 - first, last + 1 - first);
275 update_compositions (first, last + 1, CHECK_ALL);
66da2880 276 }
dcfdbac7
JB
277}
278
279DEFUN ("upcase-region", Fupcase_region, Supcase_region, 2, 2, "r",
fdb82f93
PJ
280 doc: /* Convert the region to upper case. In programs, wants two arguments.
281These arguments specify the starting and ending character numbers of
282the region to operate on. When used as a command, the text between
283point and the mark is operated on.
284See also `capitalize-region'. */)
285 (beg, end)
8c22d56c 286 Lisp_Object beg, end;
dcfdbac7 287{
8c22d56c 288 casify_region (CASE_UP, beg, end);
dcfdbac7
JB
289 return Qnil;
290}
291
292DEFUN ("downcase-region", Fdowncase_region, Sdowncase_region, 2, 2, "r",
fdb82f93
PJ
293 doc: /* Convert the region to lower case. In programs, wants two arguments.
294These arguments specify the starting and ending character numbers of
295the region to operate on. When used as a command, the text between
296point and the mark is operated on. */)
297 (beg, end)
8c22d56c 298 Lisp_Object beg, end;
dcfdbac7 299{
8c22d56c 300 casify_region (CASE_DOWN, beg, end);
dcfdbac7
JB
301 return Qnil;
302}
303
304DEFUN ("capitalize-region", Fcapitalize_region, Scapitalize_region, 2, 2, "r",
fdb82f93
PJ
305 doc: /* Convert the region to capitalized form.
306Capitalized form means each word's first character is upper case
307and the rest of it is lower case.
308In programs, give two arguments, the starting and ending
309character positions to operate on. */)
310 (beg, end)
8c22d56c 311 Lisp_Object beg, end;
dcfdbac7 312{
8c22d56c 313 casify_region (CASE_CAPITALIZE, beg, end);
dcfdbac7
JB
314 return Qnil;
315}
316
2371fad4
KH
317/* Like Fcapitalize_region but change only the initials. */
318
8cef1f78
RS
319DEFUN ("upcase-initials-region", Fupcase_initials_region,
320 Supcase_initials_region, 2, 2, "r",
fdb82f93
PJ
321 doc: /* Upcase the initial of each word in the region.
322Subsequent letters of each word are not changed.
323In programs, give two arguments, the starting and ending
324character positions to operate on. */)
325 (beg, end)
8c22d56c 326 Lisp_Object beg, end;
8cef1f78 327{
8c22d56c 328 casify_region (CASE_CAPITALIZE_UP, beg, end);
8cef1f78
RS
329 return Qnil;
330}
dcfdbac7
JB
331\f
332Lisp_Object
34628a90 333operate_on_word (arg, newpoint)
dcfdbac7 334 Lisp_Object arg;
34628a90 335 int *newpoint;
dcfdbac7 336{
39fb55ff 337 Lisp_Object val;
34628a90 338 int farend;
2371fad4 339 int iarg;
dcfdbac7 340
b7826503 341 CHECK_NUMBER (arg);
2371fad4 342 iarg = XINT (arg);
6ec8bbd2 343 farend = scan_words (PT, iarg);
dcfdbac7 344 if (!farend)
2371fad4 345 farend = iarg > 0 ? ZV : BEGV;
dcfdbac7 346
6ec8bbd2 347 *newpoint = PT > farend ? PT : farend;
18e23fd0 348 XSETFASTINT (val, farend);
dcfdbac7
JB
349
350 return val;
351}
352
353DEFUN ("upcase-word", Fupcase_word, Supcase_word, 1, 1, "p",
fdb82f93
PJ
354 doc: /* Convert following word (or ARG words) to upper case, moving over.
355With negative argument, convert previous words but do not move.
356See also `capitalize-word'. */)
357 (arg)
dcfdbac7
JB
358 Lisp_Object arg;
359{
34628a90
RS
360 Lisp_Object beg, end;
361 int newpoint;
6ec8bbd2 362 XSETFASTINT (beg, PT);
34628a90
RS
363 end = operate_on_word (arg, &newpoint);
364 casify_region (CASE_UP, beg, end);
365 SET_PT (newpoint);
dcfdbac7
JB
366 return Qnil;
367}
368
369DEFUN ("downcase-word", Fdowncase_word, Sdowncase_word, 1, 1, "p",
fdb82f93
PJ
370 doc: /* Convert following word (or ARG words) to lower case, moving over.
371With negative argument, convert previous words but do not move. */)
372 (arg)
dcfdbac7
JB
373 Lisp_Object arg;
374{
34628a90
RS
375 Lisp_Object beg, end;
376 int newpoint;
6ec8bbd2 377 XSETFASTINT (beg, PT);
34628a90
RS
378 end = operate_on_word (arg, &newpoint);
379 casify_region (CASE_DOWN, beg, end);
380 SET_PT (newpoint);
dcfdbac7
JB
381 return Qnil;
382}
383
384DEFUN ("capitalize-word", Fcapitalize_word, Scapitalize_word, 1, 1, "p",
fdb82f93
PJ
385 doc: /* Capitalize the following word (or ARG words), moving over.
386This gives the word(s) a first character in upper case
387and the rest lower case.
388With negative argument, capitalize previous words but do not move. */)
389 (arg)
dcfdbac7
JB
390 Lisp_Object arg;
391{
34628a90
RS
392 Lisp_Object beg, end;
393 int newpoint;
6ec8bbd2 394 XSETFASTINT (beg, PT);
34628a90
RS
395 end = operate_on_word (arg, &newpoint);
396 casify_region (CASE_CAPITALIZE, beg, end);
397 SET_PT (newpoint);
dcfdbac7
JB
398 return Qnil;
399}
400\f
dfcf069d 401void
dcfdbac7
JB
402syms_of_casefiddle ()
403{
a04538da
KH
404 Qidentity = intern ("identity");
405 staticpro (&Qidentity);
dcfdbac7
JB
406 defsubr (&Supcase);
407 defsubr (&Sdowncase);
408 defsubr (&Scapitalize);
8cef1f78 409 defsubr (&Supcase_initials);
dcfdbac7
JB
410 defsubr (&Supcase_region);
411 defsubr (&Sdowncase_region);
412 defsubr (&Scapitalize_region);
8cef1f78 413 defsubr (&Supcase_initials_region);
dcfdbac7
JB
414 defsubr (&Supcase_word);
415 defsubr (&Sdowncase_word);
416 defsubr (&Scapitalize_word);
417}
418
dfcf069d 419void
dcfdbac7
JB
420keys_of_casefiddle ()
421{
422 initial_define_key (control_x_map, Ctl('U'), "upcase-region");
d427b66a 423 Fput (intern ("upcase-region"), Qdisabled, Qt);
dcfdbac7 424 initial_define_key (control_x_map, Ctl('L'), "downcase-region");
d427b66a
JB
425 Fput (intern ("downcase-region"), Qdisabled, Qt);
426
dcfdbac7
JB
427 initial_define_key (meta_map, 'u', "upcase-word");
428 initial_define_key (meta_map, 'l', "downcase-word");
429 initial_define_key (meta_map, 'c', "capitalize-word");
430}
6b61353c
KH
431
432/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526
433 (do not change this comment) */