diff options
| author | Kenichi Handa | 1999-07-28 02:10:51 +0000 |
|---|---|---|
| committer | Kenichi Handa | 1999-07-28 02:10:51 +0000 |
| commit | 2d6115c83512590cda68e4a7911a82f30bf431e1 (patch) | |
| tree | 608e3e411fc02b5e0c96ba4b9d5a42c7a92c268e /src | |
| parent | be8a72f4245bbd4a5282e8c45a613b1d9ae7ac0e (diff) | |
| download | emacs-2d6115c83512590cda68e4a7911a82f30bf431e1.tar.gz emacs-2d6115c83512590cda68e4a7911a82f30bf431e1.zip | |
(count_combining): New function.
(struct textproc_rec): New structure.
(concat): Copy text properties correctly when byte combining
occurs.
Diffstat (limited to 'src')
| -rw-r--r-- | src/fns.c | 110 |
1 files changed, 81 insertions, 29 deletions
| @@ -516,6 +516,37 @@ with the original.") | |||
| 516 | return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0); | 516 | return concat (1, &arg, CONSP (arg) ? Lisp_Cons : XTYPE (arg), 0); |
| 517 | } | 517 | } |
| 518 | 518 | ||
| 519 | /* In string STR of length LEN, see if bytes before STR[I] combine | ||
| 520 | with bytes after STR[I] to form a single character. If so, return | ||
| 521 | the number of bytes after STR[I] which combine in this way. | ||
| 522 | Otherwize, return 0. */ | ||
| 523 | |||
| 524 | static int | ||
| 525 | count_combining (str, len, i) | ||
| 526 | unsigned char *str; | ||
| 527 | int len, i; | ||
| 528 | { | ||
| 529 | int j = i - 1; | ||
| 530 | |||
| 531 | if (i == 0 || i == len || CHAR_HEAD_P (str[i])) | ||
| 532 | return 0; | ||
| 533 | while (j >= 0 && !CHAR_HEAD_P (str[j])) j--; | ||
| 534 | if (j < 0 || ! BASE_LEADING_CODE_P (str[j])) | ||
| 535 | return 0; | ||
| 536 | j = i + 1; | ||
| 537 | while (j < len && ! CHAR_HEAD_P (str[j])) j++; | ||
| 538 | return j - i; | ||
| 539 | } | ||
| 540 | |||
| 541 | /* This structure holds information of an argument of `concat' that is | ||
| 542 | a string and has text properties to be copied. */ | ||
| 543 | struct textproc_rec | ||
| 544 | { | ||
| 545 | int argnum; /* refer to ARGS (arguments of `concat') */ | ||
| 546 | int from; /* refer to ARGS[argnum] (argument string) */ | ||
| 547 | int to; /* refer to VAL (the target string) */ | ||
| 548 | }; | ||
| 549 | |||
| 519 | static Lisp_Object | 550 | static Lisp_Object |
| 520 | concat (nargs, args, target_type, last_special) | 551 | concat (nargs, args, target_type, last_special) |
| 521 | int nargs; | 552 | int nargs; |
| @@ -534,11 +565,14 @@ concat (nargs, args, target_type, last_special) | |||
| 534 | Lisp_Object last_tail; | 565 | Lisp_Object last_tail; |
| 535 | Lisp_Object prev; | 566 | Lisp_Object prev; |
| 536 | int some_multibyte; | 567 | int some_multibyte; |
| 537 | /* When we make a multibyte string, we must pay attention to the | 568 | /* When we make a multibyte string, we can't copy text properties |
| 538 | byte combining problem, i.e., a byte may be combined with a | 569 | while concatinating each string because the length of resulting |
| 539 | multibyte charcter of the previous string. This flag tells if we | 570 | string can't be decided until we finish the whole concatination. |
| 540 | must consider such a situation or not. */ | 571 | So, we record strings that have text properties to be copied |
| 541 | int maybe_combine_byte; | 572 | here, and copy the text properties after the concatination. */ |
| 573 | struct textproc_rec *textprocs; | ||
| 574 | /* Number of elments in textprocs. */ | ||
| 575 | int num_textprocs = 0; | ||
| 542 | 576 | ||
| 543 | /* In append, the last arg isn't treated like the others */ | 577 | /* In append, the last arg isn't treated like the others */ |
| 544 | if (last_special && nargs > 0) | 578 | if (last_special && nargs > 0) |
| @@ -642,13 +676,15 @@ concat (nargs, args, target_type, last_special) | |||
| 642 | 676 | ||
| 643 | /* Copy the contents of the args into the result. */ | 677 | /* Copy the contents of the args into the result. */ |
| 644 | if (CONSP (val)) | 678 | if (CONSP (val)) |
| 645 | tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ | 679 | tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ |
| 646 | else | 680 | else |
| 647 | toindex = 0, toindex_byte = 0; | 681 | toindex = 0, toindex_byte = 0; |
| 648 | 682 | ||
| 649 | prev = Qnil; | 683 | prev = Qnil; |
| 684 | if (STRINGP (val)) | ||
| 685 | textprocs | ||
| 686 | = (struct textproc_rec *) alloca (sizeof (struct textproc_rec) * nargs); | ||
| 650 | 687 | ||
| 651 | maybe_combine_byte = 0; | ||
| 652 | for (argnum = 0; argnum < nargs; argnum++) | 688 | for (argnum = 0; argnum < nargs; argnum++) |
| 653 | { | 689 | { |
| 654 | Lisp_Object thislen; | 690 | Lisp_Object thislen; |
| @@ -660,29 +696,40 @@ concat (nargs, args, target_type, last_special) | |||
| 660 | if (!CONSP (this)) | 696 | if (!CONSP (this)) |
| 661 | thislen = Flength (this), thisleni = XINT (thislen); | 697 | thislen = Flength (this), thisleni = XINT (thislen); |
| 662 | 698 | ||
| 663 | if (STRINGP (this) && STRINGP (val) | ||
| 664 | && ! NULL_INTERVAL_P (XSTRING (this)->intervals)) | ||
| 665 | copy_text_properties (make_number (0), thislen, this, | ||
| 666 | make_number (toindex), val, Qnil); | ||
| 667 | |||
| 668 | /* Between strings of the same kind, copy fast. */ | 699 | /* Between strings of the same kind, copy fast. */ |
| 669 | if (STRINGP (this) && STRINGP (val) | 700 | if (STRINGP (this) && STRINGP (val) |
| 670 | && STRING_MULTIBYTE (this) == some_multibyte) | 701 | && STRING_MULTIBYTE (this) == some_multibyte) |
| 671 | { | 702 | { |
| 672 | int thislen_byte = STRING_BYTES (XSTRING (this)); | 703 | int thislen_byte = STRING_BYTES (XSTRING (this)); |
| 704 | int combined; | ||
| 705 | |||
| 673 | bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte, | 706 | bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte, |
| 674 | STRING_BYTES (XSTRING (this))); | 707 | STRING_BYTES (XSTRING (this))); |
| 675 | if (some_multibyte | 708 | combined = (some_multibyte && toindex_byte > 0 |
| 676 | && toindex_byte > 0 | 709 | ? count_combining (XSTRING (val)->data, |
| 677 | && !ASCII_BYTE_P (XSTRING (val)->data[toindex_byte - 1]) | 710 | toindex_byte + thislen_byte, |
| 678 | && !CHAR_HEAD_P (XSTRING (this)->data[0])) | 711 | toindex_byte) |
| 679 | maybe_combine_byte = 1; | 712 | : 0); |
| 713 | if (! NULL_INTERVAL_P (XSTRING (this)->intervals)) | ||
| 714 | { | ||
| 715 | textprocs[num_textprocs].argnum = argnum; | ||
| 716 | /* We ignore text properties on characters being combined. */ | ||
| 717 | textprocs[num_textprocs].from = combined; | ||
| 718 | textprocs[num_textprocs++].to = toindex; | ||
| 719 | } | ||
| 680 | toindex_byte += thislen_byte; | 720 | toindex_byte += thislen_byte; |
| 681 | toindex += thisleni; | 721 | toindex += thisleni - combined; |
| 722 | XSTRING (val)->size -= combined; | ||
| 682 | } | 723 | } |
| 683 | /* Copy a single-byte string to a multibyte string. */ | 724 | /* Copy a single-byte string to a multibyte string. */ |
| 684 | else if (STRINGP (this) && STRINGP (val)) | 725 | else if (STRINGP (this) && STRINGP (val)) |
| 685 | { | 726 | { |
| 727 | if (! NULL_INTERVAL_P (XSTRING (this)->intervals)) | ||
| 728 | { | ||
| 729 | textprocs[num_textprocs].argnum = argnum; | ||
| 730 | textprocs[num_textprocs].from = 0; | ||
| 731 | textprocs[num_textprocs++].to = toindex; | ||
| 732 | } | ||
| 686 | toindex_byte += copy_text (XSTRING (this)->data, | 733 | toindex_byte += copy_text (XSTRING (this)->data, |
| 687 | XSTRING (val)->data + toindex_byte, | 734 | XSTRING (val)->data + toindex_byte, |
| 688 | XSTRING (this)->size, 0, 1); | 735 | XSTRING (this)->size, 0, 1); |
| @@ -752,13 +799,14 @@ concat (nargs, args, target_type, last_special) | |||
| 752 | CHECK_NUMBER (elt, 0); | 799 | CHECK_NUMBER (elt, 0); |
| 753 | if (SINGLE_BYTE_CHAR_P (XINT (elt))) | 800 | if (SINGLE_BYTE_CHAR_P (XINT (elt))) |
| 754 | { | 801 | { |
| 802 | XSTRING (val)->data[toindex_byte++] = XINT (elt); | ||
| 755 | if (some_multibyte | 803 | if (some_multibyte |
| 756 | && toindex_byte > 0 | 804 | && toindex_byte > 0 |
| 757 | && !ASCII_BYTE_P (XSTRING (val)->data[toindex_byte - 1]) | 805 | && count_combining (XSTRING (val)->data, |
| 758 | && !CHAR_HEAD_P (XINT (elt))) | 806 | toindex_byte, toindex_byte - 1)) |
| 759 | maybe_combine_byte = 1; | 807 | XSTRING (val)->size--; |
| 760 | XSTRING (val)->data[toindex_byte++] = XINT (elt); | 808 | else |
| 761 | toindex++; | 809 | toindex++; |
| 762 | } | 810 | } |
| 763 | else | 811 | else |
| 764 | /* If we have any multibyte characters, | 812 | /* If we have any multibyte characters, |
| @@ -781,12 +829,16 @@ concat (nargs, args, target_type, last_special) | |||
| 781 | if (!NILP (prev)) | 829 | if (!NILP (prev)) |
| 782 | XCONS (prev)->cdr = last_tail; | 830 | XCONS (prev)->cdr = last_tail; |
| 783 | 831 | ||
| 784 | if (maybe_combine_byte) | 832 | if (num_textprocs > 0) |
| 785 | /* Character counter of the multibyte string VAL may be wrong | 833 | { |
| 786 | because of byte combining problem. We must re-calculate it. */ | 834 | for (argnum = 0; argnum < num_textprocs; argnum++) |
| 787 | XSTRING (val)->size = multibyte_chars_in_text (XSTRING (val)->data, | 835 | { |
| 788 | XSTRING (val)->size_byte); | 836 | this = args[textprocs[argnum].argnum]; |
| 789 | 837 | copy_text_properties (make_number (textprocs[argnum].from), | |
| 838 | XSTRING (this)->size, this, | ||
| 839 | make_number (textprocs[argnum].to), val, Qnil); | ||
| 840 | } | ||
| 841 | } | ||
| 790 | return val; | 842 | return val; |
| 791 | } | 843 | } |
| 792 | 844 | ||