comparison src/fns.c @ 5261:69f687b3ba9d

Move #'replace to C, add bounds-checking to it and to #'fill. 2010-09-06 Aidan Kehoe <kehoea@parhasard.net> Move #'replace to C; add bounds checking to it and to #'fill. * fns.c (Fsubseq, Ffill, mapcarX): Don't #'nreverse in #'subseq, use fill_string_range and check bounds in #'fill, use replace_string_range() in #'map-into avoiding quadratic time when modfiying the string. * fns.c (check_sequence_range, fill_string_range) (replace_string_range, replace_string_range_1, Freplace): New functions; check that arguments fit sequence dimensions, fill a string range with a given character, replace a string range from an Ibyte pointer.
author Aidan Kehoe <kehoea@parhasard.net>
date Mon, 06 Sep 2010 17:29:51 +0100
parents b5611afbcc76
children 75bcb5bef459
comparison
equal deleted inserted replaced
5260:dceee3855f15 5261:69f687b3ba9d
52 #include "opaque.h" 52 #include "opaque.h"
53 53
54 /* NOTE: This symbol is also used in lread.c */ 54 /* NOTE: This symbol is also used in lread.c */
55 #define FEATUREP_SYNTAX 55 #define FEATUREP_SYNTAX
56 56
57 Lisp_Object Qstring_lessp, Qsort, Qmerge, Qfill; 57 Lisp_Object Qstring_lessp, Qsort, Qmerge, Qfill, Qreplace;
58 Lisp_Object Qidentity; 58 Lisp_Object Qidentity;
59 Lisp_Object Qvector, Qarray, Qbit_vector, QsortX, Q_from_end, Q_initial_value; 59 Lisp_Object Qvector, Qarray, Qbit_vector, QsortX, Q_from_end, Q_initial_value;
60 Lisp_Object Qmapconcat, QmapcarX, Qmapvector, Qmapcan, Qmapc, Qmap, Qmap_into; 60 Lisp_Object Qmapconcat, QmapcarX, Qmapvector, Qmapcan, Qmapc, Qmap, Qmap_into;
61 Lisp_Object Qsome, Qevery, Qmaplist, Qmapl, Qmapcon, Qreduce; 61 Lisp_Object Qsome, Qevery, Qmaplist, Qmapl, Qmapcon, Qreduce;
62 Lisp_Object Q_start1, Q_start2, Q_end1, Q_end2;
62 63
63 Lisp_Object Qbase64_conversion_error; 64 Lisp_Object Qbase64_conversion_error;
64 65
65 Lisp_Object Vpath_separator; 66 Lisp_Object Vpath_separator;
66 67
69 70
70 static DOESNT_RETURN 71 static DOESNT_RETURN
71 mapping_interaction_error (Lisp_Object func, Lisp_Object object) 72 mapping_interaction_error (Lisp_Object func, Lisp_Object object)
72 { 73 {
73 invalid_state_2 ("object modified while traversing it", func, object); 74 invalid_state_2 ("object modified while traversing it", func, object);
75 }
76
77 static void
78 check_sequence_range (Lisp_Object sequence, Lisp_Object start,
79 Lisp_Object end, Lisp_Object length)
80 {
81 Elemcount starting = XINT (start), ending, len = XINT (length);
82
83 ending = NILP (end) ? XINT (length) : XINT (end);
84
85 if (!(0 <= starting && starting <= ending && ending <= len))
86 {
87 args_out_of_range_3 (sequence, start, make_int (ending));
88 }
74 } 89 }
75 90
76 static Lisp_Object 91 static Lisp_Object
77 mark_bit_vector (Lisp_Object UNUSED (obj)) 92 mark_bit_vector (Lisp_Object UNUSED (obj))
78 { 93 {
883 } 898 }
884 else 899 else
885 { 900 {
886 CHECK_CHAR_COERCE_INT (elt); 901 CHECK_CHAR_COERCE_INT (elt);
887 string_result_ptr += set_itext_ichar (string_result_ptr, 902 string_result_ptr += set_itext_ichar (string_result_ptr,
888 XCHAR (elt)); 903 XCHAR (elt));
889 } 904 }
890 } 905 }
891 if (args_mse) 906 if (args_mse)
892 { 907 {
893 args_mse[argnum].entry_offset = 908 args_mse[argnum].entry_offset =
1042 e = XINT (end); 1057 e = XINT (end);
1043 if (e < 0) 1058 if (e < 0)
1044 e = len + e; 1059 e = len + e;
1045 } 1060 }
1046 1061
1047 if (!(0 <= s && s <= e && e <= len)) 1062 check_sequence_range (sequence, make_int (s), make_int (e),
1048 args_out_of_range_3 (sequence, make_int (s), make_int (e)); 1063 make_int (len));
1049 1064
1050 if (VECTORP (sequence)) 1065 if (VECTORP (sequence))
1051 { 1066 {
1052 Lisp_Object result = make_vector (e - s, Qnil); 1067 Lisp_Object result = make_vector (e - s, Qnil);
1053 EMACS_INT i; 1068 EMACS_INT i;
1058 out_elts[i - s] = in_elts[i]; 1073 out_elts[i - s] = in_elts[i];
1059 return result; 1074 return result;
1060 } 1075 }
1061 else if (LISTP (sequence)) 1076 else if (LISTP (sequence))
1062 { 1077 {
1063 Lisp_Object result = Qnil; 1078 Lisp_Object result = Qnil, result_tail;
1064 EMACS_INT i; 1079 EMACS_INT i;
1065 1080
1066 sequence = Fnthcdr (make_int (s), sequence); 1081 sequence = Fnthcdr (make_int (s), sequence);
1067 1082
1068 for (i = s; i < e; i++) 1083 if (s < e)
1069 { 1084 {
1070 result = Fcons (Fcar (sequence), result); 1085 result = result_tail = Fcons (Fcar (sequence), Qnil);
1071 sequence = Fcdr (sequence); 1086 sequence = Fcdr (sequence);
1087 for (i = s + 1; i < e; i++)
1088 {
1089 XSETCDR (result_tail, Fcons (Fcar (sequence), Qnil));
1090 sequence = Fcdr (sequence);
1091 result_tail = XCDR (result_tail);
1092 }
1072 } 1093 }
1073 1094
1074 return Fnreverse (result); 1095 return result;
1075 } 1096 }
1076 else if (BIT_VECTORP (sequence)) 1097 else if (BIT_VECTORP (sequence))
1077 { 1098 {
1078 Lisp_Object result = make_bit_vector (e - s, Qzero); 1099 Lisp_Object result = make_bit_vector (e - s, Qzero);
1079 EMACS_INT i; 1100 EMACS_INT i;
3870 { 3891 {
3871 return internal_old_equal (object1, object2, 0) ? Qt : Qnil; 3892 return internal_old_equal (object1, object2, 0) ? Qt : Qnil;
3872 } 3893 }
3873 3894
3874 3895
3896 static Lisp_Object replace_string_range_1 (Lisp_Object dest,
3897 Lisp_Object start,
3898 Lisp_Object end,
3899 const Ibyte *source,
3900 const Ibyte *source_limit,
3901 Lisp_Object item);
3902
3903 /* Fill the substring of DEST beginning at START and ending before END with
3904 the character ITEM. If DEST does not have sufficient space for END -
3905 START characters at START, write as many as is possible without changing
3906 the character length of DEST. Update the string modification flag and do
3907 any sledgehammer checks we have turned on.
3908
3909 START must be a Lisp integer. END can be nil, indicating the length of the
3910 string, or a Lisp integer. The condition (<= 0 START END (length DEST))
3911 must hold, or fill_string_range() will signal an error. */
3912 static Lisp_Object
3913 fill_string_range (Lisp_Object dest, Lisp_Object item, Lisp_Object start,
3914 Lisp_Object end)
3915 {
3916 return replace_string_range_1 (dest, start, end, NULL, NULL, item);
3917 }
3918
3875 DEFUN ("fill", Ffill, 2, MANY, 0, /* 3919 DEFUN ("fill", Ffill, 2, MANY, 0, /*
3876 Destructively modify SEQUENCE by replacing each element with ITEM. 3920 Destructively modify SEQUENCE by replacing each element with ITEM.
3877 SEQUENCE is a list, vector, bit vector, or string. 3921 SEQUENCE is a list, vector, bit vector, or string.
3878 3922
3879 Optional keyword START is the index of the first element of SEQUENCE 3923 Optional keyword START is the index of the first element of SEQUENCE
3880 to be modified, and defaults to zero. Optional keyword END is the 3924 to be modified, and defaults to zero. Optional keyword END is the
3881 exclusive upper bound on the elements of SEQUENCE to be modified, and 3925 exclusive upper bound on the elements of SEQUENCE to be modified, and
3882 defaults to the length of SEQUENCE. 3926 defaults to the length of SEQUENCE.
3883 3927
3884 arguments: (SEQUENCE ITEM &key (START 0) END) 3928 arguments: (SEQUENCE ITEM &key (START 0) (END (length SEQUENCE)))
3885 */ 3929 */
3886 (int nargs, Lisp_Object *args)) 3930 (int nargs, Lisp_Object *args))
3887 { 3931 {
3888 Lisp_Object sequence = args[0]; 3932 Lisp_Object sequence = args[0];
3889 Lisp_Object item = args[1]; 3933 Lisp_Object item = args[1];
3890 Elemcount starting = 0, ending = EMACS_INT_MAX, ii; 3934 Elemcount starting = 0, ending = EMACS_INT_MAX, ii, len;
3891 3935
3892 PARSE_KEYWORDS (Qfill, nargs, args, 2, 2, (start, end), 3936 PARSE_KEYWORDS (Qfill, nargs, args, 2, 2, (start, end), (start = Qzero), 0);
3893 (start = Qzero, end = Qunbound), 0);
3894 3937
3895 CHECK_NATNUM (start); 3938 CHECK_NATNUM (start);
3896 starting = XINT (start); 3939 starting = XINT (start);
3897 3940
3898 if (!UNBOUNDP (end)) 3941 if (!NILP (end))
3899 { 3942 {
3900 CHECK_NATNUM (end); 3943 CHECK_NATNUM (end);
3901 ending = XINT (end); 3944 ending = XINT (end);
3902 } 3945 }
3903 3946
3904 retry: 3947 retry:
3905 if (STRINGP (sequence)) 3948 if (STRINGP (sequence))
3906 { 3949 {
3907 Bytecount prefix_bytecount, item_bytecount, delta;
3908 Ibyte item_buf[MAX_ICHAR_LEN];
3909 Ibyte *p, *pend;
3910
3911 CHECK_CHAR_COERCE_INT (item); 3950 CHECK_CHAR_COERCE_INT (item);
3912
3913 CHECK_LISP_WRITEABLE (sequence); 3951 CHECK_LISP_WRITEABLE (sequence);
3914 sledgehammer_check_ascii_begin (sequence); 3952
3915 item_bytecount = set_itext_ichar (item_buf, XCHAR (item)); 3953 fill_string_range (sequence, item, start, end);
3916
3917 p = XSTRING_DATA (sequence);
3918 p = (Ibyte *) itext_n_addr (p, starting);
3919 prefix_bytecount = p - XSTRING_DATA (sequence);
3920
3921 ending = min (ending, string_char_length (sequence));
3922 pend = (Ibyte *) itext_n_addr (p, ending - starting);
3923 delta = ((ending - starting) * item_bytecount) - (pend - p);
3924
3925 /* Resize the string if the bytecount for the area being modified is
3926 different. */
3927 if (delta)
3928 {
3929 resize_string (sequence, prefix_bytecount, delta);
3930 /* No need to zero-terminate the string, resize_string has done
3931 that for us. */
3932 p = XSTRING_DATA (sequence) + prefix_bytecount;
3933 pend = p + ((ending - starting) * item_bytecount);
3934 }
3935
3936 for (; p < pend; p += item_bytecount)
3937 memcpy (p, item_buf, item_bytecount);
3938
3939
3940 init_string_ascii_begin (sequence);
3941 bump_string_modiff (sequence);
3942 sledgehammer_check_ascii_begin (sequence);
3943 } 3954 }
3944 else if (VECTORP (sequence)) 3955 else if (VECTORP (sequence))
3945 { 3956 {
3946 Lisp_Object *p = XVECTOR_DATA (sequence); 3957 Lisp_Object *p = XVECTOR_DATA (sequence);
3958
3947 CHECK_LISP_WRITEABLE (sequence); 3959 CHECK_LISP_WRITEABLE (sequence);
3948 3960 len = XVECTOR_LENGTH (sequence);
3949 ending = min (ending, XVECTOR_LENGTH (sequence)); 3961
3962 check_sequence_range (sequence, start, end, make_int (len));
3963 ending = min (ending, len);
3964
3950 for (ii = starting; ii < ending; ++ii) 3965 for (ii = starting; ii < ending; ++ii)
3951 { 3966 {
3952 p[ii] = item; 3967 p[ii] = item;
3953 } 3968 }
3954 } 3969 }
3955 else if (BIT_VECTORP (sequence)) 3970 else if (BIT_VECTORP (sequence))
3956 { 3971 {
3957 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence); 3972 Lisp_Bit_Vector *v = XBIT_VECTOR (sequence);
3958 int bit; 3973 int bit;
3974
3959 CHECK_BIT (item); 3975 CHECK_BIT (item);
3960 bit = XINT (item); 3976 bit = XINT (item);
3961 CHECK_LISP_WRITEABLE (sequence); 3977 CHECK_LISP_WRITEABLE (sequence);
3962 3978 len = bit_vector_length (v);
3963 ending = min (ending, bit_vector_length (v)); 3979
3980 check_sequence_range (sequence, start, end, make_int (len));
3981 ending = min (ending, len);
3982
3964 for (ii = starting; ii < ending; ++ii) 3983 for (ii = starting; ii < ending; ++ii)
3965 { 3984 {
3966 set_bit_vector_bit (v, ii, bit); 3985 set_bit_vector_bit (v, ii, bit);
3967 } 3986 }
3968 } 3987 }
3983 break; 4002 break;
3984 } 4003 }
3985 } 4004 }
3986 ++counting; 4005 ++counting;
3987 } 4006 }
4007
4008 if (counting != ending)
4009 {
4010 check_sequence_range (sequence, start, end, Flength (sequence));
4011 }
3988 } 4012 }
3989 else 4013 else
3990 { 4014 {
3991 sequence = wrong_type_argument (Qsequencep, sequence); 4015 sequence = wrong_type_argument (Qsequencep, sequence);
3992 goto retry; 4016 goto retry;
4127 } 4151 }
4128 RETURN_UNGCPRO (Qnil); /* No non-nil args provided. */ 4152 RETURN_UNGCPRO (Qnil); /* No non-nil args provided. */
4129 } 4153 }
4130 4154
4131 4155
4156 /* Replace the substring of DEST beginning at START and ending before END
4157 with the text at SOURCE, which is END - START characters long and
4158 SOURCE_LIMIT - SOURCE octets long. If DEST does not have sufficient
4159 space for END - START characters at START, write as many as is possible
4160 without changing the length of DEST. Update the string modification flag
4161 and do any sledgehammer checks we have turned on in this build.
4162
4163 START must be a Lisp integer. END can be nil, indicating the length of the
4164 string, or a Lisp integer. The condition (<= 0 START END (length DEST))
4165 must hold, or replace_string_range() will signal an error. */
4166 static Lisp_Object
4167 replace_string_range (Lisp_Object dest, Lisp_Object start, Lisp_Object end,
4168 const Ibyte *source, const Ibyte *source_limit)
4169 {
4170 return replace_string_range_1 (dest, start, end, source, source_limit,
4171 Qnil);
4172 }
4173
4132 /* This is the guts of several mapping functions. 4174 /* This is the guts of several mapping functions.
4133 4175
4134 Call FUNCTION CALL_COUNT times, with NSEQUENCES arguments each time, 4176 Call FUNCTION CALL_COUNT times, with NSEQUENCES arguments each time,
4135 taking the elements from SEQUENCES. If VALS is non-NULL, store the 4177 taking the elements from SEQUENCES. If VALS is non-NULL, store the
4136 results into VALS, a C array of Lisp_Objects; else, if LISP_VALS is 4178 results into VALS, a C array of Lisp_Objects; else, if LISP_VALS is
4166 Lisp_Object function, int nsequences, Lisp_Object *sequences, 4208 Lisp_Object function, int nsequences, Lisp_Object *sequences,
4167 Lisp_Object caller) 4209 Lisp_Object caller)
4168 { 4210 {
4169 Lisp_Object called, *args; 4211 Lisp_Object called, *args;
4170 struct gcpro gcpro1, gcpro2; 4212 struct gcpro gcpro1, gcpro2;
4213 Ibyte *lisp_vals_staging, *cursor;
4171 int i, j; 4214 int i, j;
4172 4215
4173 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1); 4216 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1);
4174 4217
4175 args = alloca_array (Lisp_Object, nsequences + 1); 4218 args = alloca_array (Lisp_Object, nsequences + 1);
4222 } 4265 }
4223 4266
4224 if (!EQ (caller, Qsome) && !EQ (caller, Qevery)) 4267 if (!EQ (caller, Qsome) && !EQ (caller, Qevery))
4225 { 4268 {
4226 assert (LRECORDP (lisp_vals)); 4269 assert (LRECORDP (lisp_vals));
4270
4227 lisp_vals_type 4271 lisp_vals_type
4228 = (enum lrecord_type) XRECORD_LHEADER (lisp_vals)->type; 4272 = (enum lrecord_type) XRECORD_LHEADER (lisp_vals)->type;
4229 assert (NILP (lisp_vals) || lisp_vals_type != lrecord_type_symbol); 4273
4274 if (lrecord_type_string == lisp_vals_type)
4275 {
4276 lisp_vals_staging = cursor
4277 = alloca_ibytes (call_count * MAX_ICHAR_LEN);
4278 }
4230 } 4279 }
4231 4280
4232 for (i = 0; i < call_count; ++i) 4281 for (i = 0; i < call_count; ++i)
4233 { 4282 {
4234 for (j = 0; j < nsequences; ++j) 4283 for (j = 0; j < nsequences; ++j)
4303 { 4352 {
4304 called = IGNORE_MULTIPLE_VALUES (called); 4353 called = IGNORE_MULTIPLE_VALUES (called);
4305 switch (lisp_vals_type) 4354 switch (lisp_vals_type)
4306 { 4355 {
4307 case lrecord_type_symbol: 4356 case lrecord_type_symbol:
4308 /* This is #'mapc; the result of the funcall is 4357 /* Discard the result of funcall. */
4309 discarded. */
4310 break; 4358 break;
4311 case lrecord_type_cons: 4359 case lrecord_type_cons:
4312 { 4360 {
4313 if (!CONSP (lisp_vals)) 4361 if (!CONSP (lisp_vals))
4314 { 4362 {
4329 Faset (lisp_vals, make_int (i), called); 4377 Faset (lisp_vals, make_int (i), called);
4330 break; 4378 break;
4331 } 4379 }
4332 case lrecord_type_string: 4380 case lrecord_type_string:
4333 { 4381 {
4334 /* If this ever becomes a code hotspot, we can keep 4382 CHECK_CHAR_COERCE_INT (called);
4335 around pointers into the data of the string, checking 4383 cursor += set_itext_ichar (cursor, XCHAR (called));
4336 each time that it hasn't been relocated. */
4337 Faset (lisp_vals, make_int (i), called);
4338 break; 4384 break;
4339 } 4385 }
4340 case lrecord_type_bit_vector: 4386 case lrecord_type_bit_vector:
4341 { 4387 {
4342 (BITP (called) && 4388 (BITP (called) &&
4352 break; 4398 break;
4353 } 4399 }
4354 } 4400 }
4355 } 4401 }
4356 } 4402 }
4357 } 4403
4404 if (!EQ (caller, Qsome) && !EQ (caller, Qevery) &&
4405 lrecord_type_string == lisp_vals_type)
4406 {
4407 replace_string_range (lisp_vals, Qzero, make_int (call_count),
4408 lisp_vals_staging, cursor);
4409 }
4410 }
4411
4358 UNGCPRO; 4412 UNGCPRO;
4359 } 4413 }
4360 4414
4361 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /* 4415 DEFUN ("mapconcat", Fmapconcat, 3, MANY, 0, /*
4362 Call FUNCTION on each element of SEQUENCE, and concat results to a string. 4416 Call FUNCTION on each element of SEQUENCE, and concat results to a string.
5300 old = Qnil; 5354 old = Qnil;
5301 5355
5302 return old; 5356 return old;
5303 } 5357 }
5304 5358
5359 /* This function is the implementation of fill_string_range() and
5360 replace_string_range(); see the comments for those functions. */
5361 static Lisp_Object
5362 replace_string_range_1 (Lisp_Object dest, Lisp_Object start, Lisp_Object end,
5363 const Ibyte *source, const Ibyte *source_limit,
5364 Lisp_Object item)
5365 {
5366 Ibyte *destp = XSTRING_DATA (dest), *p = destp,
5367 *pend = p + XSTRING_LENGTH (dest), *pcursor, item_buf[MAX_ICHAR_LEN];
5368 Bytecount prefix_bytecount, source_len = source_limit - source;
5369 Charcount ii = 0, starting = XINT (start), ending, len;
5370 Elemcount delta;
5371
5372 while (ii < starting && p < pend)
5373 {
5374 INC_IBYTEPTR (p);
5375 ii++;
5376 }
5377
5378 pcursor = p;
5379
5380 if (NILP (end))
5381 {
5382 while (pcursor < pend)
5383 {
5384 INC_IBYTEPTR (pcursor);
5385 ii++;
5386 }
5387
5388 ending = len = ii;
5389 }
5390 else
5391 {
5392 ending = XINT (end);
5393 while (ii < ending && pcursor < pend)
5394 {
5395 INC_IBYTEPTR (pcursor);
5396 ii++;
5397 }
5398 }
5399
5400 if (pcursor == pend)
5401 {
5402 /* We have the length, check it for our callers. */
5403 check_sequence_range (dest, start, end, make_int (ii));
5404 }
5405
5406 if (!(p == pend || p == pcursor))
5407 {
5408 prefix_bytecount = p - destp;
5409
5410 if (!NILP (item))
5411 {
5412 assert (source == NULL && source_limit == NULL);
5413 source_len = set_itext_ichar (item_buf, XCHAR (item));
5414 delta = (source_len * (ending - starting)) - (pcursor - p);
5415 }
5416 else
5417 {
5418 assert (source != NULL && source_limit != NULL);
5419 delta = source_len - (pcursor - p);
5420 }
5421
5422 if (delta)
5423 {
5424 resize_string (dest, prefix_bytecount, delta);
5425 destp = XSTRING_DATA (dest);
5426 pcursor = destp + prefix_bytecount + (pcursor - p);
5427 p = destp + prefix_bytecount;
5428 }
5429
5430 if (CHARP (item))
5431 {
5432 while (starting < ending)
5433 {
5434 memcpy (p, item_buf, source_len);
5435 p += source_len;
5436 starting++;
5437 }
5438 }
5439 else
5440 {
5441 while (starting < ending && source < source_limit)
5442 {
5443 source_len = itext_copy_ichar (source, p);
5444 p += source_len, source += source_len;
5445 }
5446 }
5447
5448 init_string_ascii_begin (dest);
5449 bump_string_modiff (dest);
5450 sledgehammer_check_ascii_begin (dest);
5451 }
5452
5453 return dest;
5454 }
5455
5456 DEFUN ("replace", Freplace, 2, MANY, 0, /*
5457 Replace the elements of SEQUENCE-ONE with the elements of SEQUENCE-TWO.
5458
5459 SEQUENCE-ONE is destructively modified, and returned. Its length is not
5460 changed.
5461
5462 Keywords :start1 and :end1 specify a subsequence of SEQUENCE-ONE, and
5463 :start2 and :end2 a subsequence of SEQUENCE-TWO. See `search' for more
5464 information.
5465
5466 arguments: (SEQUENCE-ONE SEQUENCE-TWO &key (START1 0) (END1 (length SEQUENCE-ONE)) (START2 0) (END2 (length SEQUENCE-TWO)))
5467 */
5468 (int nargs, Lisp_Object *args))
5469 {
5470 Lisp_Object sequence1 = args[0], sequence2 = args[1],
5471 result = sequence1;
5472 Elemcount starting1, ending1 = EMACS_INT_MAX, starting2;
5473 Elemcount ending2 = EMACS_INT_MAX, counting, startcounting;
5474 Boolint sequence1_listp, sequence2_listp,
5475 overwriting = EQ (sequence1, sequence2);
5476
5477 PARSE_KEYWORDS (Qreplace, nargs, args, 2, 4, (start1, end1, start2, end2),
5478 (start1 = start2 = Qzero), 0);
5479
5480 CHECK_SEQUENCE (sequence1);
5481 CHECK_LISP_WRITEABLE (sequence1);
5482
5483 CHECK_SEQUENCE (sequence2);
5484
5485 CHECK_NATNUM (start1);
5486 starting1 = XINT (start1);
5487 CHECK_NATNUM (start2);
5488 starting2 = XINT (start2);
5489
5490 if (!NILP (end1))
5491 {
5492 CHECK_NATNUM (end1);
5493 ending1 = XINT (end1);
5494
5495 if (!(starting1 <= ending1))
5496 {
5497 args_out_of_range_3 (sequence1, start1, end1);
5498 }
5499 }
5500
5501 if (!NILP (end2))
5502 {
5503 CHECK_NATNUM (end2);
5504 ending2 = XINT (end2);
5505
5506 if (!(starting2 <= ending2))
5507 {
5508 args_out_of_range_3 (sequence1, start2, end2);
5509 }
5510 }
5511
5512 sequence1_listp = LISTP (sequence1);
5513 sequence2_listp = LISTP (sequence2);
5514
5515 overwriting = overwriting && starting2 <= starting1;
5516
5517 if (sequence1_listp && !ZEROP (start1))
5518 {
5519 Lisp_Object nthcdrd = Fnthcdr (start1, sequence1);
5520
5521 if (NILP (nthcdrd))
5522 {
5523 check_sequence_range (sequence1, start1, end1, Flength (sequence1));
5524 /* Give up early here. */
5525 return result;
5526 }
5527
5528 sequence1 = nthcdrd;
5529 ending1 -= starting1;
5530 starting1 = 0;
5531 }
5532
5533 if (sequence2_listp && !ZEROP (start2))
5534 {
5535 Lisp_Object nthcdrd = Fnthcdr (start2, sequence2);
5536
5537 if (NILP (nthcdrd))
5538 {
5539 check_sequence_range (sequence1, start1, end1, Flength (sequence1));
5540 /* Nothing available to replace sequence1's contents. */
5541 return result;
5542 }
5543
5544 sequence2 = nthcdrd;
5545 ending2 -= starting2;
5546 starting2 = 0;
5547 }
5548
5549 if (overwriting)
5550 {
5551 if (EQ (start1, start2))
5552 {
5553 return result;
5554 }
5555
5556 /* Our ranges may overlap. Save the data that might be overwritten. */
5557
5558 if (CONSP (sequence2))
5559 {
5560 Elemcount len = XINT (Flength (sequence2));
5561 Lisp_Object *subsequence
5562 = alloca_array (Lisp_Object, min (ending2, len));
5563 Elemcount counting = 0, ii = 0;
5564
5565 LIST_LOOP_2 (elt, sequence2)
5566 {
5567 if (counting == ending2)
5568 {
5569 break;
5570 }
5571
5572 subsequence[ii++] = elt;
5573 counting++;
5574 }
5575
5576 check_sequence_range (sequence1, start1, end1,
5577 /* The XINT (start2) is intentional here; we
5578 called #'length after doing (nthcdr
5579 start2 sequence2). */
5580 make_int (XINT (start2) + len));
5581 check_sequence_range (sequence2, start2, end2,
5582 make_int (XINT (start2) + len));
5583
5584 while (starting1 < ending1
5585 && starting2 < ending2 && !NILP (sequence1))
5586 {
5587 XSETCAR (sequence1, subsequence[starting2]);
5588 sequence1 = XCDR (sequence1);
5589 starting1++;
5590 starting2++;
5591 }
5592 }
5593 else if (STRINGP (sequence2))
5594 {
5595 Ibyte *p = XSTRING_DATA (sequence2),
5596 *pend = p + XSTRING_LENGTH (sequence2), *pcursor,
5597 *staging;
5598 Bytecount ii = 0;
5599
5600 while (ii < starting2 && p < pend)
5601 {
5602 INC_IBYTEPTR (p);
5603 ii++;
5604 }
5605
5606 pcursor = p;
5607
5608 while (ii < ending2 && starting1 < ending1 && pcursor < pend)
5609 {
5610 INC_IBYTEPTR (pcursor);
5611 starting1++;
5612 ii++;
5613 }
5614
5615 if (pcursor == pend)
5616 {
5617 check_sequence_range (sequence1, start1, end1, make_int (ii));
5618 check_sequence_range (sequence2, start2, end2, make_int (ii));
5619 }
5620 else
5621 {
5622 assert ((pcursor - p) > 0);
5623 staging = alloca_ibytes (pcursor - p);
5624 memcpy (staging, p, pcursor - p);
5625 replace_string_range (result, start1,
5626 make_int (starting1),
5627 staging, staging + (pcursor - p));
5628 }
5629 }
5630 else
5631 {
5632 Elemcount seq_len = XINT (Flength (sequence2)), ii = 0,
5633 subseq_len = min (min (ending1 - starting1, seq_len - starting1),
5634 min (ending2 - starting2, seq_len - starting2));
5635 Lisp_Object *subsequence = alloca_array (Lisp_Object, subseq_len);
5636
5637 check_sequence_range (sequence1, start1, end1, make_int (seq_len));
5638 check_sequence_range (sequence2, start2, end2, make_int (seq_len));
5639
5640 while (starting2 < ending2 && ii < seq_len)
5641 {
5642 subsequence[ii] = Faref (sequence2, make_int (starting2));
5643 ii++, starting2++;
5644 }
5645
5646 ii = 0;
5647
5648 while (starting1 < ending1 && ii < seq_len)
5649 {
5650 Faset (sequence1, make_int (starting1), subsequence[ii]);
5651 ii++, starting1++;
5652 }
5653 }
5654 }
5655 else if (sequence1_listp && sequence2_listp)
5656 {
5657 Lisp_Object sequence1_tortoise = sequence1,
5658 sequence2_tortoise = sequence2;
5659 Elemcount shortest_len = 0;
5660
5661 counting = startcounting = min (ending1, ending2);
5662
5663 while (counting-- > 0 && !NILP (sequence1) && !NILP (sequence2))
5664 {
5665 XSETCAR (sequence1,
5666 CONSP (sequence2) ? XCAR (sequence2)
5667 : Fcar (sequence2));
5668 sequence1 = CONSP (sequence1) ? XCDR (sequence1)
5669 : Fcdr (sequence1);
5670 sequence2 = CONSP (sequence2) ? XCDR (sequence2)
5671 : Fcdr (sequence2);
5672
5673 shortest_len++;
5674
5675 if (startcounting - counting > CIRCULAR_LIST_SUSPICION_LENGTH)
5676 {
5677 if (counting & 1)
5678 {
5679 sequence1_tortoise = XCDR (sequence1_tortoise);
5680 sequence2_tortoise = XCDR (sequence2_tortoise);
5681 }
5682
5683 if (EQ (sequence1, sequence1_tortoise))
5684 {
5685 signal_circular_list_error (sequence1);
5686 }
5687
5688 if (EQ (sequence2, sequence2_tortoise))
5689 {
5690 signal_circular_list_error (sequence2);
5691 }
5692 }
5693 }
5694
5695 if (NILP (sequence1))
5696 {
5697 check_sequence_range (sequence1, start1, end1,
5698 make_int (XINT (start1) + shortest_len));
5699 }
5700 else if (NILP (sequence2))
5701 {
5702 check_sequence_range (sequence2, start2, end2,
5703 make_int (XINT (start2) + shortest_len));
5704 }
5705 }
5706 else if (sequence1_listp)
5707 {
5708 if (STRINGP (sequence2))
5709 {
5710 Ibyte *s2_data = XSTRING_DATA (sequence2),
5711 *s2_end = s2_data + XSTRING_LENGTH (sequence2);
5712 Elemcount char_count = 0;
5713 Lisp_Object character;
5714
5715 while (char_count < starting2 && s2_data < s2_end)
5716 {
5717 INC_IBYTEPTR (s2_data);
5718 char_count++;
5719 }
5720
5721 while (starting1 < ending1 && starting2 < ending2
5722 && s2_data < s2_end && !NILP (sequence1))
5723 {
5724 character = make_char (itext_ichar (s2_data));
5725 CONSP (sequence1) ?
5726 XSETCAR (sequence1, character)
5727 : Fsetcar (sequence1, character);
5728 sequence1 = XCDR (sequence1);
5729 starting1++;
5730 starting2++;
5731 char_count++;
5732 INC_IBYTEPTR (s2_data);
5733 }
5734
5735 if (NILP (sequence1))
5736 {
5737 check_sequence_range (sequence1, start1, end1,
5738 make_int (XINT (start1) + starting1));
5739 }
5740
5741 if (s2_data == s2_end)
5742 {
5743 check_sequence_range (sequence2, start2, end2,
5744 make_int (char_count));
5745 }
5746 }
5747 else
5748 {
5749 Elemcount len2 = XINT (Flength (sequence2));
5750 check_sequence_range (sequence2, start2, end2, make_int (len2));
5751
5752 ending2 = min (ending2, len2);
5753 while (starting2 < ending2
5754 && starting1 < ending1 && !NILP (sequence1))
5755 {
5756 CHECK_CONS (sequence1);
5757 XSETCAR (sequence1, Faref (sequence2, make_int (starting2)));
5758 sequence1 = XCDR (sequence1);
5759 starting1++;
5760 starting2++;
5761 }
5762
5763 if (NILP (sequence1))
5764 {
5765 check_sequence_range (sequence1, start1, end1,
5766 make_int (XINT (start1) + starting1));
5767 }
5768 }
5769 }
5770 else if (sequence2_listp)
5771 {
5772 if (STRINGP (sequence1))
5773 {
5774 Elemcount ii = 0, count, len = string_char_length (sequence1);
5775 Ibyte *staging, *cursor;
5776 Lisp_Object obj;
5777
5778 check_sequence_range (sequence1, start1, end1, make_int (len));
5779 ending1 = min (ending1, len);
5780 count = ending1 - starting1;
5781 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN);
5782
5783 while (ii < count && !NILP (sequence2))
5784 {
5785 obj = CONSP (sequence2) ? XCAR (sequence2)
5786 : Fcar (sequence2);
5787
5788 CHECK_CHAR_COERCE_INT (obj);
5789 cursor += set_itext_ichar (cursor, XCHAR (obj));
5790 ii++;
5791 sequence2 = XCDR (sequence2);
5792 }
5793
5794 if (NILP (sequence2))
5795 {
5796 check_sequence_range (sequence2, start2, end2,
5797 make_int (XINT (start2) + ii));
5798 }
5799
5800 replace_string_range (result, start1, make_int (XINT (start1) + ii),
5801 staging, cursor);
5802 }
5803 else
5804 {
5805 Elemcount len = XINT (Flength (sequence1));
5806
5807 check_sequence_range (sequence1, start2, end1, make_int (len));
5808 ending1 = min (ending2, min (ending1, len));
5809
5810 while (starting1 < ending1 && !NILP (sequence2))
5811 {
5812 Faset (sequence1, make_int (starting1),
5813 CONSP (sequence2) ? XCAR (sequence2)
5814 : Fcar (sequence2));
5815 sequence2 = XCDR (sequence2);
5816 starting1++;
5817 starting2++;
5818 }
5819
5820 if (NILP (sequence2))
5821 {
5822 check_sequence_range (sequence2, start2, end2,
5823 make_int (XINT (start2) + starting2));
5824 }
5825 }
5826 }
5827 else
5828 {
5829 if (STRINGP (sequence1) && STRINGP (sequence2))
5830 {
5831 Ibyte *p2 = XSTRING_DATA (sequence2),
5832 *p2end = p2 + XSTRING_LENGTH (sequence2), *p2cursor;
5833 Charcount ii = 0, len1 = string_char_length (sequence1);
5834
5835 while (ii < starting2 && p2 < p2end)
5836 {
5837 INC_IBYTEPTR (p2);
5838 ii++;
5839 }
5840
5841 p2cursor = p2;
5842 ending1 = min (ending1, len1);
5843
5844 while (ii < ending2 && starting1 < ending1 && p2cursor < p2end)
5845 {
5846 INC_IBYTEPTR (p2cursor);
5847 ii++;
5848 starting1++;
5849 }
5850
5851 if (p2cursor == p2end)
5852 {
5853 check_sequence_range (sequence2, start2, end2, make_int (ii));
5854 }
5855
5856 /* This isn't great; any error message won't necessarily reflect
5857 the END1 that was supplied to #'replace. */
5858 replace_string_range (result, start1, make_int (starting1),
5859 p2, p2cursor);
5860 }
5861 else if (STRINGP (sequence1))
5862 {
5863 Ibyte *staging, *cursor;
5864 Elemcount count, len1 = string_char_length (sequence1);
5865 Elemcount len2 = XINT (Flength (sequence2)), ii = 0;;
5866 Lisp_Object obj;
5867
5868 check_sequence_range (sequence1, start1, end1, make_int (len1));
5869 check_sequence_range (sequence2, start2, end2, make_int (len2));
5870
5871 ending1 = min (ending1, len1);
5872 ending2 = min (ending2, len2);
5873 count = min (ending1 - starting1, ending2 - starting2);
5874 staging = cursor = alloca_ibytes (count * MAX_ICHAR_LEN);
5875
5876 ii = 0;
5877 while (ii < count)
5878 {
5879 obj = Faref (sequence2, make_int (starting2));
5880
5881 CHECK_CHAR_COERCE_INT (obj);
5882 cursor += set_itext_ichar (cursor, XCHAR (obj));
5883 starting2++, ii++;
5884 }
5885
5886 replace_string_range (result, start1,
5887 make_int (XINT (start1) + count),
5888 staging, cursor);
5889 }
5890 else if (STRINGP (sequence2))
5891 {
5892 Ibyte *p2 = XSTRING_DATA (sequence2),
5893 *p2end = p2 + XSTRING_LENGTH (sequence2);
5894 Elemcount len1 = XINT (Flength (sequence1)), ii = 0;
5895
5896 check_sequence_range (sequence1, start1, end1, make_int (len1));
5897 ending1 = min (ending1, len1);
5898
5899 while (ii < starting2 && p2 < p2end)
5900 {
5901 INC_IBYTEPTR (p2);
5902 ii++;
5903 }
5904
5905 while (p2 < p2end && starting1 < ending1 && starting2 < ending2)
5906 {
5907 Faset (sequence1, make_int (starting1),
5908 make_char (itext_ichar (p2)));
5909 INC_IBYTEPTR (p2);
5910 starting1++;
5911 starting2++;
5912 ii++;
5913 }
5914
5915 if (p2 == p2end)
5916 {
5917 check_sequence_range (sequence2, start2, end2, make_int (ii));
5918 }
5919 }
5920 else
5921 {
5922 Elemcount len1 = XINT (Flength (sequence1)),
5923 len2 = XINT (Flength (sequence2));
5924
5925 check_sequence_range (sequence1, start1, end1, make_int (len1));
5926 check_sequence_range (sequence2, start2, end2, make_int (len2));
5927
5928 ending1 = min (ending1, len1);
5929 ending2 = min (ending2, len2);
5930
5931 while (starting1 < ending1 && starting2 < ending2)
5932 {
5933 Faset (sequence1, make_int (starting1),
5934 Faref (sequence2, make_int (starting2)));
5935 starting1++;
5936 starting2++;
5937 }
5938 }
5939 }
5940
5941 return result;
5942 }
5305 5943
5306 Lisp_Object 5944 Lisp_Object
5307 add_suffix_to_symbol (Lisp_Object symbol, const Ascbyte *ascii_string) 5945 add_suffix_to_symbol (Lisp_Object symbol, const Ascbyte *ascii_string)
5308 { 5946 {
5309 return Fintern (concat2 (Fsymbol_name (symbol), 5947 return Fintern (concat2 (Fsymbol_name (symbol),
5945 DEFSYMBOL (Qstring); 6583 DEFSYMBOL (Qstring);
5946 DEFSYMBOL (Qlist); 6584 DEFSYMBOL (Qlist);
5947 DEFSYMBOL (Qbit_vector); 6585 DEFSYMBOL (Qbit_vector);
5948 defsymbol (&QsortX, "sort*"); 6586 defsymbol (&QsortX, "sort*");
5949 DEFSYMBOL (Qreduce); 6587 DEFSYMBOL (Qreduce);
6588 DEFSYMBOL (Qreplace);
5950 6589
5951 DEFSYMBOL (Qmapconcat); 6590 DEFSYMBOL (Qmapconcat);
5952 defsymbol (&QmapcarX, "mapcar*"); 6591 defsymbol (&QmapcarX, "mapcar*");
5953 DEFSYMBOL (Qmapvector); 6592 DEFSYMBOL (Qmapvector);
5954 DEFSYMBOL (Qmapcan); 6593 DEFSYMBOL (Qmapcan);
5961 DEFSYMBOL (Qmapl); 6600 DEFSYMBOL (Qmapl);
5962 DEFSYMBOL (Qmapcon); 6601 DEFSYMBOL (Qmapcon);
5963 6602
5964 DEFKEYWORD (Q_from_end); 6603 DEFKEYWORD (Q_from_end);
5965 DEFKEYWORD (Q_initial_value); 6604 DEFKEYWORD (Q_initial_value);
6605 DEFKEYWORD (Q_start1);
6606 DEFKEYWORD (Q_start2);
6607 DEFKEYWORD (Q_end1);
6608 DEFKEYWORD (Q_end2);
5966 6609
5967 DEFSYMBOL (Qyes_or_no_p); 6610 DEFSYMBOL (Qyes_or_no_p);
5968 6611
5969 DEFERROR_STANDARD (Qbase64_conversion_error, Qconversion_error); 6612 DEFERROR_STANDARD (Qbase64_conversion_error, Qconversion_error);
5970 6613
6060 DEFSUBR (Fmapl); 6703 DEFSUBR (Fmapl);
6061 DEFSUBR (Fmapcon); 6704 DEFSUBR (Fmapcon);
6062 6705
6063 DEFSUBR (Freduce); 6706 DEFSUBR (Freduce);
6064 DEFSUBR (Freplace_list); 6707 DEFSUBR (Freplace_list);
6708 DEFSUBR (Freplace);
6065 DEFSUBR (Fload_average); 6709 DEFSUBR (Fload_average);
6066 DEFSUBR (Ffeaturep); 6710 DEFSUBR (Ffeaturep);
6067 DEFSUBR (Frequire); 6711 DEFSUBR (Frequire);
6068 DEFSUBR (Fprovide); 6712 DEFSUBR (Fprovide);
6069 DEFSUBR (Fbase64_encode_region); 6713 DEFSUBR (Fbase64_encode_region);