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