(struct xftface_info): Delete the member xft_draw.
[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,
4e6835db 3 2005, 2006, 2007 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);
2371fad4 182 int start, end;
4c7b7eab 183 int start_byte, end_byte;
66da2880 184 int changed = 0;
2422e50a
KH
185 int opoint = PT;
186 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 {
2422e50a
KH
229 changed = 1;
230 if (! multibyte)
231 {
232 MAKE_CHAR_UNIBYTE (c);
233 FETCH_BYTE (start_byte) = c;
234 }
235 else if (ASCII_CHAR_P (c2) && ASCII_CHAR_P (c))
236 FETCH_BYTE (start_byte) = c;
08588bfa 237 else
a04538da 238 {
08588bfa 239 int tolen = CHAR_BYTES (c);
2422e50a 240 int j;
66da2880 241 unsigned char str[MAX_MULTIBYTE_LENGTH];
a04538da 242
2422e50a 243 CHAR_STRING (c, str);
08588bfa
KH
244 if (len == tolen)
245 {
246 /* Length is unchanged. */
247 for (j = 0; j < len; ++j)
248 FETCH_BYTE (start_byte + j) = str[j];
249 }
250 else
251 {
252 /* Replace one character with the other,
253 keeping text properties the same. */
254 replace_range_2 (start, start_byte,
255 start + 1, start_byte + len,
256 str, 1, tolen,
257 0);
258 len = tolen;
259 }
a04538da 260 }
a04538da 261 }
2422e50a
KH
262 start++;
263 start_byte += len;
dcfdbac7
JB
264 }
265
8f924df7
KH
266 if (PT != opoint)
267 TEMP_SET_PT_BOTH (opoint, opoint_byte);
268
66da2880
KH
269 if (changed)
270 {
2422e50a 271 start = XFASTINT (b);
66da2880
KH
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}
6b61353c
KH
429
430/* arch-tag: 60a73c66-5489-47e7-a81f-cead4057c526
431 (do not change this comment) */