(Ffind_charset_string): The variable CHARSETS is
[bpt/emacs.git] / src / casetab.c
CommitLineData
dcfdbac7 1/* GNU Emacs routines to deal with case tables.
3a22ee35 2 Copyright (C) 1993, 1994 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/* Written by Howard Gayle. See chartab.c for details. */
22
18160b98 23#include <config.h>
dcfdbac7
JB
24#include "lisp.h"
25#include "buffer.h"
c0c15b93 26#include "charset.h"
dcfdbac7 27
7f7fef04 28Lisp_Object Qcase_table_p, Qcase_table;
dcfdbac7
JB
29Lisp_Object Vascii_downcase_table, Vascii_upcase_table;
30Lisp_Object Vascii_canon_table, Vascii_eqv_table;
31
7f7fef04 32static void compute_trt_inverse ();
dcfdbac7
JB
33
34DEFUN ("case-table-p", Fcase_table_p, Scase_table_p, 1, 1, 0,
2858a1c1 35 "Return t iff OBJECT is a case table.\n\
dcfdbac7 36See `set-case-table' for more information on these data structures.")
2858a1c1
EN
37 (object)
38 Lisp_Object object;
dcfdbac7 39{
4b3bd052 40 Lisp_Object up, canon, eqv;
dcfdbac7 41
2858a1c1 42 if (! CHAR_TABLE_P (object))
7f7fef04 43 return Qnil;
2858a1c1 44 if (! EQ (XCHAR_TABLE (object)->purpose, Qcase_table))
7f7fef04 45 return Qnil;
dcfdbac7 46
2858a1c1
EN
47 up = XCHAR_TABLE (object)->extras[0];
48 canon = XCHAR_TABLE (object)->extras[1];
49 eqv = XCHAR_TABLE (object)->extras[2];
7f7fef04
RS
50
51 return ((NILP (up) || CHAR_TABLE_P (up))
d427b66a 52 && ((NILP (canon) && NILP (eqv))
7f7fef04
RS
53 || (CHAR_TABLE_P (canon)
54 && (NILP (eqv) || CHAR_TABLE_P (eqv))))
dcfdbac7
JB
55 ? Qt : Qnil);
56}
57
58static Lisp_Object
59check_case_table (obj)
60 Lisp_Object obj;
61{
62 register Lisp_Object tem;
63
d427b66a 64 while (tem = Fcase_table_p (obj), NILP (tem))
b37902c8 65 obj = wrong_type_argument (Qcase_table_p, obj);
dcfdbac7
JB
66 return (obj);
67}
68
69DEFUN ("current-case-table", Fcurrent_case_table, Scurrent_case_table, 0, 0, 0,
70 "Return the case table of the current buffer.")
71 ()
72{
7f7fef04 73 return current_buffer->downcase_table;
dcfdbac7
JB
74}
75
a1de6b4b 76DEFUN ("standard-case-table", Fstandard_case_table, Sstandard_case_table, 0, 0, 0,
dcfdbac7
JB
77 "Return the standard case table.\n\
78This is the one used for new buffers.")
79 ()
80{
7f7fef04 81 return Vascii_downcase_table;
dcfdbac7
JB
82}
83
d9da9451
JB
84static Lisp_Object set_case_table ();
85
dcfdbac7
JB
86DEFUN ("set-case-table", Fset_case_table, Sset_case_table, 1, 1, 0,
87 "Select a new case table for the current buffer.\n\
c7608f45
RS
88A case table is a char-table which maps characters\n\
89to their lower-case equivalents. It also has three \"extra\" slots\n\
90which may be additional char-tables or nil.\n\
7f7fef04 91These slots are called UPCASE, CANONICALIZE and EQUIVALENCES.\n\
dcfdbac7
JB
92UPCASE maps each character to its upper-case equivalent;\n\
93 if lower and upper case characters are in 1-1 correspondence,\n\
94 you may use nil and the upcase table will be deduced from DOWNCASE.\n\
95CANONICALIZE maps each character to a canonical equivalent;\n\
96 any two characters that are related by case-conversion have the same\n\
5a0fd72f
RS
97 canonical equivalent character; it may be nil, in which case it is\n\
98 deduced from DOWNCASE and UPCASE.\n\
dcfdbac7 99EQUIVALENCES is a map that cyclicly permutes each equivalence class\n\
5a0fd72f
RS
100 (of characters with the same canonical equivalent); it may be nil,\n\
101 in which case it is deduced from CANONICALIZE.")
dcfdbac7
JB
102 (table)
103 Lisp_Object table;
104{
d9da9451 105 return set_case_table (table, 0);
dcfdbac7
JB
106}
107
a1de6b4b 108DEFUN ("set-standard-case-table", Fset_standard_case_table, Sset_standard_case_table, 1, 1, 0,
dcfdbac7
JB
109 "Select a new standard case table for new buffers.\n\
110See `set-case-table' for more info on case tables.")
111 (table)
112 Lisp_Object table;
113{
d9da9451 114 return set_case_table (table, 1);
dcfdbac7
JB
115}
116
d9da9451 117static Lisp_Object
dcfdbac7
JB
118set_case_table (table, standard)
119 Lisp_Object table;
120 int standard;
121{
4b3bd052 122 Lisp_Object up, canon, eqv;
dcfdbac7
JB
123
124 check_case_table (table);
125
7f7fef04
RS
126 up = XCHAR_TABLE (table)->extras[0];
127 canon = XCHAR_TABLE (table)->extras[1];
128 eqv = XCHAR_TABLE (table)->extras[2];
dcfdbac7 129
d427b66a 130 if (NILP (up))
dcfdbac7 131 {
7f7fef04 132 up = Fmake_char_table (Qcase_table, Qnil);
c0c15b93 133 compute_trt_inverse (table, up);
7f7fef04 134 XCHAR_TABLE (table)->extras[0] = up;
dcfdbac7
JB
135 }
136
d427b66a 137 if (NILP (canon))
dcfdbac7
JB
138 {
139 register int i;
7f7fef04 140 Lisp_Object *upvec = XCHAR_TABLE (up)->contents;
4b3bd052 141 Lisp_Object *downvec = XCHAR_TABLE (table)->contents;
dcfdbac7 142
4b3bd052 143 canon = Fmake_char_table (Qcase_table, Qnil);
dcfdbac7
JB
144
145 /* Set up the CANON vector; for each character,
146 this sequence of upcasing and downcasing ought to
147 get the "preferred" lowercase equivalent. */
c0c15b93 148 for (i = 0; i < CHAR_TABLE_SINGLE_BYTE_SLOTS; i++)
7f7fef04
RS
149 XCHAR_TABLE (canon)->contents[i] = downvec[upvec[downvec[i]]];
150 XCHAR_TABLE (table)->extras[1] = canon;
5a0fd72f
RS
151 }
152
153 if (NILP (eqv))
154 {
7f7fef04 155 eqv = Fmake_char_table (Qcase_table, Qnil);
c0c15b93 156 compute_trt_inverse (canon, eqv);
4b3bd052 157 XCHAR_TABLE (table)->extras[2] = eqv;
dcfdbac7
JB
158 }
159
160 if (standard)
4b3bd052 161 Vascii_downcase_table = table;
dcfdbac7 162 else
6c6fcbf8
RS
163 {
164 current_buffer->downcase_table = table;
165 current_buffer->upcase_table = up;
166 current_buffer->case_canon_table = canon;
167 current_buffer->case_eqv_table = eqv;
168 }
7f7fef04 169
dcfdbac7
JB
170 return table;
171}
172\f
e16696ba
KH
173/* Using the scratch array at BYTES of which the first DEPTH elements
174 are already set, and using the multi-byte structure inherited from
175 TRT, make INVERSE be an identity mapping. That is, for each slot
176 that's indexed by a single byte, store that byte in INVERSE.
177 Where TRT has a subtable, make a corresponding subtable in INVERSE
178 and recursively initialize that subtable so that its elements are
179 the multi-byte characters that correspond to the index bytes.
180 This is the first step in generating an inverse mapping. */
181
c0c15b93
KH
182static void
183compute_trt_identity (bytes, depth, trt, inverse)
184 unsigned char *bytes;
185 int depth;
186 struct Lisp_Char_Table *trt, *inverse;
187{
188 register int i;
4edca269 189 int lim = (depth == 0 ? CHAR_TABLE_ORDINARY_SLOTS : SUB_CHAR_TABLE_ORDINARY_SLOTS);
c0c15b93 190
4edca269 191 for (i = 0; i < lim; i++)
c0c15b93
KH
192 {
193 if (NATNUMP (trt->contents[i]))
194 {
195 bytes[depth] = i;
196 XSETFASTINT (inverse->contents[i],
197 (depth == 0 && i < CHAR_TABLE_SINGLE_BYTE_SLOTS ? i
4edca269 198 : MAKE_NON_ASCII_CHAR (bytes[0], bytes[1], bytes[2])));
c0c15b93 199 }
4edca269 200 else if (SUB_CHAR_TABLE_P (trt->contents[i]))
c0c15b93 201 {
4edca269
RS
202 bytes[depth] = i - 128;
203 inverse->contents[i] = make_sub_char_table (Qnil);
c0c15b93
KH
204 compute_trt_identity (bytes, depth + 1,
205 XCHAR_TABLE (trt->contents[i]),
206 XCHAR_TABLE (inverse->contents[i]));
207 }
208 else /* must be Qnil or Qidentity */
209 inverse->contents[i] = trt->contents[i];
210 }
211}
dcfdbac7 212
e16696ba
KH
213/* Using the scratch array at BYTES of which the first DEPTH elements
214 are already set, permute the elements of INVERSE (which is initially
215 an identity mapping) so that it has one cycle for each equivalence
216 class induced by the translation table TRT. IBASE is the lispy
217 version of the outermost (depth 0) instance of INVERSE. */
218
7f7fef04 219static void
c0c15b93
KH
220compute_trt_shuffle (bytes, depth, ibase, trt, inverse)
221 unsigned char *bytes;
222 int depth;
223 Lisp_Object ibase;
7f7fef04 224 struct Lisp_Char_Table *trt, *inverse;
dcfdbac7 225{
c0c15b93
KH
226 register int i;
227 Lisp_Object j, tem, q;
4edca269 228 int lim = (depth == 0 ? CHAR_TABLE_ORDINARY_SLOTS : SUB_CHAR_TABLE_ORDINARY_SLOTS);
dcfdbac7 229
4edca269 230 for (i = 0; i < lim; i++)
dcfdbac7 231 {
c0c15b93
KH
232 bytes[depth] = i;
233 XSETFASTINT (j,
234 (depth == 0 && i < CHAR_TABLE_SINGLE_BYTE_SLOTS ? i
4edca269 235 : MAKE_NON_ASCII_CHAR (bytes[0], bytes[1], bytes[2])));
c0c15b93
KH
236 q = trt->contents[i];
237 if (NATNUMP (q) && XFASTINT (q) != XFASTINT (j))
238 {
239 tem = Faref (ibase, q);
240 Faset (ibase, q, j);
241 Faset (ibase, j, tem);
242 }
4edca269 243 else if (SUB_CHAR_TABLE_P (q))
dcfdbac7 244 {
4edca269 245 bytes[depth] = i - 128;
c0c15b93
KH
246 compute_trt_shuffle (bytes, depth + 1, ibase,
247 XCHAR_TABLE (trt->contents[i]),
248 XCHAR_TABLE (inverse->contents[i]));
dcfdbac7
JB
249 }
250 }
251}
c0c15b93
KH
252
253/* Given a translate table TRT, store the inverse mapping into INVERSE.
254 Since TRT is not one-to-one, INVERSE is not a simple mapping.
255 Instead, it divides the space of characters into equivalence classes.
256 All characters in a given class form one circular list, chained through
257 the elements of INVERSE. */
258
259static void
260compute_trt_inverse (trt, inv)
261 Lisp_Object trt, inv;
262{
263 unsigned char bytes[3];
264 compute_trt_identity (bytes, 0, XCHAR_TABLE (trt), XCHAR_TABLE (inv));
265 compute_trt_shuffle (bytes, 0, inv, XCHAR_TABLE (trt), XCHAR_TABLE (inv));
266}
dcfdbac7
JB
267\f
268init_casetab_once ()
269{
270 register int i;
7f7fef04
RS
271 Lisp_Object down, up;
272 Qcase_table = intern ("case-table");
273 staticpro (&Qcase_table);
274
275 /* Intern this now in case it isn't already done.
276 Setting this variable twice is harmless.
277 But don't staticpro it here--that is done in alloc.c. */
278 Qchar_table_extra_slots = intern ("char-table-extra-slots");
dcfdbac7 279
7f7fef04
RS
280 /* Now we are ready to set up this property, so we can
281 create char tables. */
4b3bd052 282 Fput (Qcase_table, Qchar_table_extra_slots, make_number (3));
7f7fef04
RS
283
284 down = Fmake_char_table (Qcase_table, Qnil);
285 Vascii_downcase_table = down;
e1b490ca 286 XCHAR_TABLE (down)->purpose = Qcase_table;
dcfdbac7 287
c0c15b93
KH
288 for (i = 0; i < CHAR_TABLE_SINGLE_BYTE_SLOTS; i++)
289 XSETFASTINT (XCHAR_TABLE (down)->contents[i],
290 (i >= 'A' && i <= 'Z') ? i + ('a' - 'A') : i);
7f7fef04
RS
291
292 XCHAR_TABLE (down)->extras[1] = Fcopy_sequence (down);
dcfdbac7 293
7f7fef04
RS
294 up = Fmake_char_table (Qcase_table, Qnil);
295 XCHAR_TABLE (down)->extras[0] = up;
dcfdbac7 296
c0c15b93
KH
297 for (i = 0; i < CHAR_TABLE_SINGLE_BYTE_SLOTS; i++)
298 XSETFASTINT (XCHAR_TABLE (up)->contents[i],
299 ((i >= 'A' && i <= 'Z')
300 ? i + ('a' - 'A')
301 : ((i >= 'a' && i <= 'z')
302 ? i + ('A' - 'a')
303 : i)));
7f7fef04
RS
304
305 XCHAR_TABLE (down)->extras[2] = Fcopy_sequence (up);
dcfdbac7
JB
306}
307
308syms_of_casetab ()
309{
310 Qcase_table_p = intern ("case-table-p");
311 staticpro (&Qcase_table_p);
7f7fef04 312
8f84b1a1 313 staticpro (&Vascii_canon_table);
dcfdbac7 314 staticpro (&Vascii_downcase_table);
8f84b1a1
EN
315 staticpro (&Vascii_eqv_table);
316 staticpro (&Vascii_upcase_table);
dcfdbac7
JB
317
318 defsubr (&Scase_table_p);
319 defsubr (&Scurrent_case_table);
320 defsubr (&Sstandard_case_table);
321 defsubr (&Sset_case_table);
322 defsubr (&Sset_standard_case_table);
dcfdbac7 323}