Mercurial > hg > xemacs-beta
comparison src/fns.c @ 5303:4c4085177ca5
Fix some bugs in fns.c, discovered in passing while doing other work.
2010-11-14 Aidan Kehoe <kehoea@parhasard.net>
* fns.c (Fnreverse):
Check that non-list sequences are writable from Lisp before
modifying them. (There's an argument that we should do this for
list sequences too, but for the moment other code (e.g. #'setcar)
doesn't.)
(mapcarX): Initialise lisp_vals_staging, lisp_vals_type
explicitly, for the sake of compile warnings. Check if
lisp_vals_staging is non-NULL when deciding whether to replace a
string's range.
(Fsome): Cross-reference to #'find-if in the doc string for this
function.
(Freduce): GCPRO accum in this function, when a key argument is
specicified it can be silently garbage-collected. When deciding
whether to iterate across a string, check whether the cursor
exceeds the byte len; while iterating, increment an integer
counter. Don't ABORT() if check_sequence_range() returns when
handed a suspicious sequence; it is legal to supply the length of
SEQUENCE as the :end keyword value, and this will provoke our
suspicions, legitimately enough. (Problems with this function
revealed by Paul Dietz' ANSI test suite, thank you Paul Dietz.)
(Freplace): Check list sequence lengths using the arguments, not
the conses we're currently looking at, thank you Paul Dietz.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Sun, 14 Nov 2010 14:54:09 +0000 |
parents | 6468cf6f0b9d |
children | cde1608596d0 002cb5224e4f |
comparison
equal
deleted
inserted
replaced
5302:6468cf6f0b9d | 5303:4c4085177ca5 |
---|---|
1106 if (0 != ss) | 1106 if (0 != ss) |
1107 { | 1107 { |
1108 sequence = Fnthcdr (make_int (ss), sequence); | 1108 sequence = Fnthcdr (make_int (ss), sequence); |
1109 } | 1109 } |
1110 | 1110 |
1111 ii = ss + 1; | |
1112 | |
1111 if (ss < ee && !NILP (sequence)) | 1113 if (ss < ee && !NILP (sequence)) |
1112 { | 1114 { |
1113 result = result_tail = Fcons (Fcar (sequence), Qnil); | 1115 result = result_tail = Fcons (Fcar (sequence), Qnil); |
1114 sequence = Fcdr (sequence); | 1116 sequence = Fcdr (sequence); |
1115 ii = ss + 1; | |
1116 | 1117 |
1117 { | 1118 { |
1118 EXTERNAL_LIST_LOOP_2 (elt, sequence) | 1119 EXTERNAL_LIST_LOOP_2 (elt, sequence) |
1119 { | 1120 { |
1120 if (!(ii < ee)) | 1121 if (!(ii < ee)) |
2126 else if (VECTORP (sequence)) | 2127 else if (VECTORP (sequence)) |
2127 { | 2128 { |
2128 Elemcount length = XVECTOR_LENGTH (sequence), ii = length; | 2129 Elemcount length = XVECTOR_LENGTH (sequence), ii = length; |
2129 Elemcount half = length / 2; | 2130 Elemcount half = length / 2; |
2130 Lisp_Object swap = Qnil; | 2131 Lisp_Object swap = Qnil; |
2132 CHECK_LISP_WRITEABLE (sequence); | |
2131 | 2133 |
2132 while (ii > half) | 2134 while (ii > half) |
2133 { | 2135 { |
2134 swap = XVECTOR_DATA (sequence) [length - ii]; | 2136 swap = XVECTOR_DATA (sequence) [length - ii]; |
2135 XVECTOR_DATA (sequence) [length - ii] | 2137 XVECTOR_DATA (sequence) [length - ii] |
2142 { | 2144 { |
2143 Elemcount length = XSTRING_LENGTH (sequence); | 2145 Elemcount length = XSTRING_LENGTH (sequence); |
2144 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; | 2146 Ibyte *staging = alloca_ibytes (length), *staging_end = staging + length; |
2145 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; | 2147 Ibyte *cursor = XSTRING_DATA (sequence), *endp = cursor + length; |
2146 | 2148 |
2149 CHECK_LISP_WRITEABLE (sequence); | |
2147 while (cursor < endp) | 2150 while (cursor < endp) |
2148 { | 2151 { |
2149 staging_end -= itext_ichar_len (cursor); | 2152 staging_end -= itext_ichar_len (cursor); |
2150 itext_copy_ichar (cursor, staging_end); | 2153 itext_copy_ichar (cursor, staging_end); |
2151 INC_IBYTEPTR (cursor); | 2154 INC_IBYTEPTR (cursor); |
2163 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); | 2166 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); |
2164 Elemcount length = bit_vector_length (bv), ii = length; | 2167 Elemcount length = bit_vector_length (bv), ii = length; |
2165 Elemcount half = length / 2; | 2168 Elemcount half = length / 2; |
2166 int swap = 0; | 2169 int swap = 0; |
2167 | 2170 |
2171 CHECK_LISP_WRITEABLE (sequence); | |
2168 while (ii > half) | 2172 while (ii > half) |
2169 { | 2173 { |
2170 swap = bit_vector_bit (bv, length - ii); | 2174 swap = bit_vector_bit (bv, length - ii); |
2171 set_bit_vector_bit (bv, length - ii, bit_vector_bit (bv, ii - 1)); | 2175 set_bit_vector_bit (bv, length - ii, bit_vector_bit (bv, ii - 1)); |
2172 set_bit_vector_bit (bv, ii - 1, swap); | 2176 set_bit_vector_bit (bv, ii - 1, swap); |
4448 Lisp_Object function, int nsequences, Lisp_Object *sequences, | 4452 Lisp_Object function, int nsequences, Lisp_Object *sequences, |
4449 Lisp_Object caller) | 4453 Lisp_Object caller) |
4450 { | 4454 { |
4451 Lisp_Object called, *args; | 4455 Lisp_Object called, *args; |
4452 struct gcpro gcpro1, gcpro2; | 4456 struct gcpro gcpro1, gcpro2; |
4453 Ibyte *lisp_vals_staging, *cursor; | 4457 Ibyte *lisp_vals_staging = NULL, *cursor = NULL; |
4454 int i, j; | 4458 int i, j; |
4455 | 4459 |
4456 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1); | 4460 assert ((EQ (caller, Qsome) || EQ (caller, Qevery)) ? vals == NULL : 1); |
4457 | 4461 |
4458 args = alloca_array (Lisp_Object, nsequences + 1); | 4462 args = alloca_array (Lisp_Object, nsequences + 1); |
4495 vals[i] = IGNORE_MULTIPLE_VALUES (Ffuncall (nsequences + 1, args)); | 4499 vals[i] = IGNORE_MULTIPLE_VALUES (Ffuncall (nsequences + 1, args)); |
4496 } | 4500 } |
4497 } | 4501 } |
4498 else | 4502 else |
4499 { | 4503 { |
4500 enum lrecord_type lisp_vals_type; | 4504 enum lrecord_type lisp_vals_type = lrecord_type_symbol; |
4501 Binbyte *sequence_types = alloca_array (Binbyte, nsequences); | 4505 Binbyte *sequence_types = alloca_array (Binbyte, nsequences); |
4502 for (j = 0; j < nsequences; ++j) | 4506 for (j = 0; j < nsequences; ++j) |
4503 { | 4507 { |
4504 sequence_types[j] = XRECORD_LHEADER (sequences[j])->type; | 4508 sequence_types[j] = XRECORD_LHEADER (sequences[j])->type; |
4505 } | 4509 } |
4514 if (lrecord_type_string == lisp_vals_type) | 4518 if (lrecord_type_string == lisp_vals_type) |
4515 { | 4519 { |
4516 lisp_vals_staging = cursor | 4520 lisp_vals_staging = cursor |
4517 = alloca_ibytes (call_count * MAX_ICHAR_LEN); | 4521 = alloca_ibytes (call_count * MAX_ICHAR_LEN); |
4518 } | 4522 } |
4523 else if (ARRAYP (lisp_vals)) | |
4524 { | |
4525 CHECK_LISP_WRITEABLE (lisp_vals); | |
4526 } | |
4519 } | 4527 } |
4520 | 4528 |
4521 for (i = 0; i < call_count; ++i) | 4529 for (i = 0; i < call_count; ++i) |
4522 { | 4530 { |
4523 for (j = 0; j < nsequences; ++j) | 4531 for (j = 0; j < nsequences; ++j) |
4639 } | 4647 } |
4640 } | 4648 } |
4641 } | 4649 } |
4642 } | 4650 } |
4643 | 4651 |
4644 if (!EQ (caller, Qsome) && !EQ (caller, Qevery) && | 4652 if (lisp_vals_staging != NULL) |
4645 lrecord_type_string == lisp_vals_type) | 4653 { |
4646 { | 4654 CHECK_LISP_WRITEABLE (lisp_vals); |
4647 replace_string_range (lisp_vals, Qzero, make_int (call_count), | 4655 replace_string_range (lisp_vals, Qzero, make_int (call_count), |
4648 lisp_vals_staging, cursor); | 4656 lisp_vals_staging, cursor); |
4649 } | 4657 } |
4650 } | 4658 } |
4651 | 4659 |
4657 one of them is not a sequence. */ | 4665 one of them is not a sequence. */ |
4658 static Elemcount | 4666 static Elemcount |
4659 shortest_length_among_sequences (int nsequences, Lisp_Object *sequences) | 4667 shortest_length_among_sequences (int nsequences, Lisp_Object *sequences) |
4660 { | 4668 { |
4661 Elemcount len = EMACS_INT_MAX; | 4669 Elemcount len = EMACS_INT_MAX; |
4662 Lisp_Object length; | 4670 Lisp_Object length = Qnil; |
4663 int i; | 4671 int i; |
4664 | 4672 |
4665 for (i = 0; i < nsequences; ++i) | 4673 for (i = 0; i < nsequences; ++i) |
4666 { | 4674 { |
4667 if (CONSP (sequences[i])) | 4675 if (CONSP (sequences[i])) |
4950 | 4958 |
4951 If so, return the value (possibly multiple) given by PREDICATE. | 4959 If so, return the value (possibly multiple) given by PREDICATE. |
4952 | 4960 |
4953 With optional SEQUENCES, call PREDICATE each time with as many arguments as | 4961 With optional SEQUENCES, call PREDICATE each time with as many arguments as |
4954 there are SEQUENCES (plus one for the element from SEQUENCE). | 4962 there are SEQUENCES (plus one for the element from SEQUENCE). |
4963 | |
4964 See also `find-if', which returns the corresponding element of SEQUENCE, | |
4965 rather than the value given by PREDICATE, and accepts bounding index | |
4966 keywords. | |
4955 | 4967 |
4956 arguments: (PREDICATE SEQUENCE &rest SEQUENCES) | 4968 arguments: (PREDICATE SEQUENCE &rest SEQUENCES) |
4957 */ | 4969 */ |
4958 (int nargs, Lisp_Object *args)) | 4970 (int nargs, Lisp_Object *args)) |
4959 { | 4971 { |
5203 } | 5215 } |
5204 | 5216 |
5205 if (VECTORP (sequence)) | 5217 if (VECTORP (sequence)) |
5206 { | 5218 { |
5207 Lisp_Vector *vv = XVECTOR (sequence); | 5219 Lisp_Vector *vv = XVECTOR (sequence); |
5220 struct gcpro gcpro1; | |
5208 | 5221 |
5209 check_sequence_range (sequence, start, end, make_int (vv->size)); | 5222 check_sequence_range (sequence, start, end, make_int (vv->size)); |
5210 | 5223 |
5211 ending = min (ending, vv->size); | 5224 ending = min (ending, vv->size); |
5225 | |
5226 GCPRO1 (accum); | |
5212 | 5227 |
5213 if (!UNBOUNDP (initial_value)) | 5228 if (!UNBOUNDP (initial_value)) |
5214 { | 5229 { |
5215 accum = initial_value; | 5230 accum = initial_value; |
5216 } | 5231 } |
5240 for (ii = ending - 1; ii >= starting; --ii) | 5255 for (ii = ending - 1; ii >= starting; --ii) |
5241 { | 5256 { |
5242 accum = CALL2 (function, KEY (key, vv->contents[ii]), accum); | 5257 accum = CALL2 (function, KEY (key, vv->contents[ii]), accum); |
5243 } | 5258 } |
5244 } | 5259 } |
5260 | |
5261 UNGCPRO; | |
5245 } | 5262 } |
5246 else if (BIT_VECTORP (sequence)) | 5263 else if (BIT_VECTORP (sequence)) |
5247 { | 5264 { |
5248 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); | 5265 Lisp_Bit_Vector *bv = XBIT_VECTOR (sequence); |
5266 struct gcpro gcpro1; | |
5249 | 5267 |
5250 check_sequence_range (sequence, start, end, make_int (bv->size)); | 5268 check_sequence_range (sequence, start, end, make_int (bv->size)); |
5251 | |
5252 ending = min (ending, bv->size); | 5269 ending = min (ending, bv->size); |
5270 | |
5271 GCPRO1 (accum); | |
5253 | 5272 |
5254 if (!UNBOUNDP (initial_value)) | 5273 if (!UNBOUNDP (initial_value)) |
5255 { | 5274 { |
5256 accum = initial_value; | 5275 accum = initial_value; |
5257 } | 5276 } |
5285 make_int (bit_vector_bit (bv, | 5304 make_int (bit_vector_bit (bv, |
5286 ii))), | 5305 ii))), |
5287 accum); | 5306 accum); |
5288 } | 5307 } |
5289 } | 5308 } |
5309 | |
5310 UNGCPRO; | |
5311 | |
5290 } | 5312 } |
5291 else if (STRINGP (sequence)) | 5313 else if (STRINGP (sequence)) |
5292 { | 5314 { |
5315 struct gcpro gcpro1; | |
5316 | |
5317 GCPRO1 (accum); | |
5318 | |
5293 if (NILP (from_end)) | 5319 if (NILP (from_end)) |
5294 { | 5320 { |
5295 Bytecount byte_len = XSTRING_LENGTH (sequence); | 5321 Bytecount byte_len = XSTRING_LENGTH (sequence); |
5296 Bytecount cursor_offset = 0; | 5322 Bytecount cursor_offset = 0; |
5297 const Ibyte *startp = XSTRING_DATA (sequence); | 5323 const Ibyte *startp = XSTRING_DATA (sequence); |
5305 | 5331 |
5306 if (!UNBOUNDP (initial_value)) | 5332 if (!UNBOUNDP (initial_value)) |
5307 { | 5333 { |
5308 accum = initial_value; | 5334 accum = initial_value; |
5309 } | 5335 } |
5310 else if (ending - starting) | 5336 else if (ending - starting && cursor_offset < byte_len) |
5311 { | 5337 { |
5312 accum = KEY (key, make_char (itext_ichar (cursor))); | 5338 accum = KEY (key, make_char (itext_ichar (cursor))); |
5313 starting++; | 5339 starting++; |
5314 startp = XSTRING_DATA (sequence); | 5340 startp = XSTRING_DATA (sequence); |
5315 cursor = startp + cursor_offset; | 5341 cursor = startp + cursor_offset; |
5320 mapping_interaction_error (Qreduce, sequence); | 5346 mapping_interaction_error (Qreduce, sequence); |
5321 } | 5347 } |
5322 | 5348 |
5323 INC_IBYTEPTR (cursor); | 5349 INC_IBYTEPTR (cursor); |
5324 cursor_offset = cursor - startp; | 5350 cursor_offset = cursor - startp; |
5351 ii++; | |
5325 } | 5352 } |
5326 | 5353 |
5327 while (cursor_offset < byte_len && ii < ending) | 5354 while (cursor_offset < byte_len && ii < ending) |
5328 { | 5355 { |
5329 accum = CALL2 (function, accum, | 5356 accum = CALL2 (function, accum, |
5344 } | 5371 } |
5345 | 5372 |
5346 if (ii < starting || (ii < ending && !NILP (end))) | 5373 if (ii < starting || (ii < ending && !NILP (end))) |
5347 { | 5374 { |
5348 check_sequence_range (sequence, start, end, Flength (sequence)); | 5375 check_sequence_range (sequence, start, end, Flength (sequence)); |
5349 ABORT (); | |
5350 } | 5376 } |
5351 } | 5377 } |
5352 else | 5378 else |
5353 { | 5379 { |
5354 Elemcount len = string_char_length (sequence); | 5380 Elemcount len = string_char_length (sequence); |
5355 Bytecount cursor_offset, byte_len = XSTRING_LENGTH (sequence); | 5381 Bytecount cursor_offset, byte_len = XSTRING_LENGTH (sequence); |
5356 const Ibyte *cursor; | 5382 const Ibyte *cursor; |
5357 | 5383 |
5358 check_sequence_range (sequence, start, end, make_int (len)); | 5384 check_sequence_range (sequence, start, end, make_int (len)); |
5359 | |
5360 ending = min (ending, len); | 5385 ending = min (ending, len); |
5361 cursor = string_char_addr (sequence, ending - 1); | 5386 cursor = string_char_addr (sequence, ending - 1); |
5362 cursor_offset = cursor - XSTRING_DATA (sequence); | 5387 cursor_offset = cursor - XSTRING_DATA (sequence); |
5363 | 5388 |
5364 if (!UNBOUNDP (initial_value)) | 5389 if (!UNBOUNDP (initial_value)) |
5401 DEC_IBYTEPTR (cursor); | 5426 DEC_IBYTEPTR (cursor); |
5402 cursor_offset = cursor - XSTRING_DATA (sequence); | 5427 cursor_offset = cursor - XSTRING_DATA (sequence); |
5403 } | 5428 } |
5404 } | 5429 } |
5405 } | 5430 } |
5431 | |
5432 UNGCPRO; | |
5406 } | 5433 } |
5407 else if (LISTP (sequence)) | 5434 else if (LISTP (sequence)) |
5408 { | 5435 { |
5409 if (NILP (from_end)) | 5436 if (NILP (from_end)) |
5410 { | 5437 { |
5411 struct gcpro gcpro1; | 5438 struct gcpro gcpro1, gcpro2; |
5412 Lisp_Object tailed = Qnil; | 5439 Lisp_Object tailed = Qnil; |
5413 | 5440 |
5414 GCPRO1 (tailed); | 5441 GCPRO2 (tailed, accum); |
5415 | 5442 |
5416 if (!UNBOUNDP (initial_value)) | 5443 if (!UNBOUNDP (initial_value)) |
5417 { | 5444 { |
5418 accum = initial_value; | 5445 accum = initial_value; |
5419 } | 5446 } |
5462 UNGCPRO; | 5489 UNGCPRO; |
5463 | 5490 |
5464 if (ii < starting || (ii < ending && !NILP (end))) | 5491 if (ii < starting || (ii < ending && !NILP (end))) |
5465 { | 5492 { |
5466 check_sequence_range (sequence, start, end, Flength (sequence)); | 5493 check_sequence_range (sequence, start, end, Flength (sequence)); |
5467 ABORT (); | |
5468 } | 5494 } |
5469 } | 5495 } |
5470 else | 5496 else |
5471 { | 5497 { |
5472 Boolint need_accum = 0; | 5498 Boolint need_accum = 0; |
5928 } | 5954 } |
5929 } | 5955 } |
5930 | 5956 |
5931 if (NILP (sequence1)) | 5957 if (NILP (sequence1)) |
5932 { | 5958 { |
5933 check_sequence_range (sequence1, start1, end1, | 5959 check_sequence_range (args[0], start1, end1, |
5934 make_int (XINT (start1) + shortest_len)); | 5960 make_int (XINT (start1) + shortest_len)); |
5935 } | 5961 } |
5936 else if (NILP (sequence2)) | 5962 else if (NILP (sequence2)) |
5937 { | 5963 { |
5938 check_sequence_range (sequence2, start2, end2, | 5964 check_sequence_range (args[1], start2, end2, |
5939 make_int (XINT (start2) + shortest_len)); | 5965 make_int (XINT (start2) + shortest_len)); |
5940 } | 5966 } |
5941 } | 5967 } |
5942 else if (sequence1_listp) | 5968 else if (sequence1_listp) |
5943 { | 5969 { |
5996 starting2++; | 6022 starting2++; |
5997 } | 6023 } |
5998 | 6024 |
5999 if (NILP (sequence1)) | 6025 if (NILP (sequence1)) |
6000 { | 6026 { |
6001 check_sequence_range (sequence1, start1, end1, | 6027 check_sequence_range (args[0], start1, end1, |
6002 make_int (XINT (start1) + starting1)); | 6028 make_int (XINT (start1) + starting1)); |
6003 } | 6029 } |
6004 } | 6030 } |
6005 } | 6031 } |
6006 else if (sequence2_listp) | 6032 else if (sequence2_listp) |
6053 starting2++; | 6079 starting2++; |
6054 } | 6080 } |
6055 | 6081 |
6056 if (NILP (sequence2)) | 6082 if (NILP (sequence2)) |
6057 { | 6083 { |
6058 check_sequence_range (sequence2, start2, end2, | 6084 check_sequence_range (args[1], start2, end2, |
6059 make_int (XINT (start2) + starting2)); | 6085 make_int (XINT (start2) + starting2)); |
6060 } | 6086 } |
6061 } | 6087 } |
6062 } | 6088 } |
6063 else | 6089 else |