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