Initial revision
[chise/xemacs-chise.git.1] / src / casefiddle.c
1 /* XEmacs case conversion functions.
2    Copyright (C) 1985, 1992, 1993, 1994 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 /* Synched up with: FSF 19.34. */
22
23 #include <config.h>
24 #include "lisp.h"
25
26 #include "buffer.h"
27 #include "commands.h"
28 #include "insdel.h"
29 #include "syntax.h"
30
31 enum case_action {CASE_UP, CASE_DOWN, CASE_CAPITALIZE, CASE_CAPITALIZE_UP};
32 \f
33 static Lisp_Object
34 casify_object (enum case_action flag, Lisp_Object obj, Lisp_Object buffer)
35 {
36   struct buffer *buf = decode_buffer (buffer, 0);
37   REGISTER int inword = (flag == CASE_DOWN);
38   struct Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->mirror_syntax_table);
39
40   while (1)
41     {
42       if (CHAR_OR_CHAR_INTP (obj))
43         {
44           Emchar c;
45           CHECK_CHAR_COERCE_INT (obj);
46           c = XCHAR (obj);
47           if (IN_TRT_TABLE_DOMAIN (c))
48             {
49               if (inword)
50                 obj = make_char (DOWNCASE (buf, c));
51               else if (!UPPERCASEP (buf, c))
52                 obj = make_char (UPCASE1 (buf, c));
53             }
54           return obj;
55         }
56       if (STRINGP (obj))
57         {
58           Charcount i;
59           Charcount len = XSTRING_CHAR_LENGTH (obj);
60           obj = Fcopy_sequence (obj);
61           for (i = 0; i < len; i++)
62             {
63               Emchar c = string_char (XSTRING (obj), i);
64               if (inword && flag != CASE_CAPITALIZE_UP)
65                 c = DOWNCASE (buf, c);
66               else if (!UPPERCASEP (buf, c)
67                        && (!inword || flag != CASE_CAPITALIZE_UP))
68                 c = UPCASE1 (buf, c);
69               set_string_char (XSTRING (obj), i, c);
70               if ((int) flag >= (int) CASE_CAPITALIZE)
71                 inword = WORD_SYNTAX_P (syntax_table, c);
72             }
73           return obj;
74         }
75       obj = wrong_type_argument (Qchar_or_string_p, obj);
76     }
77 }
78
79 DEFUN ("upcase", Fupcase, 1, 2, 0, /*
80 Convert argument to upper case and return that.
81 The argument may be a character or string.  The result has the same type.
82 The argument object is not altered--the value is a copy.
83 See also `capitalize', `downcase' and `upcase-initials'.
84 Optional second arg BUFFER specifies which buffer's case tables to use,
85  and defaults to the current buffer.
86 */
87        (obj, buffer))
88 {
89   return casify_object (CASE_UP, obj, buffer);
90 }
91
92 DEFUN ("downcase", Fdowncase, 1, 2, 0, /*
93 Convert argument to lower case and return that.
94 The argument may be a character or string.  The result has the same type.
95 The argument object is not altered--the value is a copy.
96 Optional second arg BUFFER specifies which buffer's case tables to use,
97  and defaults to the current buffer.
98 */
99        (obj, buffer))
100 {
101   return casify_object (CASE_DOWN, obj, buffer);
102 }
103
104 DEFUN ("capitalize", Fcapitalize, 1, 2, 0, /*
105 Convert argument to capitalized form and return that.
106 This means that each word's first character is upper case
107 and the rest is lower case.
108 The argument may be a character or string.  The result has the same type.
109 The argument object is not altered--the value is a copy.
110 Optional second arg BUFFER specifies which buffer's case tables to use,
111  and defaults to the current buffer.
112 */
113        (obj, buffer))
114 {
115   return casify_object (CASE_CAPITALIZE, obj, buffer);
116 }
117
118 /* Like Fcapitalize but change only the initials.  */
119
120 DEFUN ("upcase-initials", Fupcase_initials, 1, 2, 0, /*
121 Convert the initial of each word in the argument to upper case.
122 Do not change the other letters of each word.
123 The argument may be a character or string.  The result has the same type.
124 The argument object is not altered--the value is a copy.
125 Optional second arg BUFFER specifies which buffer's case tables to use,
126  and defaults to the current buffer.
127 */
128        (obj, buffer))
129 {
130   return casify_object (CASE_CAPITALIZE_UP, obj, buffer);
131 }
132 \f
133 /* flag is CASE_UP, CASE_DOWN or CASE_CAPITALIZE or CASE_CAPITALIZE_UP.
134    b and e specify range of buffer to operate on. */
135
136 static void
137 casify_region_internal (enum case_action flag, Lisp_Object b, Lisp_Object e,
138                         struct buffer *buf)
139 {
140   /* This function can GC */
141   REGISTER Bufpos i;
142   Bufpos start, end;
143   REGISTER int inword = (flag == CASE_DOWN);
144   struct Lisp_Char_Table *syntax_table = XCHAR_TABLE (buf->mirror_syntax_table);
145   int mccount;
146
147   if (EQ (b, e))
148     /* Not modifying because nothing marked */
149     return;
150
151   get_buffer_range_char (buf, b, e, &start, &end, 0);
152
153   mccount = begin_multiple_change (buf, start, end);
154   record_change (buf, start, end - start);
155
156   for (i = start; i < end; i++)
157     {
158       Emchar c = BUF_FETCH_CHAR (buf, i);
159       Emchar oldc = c;
160
161       if (inword && flag != CASE_CAPITALIZE_UP)
162         c = DOWNCASE (buf, c);
163       else if (!UPPERCASEP (buf, c)
164                && (!inword || flag != CASE_CAPITALIZE_UP))
165         c = UPCASE1 (buf, c);
166
167       if (oldc != c)
168         {
169           buffer_replace_char (buf, i, c, 1, (i == start));
170           BUF_MODIFF (buf)++;
171         }
172       /* !!#### need to revalidate the start and end pointers in case
173          the buffer was changed */
174       if ((int) flag >= (int) CASE_CAPITALIZE)
175         inword = WORD_SYNTAX_P (syntax_table, c);
176     }
177   end_multiple_change (buf, mccount);
178 }
179
180 static Lisp_Object
181 casify_region (enum case_action flag, Lisp_Object b, Lisp_Object e,
182                Lisp_Object buffer)
183 {
184   casify_region_internal (flag, b, e, decode_buffer (buffer, 1));
185   return Qnil;
186 }
187
188 DEFUN ("upcase-region", Fupcase_region, 2, 3, "r", /*
189 Convert the region to upper case.  In programs, wants two arguments.
190 These arguments specify the starting and ending character numbers of
191  the region to operate on.  When used as a command, the text between
192  point and the mark is operated on.
193 See also `capitalize-region'.
194 Optional third arg BUFFER defaults to the current buffer.
195 */
196        (b, e, buffer))
197 {
198   /* This function can GC */
199   return casify_region (CASE_UP, b, e, buffer);
200 }
201
202 DEFUN ("downcase-region", Fdowncase_region, 2, 3, "r", /*
203 Convert the region to lower case.  In programs, wants two arguments.
204 These arguments specify the starting and ending character numbers of
205  the region to operate on.  When used as a command, the text between
206  point and the mark is operated on.
207 Optional third arg BUFFER defaults to the current buffer.
208 */
209        (b, e, buffer))
210 {
211   /* This function can GC */
212   return casify_region (CASE_DOWN, b, e, buffer);
213 }
214
215 DEFUN ("capitalize-region", Fcapitalize_region, 2, 3, "r", /*
216 Convert the region to capitalized form.
217 Capitalized form means each word's first character is upper case
218  and the rest of it is lower case.
219 In programs, give two arguments, the starting and ending
220  character positions to operate on.
221 Optional third arg BUFFER defaults to the current buffer.
222 */
223        (b, e, buffer))
224 {
225   /* This function can GC */
226   return casify_region (CASE_CAPITALIZE, b, e, buffer);
227 }
228
229 /* Like Fcapitalize_region but change only the initials.  */
230
231 DEFUN ("upcase-initials-region", Fupcase_initials_region, 2, 3, "r", /*
232 Upcase the initial of each word in the region.
233 Subsequent letters of each word are not changed.
234 In programs, give two arguments, the starting and ending
235  character positions to operate on.
236 Optional third arg BUFFER defaults to the current buffer.
237 */
238        (b, e, buffer))
239 {
240   return casify_region (CASE_CAPITALIZE_UP, b, e, buffer);
241 }
242
243 \f
244 static Lisp_Object
245 casify_word (enum case_action flag, Lisp_Object arg, Lisp_Object buffer)
246 {
247   Bufpos farend;
248   struct buffer *buf = decode_buffer (buffer, 1);
249
250   CHECK_INT (arg);
251
252   farend = scan_words (buf, BUF_PT (buf), XINT (arg));
253   if (!farend)
254     farend = XINT (arg) > 0 ? BUF_ZV (buf) : BUF_BEGV (buf);
255
256   casify_region_internal (flag, make_int (BUF_PT (buf)), make_int (farend), buf);
257   BUF_SET_PT (buf, max (BUF_PT (buf), farend));
258   return Qnil;
259 }
260
261 DEFUN ("upcase-word", Fupcase_word, 1, 2, "p", /*
262 Convert following word (or ARG words) to upper case, moving over.
263 With negative argument, convert previous words but do not move.
264 See also `capitalize-word'.
265 Optional second arg BUFFER defaults to the current buffer.
266 */
267        (arg, buffer))
268 {
269   /* This function can GC */
270   return casify_word (CASE_UP, arg, buffer);
271 }
272
273 DEFUN ("downcase-word", Fdowncase_word, 1, 2, "p", /*
274 Convert following word (or ARG words) to lower case, moving over.
275 With negative argument, convert previous words but do not move.
276 Optional second arg BUFFER defaults to the current buffer.
277 */
278        (arg, buffer))
279 {
280   /* This function can GC */
281   return casify_word (CASE_DOWN, arg, buffer);
282 }
283
284 DEFUN ("capitalize-word", Fcapitalize_word, 1, 2, "p", /*
285 Capitalize the following word (or ARG words), moving over.
286 This gives the word(s) a first character in upper case
287  and the rest lower case.
288 With negative argument, capitalize previous words but do not move.
289 Optional second arg BUFFER defaults to the current buffer.
290 */
291        (arg, buffer))
292 {
293   /* This function can GC */
294   return casify_word (CASE_CAPITALIZE, arg, buffer);
295 }
296 \f
297
298 void
299 syms_of_casefiddle (void)
300 {
301   DEFSUBR (Fupcase);
302   DEFSUBR (Fdowncase);
303   DEFSUBR (Fcapitalize);
304   DEFSUBR (Fupcase_initials);
305   DEFSUBR (Fupcase_region);
306   DEFSUBR (Fdowncase_region);
307   DEFSUBR (Fcapitalize_region);
308   DEFSUBR (Fupcase_initials_region);
309   DEFSUBR (Fupcase_word);
310   DEFSUBR (Fdowncase_word);
311   DEFSUBR (Fcapitalize_word);
312 }