diff options
| author | Richard M. Stallman | 1998-01-09 22:41:43 +0000 |
|---|---|---|
| committer | Richard M. Stallman | 1998-01-09 22:41:43 +0000 |
| commit | ea35ce3d99adfbe260d32b6f30c7ec0b0895219a (patch) | |
| tree | f09a52667e10dc0edcdb03a4da053fffc215fcb9 /src | |
| parent | 1f24f4fdd2b7203aa75728a4437cb0520a8e6877 (diff) | |
| download | emacs-ea35ce3d99adfbe260d32b6f30c7ec0b0895219a.tar.gz emacs-ea35ce3d99adfbe260d32b6f30c7ec0b0895219a.zip | |
(map_char_table): Unconditionally consider non-ASCII charsets.
(Fsubstring): Use make_multibyte_string.
(concat, Fsubstring, internal_equal, mapcar1):
Distinguish bytes and chars when indexing strings.
(Fstring_equal, Fstring_lessp): Likewise.
(substring_both): New function.
(string_make_multibyte, string_make_unibyte): New functions.
(string_char_to_byte, string_byte_to_char): New functions.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 454 |
1 files changed, 339 insertions, 115 deletions
| @@ -178,7 +178,7 @@ which is at least the number of distinct elements.") | |||
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0, | 180 | DEFUN ("string-equal", Fstring_equal, Sstring_equal, 2, 2, 0, |
| 181 | "T if two strings have identical contents.\n\ | 181 | "Return t if two strings have identical contents.\n\ |
| 182 | Case is significant, but text properties are ignored.\n\ | 182 | Case is significant, but text properties are ignored.\n\ |
| 183 | Symbols are also allowed; their print names are used instead.") | 183 | Symbols are also allowed; their print names are used instead.") |
| 184 | (s1, s2) | 184 | (s1, s2) |
| @@ -191,14 +191,15 @@ Symbols are also allowed; their print names are used instead.") | |||
| 191 | CHECK_STRING (s1, 0); | 191 | CHECK_STRING (s1, 0); |
| 192 | CHECK_STRING (s2, 1); | 192 | CHECK_STRING (s2, 1); |
| 193 | 193 | ||
| 194 | if (XSTRING (s1)->size != XSTRING (s2)->size || | 194 | if (XSTRING (s1)->size != XSTRING (s2)->size |
| 195 | bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size)) | 195 | || XSTRING (s1)->size_byte != XSTRING (s2)->size_byte |
| 196 | || bcmp (XSTRING (s1)->data, XSTRING (s2)->data, XSTRING (s1)->size_byte)) | ||
| 196 | return Qnil; | 197 | return Qnil; |
| 197 | return Qt; | 198 | return Qt; |
| 198 | } | 199 | } |
| 199 | 200 | ||
| 200 | DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0, | 201 | DEFUN ("string-lessp", Fstring_lessp, Sstring_lessp, 2, 2, 0, |
| 201 | "T if first arg string is less than second in lexicographic order.\n\ | 202 | "Return t if first arg string is less than second in lexicographic order.\n\ |
| 202 | Case is significant.\n\ | 203 | Case is significant.\n\ |
| 203 | Symbols are also allowed; their print names are used instead.") | 204 | Symbols are also allowed; their print names are used instead.") |
| 204 | (s1, s2) | 205 | (s1, s2) |
| @@ -217,16 +218,16 @@ Symbols are also allowed; their print names are used instead.") | |||
| 217 | 218 | ||
| 218 | p1 = XSTRING (s1)->data; | 219 | p1 = XSTRING (s1)->data; |
| 219 | p2 = XSTRING (s2)->data; | 220 | p2 = XSTRING (s2)->data; |
| 220 | end = XSTRING (s1)->size; | 221 | end = XSTRING (s1)->size_byte; |
| 221 | if (end > XSTRING (s2)->size) | 222 | if (end > XSTRING (s2)->size_byte) |
| 222 | end = XSTRING (s2)->size; | 223 | end = XSTRING (s2)->size_byte; |
| 223 | 224 | ||
| 224 | for (i = 0; i < end; i++) | 225 | for (i = 0; i < end; i++) |
| 225 | { | 226 | { |
| 226 | if (p1[i] != p2[i]) | 227 | if (p1[i] != p2[i]) |
| 227 | return p1[i] < p2[i] ? Qt : Qnil; | 228 | return p1[i] < p2[i] ? Qt : Qnil; |
| 228 | } | 229 | } |
| 229 | return i < XSTRING (s2)->size ? Qt : Qnil; | 230 | return i < XSTRING (s2)->size_byte ? Qt : Qnil; |
| 230 | } | 231 | } |
| 231 | 232 | ||
| 232 | static Lisp_Object concat (); | 233 | static Lisp_Object concat (); |
| @@ -379,14 +380,16 @@ concat (nargs, args, target_type, last_special) | |||
| 379 | int last_special; | 380 | int last_special; |
| 380 | { | 381 | { |
| 381 | Lisp_Object val; | 382 | Lisp_Object val; |
| 382 | Lisp_Object len; | ||
| 383 | register Lisp_Object tail; | 383 | register Lisp_Object tail; |
| 384 | register Lisp_Object this; | 384 | register Lisp_Object this; |
| 385 | int toindex; | 385 | int toindex; |
| 386 | register int leni; | 386 | int toindex_byte; |
| 387 | register int result_len; | ||
| 388 | register int result_len_byte; | ||
| 387 | register int argnum; | 389 | register int argnum; |
| 388 | Lisp_Object last_tail; | 390 | Lisp_Object last_tail; |
| 389 | Lisp_Object prev; | 391 | Lisp_Object prev; |
| 392 | int some_multibyte; | ||
| 390 | 393 | ||
| 391 | /* In append, the last arg isn't treated like the others */ | 394 | /* In append, the last arg isn't treated like the others */ |
| 392 | if (last_special && nargs > 0) | 395 | if (last_special && nargs > 0) |
| @@ -397,6 +400,7 @@ concat (nargs, args, target_type, last_special) | |||
| 397 | else | 400 | else |
| 398 | last_tail = Qnil; | 401 | last_tail = Qnil; |
| 399 | 402 | ||
| 403 | /* Canonicalize each argument. */ | ||
| 400 | for (argnum = 0; argnum < nargs; argnum++) | 404 | for (argnum = 0; argnum < nargs; argnum++) |
| 401 | { | 405 | { |
| 402 | this = args[argnum]; | 406 | this = args[argnum]; |
| @@ -410,56 +414,77 @@ concat (nargs, args, target_type, last_special) | |||
| 410 | } | 414 | } |
| 411 | } | 415 | } |
| 412 | 416 | ||
| 413 | for (argnum = 0, leni = 0; argnum < nargs; argnum++) | 417 | /* Compute total length in chars of arguments in RESULT_LEN. |
| 418 | If desired output is a string, also compute length in bytes | ||
| 419 | in RESULT_LEN_BYTE, and determine in SOME_MULTIBYTE | ||
| 420 | whether the result should be a multibyte string. */ | ||
| 421 | result_len_byte = 0; | ||
| 422 | result_len = 0; | ||
| 423 | some_multibyte = 0; | ||
| 424 | for (argnum = 0; argnum < nargs; argnum++) | ||
| 414 | { | 425 | { |
| 426 | int len; | ||
| 415 | this = args[argnum]; | 427 | this = args[argnum]; |
| 416 | len = Flength (this); | 428 | len = XFASTINT (Flength (this)); |
| 417 | if ((VECTORP (this) || CONSP (this)) && target_type == Lisp_String) | 429 | if (target_type == Lisp_String) |
| 418 | |||
| 419 | { | 430 | { |
| 420 | /* We must pay attention to a multibyte character which | 431 | /* We must pay attention to a multibyte character which |
| 421 | takes more than one byte in string. */ | 432 | takes more than one byte in string. */ |
| 422 | int i; | 433 | int i; |
| 423 | Lisp_Object ch; | 434 | Lisp_Object ch; |
| 435 | int this_len_byte; | ||
| 424 | 436 | ||
| 425 | if (VECTORP (this)) | 437 | if (VECTORP (this)) |
| 426 | for (i = 0; i < XFASTINT (len); i++) | 438 | for (i = 0; i < len; i++) |
| 427 | { | 439 | { |
| 428 | ch = XVECTOR (this)->contents[i]; | 440 | ch = XVECTOR (this)->contents[i]; |
| 429 | if (! INTEGERP (ch)) | 441 | if (! INTEGERP (ch)) |
| 430 | wrong_type_argument (Qintegerp, ch); | 442 | wrong_type_argument (Qintegerp, ch); |
| 431 | leni += XFASTINT (Fchar_bytes (ch)); | 443 | this_len_byte = XFASTINT (Fchar_bytes (ch)); |
| 444 | result_len_byte += this_len_byte; | ||
| 445 | if (this_len_byte > 1) | ||
| 446 | some_multibyte = 1; | ||
| 432 | } | 447 | } |
| 433 | else | 448 | else if (CONSP (this)) |
| 434 | for (; CONSP (this); this = XCONS (this)->cdr) | 449 | for (; CONSP (this); this = XCONS (this)->cdr) |
| 435 | { | 450 | { |
| 436 | ch = XCONS (this)->car; | 451 | ch = XCONS (this)->car; |
| 437 | if (! INTEGERP (ch)) | 452 | if (! INTEGERP (ch)) |
| 438 | wrong_type_argument (Qintegerp, ch); | 453 | wrong_type_argument (Qintegerp, ch); |
| 439 | leni += XFASTINT (Fchar_bytes (ch)); | 454 | this_len_byte = XFASTINT (Fchar_bytes (ch)); |
| 455 | result_len_byte += this_len_byte; | ||
| 456 | if (this_len_byte > 1) | ||
| 457 | some_multibyte = 1; | ||
| 440 | } | 458 | } |
| 459 | else | ||
| 460 | { | ||
| 461 | result_len_byte += XSTRING (this)->size_byte; | ||
| 462 | if (STRING_MULTIBYTE (this)) | ||
| 463 | some_multibyte = 1; | ||
| 464 | } | ||
| 441 | } | 465 | } |
| 442 | else | 466 | |
| 443 | leni += XFASTINT (len); | 467 | result_len += len; |
| 444 | } | 468 | } |
| 445 | 469 | ||
| 446 | XSETFASTINT (len, leni); | 470 | /* In `append', if all but last arg are nil, return last arg. */ |
| 471 | if (target_type == Lisp_Cons && EQ (val, Qnil)) | ||
| 472 | return last_tail; | ||
| 447 | 473 | ||
| 474 | /* Create the output object. */ | ||
| 448 | if (target_type == Lisp_Cons) | 475 | if (target_type == Lisp_Cons) |
| 449 | val = Fmake_list (len, Qnil); | 476 | val = Fmake_list (make_number (result_len), Qnil); |
| 450 | else if (target_type == Lisp_Vectorlike) | 477 | else if (target_type == Lisp_Vectorlike) |
| 451 | val = Fmake_vector (len, Qnil); | 478 | val = Fmake_vector (make_number (result_len), Qnil); |
| 452 | else | 479 | else |
| 453 | val = Fmake_string (len, len); | 480 | val = make_uninit_multibyte_string (result_len, result_len_byte); |
| 454 | 481 | ||
| 455 | /* In append, if all but last arg are nil, return last arg */ | ||
| 456 | if (target_type == Lisp_Cons && EQ (val, Qnil)) | ||
| 457 | return last_tail; | ||
| 458 | 482 | ||
| 483 | /* Copy the contents of the args into the result. */ | ||
| 459 | if (CONSP (val)) | 484 | if (CONSP (val)) |
| 460 | tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ | 485 | tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ |
| 461 | else | 486 | else |
| 462 | toindex = 0; | 487 | toindex = 0, toindex_byte = 0; |
| 463 | 488 | ||
| 464 | prev = Qnil; | 489 | prev = Qnil; |
| 465 | 490 | ||
| @@ -468,6 +493,7 @@ concat (nargs, args, target_type, last_special) | |||
| 468 | Lisp_Object thislen; | 493 | Lisp_Object thislen; |
| 469 | int thisleni; | 494 | int thisleni; |
| 470 | register unsigned int thisindex = 0; | 495 | register unsigned int thisindex = 0; |
| 496 | register unsigned int thisindex_byte = 0; | ||
| 471 | 497 | ||
| 472 | this = args[argnum]; | 498 | this = args[argnum]; |
| 473 | if (!CONSP (this)) | 499 | if (!CONSP (this)) |
| @@ -475,71 +501,106 @@ concat (nargs, args, target_type, last_special) | |||
| 475 | 501 | ||
| 476 | if (STRINGP (this) && STRINGP (val) | 502 | if (STRINGP (this) && STRINGP (val) |
| 477 | && ! NULL_INTERVAL_P (XSTRING (this)->intervals)) | 503 | && ! NULL_INTERVAL_P (XSTRING (this)->intervals)) |
| 478 | { | 504 | copy_text_properties (make_number (0), thislen, this, |
| 479 | copy_text_properties (make_number (0), thislen, this, | 505 | make_number (toindex), val, Qnil); |
| 480 | make_number (toindex), val, Qnil); | ||
| 481 | } | ||
| 482 | 506 | ||
| 483 | while (1) | 507 | /* Between strings of the same kind, copy fast. */ |
| 508 | if (STRINGP (this) && STRINGP (val) | ||
| 509 | && STRING_MULTIBYTE (this) == some_multibyte) | ||
| 484 | { | 510 | { |
| 485 | register Lisp_Object elt; | 511 | int thislen_byte = XSTRING (this)->size_byte; |
| 486 | 512 | bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte, | |
| 487 | /* Fetch next element of `this' arg into `elt', or break if | 513 | XSTRING (this)->size_byte); |
| 488 | `this' is exhausted. */ | 514 | toindex_byte += thislen_byte; |
| 489 | if (NILP (this)) break; | 515 | toindex += thisleni; |
| 490 | if (CONSP (this)) | 516 | } |
| 491 | elt = XCONS (this)->car, this = XCONS (this)->cdr; | 517 | else |
| 492 | else | 518 | /* Copy element by element. */ |
| 493 | { | 519 | while (1) |
| 494 | if (thisindex >= thisleni) break; | 520 | { |
| 495 | if (STRINGP (this)) | 521 | register Lisp_Object elt; |
| 496 | XSETFASTINT (elt, XSTRING (this)->data[thisindex++]); | 522 | |
| 497 | else if (BOOL_VECTOR_P (this)) | 523 | /* Fetch next element of `this' arg into `elt', or break if |
| 498 | { | 524 | `this' is exhausted. */ |
| 499 | int size_in_chars | 525 | if (NILP (this)) break; |
| 500 | = ((XBOOL_VECTOR (this)->size + BITS_PER_CHAR - 1) | 526 | if (CONSP (this)) |
| 501 | / BITS_PER_CHAR); | 527 | elt = XCONS (this)->car, this = XCONS (this)->cdr; |
| 502 | int byte; | 528 | else |
| 503 | byte = XBOOL_VECTOR (val)->data[thisindex / BITS_PER_CHAR]; | 529 | { |
| 504 | if (byte & (1 << (thisindex % BITS_PER_CHAR))) | 530 | if (thisindex >= thisleni) break; |
| 505 | elt = Qt; | 531 | if (STRINGP (this)) |
| 506 | else | 532 | { |
| 507 | elt = Qnil; | 533 | if (STRING_MULTIBYTE (this)) |
| 508 | } | 534 | { |
| 509 | else | 535 | int c; |
| 510 | elt = XVECTOR (this)->contents[thisindex++]; | 536 | FETCH_STRING_CHAR_ADVANCE (c, this, |
| 511 | } | 537 | thisindex, |
| 538 | thisindex_byte); | ||
| 539 | XSETFASTINT (elt, c); | ||
| 540 | } | ||
| 541 | else | ||
| 542 | { | ||
| 543 | unsigned char c; | ||
| 544 | XSETFASTINT (elt, XSTRING (this)->data[thisindex++]); | ||
| 545 | if (some_multibyte && XINT (elt) >= 0200 | ||
| 546 | && XINT (elt) < 0400) | ||
| 547 | { | ||
| 548 | c = XINT (elt); | ||
| 549 | copy_text (&c, &c, 1, 0, 1); | ||
| 550 | XSETINT (elt, c); | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | ||
| 554 | else if (BOOL_VECTOR_P (this)) | ||
| 555 | { | ||
| 556 | int size_in_chars | ||
| 557 | = ((XBOOL_VECTOR (this)->size + BITS_PER_CHAR - 1) | ||
| 558 | / BITS_PER_CHAR); | ||
| 559 | int byte; | ||
| 560 | byte = XBOOL_VECTOR (val)->data[thisindex / BITS_PER_CHAR]; | ||
| 561 | if (byte & (1 << (thisindex % BITS_PER_CHAR))) | ||
| 562 | elt = Qt; | ||
| 563 | else | ||
| 564 | elt = Qnil; | ||
| 565 | } | ||
| 566 | else | ||
| 567 | elt = XVECTOR (this)->contents[thisindex++]; | ||
| 568 | } | ||
| 512 | 569 | ||
| 513 | /* Store into result */ | 570 | /* Store this element into the result. */ |
| 514 | if (toindex < 0) | 571 | if (toindex < 0) |
| 515 | { | ||
| 516 | XCONS (tail)->car = elt; | ||
| 517 | prev = tail; | ||
| 518 | tail = XCONS (tail)->cdr; | ||
| 519 | } | ||
| 520 | else if (VECTORP (val)) | ||
| 521 | XVECTOR (val)->contents[toindex++] = elt; | ||
| 522 | else | ||
| 523 | { | ||
| 524 | while (!INTEGERP (elt)) | ||
| 525 | elt = wrong_type_argument (Qintegerp, elt); | ||
| 526 | { | 572 | { |
| 527 | int c = XINT (elt); | 573 | XCONS (tail)->car = elt; |
| 528 | unsigned char work[4], *str; | 574 | prev = tail; |
| 529 | int i = CHAR_STRING (c, work, str); | 575 | tail = XCONS (tail)->cdr; |
| 530 | |||
| 531 | #ifdef MASSC_REGISTER_BUG | ||
| 532 | /* Even removing all "register"s doesn't disable this bug! | ||
| 533 | Nothing simpler than this seems to work. */ | ||
| 534 | unsigned char *p = & XSTRING (val)->data[toindex]; | ||
| 535 | bcopy (str, p, i); | ||
| 536 | #else | ||
| 537 | bcopy (str, & XSTRING (val)->data[toindex], i); | ||
| 538 | #endif | ||
| 539 | toindex += i; | ||
| 540 | } | 576 | } |
| 541 | } | 577 | else if (VECTORP (val)) |
| 542 | } | 578 | XVECTOR (val)->contents[toindex++] = elt; |
| 579 | else | ||
| 580 | { | ||
| 581 | CHECK_NUMBER (elt, 0); | ||
| 582 | if (SINGLE_BYTE_CHAR_P (XINT (elt))) | ||
| 583 | { | ||
| 584 | XSTRING (val)->data[toindex++] = XINT (elt); | ||
| 585 | toindex_byte++; | ||
| 586 | } | ||
| 587 | else | ||
| 588 | /* If we have any multibyte characters, | ||
| 589 | we already decided to make a multibyte string. */ | ||
| 590 | { | ||
| 591 | int c = XINT (elt); | ||
| 592 | unsigned char work[4], *str; | ||
| 593 | int i = CHAR_STRING (c, work, str); | ||
| 594 | |||
| 595 | /* P exists as a variable | ||
| 596 | to avoid a bug on the Masscomp C compiler. */ | ||
| 597 | unsigned char *p = & XSTRING (val)->data[toindex_byte]; | ||
| 598 | bcopy (str, p, i); | ||
| 599 | toindex_byte += i; | ||
| 600 | toindex++; | ||
| 601 | } | ||
| 602 | } | ||
| 603 | } | ||
| 543 | } | 604 | } |
| 544 | if (!NILP (prev)) | 605 | if (!NILP (prev)) |
| 545 | XCONS (prev)->cdr = last_tail; | 606 | XCONS (prev)->cdr = last_tail; |
| @@ -547,6 +608,90 @@ concat (nargs, args, target_type, last_special) | |||
| 547 | return val; | 608 | return val; |
| 548 | } | 609 | } |
| 549 | 610 | ||
| 611 | /* Return the character index corresponding to CHAR_INDEX in STRING. */ | ||
| 612 | |||
| 613 | int | ||
| 614 | string_char_to_byte (string, char_index) | ||
| 615 | Lisp_Object string; | ||
| 616 | int char_index; | ||
| 617 | { | ||
| 618 | int i = 0, i_byte = 0; | ||
| 619 | |||
| 620 | if (! STRING_MULTIBYTE (string)) | ||
| 621 | return char_index; | ||
| 622 | |||
| 623 | while (i < char_index) | ||
| 624 | { | ||
| 625 | int c; | ||
| 626 | FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte); | ||
| 627 | } | ||
| 628 | |||
| 629 | return i_byte; | ||
| 630 | } | ||
| 631 | |||
| 632 | /* Return the character index corresponding to BYTE_INDEX in STRING. */ | ||
| 633 | |||
| 634 | int | ||
| 635 | string_byte_to_char (string, byte_index) | ||
| 636 | Lisp_Object string; | ||
| 637 | int byte_index; | ||
| 638 | { | ||
| 639 | int i = 0, i_byte = 0; | ||
| 640 | |||
| 641 | if (! STRING_MULTIBYTE (string)) | ||
| 642 | return byte_index; | ||
| 643 | |||
| 644 | while (i_byte < byte_index) | ||
| 645 | { | ||
| 646 | int c; | ||
| 647 | FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte); | ||
| 648 | } | ||
| 649 | |||
| 650 | return i; | ||
| 651 | } | ||
| 652 | |||
| 653 | /* Convert STRING to a multibyte string. | ||
| 654 | Single-byte characters 0200 through 0377 are converted | ||
| 655 | by adding nonascii_insert_offset to each. */ | ||
| 656 | |||
| 657 | Lisp_Object | ||
| 658 | string_make_multibyte (string) | ||
| 659 | Lisp_Object string; | ||
| 660 | { | ||
| 661 | unsigned char *buf; | ||
| 662 | int nbytes; | ||
| 663 | |||
| 664 | if (STRING_MULTIBYTE (string)) | ||
| 665 | return string; | ||
| 666 | |||
| 667 | nbytes = count_size_as_multibyte (XSTRING (string)->data, | ||
| 668 | XSTRING (string)->size); | ||
| 669 | buf = (unsigned char *) alloca (nbytes); | ||
| 670 | copy_text (XSTRING (string)->data, buf, XSTRING (string)->size_byte, | ||
| 671 | 0, 1); | ||
| 672 | |||
| 673 | return make_multibyte_string (buf, XSTRING (string)->size, nbytes); | ||
| 674 | } | ||
| 675 | |||
| 676 | /* Convert STRING to a single-byte string. */ | ||
| 677 | |||
| 678 | Lisp_Object | ||
| 679 | string_make_unibyte (string) | ||
| 680 | Lisp_Object string; | ||
| 681 | { | ||
| 682 | unsigned char *buf; | ||
| 683 | |||
| 684 | if (! STRING_MULTIBYTE (string)) | ||
| 685 | return string; | ||
| 686 | |||
| 687 | buf = (unsigned char *) alloca (XSTRING (string)->size); | ||
| 688 | |||
| 689 | copy_text (XSTRING (string)->data, buf, XSTRING (string)->size_byte, | ||
| 690 | 1, 0); | ||
| 691 | |||
| 692 | return make_unibyte_string (buf, XSTRING (string)->size); | ||
| 693 | } | ||
| 694 | |||
| 550 | DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0, | 695 | DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0, |
| 551 | "Return a copy of ALIST.\n\ | 696 | "Return a copy of ALIST.\n\ |
| 552 | This is an alist which represents the same mapping from objects to objects,\n\ | 697 | This is an alist which represents the same mapping from objects to objects,\n\ |
| @@ -586,6 +731,9 @@ This function allows vectors as well as strings.") | |||
| 586 | { | 731 | { |
| 587 | Lisp_Object res; | 732 | Lisp_Object res; |
| 588 | int size; | 733 | int size; |
| 734 | int size_byte; | ||
| 735 | int from_char, to_char; | ||
| 736 | int from_byte, to_byte; | ||
| 589 | 737 | ||
| 590 | if (! (STRINGP (string) || VECTORP (string))) | 738 | if (! (STRINGP (string) || VECTORP (string))) |
| 591 | wrong_type_argument (Qarrayp, string); | 739 | wrong_type_argument (Qarrayp, string); |
| @@ -593,32 +741,89 @@ This function allows vectors as well as strings.") | |||
| 593 | CHECK_NUMBER (from, 1); | 741 | CHECK_NUMBER (from, 1); |
| 594 | 742 | ||
| 595 | if (STRINGP (string)) | 743 | if (STRINGP (string)) |
| 596 | size = XSTRING (string)->size; | 744 | { |
| 745 | size = XSTRING (string)->size; | ||
| 746 | size_byte = XSTRING (string)->size_byte; | ||
| 747 | } | ||
| 597 | else | 748 | else |
| 598 | size = XVECTOR (string)->size; | 749 | size = XVECTOR (string)->size; |
| 599 | 750 | ||
| 600 | if (NILP (to)) | 751 | if (NILP (to)) |
| 601 | XSETINT (to, size); | 752 | { |
| 753 | to_char = size; | ||
| 754 | to_byte = size_byte; | ||
| 755 | } | ||
| 602 | else | 756 | else |
| 603 | CHECK_NUMBER (to, 2); | 757 | { |
| 758 | CHECK_NUMBER (to, 2); | ||
| 759 | |||
| 760 | to_char = XINT (to); | ||
| 761 | if (to_char < 0) | ||
| 762 | to_char += size; | ||
| 763 | |||
| 764 | if (STRINGP (string)) | ||
| 765 | to_byte = string_char_to_byte (string, to_char); | ||
| 766 | } | ||
| 767 | |||
| 768 | from_char = XINT (from); | ||
| 769 | if (from_char < 0) | ||
| 770 | from_char += size; | ||
| 771 | if (STRINGP (string)) | ||
| 772 | from_byte = string_char_to_byte (string, from_char); | ||
| 604 | 773 | ||
| 605 | if (XINT (from) < 0) | 774 | if (!(0 <= from_char && from_char <= to_char && to_char <= size)) |
| 606 | XSETINT (from, XINT (from) + size); | 775 | args_out_of_range_3 (string, make_number (from_char), |
| 607 | if (XINT (to) < 0) | 776 | make_number (to_char)); |
| 608 | XSETINT (to, XINT (to) + size); | ||
| 609 | if (!(0 <= XINT (from) && XINT (from) <= XINT (to) | ||
| 610 | && XINT (to) <= size)) | ||
| 611 | args_out_of_range_3 (string, from, to); | ||
| 612 | 777 | ||
| 613 | if (STRINGP (string)) | 778 | if (STRINGP (string)) |
| 614 | { | 779 | { |
| 615 | res = make_string (XSTRING (string)->data + XINT (from), | 780 | res = make_multibyte_string (XSTRING (string)->data + from_byte, |
| 616 | XINT (to) - XINT (from)); | 781 | to_char - from_char, to_byte - from_byte); |
| 782 | copy_text_properties (from_char, to_char, string, | ||
| 783 | make_number (0), res, Qnil); | ||
| 784 | } | ||
| 785 | else | ||
| 786 | res = Fvector (to_char - from_char, | ||
| 787 | XVECTOR (string)->contents + from_char); | ||
| 788 | |||
| 789 | return res; | ||
| 790 | } | ||
| 791 | |||
| 792 | /* Extract a substring of STRING, giving start and end positions | ||
| 793 | both in characters and in bytes. */ | ||
| 794 | |||
| 795 | Lisp_Object | ||
| 796 | substring_both (string, from, from_byte, to, to_byte) | ||
| 797 | Lisp_Object string; | ||
| 798 | int from, from_byte, to, to_byte; | ||
| 799 | { | ||
| 800 | Lisp_Object res; | ||
| 801 | int size; | ||
| 802 | int size_byte; | ||
| 803 | |||
| 804 | if (! (STRINGP (string) || VECTORP (string))) | ||
| 805 | wrong_type_argument (Qarrayp, string); | ||
| 806 | |||
| 807 | if (STRINGP (string)) | ||
| 808 | { | ||
| 809 | size = XSTRING (string)->size; | ||
| 810 | size_byte = XSTRING (string)->size_byte; | ||
| 811 | } | ||
| 812 | else | ||
| 813 | size = XVECTOR (string)->size; | ||
| 814 | |||
| 815 | if (!(0 <= from && from <= to && to <= size)) | ||
| 816 | args_out_of_range_3 (string, make_number (from), make_number (to)); | ||
| 817 | |||
| 818 | if (STRINGP (string)) | ||
| 819 | { | ||
| 820 | res = make_multibyte_string (XSTRING (string)->data + from_byte, | ||
| 821 | to - from, to_byte - from_byte); | ||
| 617 | copy_text_properties (from, to, string, make_number (0), res, Qnil); | 822 | copy_text_properties (from, to, string, make_number (0), res, Qnil); |
| 618 | } | 823 | } |
| 619 | else | 824 | else |
| 620 | res = Fvector (XINT (to) - XINT (from), | 825 | res = Fvector (to - from, |
| 621 | XVECTOR (string)->contents + XINT (from)); | 826 | XVECTOR (string)->contents + from); |
| 622 | 827 | ||
| 623 | return res; | 828 | return res; |
| 624 | } | 829 | } |
| @@ -1081,7 +1286,7 @@ It can be retrieved with `(get SYMBOL PROPNAME)'.") | |||
| 1081 | } | 1286 | } |
| 1082 | 1287 | ||
| 1083 | DEFUN ("equal", Fequal, Sequal, 2, 2, 0, | 1288 | DEFUN ("equal", Fequal, Sequal, 2, 2, 0, |
| 1084 | "T if two Lisp objects have similar structure and contents.\n\ | 1289 | "Return t if two Lisp objects have similar structure and contents.\n\ |
| 1085 | They must have the same data type.\n\ | 1290 | They must have the same data type.\n\ |
| 1086 | Conses are compared by comparing the cars and the cdrs.\n\ | 1291 | Conses are compared by comparing the cars and the cdrs.\n\ |
| 1087 | Vectors and strings are compared element by element.\n\ | 1292 | Vectors and strings are compared element by element.\n\ |
| @@ -1191,8 +1396,10 @@ internal_equal (o1, o2, depth) | |||
| 1191 | case Lisp_String: | 1396 | case Lisp_String: |
| 1192 | if (XSTRING (o1)->size != XSTRING (o2)->size) | 1397 | if (XSTRING (o1)->size != XSTRING (o2)->size) |
| 1193 | return 0; | 1398 | return 0; |
| 1399 | if (XSTRING (o1)->size_byte != XSTRING (o2)->size_byte) | ||
| 1400 | return 0; | ||
| 1194 | if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data, | 1401 | if (bcmp (XSTRING (o1)->data, XSTRING (o2)->data, |
| 1195 | XSTRING (o1)->size)) | 1402 | XSTRING (o1)->size_byte)) |
| 1196 | return 0; | 1403 | return 0; |
| 1197 | return 1; | 1404 | return 1; |
| 1198 | } | 1405 | } |
| @@ -1250,7 +1457,7 @@ ARRAY is a vector, string, char-table, or bool-vector.") | |||
| 1250 | } | 1457 | } |
| 1251 | return array; | 1458 | return array; |
| 1252 | } | 1459 | } |
| 1253 | 1460 | ||
| 1254 | DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype, | 1461 | DEFUN ("char-table-subtype", Fchar_table_subtype, Schar_table_subtype, |
| 1255 | 1, 1, 0, | 1462 | 1, 1, 0, |
| 1256 | "Return the subtype of char-table CHAR-TABLE. The value is a symbol.") | 1463 | "Return the subtype of char-table CHAR-TABLE. The value is a symbol.") |
| @@ -1332,7 +1539,7 @@ DEFUN ("set-char-table-extra-slot", Fset_char_table_extra_slot, | |||
| 1332 | 1539 | ||
| 1333 | return XCHAR_TABLE (char_table)->extras[XINT (n)] = value; | 1540 | return XCHAR_TABLE (char_table)->extras[XINT (n)] = value; |
| 1334 | } | 1541 | } |
| 1335 | 1542 | ||
| 1336 | DEFUN ("char-table-range", Fchar_table_range, Schar_table_range, | 1543 | DEFUN ("char-table-range", Fchar_table_range, Schar_table_range, |
| 1337 | 2, 2, 0, | 1544 | 2, 2, 0, |
| 1338 | "Return the value in CHAR-TABLE for a range of characters RANGE.\n\ | 1545 | "Return the value in CHAR-TABLE for a range of characters RANGE.\n\ |
| @@ -1454,7 +1661,6 @@ See also the documentation of make-char.") | |||
| 1454 | XCHAR_TABLE (char_table)->contents[code1] = value; | 1661 | XCHAR_TABLE (char_table)->contents[code1] = value; |
| 1455 | return value; | 1662 | return value; |
| 1456 | } | 1663 | } |
| 1457 | |||
| 1458 | 1664 | ||
| 1459 | /* Map C_FUNCTION or FUNCTION over SUBTABLE, calling it for each | 1665 | /* Map C_FUNCTION or FUNCTION over SUBTABLE, calling it for each |
| 1460 | character or group of characters that share a value. | 1666 | character or group of characters that share a value. |
| @@ -1483,8 +1689,11 @@ map_char_table (c_function, function, subtable, arg, depth, indices) | |||
| 1483 | else | 1689 | else |
| 1484 | call2 (function, make_number (i), elt); | 1690 | call2 (function, make_number (i), elt); |
| 1485 | } | 1691 | } |
| 1692 | #if 0 /* If the char table has entries for higher characters, | ||
| 1693 | we should report them. */ | ||
| 1486 | if (NILP (current_buffer->enable_multibyte_characters)) | 1694 | if (NILP (current_buffer->enable_multibyte_characters)) |
| 1487 | return; | 1695 | return; |
| 1696 | #endif | ||
| 1488 | to = CHAR_TABLE_ORDINARY_SLOTS; | 1697 | to = CHAR_TABLE_ORDINARY_SLOTS; |
| 1489 | } | 1698 | } |
| 1490 | else | 1699 | else |
| @@ -1597,9 +1806,9 @@ Only the last argument is not altered, and need not be a list.") | |||
| 1597 | } | 1806 | } |
| 1598 | 1807 | ||
| 1599 | /* This is the guts of all mapping functions. | 1808 | /* This is the guts of all mapping functions. |
| 1600 | Apply fn to each element of seq, one by one, | 1809 | Apply FN to each element of SEQ, one by one, |
| 1601 | storing the results into elements of vals, a C vector of Lisp_Objects. | 1810 | storing the results into elements of VALS, a C vector of Lisp_Objects. |
| 1602 | leni is the length of vals, which should also be the length of seq. */ | 1811 | LENI is the length of VALS, which should also be the length of SEQ. */ |
| 1603 | 1812 | ||
| 1604 | static void | 1813 | static void |
| 1605 | mapcar1 (leni, vals, fn, seq) | 1814 | mapcar1 (leni, vals, fn, seq) |
| @@ -1630,14 +1839,29 @@ mapcar1 (leni, vals, fn, seq) | |||
| 1630 | vals[i] = call1 (fn, dummy); | 1839 | vals[i] = call1 (fn, dummy); |
| 1631 | } | 1840 | } |
| 1632 | } | 1841 | } |
| 1633 | else if (STRINGP (seq)) | 1842 | else if (STRINGP (seq) && ! STRING_MULTIBYTE (seq)) |
| 1634 | { | 1843 | { |
| 1844 | /* Single-byte string. */ | ||
| 1635 | for (i = 0; i < leni; i++) | 1845 | for (i = 0; i < leni; i++) |
| 1636 | { | 1846 | { |
| 1637 | XSETFASTINT (dummy, XSTRING (seq)->data[i]); | 1847 | XSETFASTINT (dummy, XSTRING (seq)->data[i]); |
| 1638 | vals[i] = call1 (fn, dummy); | 1848 | vals[i] = call1 (fn, dummy); |
| 1639 | } | 1849 | } |
| 1640 | } | 1850 | } |
| 1851 | else if (STRINGP (seq)) | ||
| 1852 | { | ||
| 1853 | /* Multi-byte string. */ | ||
| 1854 | int len_byte = XSTRING (seq)->size_byte; | ||
| 1855 | int i_byte; | ||
| 1856 | |||
| 1857 | for (i = 0, i_byte = 0; i < leni;) | ||
| 1858 | { | ||
| 1859 | int c; | ||
| 1860 | FETCH_STRING_CHAR_ADVANCE (c, seq, i, i_byte) | ||
| 1861 | XSETFASTINT (dummy, c); | ||
| 1862 | vals[i] = call1 (fn, dummy); | ||
| 1863 | } | ||
| 1864 | } | ||
| 1641 | else /* Must be a list, since Flength did not get an error */ | 1865 | else /* Must be a list, since Flength did not get an error */ |
| 1642 | { | 1866 | { |
| 1643 | tail = seq; | 1867 | tail = seq; |
| @@ -1752,7 +1976,7 @@ Also accepts Space to mean yes, or Delete to mean no.") | |||
| 1752 | #endif /* HAVE_MENUS */ | 1976 | #endif /* HAVE_MENUS */ |
| 1753 | cursor_in_echo_area = 1; | 1977 | cursor_in_echo_area = 1; |
| 1754 | choose_minibuf_frame (); | 1978 | choose_minibuf_frame (); |
| 1755 | message_nolog ("%s(y or n) ", XSTRING (xprompt)->data); | 1979 | message_with_string ("%s(y or n) ", xprompt, 0); |
| 1756 | 1980 | ||
| 1757 | if (minibuffer_auto_raise) | 1981 | if (minibuffer_auto_raise) |
| 1758 | { | 1982 | { |
| @@ -1815,8 +2039,8 @@ Also accepts Space to mean yes, or Delete to mean no.") | |||
| 1815 | if (! noninteractive) | 2039 | if (! noninteractive) |
| 1816 | { | 2040 | { |
| 1817 | cursor_in_echo_area = -1; | 2041 | cursor_in_echo_area = -1; |
| 1818 | message_nolog ("%s(y or n) %c", | 2042 | message_with_string (answer ? "%s(y or n) y" : "%s(y or n) n", |
| 1819 | XSTRING (xprompt)->data, answer ? 'y' : 'n'); | 2043 | xprompt, 0); |
| 1820 | } | 2044 | } |
| 1821 | 2045 | ||
| 1822 | unbind_to (count, Qnil); | 2046 | unbind_to (count, Qnil); |