comparison src/editfns.c @ 17031:c612a2cdd83b

Include charset.h. (Fchar_to_string, Fstring_to_char): Handle multibyte characters. (Fsref): New function. (Fgoto_char): Force point to be at a character boundary. (Ffollowing_char, Fpreceding_char): Handle multibyte characters. (Fchar_after): Handle multibyte characters. (Fchar_before): New function. (general_insert_function): New function. (Finsert, Finsert_and_inherit, Finsert_before_markers): Use it. (Finsert_char): Doc-string refer to markers of before-insertion-type. Handle multibyte characters. (Fsubst_char_in_region): Handle multibyte characters. (Fchar_equal): Don't consider `case' of multibyte characters. (syms_of_editfns): Handle the new function `char-before'.
author Karl Heuer <kwzh@gnu.org>
date Thu, 20 Feb 1997 06:48:37 +0000
parents ab49512bcdff
children dd39f3c57b3e
comparison
equal deleted inserted replaced
17030:42d758739319 17031:c612a2cdd83b
30 #endif 30 #endif
31 31
32 #include "lisp.h" 32 #include "lisp.h"
33 #include "intervals.h" 33 #include "intervals.h"
34 #include "buffer.h" 34 #include "buffer.h"
35 #include "charset.h"
35 #include "window.h" 36 #include "window.h"
36 37
37 #include "systime.h" 38 #include "systime.h"
38 39
39 #define min(a, b) ((a) < (b) ? (a) : (b)) 40 #define min(a, b) ((a) < (b) ? (a) : (b))
112 else if (NILP (Vuser_full_name)) 113 else if (NILP (Vuser_full_name))
113 Vuser_full_name = build_string ("unknown"); 114 Vuser_full_name = build_string ("unknown");
114 } 115 }
115 116
116 DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0, 117 DEFUN ("char-to-string", Fchar_to_string, Schar_to_string, 1, 1, 0,
117 "Convert arg CHARACTER to a one-character string containing that character.") 118 "Convert arg CHAR to a string containing multi-byte form of that character.")
118 (character) 119 (character)
119 Lisp_Object character; 120 Lisp_Object character;
120 { 121 {
121 char c; 122 int len;
123 char workbuf[4], *str;
124
122 CHECK_NUMBER (character, 0); 125 CHECK_NUMBER (character, 0);
123 126
124 c = XINT (character); 127 len = CHAR_STRING (XFASTINT (character), workbuf, str);
125 return make_string (&c, 1); 128 return make_string (str, len);
126 } 129 }
127 130
128 DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0, 131 DEFUN ("string-to-char", Fstring_to_char, Sstring_to_char, 1, 1, 0,
129 "Convert arg STRING to a character, the first character of that string.") 132 "Convert arg STRING to a character, the first character of that string.\n\
133 A multibyte character is handled correctly.")
130 (string) 134 (string)
131 register Lisp_Object string; 135 register Lisp_Object string;
132 { 136 {
133 register Lisp_Object val; 137 register Lisp_Object val;
134 register struct Lisp_String *p; 138 register struct Lisp_String *p;
135 CHECK_STRING (string, 0); 139 CHECK_STRING (string, 0);
136
137 p = XSTRING (string); 140 p = XSTRING (string);
138 if (p->size) 141 if (p->size)
139 XSETFASTINT (val, ((unsigned char *) p->data)[0]); 142 XSETFASTINT (val, STRING_CHAR (p->data, p->size));
140 else 143 else
141 XSETFASTINT (val, 0); 144 XSETFASTINT (val, 0);
142 return val; 145 return val;
143 } 146 }
147
148 DEFUN ("sref", Fsref, Ssref, 2, 2, 0,
149 "Return the character in STRING at INDEX. INDEX starts at 0.\n\
150 A multibyte character is handled correctly.\n\
151 INDEX not pointing at character boundary is an error.")
152 (str, idx)
153 Lisp_Object str, idx;
154 {
155 register int idxval, len;
156 register unsigned char *p;
157 register Lisp_Object val;
158
159 CHECK_STRING (str, 0);
160 CHECK_NUMBER (idx, 1);
161 idxval = XINT (idx);
162 if (idxval < 0 || idxval >= (len = XVECTOR (str)->size))
163 args_out_of_range (str, idx);
164 p = XSTRING (str)->data + idxval;
165 if (!CHAR_HEAD_P (p))
166 error ("Not character boundary");
167
168 len = XSTRING (str)->size - idxval;
169 XSETFASTINT (val, STRING_CHAR (p, len));
170 return val;
171 }
172
144 173
145 static Lisp_Object 174 static Lisp_Object
146 buildmark (val) 175 buildmark (val)
147 int val; 176 int val;
148 { 177 {
181 return num; 210 return num;
182 } 211 }
183 212
184 DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ", 213 DEFUN ("goto-char", Fgoto_char, Sgoto_char, 1, 1, "NGoto char: ",
185 "Set point to POSITION, a number or marker.\n\ 214 "Set point to POSITION, a number or marker.\n\
186 Beginning of buffer is position (point-min), end is (point-max).") 215 Beginning of buffer is position (point-min), end is (point-max).\n\
216 If the position is in the middle of a multibyte form,\n\
217 the actual point is set at the head of the multibyte form\n\
218 except in the case that `enable-multibyte-characters' is nil.")
187 (position) 219 (position)
188 register Lisp_Object position; 220 register Lisp_Object position;
189 { 221 {
222 int pos;
223 unsigned char *p;
224
190 CHECK_NUMBER_COERCE_MARKER (position, 0); 225 CHECK_NUMBER_COERCE_MARKER (position, 0);
191 226
192 SET_PT (clip_to_bounds (BEGV, XINT (position), ZV)); 227 pos = clip_to_bounds (BEGV, XINT (position), ZV);
228 /* If POS is in a middle of multi-byte form (i.e. *P >= 0xA0), we
229 must decrement POS until it points the head of the multi-byte
230 form. */
231 if (!NILP (current_buffer->enable_multibyte_characters)
232 && *(p = POS_ADDR (pos)) >= 0xA0
233 && pos > BEGV)
234 {
235 /* Since a multi-byte form does not contain the gap, POS should
236 not stride over the gap while it is being decreased. So, we
237 set the limit as below. */
238 unsigned char *p_min = pos < GPT ? BEG_ADDR : GAP_END_ADDR;
239 unsigned int saved_pos = pos;
240
241 do {
242 p--, pos--;
243 } while (p > p_min && *p >= 0xA0);
244 if (*p < 0x80)
245 /* This was an invalid multi-byte form. */
246 pos = saved_pos;
247 XSETFASTINT (position, pos);
248 }
249 SET_PT (pos);
193 return position; 250 return position;
194 } 251 }
195 252
196 static Lisp_Object 253 static Lisp_Object
197 region_limit (beginningp) 254 region_limit (beginningp)
424 return buildmark (ZV); 481 return buildmark (ZV);
425 } 482 }
426 483
427 DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0, 484 DEFUN ("following-char", Ffollowing_char, Sfollowing_char, 0, 0, 0,
428 "Return the character following point, as a number.\n\ 485 "Return the character following point, as a number.\n\
429 At the end of the buffer or accessible region, return 0.") 486 At the end of the buffer or accessible region, return 0.\n\
487 If `enable-multibyte-characters' is nil or point is not\n\
488 at character boundary, multibyte form is ignored,\n\
489 and only one byte following point is returned as a character.")
430 () 490 ()
431 { 491 {
432 Lisp_Object temp; 492 Lisp_Object temp;
433 if (PT >= ZV) 493 if (PT >= ZV)
434 XSETFASTINT (temp, 0); 494 XSETFASTINT (temp, 0);
437 return temp; 497 return temp;
438 } 498 }
439 499
440 DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0, 500 DEFUN ("preceding-char", Fprevious_char, Sprevious_char, 0, 0, 0,
441 "Return the character preceding point, as a number.\n\ 501 "Return the character preceding point, as a number.\n\
442 At the beginning of the buffer or accessible region, return 0.") 502 At the beginning of the buffer or accessible region, return 0.\n\
503 If `enable-multibyte-characters' is nil or point is not\n\
504 at character boundary, multi-byte form is ignored,\n\
505 and only one byte preceding point is returned as a character.")
443 () 506 ()
444 { 507 {
445 Lisp_Object temp; 508 Lisp_Object temp;
446 if (PT <= BEGV) 509 if (PT <= BEGV)
447 XSETFASTINT (temp, 0); 510 XSETFASTINT (temp, 0);
511 else if (!NILP (current_buffer->enable_multibyte_characters))
512 {
513 int pos = PT;
514 DEC_POS (pos);
515 XSETFASTINT (temp, FETCH_CHAR (pos));
516 }
448 else 517 else
449 XSETFASTINT (temp, FETCH_CHAR (PT - 1)); 518 XSETFASTINT (temp, FETCH_BYTE (point - 1));
450 return temp; 519 return temp;
451 } 520 }
452 521
453 DEFUN ("bobp", Fbobp, Sbobp, 0, 0, 0, 522 DEFUN ("bobp", Fbobp, Sbobp, 0, 0, 0,
454 "Return T if point is at the beginning of the buffer.\n\ 523 "Return T if point is at the beginning of the buffer.\n\
472 541
473 DEFUN ("bolp", Fbolp, Sbolp, 0, 0, 0, 542 DEFUN ("bolp", Fbolp, Sbolp, 0, 0, 0,
474 "Return T if point is at the beginning of a line.") 543 "Return T if point is at the beginning of a line.")
475 () 544 ()
476 { 545 {
477 if (PT == BEGV || FETCH_CHAR (PT - 1) == '\n') 546 if (PT == BEGV || FETCH_BYTE (PT - 1) == '\n')
478 return Qt; 547 return Qt;
479 return Qnil; 548 return Qnil;
480 } 549 }
481 550
482 DEFUN ("eolp", Feolp, Seolp, 0, 0, 0, 551 DEFUN ("eolp", Feolp, Seolp, 0, 0, 0,
483 "Return T if point is at the end of a line.\n\ 552 "Return T if point is at the end of a line.\n\
484 `End of a line' includes point being at the end of the buffer.") 553 `End of a line' includes point being at the end of the buffer.")
485 () 554 ()
486 { 555 {
487 if (PT == ZV || FETCH_CHAR (PT) == '\n') 556 if (PT == ZV || FETCH_BYTE (PT) == '\n')
488 return Qt; 557 return Qt;
489 return Qnil; 558 return Qnil;
490 } 559 }
491 560
492 DEFUN ("char-after", Fchar_after, Schar_after, 1, 1, 0, 561 DEFUN ("char-after", Fchar_after, Schar_after, 1, 1, 0,
493 "Return character in current buffer at position POS.\n\ 562 "Return character in current buffer at position POS.\n\
494 POS is an integer or a buffer pointer.\n\ 563 POS is an integer or a buffer pointer.\n\
495 If POS is out of range, the value is nil.") 564 If POS is out of range, the value is nil.\n\
565 If `enable-multibyte-characters' is nil or POS is not at character boundary,\n\
566 multi-byte form is ignored, and only one byte at POS\n\
567 is returned as a character.")
496 (pos) 568 (pos)
497 Lisp_Object pos; 569 Lisp_Object pos;
498 { 570 {
499 register Lisp_Object val; 571 register Lisp_Object val;
500 register int n; 572 register int n;
504 n = XINT (pos); 576 n = XINT (pos);
505 if (n < BEGV || n >= ZV) return Qnil; 577 if (n < BEGV || n >= ZV) return Qnil;
506 578
507 XSETFASTINT (val, FETCH_CHAR (n)); 579 XSETFASTINT (val, FETCH_CHAR (n));
508 return val; 580 return val;
581 }
582
583 DEFUN ("char-before", Fchar_before, Schar_before, 1, 1, 0,
584 "Return character in current buffer preceding position POS.\n\
585 POS is an integer or a buffer pointer.\n\
586 If POS is out of range, the value is nil.\n\
587 If `enable-multibyte-characters' is nil or POS is not at character boundary,\n\
588 multi-byte form is ignored, and only one byte preceding POS\n\
589 is returned as a character.")
590 (pos)
591 Lisp_Object pos;
592 {
593 register Lisp_Object val;
594 register int n;
595
596 CHECK_NUMBER_COERCE_MARKER (pos, 0);
597
598 n = XINT (pos);
599 if (n <= BEGV || n > ZV) return Qnil;
600
601 if (!NILP (current_buffer->enable_multibyte_characters))
602 {
603 DEC_POS (pos);
604 XSETFASTINT (val, FETCH_CHAR (pos));
605 }
606 else
607 {
608 pos--;
609 XSETFASTINT (val, FETCH_BYTE (pos));
610 }
611 return val;
509 } 612 }
510 613
511 DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 1, 0, 614 DEFUN ("user-login-name", Fuser_login_name, Suser_login_name, 0, 1, 0,
512 "Return the name under which the user logged in, as a string.\n\ 615 "Return the name under which the user logged in, as a string.\n\
513 This is based on the effective uid, not the real uid.\n\ 616 This is based on the effective uid, not the real uid.\n\
1112 1215
1113 tzset (); 1216 tzset ();
1114 #endif 1217 #endif
1115 } 1218 }
1116 1219
1220 /* Insert NARGS Lisp objects in the array ARGS by calling INSERT_FUNC
1221 (if a type of object is Lisp_Int) or INSERT_FROM_STRING_FUNC (if a
1222 type of object is Lisp_String). INHERIT is passed to
1223 INSERT_FROM_STRING_FUNC as the last argument. */
1224
1225 general_insert_function (insert_func, insert_from_string_func,
1226 inherit, nargs, args)
1227 int (*insert_func)(), (*insert_from_string_func)();
1228 int inherit, nargs;
1229 register Lisp_Object *args;
1230 {
1231 register int argnum;
1232 register Lisp_Object val;
1233
1234 for (argnum = 0; argnum < nargs; argnum++)
1235 {
1236 val = args[argnum];
1237 retry:
1238 if (INTEGERP (val))
1239 {
1240 char workbuf[4], *str;
1241 int len;
1242
1243 if (!NILP (current_buffer->enable_multibyte_characters))
1244 len = CHAR_STRING (XFASTINT (val), workbuf, str);
1245 else
1246 workbuf[0] = XINT (val), str = workbuf, len = 1;
1247 (*insert_func) (str, len);
1248 }
1249 else if (STRINGP (val))
1250 {
1251 (*insert_from_string_func) (val, 0, XSTRING (val)->size, inherit);
1252 }
1253 else
1254 {
1255 val = wrong_type_argument (Qchar_or_string_p, val);
1256 goto retry;
1257 }
1258 }
1259 }
1260
1117 void 1261 void
1118 insert1 (arg) 1262 insert1 (arg)
1119 Lisp_Object arg; 1263 Lisp_Object arg;
1120 { 1264 {
1121 Finsert (1, &arg); 1265 Finsert (1, &arg);
1127 not be used after calling insert or insert_from_string, so 1271 not be used after calling insert or insert_from_string, so
1128 we don't care if it gets trashed. */ 1272 we don't care if it gets trashed. */
1129 1273
1130 DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0, 1274 DEFUN ("insert", Finsert, Sinsert, 0, MANY, 0,
1131 "Insert the arguments, either strings or characters, at point.\n\ 1275 "Insert the arguments, either strings or characters, at point.\n\
1132 Point moves forward so that it ends up after the inserted text.\n\ 1276 Point and before-insertion-markers move forward so that it ends up\n\
1277 after the inserted text.\n\
1133 Any other markers at the point of insertion remain before the text.") 1278 Any other markers at the point of insertion remain before the text.")
1134 (nargs, args) 1279 (nargs, args)
1135 int nargs; 1280 int nargs;
1136 register Lisp_Object *args; 1281 register Lisp_Object *args;
1137 { 1282 {
1138 register int argnum; 1283 general_insert_function (insert, insert_from_string, 0, nargs, args);
1139 register Lisp_Object tem;
1140 char str[1];
1141
1142 for (argnum = 0; argnum < nargs; argnum++)
1143 {
1144 tem = args[argnum];
1145 retry:
1146 if (INTEGERP (tem))
1147 {
1148 str[0] = XINT (tem);
1149 insert (str, 1);
1150 }
1151 else if (STRINGP (tem))
1152 {
1153 insert_from_string (tem, 0, XSTRING (tem)->size, 0);
1154 }
1155 else
1156 {
1157 tem = wrong_type_argument (Qchar_or_string_p, tem);
1158 goto retry;
1159 }
1160 }
1161
1162 return Qnil; 1284 return Qnil;
1163 } 1285 }
1164 1286
1165 DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit, 1287 DEFUN ("insert-and-inherit", Finsert_and_inherit, Sinsert_and_inherit,
1166 0, MANY, 0, 1288 0, MANY, 0,
1167 "Insert the arguments at point, inheriting properties from adjoining text.\n\ 1289 "Insert the arguments at point, inheriting properties from adjoining text.\n\
1168 Point moves forward so that it ends up after the inserted text.\n\ 1290 Point and before-insertion-markers move forward so that it ends up\n\
1291 after the inserted text.\n\
1169 Any other markers at the point of insertion remain before the text.") 1292 Any other markers at the point of insertion remain before the text.")
1170 (nargs, args) 1293 (nargs, args)
1171 int nargs; 1294 int nargs;
1172 register Lisp_Object *args; 1295 register Lisp_Object *args;
1173 { 1296 {
1174 register int argnum; 1297 general_insert_function (insert_and_inherit, insert_from_string, 1,
1175 register Lisp_Object tem; 1298 nargs, args);
1176 char str[1];
1177
1178 for (argnum = 0; argnum < nargs; argnum++)
1179 {
1180 tem = args[argnum];
1181 retry:
1182 if (INTEGERP (tem))
1183 {
1184 str[0] = XINT (tem);
1185 insert_and_inherit (str, 1);
1186 }
1187 else if (STRINGP (tem))
1188 {
1189 insert_from_string (tem, 0, XSTRING (tem)->size, 1);
1190 }
1191 else
1192 {
1193 tem = wrong_type_argument (Qchar_or_string_p, tem);
1194 goto retry;
1195 }
1196 }
1197
1198 return Qnil; 1299 return Qnil;
1199 } 1300 }
1200 1301
1201 DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0, 1302 DEFUN ("insert-before-markers", Finsert_before_markers, Sinsert_before_markers, 0, MANY, 0,
1202 "Insert strings or characters at point, relocating markers after the text.\n\ 1303 "Insert strings or characters at point, relocating markers after the text.\n\
1203 Point moves forward so that it ends up after the inserted text.\n\ 1304 Point and before-insertion-markers move forward so that it ends up\n\
1305 after the inserted text.\n\
1204 Any other markers at the point of insertion also end up after the text.") 1306 Any other markers at the point of insertion also end up after the text.")
1205 (nargs, args) 1307 (nargs, args)
1206 int nargs; 1308 int nargs;
1207 register Lisp_Object *args; 1309 register Lisp_Object *args;
1208 { 1310 {
1209 register int argnum; 1311 general_insert_function (insert_before_markers,
1210 register Lisp_Object tem; 1312 insert_from_string_before_markers, 0,
1211 char str[1]; 1313 nargs, args);
1212
1213 for (argnum = 0; argnum < nargs; argnum++)
1214 {
1215 tem = args[argnum];
1216 retry:
1217 if (INTEGERP (tem))
1218 {
1219 str[0] = XINT (tem);
1220 insert_before_markers (str, 1);
1221 }
1222 else if (STRINGP (tem))
1223 {
1224 insert_from_string_before_markers (tem, 0, XSTRING (tem)->size, 0);
1225 }
1226 else
1227 {
1228 tem = wrong_type_argument (Qchar_or_string_p, tem);
1229 goto retry;
1230 }
1231 }
1232
1233 return Qnil; 1314 return Qnil;
1234 } 1315 }
1235 1316
1236 DEFUN ("insert-before-markers-and-inherit", Finsert_and_inherit_before_markers, 1317 DEFUN ("insert-before-markers-and-inherit", Finsert_and_inherit_before_markers,
1237 Sinsert_and_inherit_before_markers, 0, MANY, 0, 1318 Sinsert_and_inherit_before_markers, 0, MANY, 0,
1240 Any other markers at the point of insertion also end up after the text.") 1321 Any other markers at the point of insertion also end up after the text.")
1241 (nargs, args) 1322 (nargs, args)
1242 int nargs; 1323 int nargs;
1243 register Lisp_Object *args; 1324 register Lisp_Object *args;
1244 { 1325 {
1245 register int argnum; 1326 general_insert_function (insert_before_markers_and_inherit,
1246 register Lisp_Object tem; 1327 insert_from_string_before_markers, 1,
1247 char str[1]; 1328 nargs, args);
1248
1249 for (argnum = 0; argnum < nargs; argnum++)
1250 {
1251 tem = args[argnum];
1252 retry:
1253 if (INTEGERP (tem))
1254 {
1255 str[0] = XINT (tem);
1256 insert_before_markers_and_inherit (str, 1);
1257 }
1258 else if (STRINGP (tem))
1259 {
1260 insert_from_string_before_markers (tem, 0, XSTRING (tem)->size, 1);
1261 }
1262 else
1263 {
1264 tem = wrong_type_argument (Qchar_or_string_p, tem);
1265 goto retry;
1266 }
1267 }
1268
1269 return Qnil; 1329 return Qnil;
1270 } 1330 }
1271 1331
1272 DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0, 1332 DEFUN ("insert-char", Finsert_char, Sinsert_char, 2, 3, 0,
1273 "Insert COUNT (second arg) copies of CHARACTER (first arg).\n\ 1333 "Insert COUNT (second arg) copies of CHARACTER (first arg).\n\
1274 Point and all markers are affected as in the function `insert'.\n\ 1334 Point and before-insertion-markers are affected as in the function `insert'.\n\
1275 Both arguments are required.\n\ 1335 Both arguments are required.\n\
1276 The optional third arg INHERIT, if non-nil, says to inherit text properties\n\ 1336 The optional third arg INHERIT, if non-nil, says to inherit text properties\n\
1277 from adjoining text, if those properties are sticky.") 1337 from adjoining text, if those properties are sticky.")
1278 (character, count, inherit) 1338 (character, count, inherit)
1279 Lisp_Object character, count, inherit; 1339 Lisp_Object character, count, inherit;
1280 { 1340 {
1281 register unsigned char *string; 1341 register unsigned char *string;
1282 register int strlen; 1342 register int strlen;
1283 register int i, n; 1343 register int i, n;
1344 int len;
1345 unsigned char workbuf[4], *str;
1284 1346
1285 CHECK_NUMBER (character, 0); 1347 CHECK_NUMBER (character, 0);
1286 CHECK_NUMBER (count, 1); 1348 CHECK_NUMBER (count, 1);
1287 1349
1288 n = XINT (count); 1350 if (!NILP (current_buffer->enable_multibyte_characters))
1351 len = CHAR_STRING (XFASTINT (character), workbuf, str);
1352 else
1353 workbuf[0] = XFASTINT (character), str = workbuf, len = 1;
1354 n = XINT (count) * len;
1289 if (n <= 0) 1355 if (n <= 0)
1290 return Qnil; 1356 return Qnil;
1291 strlen = min (n, 256); 1357 strlen = min (n, 256 * len);
1292 string = (unsigned char *) alloca (strlen); 1358 string = (unsigned char *) alloca (strlen);
1293 for (i = 0; i < strlen; i++) 1359 for (i = 0; i < strlen; i++)
1294 string[i] = XFASTINT (character); 1360 string[i] = str[i % len];
1295 while (n >= strlen) 1361 while (n >= strlen)
1296 { 1362 {
1297 if (!NILP (inherit)) 1363 if (!NILP (inherit))
1298 insert_and_inherit (string, strlen); 1364 insert_and_inherit (string, strlen);
1299 else 1365 else
1335 1401
1336 if (start < GPT && GPT < end) 1402 if (start < GPT && GPT < end)
1337 move_gap (start); 1403 move_gap (start);
1338 1404
1339 result = make_uninit_string (end - start); 1405 result = make_uninit_string (end - start);
1340 bcopy (&FETCH_CHAR (start), XSTRING (result)->data, end - start); 1406 bcopy (POS_ADDR (start), XSTRING (result)->data, end - start);
1341 1407
1342 /* If desired, update and copy the text properties. */ 1408 /* If desired, update and copy the text properties. */
1343 #ifdef USE_TEXT_PROPERTIES 1409 #ifdef USE_TEXT_PROPERTIES
1344 if (props) 1410 if (props)
1345 { 1411 {
1625 1691
1626 DEFUN ("subst-char-in-region", Fsubst_char_in_region, 1692 DEFUN ("subst-char-in-region", Fsubst_char_in_region,
1627 Ssubst_char_in_region, 4, 5, 0, 1693 Ssubst_char_in_region, 4, 5, 0,
1628 "From START to END, replace FROMCHAR with TOCHAR each time it occurs.\n\ 1694 "From START to END, replace FROMCHAR with TOCHAR each time it occurs.\n\
1629 If optional arg NOUNDO is non-nil, don't record this change for undo\n\ 1695 If optional arg NOUNDO is non-nil, don't record this change for undo\n\
1630 and don't mark the buffer as really changed.") 1696 and don't mark the buffer as really changed.\n\
1697 Both characters must have the same length of multi-byte form.")
1631 (start, end, fromchar, tochar, noundo) 1698 (start, end, fromchar, tochar, noundo)
1632 Lisp_Object start, end, fromchar, tochar, noundo; 1699 Lisp_Object start, end, fromchar, tochar, noundo;
1633 { 1700 {
1634 register int pos, stop, look; 1701 register int pos, stop, i, len;
1635 int changed = 0; 1702 int changed = 0;
1703 unsigned char fromwork[4], *fromstr, towork[4], *tostr, *p;
1636 int count = specpdl_ptr - specpdl; 1704 int count = specpdl_ptr - specpdl;
1637 1705
1638 validate_region (&start, &end); 1706 validate_region (&start, &end);
1639 CHECK_NUMBER (fromchar, 2); 1707 CHECK_NUMBER (fromchar, 2);
1640 CHECK_NUMBER (tochar, 3); 1708 CHECK_NUMBER (tochar, 3);
1641 1709
1710 if (! NILP (current_buffer->enable_multibyte_characters))
1711 {
1712 len = CHAR_STRING (XFASTINT (fromchar), fromwork, fromstr);
1713 if (CHAR_STRING (XFASTINT (tochar), towork, tostr) != len)
1714 error ("Characters in subst-char-in-region have different byte-lengths");
1715 }
1716 else
1717 {
1718 len = 1;
1719 fromwork[0] = XFASTINT (fromchar), fromstr = fromwork;
1720 towork[0] = XFASTINT (tochar), tostr = towork;
1721 }
1722
1642 pos = XINT (start); 1723 pos = XINT (start);
1643 stop = XINT (end); 1724 stop = XINT (end);
1644 look = XINT (fromchar);
1645 1725
1646 /* If we don't want undo, turn off putting stuff on the list. 1726 /* If we don't want undo, turn off putting stuff on the list.
1647 That's faster than getting rid of things, 1727 That's faster than getting rid of things,
1648 and it prevents even the entry for a first change. 1728 and it prevents even the entry for a first change.
1649 Also inhibit locking the file. */ 1729 Also inhibit locking the file. */
1656 record_unwind_protect (subst_char_in_region_unwind_1, 1736 record_unwind_protect (subst_char_in_region_unwind_1,
1657 current_buffer->filename); 1737 current_buffer->filename);
1658 current_buffer->filename = Qnil; 1738 current_buffer->filename = Qnil;
1659 } 1739 }
1660 1740
1661 while (pos < stop) 1741 if (pos < GPT)
1662 { 1742 stop = min(stop, GPT);
1663 if (FETCH_CHAR (pos) == look) 1743 p = POS_ADDR (pos);
1744 while (1)
1745 {
1746 if (pos >= stop)
1747 {
1748 if (pos >= XINT (end)) break;
1749 stop = XINT (end);
1750 p = POS_ADDR (pos);
1751 }
1752 if (p[0] == fromstr[0]
1753 && (len == 1
1754 || (p[1] == fromstr[1]
1755 && (len == 2 || (p[2] == fromstr[2]
1756 && (len == 3 || p[3] == fromstr[3]))))))
1664 { 1757 {
1665 if (! changed) 1758 if (! changed)
1666 { 1759 {
1667 modify_region (current_buffer, XINT (start), stop); 1760 modify_region (current_buffer, XINT (start), XINT (end));
1668 1761
1669 if (! NILP (noundo)) 1762 if (! NILP (noundo))
1670 { 1763 {
1671 if (MODIFF - 1 == SAVE_MODIFF) 1764 if (MODIFF - 1 == SAVE_MODIFF)
1672 SAVE_MODIFF++; 1765 SAVE_MODIFF++;
1673 if (MODIFF - 1 == current_buffer->auto_save_modified) 1766 if (MODIFF - 1 == current_buffer->auto_save_modified)
1674 current_buffer->auto_save_modified++; 1767 current_buffer->auto_save_modified++;
1675 } 1768 }
1676 1769
1677 changed = 1; 1770 changed = 1;
1678 } 1771 }
1679 1772
1680 if (NILP (noundo)) 1773 if (NILP (noundo))
1681 record_change (pos, 1); 1774 record_change (pos, len);
1682 FETCH_CHAR (pos) = XINT (tochar); 1775 for (i = 0; i < len; i++) *p++ = tostr[i];
1776 pos += len;
1683 } 1777 }
1684 pos++; 1778 else
1779 pos++, p++;
1685 } 1780 }
1686 1781
1687 if (changed) 1782 if (changed)
1688 signal_after_change (XINT (start), 1783 signal_after_change (XINT (start),
1689 stop - XINT (start), stop - XINT (start)); 1784 stop - XINT (start), stop - XINT (start));
1720 modify_region (current_buffer, pos, stop); 1815 modify_region (current_buffer, pos, stop);
1721 1816
1722 cnt = 0; 1817 cnt = 0;
1723 for (; pos < stop; ++pos) 1818 for (; pos < stop; ++pos)
1724 { 1819 {
1725 oc = FETCH_CHAR (pos); 1820 oc = FETCH_BYTE (pos);
1726 if (oc < size) 1821 if (oc < size)
1727 { 1822 {
1728 nc = tt[oc]; 1823 nc = tt[oc];
1729 if (nc != oc) 1824 if (nc != oc)
1730 { 1825 {
1731 record_change (pos, 1); 1826 record_change (pos, 1);
1732 FETCH_CHAR (pos) = nc; 1827 *(POS_ADDR (pos)) = nc;
1733 signal_after_change (pos, 1, 1); 1828 signal_after_change (pos, 1, 1);
1734 ++cnt; 1829 ++cnt;
1735 } 1830 }
1736 } 1831 }
1737 } 1832 }
2198 { 2293 {
2199 Lisp_Object *downcase = DOWNCASE_TABLE; 2294 Lisp_Object *downcase = DOWNCASE_TABLE;
2200 CHECK_NUMBER (c1, 0); 2295 CHECK_NUMBER (c1, 0);
2201 CHECK_NUMBER (c2, 1); 2296 CHECK_NUMBER (c2, 1);
2202 2297
2203 if (!NILP (current_buffer->case_fold_search) 2298 if ((!NILP (current_buffer->case_fold_search)
2299 && SINGLE_BYTE_CHAR_P (c1) /* For the moment, downcase table is */
2300 && SINGLE_BYTE_CHAR_P (c2) /* implemented only for ASCII characters. */
2301 )
2204 ? ((XINT (downcase[0xff & XFASTINT (c1)]) 2302 ? ((XINT (downcase[0xff & XFASTINT (c1)])
2205 == XINT (downcase[0xff & XFASTINT (c2)])) 2303 == XINT (downcase[0xff & XFASTINT (c2)]))
2206 && (XFASTINT (c1) & ~0xff) == (XFASTINT (c2) & ~0xff)) 2304 && (XFASTINT (c1) & ~0xff) == (XFASTINT (c2) & ~0xff))
2207 : XINT (c1) == XINT (c2)) 2305 : XINT (c1) == XINT (c2))
2208 return Qt; 2306 return Qt;
2589 2687
2590 defsubr (&Schar_equal); 2688 defsubr (&Schar_equal);
2591 defsubr (&Sgoto_char); 2689 defsubr (&Sgoto_char);
2592 defsubr (&Sstring_to_char); 2690 defsubr (&Sstring_to_char);
2593 defsubr (&Schar_to_string); 2691 defsubr (&Schar_to_string);
2692 defsubr (&Ssref);
2594 defsubr (&Sbuffer_substring); 2693 defsubr (&Sbuffer_substring);
2595 defsubr (&Sbuffer_substring_no_properties); 2694 defsubr (&Sbuffer_substring_no_properties);
2596 defsubr (&Sbuffer_string); 2695 defsubr (&Sbuffer_string);
2597 2696
2598 defsubr (&Spoint_marker); 2697 defsubr (&Spoint_marker);
2619 defsubr (&Sbolp); 2718 defsubr (&Sbolp);
2620 defsubr (&Seolp); 2719 defsubr (&Seolp);
2621 defsubr (&Sfollowing_char); 2720 defsubr (&Sfollowing_char);
2622 defsubr (&Sprevious_char); 2721 defsubr (&Sprevious_char);
2623 defsubr (&Schar_after); 2722 defsubr (&Schar_after);
2723 defsubr (&Schar_before);
2624 defsubr (&Sinsert); 2724 defsubr (&Sinsert);
2625 defsubr (&Sinsert_before_markers); 2725 defsubr (&Sinsert_before_markers);
2626 defsubr (&Sinsert_and_inherit); 2726 defsubr (&Sinsert_and_inherit);
2627 defsubr (&Sinsert_and_inherit_before_markers); 2727 defsubr (&Sinsert_and_inherit_before_markers);
2628 defsubr (&Sinsert_char); 2728 defsubr (&Sinsert_char);