Mercurial > hg > xemacs-beta
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); |