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