Mercurial > emacs
comparison src/fns.c @ 20667:64af046211eb
(concat): Move the test for all nil in `append'
back to the right place.
Always compute result_len_byte as for a multibyte string. Then,
if the result will be single-byte, don't use that computation.
When converting single-byte to multibyte, don't use copy_text.
Do use copy_text between single-byte string and multibyte string.
(Fstring_make_multibyte, Fstring_make_unibyte): New functions.
(syms_of_fns): defsubr them.
(string_char_to_byte): Count from the beginning or the end,
whichever is closer. Keep a cache of recent values.
(string_byte_to_char): Likewise.
(Fstring_lessp): Compare the strings char by char.
author | Karl Heuer <kwzh@gnu.org> |
---|---|
date | Sun, 18 Jan 1998 04:37:08 +0000 |
parents | 12240a9b3679 |
children | 907d8633c8cc |
comparison
equal
deleted
inserted
replaced
20666:7e740edb4d52 | 20667:64af046211eb |
---|---|
37 #include "window.h" | 37 #include "window.h" |
38 | 38 |
39 #ifndef NULL | 39 #ifndef NULL |
40 #define NULL (void *)0 | 40 #define NULL (void *)0 |
41 #endif | 41 #endif |
42 | |
43 #define DEFAULT_NONASCII_INSERT_OFFSET 0x800 | |
42 | 44 |
43 /* Nonzero enables use of dialog boxes for questions | 45 /* Nonzero enables use of dialog boxes for questions |
44 asked by mouse commands. */ | 46 asked by mouse commands. */ |
45 int use_dialog_box; | 47 int use_dialog_box; |
46 | 48 |
203 Case is significant.\n\ | 205 Case is significant.\n\ |
204 Symbols are also allowed; their print names are used instead.") | 206 Symbols are also allowed; their print names are used instead.") |
205 (s1, s2) | 207 (s1, s2) |
206 register Lisp_Object s1, s2; | 208 register Lisp_Object s1, s2; |
207 { | 209 { |
208 register int i; | |
209 register unsigned char *p1, *p2; | |
210 register int end; | 210 register int end; |
211 register int i1, i1_byte, i2, i2_byte; | |
211 | 212 |
212 if (SYMBOLP (s1)) | 213 if (SYMBOLP (s1)) |
213 XSETSTRING (s1, XSYMBOL (s1)->name); | 214 XSETSTRING (s1, XSYMBOL (s1)->name); |
214 if (SYMBOLP (s2)) | 215 if (SYMBOLP (s2)) |
215 XSETSTRING (s2, XSYMBOL (s2)->name); | 216 XSETSTRING (s2, XSYMBOL (s2)->name); |
216 CHECK_STRING (s1, 0); | 217 CHECK_STRING (s1, 0); |
217 CHECK_STRING (s2, 1); | 218 CHECK_STRING (s2, 1); |
218 | 219 |
219 p1 = XSTRING (s1)->data; | 220 i1 = i1_byte = i2 = i2_byte = 0; |
220 p2 = XSTRING (s2)->data; | 221 |
221 end = XSTRING (s1)->size_byte; | 222 end = XSTRING (s1)->size; |
222 if (end > XSTRING (s2)->size_byte) | 223 if (end > XSTRING (s2)->size) |
223 end = XSTRING (s2)->size_byte; | 224 end = XSTRING (s2)->size; |
224 | 225 |
225 for (i = 0; i < end; i++) | 226 while (i1 < end) |
226 { | 227 { |
227 if (p1[i] != p2[i]) | 228 /* When we find a mismatch, we must compare the |
228 return p1[i] < p2[i] ? Qt : Qnil; | 229 characters, not just the bytes. */ |
229 } | 230 int c1, c2; |
230 return i < XSTRING (s2)->size_byte ? Qt : Qnil; | 231 |
232 if (STRING_MULTIBYTE (s1)) | |
233 FETCH_STRING_CHAR_ADVANCE (c1, s1, i1, i1_byte); | |
234 else | |
235 c1 = XSTRING (s1)->data[i1++]; | |
236 | |
237 if (STRING_MULTIBYTE (s2)) | |
238 FETCH_STRING_CHAR_ADVANCE (c2, s2, i2, i2_byte); | |
239 else | |
240 c2 = XSTRING (s2)->data[i2++]; | |
241 | |
242 if (c1 != c2) | |
243 return c1 < c2 ? Qt : Qnil; | |
244 } | |
245 return i1 < XSTRING (s2)->size ? Qt : Qnil; | |
231 } | 246 } |
232 | 247 |
233 static Lisp_Object concat (); | 248 static Lisp_Object concat (); |
234 | 249 |
235 /* ARGSUSED */ | 250 /* ARGSUSED */ |
426 int len; | 441 int len; |
427 this = args[argnum]; | 442 this = args[argnum]; |
428 len = XFASTINT (Flength (this)); | 443 len = XFASTINT (Flength (this)); |
429 if (target_type == Lisp_String) | 444 if (target_type == Lisp_String) |
430 { | 445 { |
431 /* We must pay attention to a multibyte character which | 446 /* We must count the number of bytes needed in the string |
432 takes more than one byte in string. */ | 447 as well as the number of characters. */ |
433 int i; | 448 int i; |
434 Lisp_Object ch; | 449 Lisp_Object ch; |
435 int this_len_byte; | 450 int this_len_byte; |
436 | 451 |
437 if (VECTORP (this)) | 452 if (VECTORP (this)) |
457 some_multibyte = 1; | 472 some_multibyte = 1; |
458 } | 473 } |
459 else if (STRINGP (this)) | 474 else if (STRINGP (this)) |
460 { | 475 { |
461 result_len_byte += XSTRING (this)->size_byte; | 476 result_len_byte += XSTRING (this)->size_byte; |
462 if (STRING_MULTIBYTE (this)) | 477 { |
463 some_multibyte = 1; | 478 some_multibyte = 1; |
479 result_len_byte += XSTRING (this)->size_byte; | |
480 } | |
481 else | |
482 result_len_byte += count_size_as_multibyte (XSTRING (this)->data, | |
483 XSTRING (this)->size); | |
464 } | 484 } |
465 } | 485 } |
466 | 486 |
467 result_len += len; | 487 result_len += len; |
468 } | 488 } |
469 | 489 |
470 /* In `append', if all but last arg are nil, return last arg. */ | 490 if (! some_multibyte) |
471 if (target_type == Lisp_Cons && EQ (val, Qnil)) | 491 result_len_byte = result_len; |
472 return last_tail; | |
473 | 492 |
474 /* Create the output object. */ | 493 /* Create the output object. */ |
475 if (target_type == Lisp_Cons) | 494 if (target_type == Lisp_Cons) |
476 val = Fmake_list (make_number (result_len), Qnil); | 495 val = Fmake_list (make_number (result_len), Qnil); |
477 else if (target_type == Lisp_Vectorlike) | 496 else if (target_type == Lisp_Vectorlike) |
478 val = Fmake_vector (make_number (result_len), Qnil); | 497 val = Fmake_vector (make_number (result_len), Qnil); |
479 else | 498 else |
480 val = make_uninit_multibyte_string (result_len, result_len_byte); | 499 val = make_uninit_multibyte_string (result_len, result_len_byte); |
481 | 500 |
501 /* In `append', if all but last arg are nil, return last arg. */ | |
502 if (target_type == Lisp_Cons && EQ (val, Qnil)) | |
503 return last_tail; | |
482 | 504 |
483 /* Copy the contents of the args into the result. */ | 505 /* Copy the contents of the args into the result. */ |
484 if (CONSP (val)) | 506 if (CONSP (val)) |
485 tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ | 507 tail = val, toindex = -1; /* -1 in toindex is flag we are making a list */ |
486 else | 508 else |
510 { | 532 { |
511 int thislen_byte = XSTRING (this)->size_byte; | 533 int thislen_byte = XSTRING (this)->size_byte; |
512 bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte, | 534 bcopy (XSTRING (this)->data, XSTRING (val)->data + toindex_byte, |
513 XSTRING (this)->size_byte); | 535 XSTRING (this)->size_byte); |
514 toindex_byte += thislen_byte; | 536 toindex_byte += thislen_byte; |
537 toindex += thisleni; | |
538 } | |
539 /* Copy a single-byte string to a multibyte string. */ | |
540 else if (STRINGP (this) && STRINGP (val)) | |
541 { | |
542 toindex_byte += copy_text (XSTRING (this)->data, | |
543 XSTRING (val)->data + toindex_byte, | |
544 XSTRING (this)->size, 0, 1); | |
515 toindex += thisleni; | 545 toindex += thisleni; |
516 } | 546 } |
517 else | 547 else |
518 /* Copy element by element. */ | 548 /* Copy element by element. */ |
519 while (1) | 549 while (1) |
544 XSETFASTINT (elt, XSTRING (this)->data[thisindex++]); | 574 XSETFASTINT (elt, XSTRING (this)->data[thisindex++]); |
545 if (some_multibyte && XINT (elt) >= 0200 | 575 if (some_multibyte && XINT (elt) >= 0200 |
546 && XINT (elt) < 0400) | 576 && XINT (elt) < 0400) |
547 { | 577 { |
548 c = XINT (elt); | 578 c = XINT (elt); |
549 copy_text (&c, &c, 1, 0, 1); | 579 if (nonascii_insert_offset > 0) |
580 c += nonascii_insert_offset; | |
581 else | |
582 c += DEFAULT_NONASCII_INSERT_OFFSET; | |
583 | |
550 XSETINT (elt, c); | 584 XSETINT (elt, c); |
551 } | 585 } |
552 } | 586 } |
553 } | 587 } |
554 else if (BOOL_VECTOR_P (this)) | 588 else if (BOOL_VECTOR_P (this)) |
606 XCONS (prev)->cdr = last_tail; | 640 XCONS (prev)->cdr = last_tail; |
607 | 641 |
608 return val; | 642 return val; |
609 } | 643 } |
610 | 644 |
645 static Lisp_Object string_char_byte_cache_string; | |
646 static int string_char_byte_cache_charpos; | |
647 static int string_char_byte_cache_bytepos; | |
648 | |
611 /* Return the character index corresponding to CHAR_INDEX in STRING. */ | 649 /* Return the character index corresponding to CHAR_INDEX in STRING. */ |
612 | 650 |
613 int | 651 int |
614 string_char_to_byte (string, char_index) | 652 string_char_to_byte (string, char_index) |
615 Lisp_Object string; | 653 Lisp_Object string; |
616 int char_index; | 654 int char_index; |
617 { | 655 { |
618 int i = 0, i_byte = 0; | 656 int i, i_byte; |
657 int best_below, best_below_byte; | |
658 int best_above, best_above_byte; | |
619 | 659 |
620 if (! STRING_MULTIBYTE (string)) | 660 if (! STRING_MULTIBYTE (string)) |
621 return char_index; | 661 return char_index; |
622 | 662 |
623 while (i < char_index) | 663 best_below = best_below_byte = 0; |
624 { | 664 best_above = XSTRING (string)->size; |
625 int c; | 665 best_above_byte = XSTRING (string)->size_byte; |
626 FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte); | 666 |
627 } | 667 if (EQ (string, string_char_byte_cache_string)) |
668 { | |
669 if (string_char_byte_cache_charpos < char_index) | |
670 { | |
671 best_below = string_char_byte_cache_charpos; | |
672 best_below_byte = string_char_byte_cache_bytepos; | |
673 } | |
674 else | |
675 { | |
676 best_above = string_char_byte_cache_charpos; | |
677 best_above_byte = string_char_byte_cache_bytepos; | |
678 } | |
679 } | |
680 | |
681 if (char_index - best_below < best_above - char_index) | |
682 { | |
683 while (best_below < char_index) | |
684 { | |
685 int c; | |
686 FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte); | |
687 } | |
688 i = best_below; | |
689 i_byte = best_below_byte; | |
690 } | |
691 else | |
692 { | |
693 while (best_above > char_index) | |
694 { | |
695 int best_above_byte_saved = --best_above_byte; | |
696 | |
697 while (best_above_byte > 0 | |
698 && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte])) | |
699 best_above_byte--; | |
700 if (XSTRING (string)->data[best_above_byte] < 0x80) | |
701 best_above_byte = best_above_byte_saved; | |
702 best_above--; | |
703 } | |
704 i = best_above; | |
705 i_byte = best_above_byte; | |
706 } | |
707 | |
708 string_char_byte_cache_bytepos = i_byte; | |
709 string_char_byte_cache_charpos = i; | |
710 string_char_byte_cache_string = string; | |
628 | 711 |
629 return i_byte; | 712 return i_byte; |
630 } | 713 } |
631 | 714 |
632 /* Return the character index corresponding to BYTE_INDEX in STRING. */ | 715 /* Return the character index corresponding to BYTE_INDEX in STRING. */ |
633 | 716 |
634 int | 717 int |
635 string_byte_to_char (string, byte_index) | 718 string_byte_to_char (string, byte_index) |
636 Lisp_Object string; | 719 Lisp_Object string; |
637 int byte_index; | 720 int byte_index; |
638 { | 721 { |
639 int i = 0, i_byte = 0; | 722 int i, i_byte; |
723 int best_below, best_below_byte; | |
724 int best_above, best_above_byte; | |
640 | 725 |
641 if (! STRING_MULTIBYTE (string)) | 726 if (! STRING_MULTIBYTE (string)) |
642 return byte_index; | 727 return byte_index; |
643 | 728 |
644 while (i_byte < byte_index) | 729 best_below = best_below_byte = 0; |
645 { | 730 best_above = XSTRING (string)->size; |
646 int c; | 731 best_above_byte = XSTRING (string)->size_byte; |
647 FETCH_STRING_CHAR_ADVANCE (c, string, i, i_byte); | 732 |
648 } | 733 if (EQ (string, string_char_byte_cache_string)) |
734 { | |
735 if (string_char_byte_cache_bytepos < byte_index) | |
736 { | |
737 best_below = string_char_byte_cache_charpos; | |
738 best_below_byte = string_char_byte_cache_bytepos; | |
739 } | |
740 else | |
741 { | |
742 best_above = string_char_byte_cache_charpos; | |
743 best_above_byte = string_char_byte_cache_bytepos; | |
744 } | |
745 } | |
746 | |
747 if (byte_index - best_below_byte < best_above_byte - byte_index) | |
748 { | |
749 while (best_below_byte < byte_index) | |
750 { | |
751 int c; | |
752 FETCH_STRING_CHAR_ADVANCE (c, string, best_below, best_below_byte); | |
753 } | |
754 i = best_below; | |
755 i_byte = best_below_byte; | |
756 } | |
757 else | |
758 { | |
759 while (best_above_byte > byte_index) | |
760 { | |
761 int best_above_byte_saved = --best_above_byte; | |
762 | |
763 while (best_above_byte > 0 | |
764 && !CHAR_HEAD_P (XSTRING (string)->data[best_above_byte])) | |
765 best_above_byte--; | |
766 if (XSTRING (string)->data[best_above_byte] < 0x80) | |
767 best_above_byte = best_above_byte_saved; | |
768 best_above--; | |
769 } | |
770 i = best_above; | |
771 i_byte = best_above_byte; | |
772 } | |
773 | |
774 string_char_byte_cache_bytepos = i_byte; | |
775 string_char_byte_cache_charpos = i; | |
776 string_char_byte_cache_string = string; | |
649 | 777 |
650 return i; | 778 return i; |
651 } | 779 } |
652 | 780 |
653 /* Convert STRING to a multibyte string. | 781 /* Convert STRING to a multibyte string. |
654 Single-byte characters 0200 through 0377 are converted | 782 Single-byte characters 0200 through 0377 are converted |
655 by adding nonascii_insert_offset to each. */ | 783 by adding nonascii_insert_offset to each. */ |
656 | 784 |
657 Lisp_Object | 785 Lisp_Object |
688 | 816 |
689 copy_text (XSTRING (string)->data, buf, XSTRING (string)->size_byte, | 817 copy_text (XSTRING (string)->data, buf, XSTRING (string)->size_byte, |
690 1, 0); | 818 1, 0); |
691 | 819 |
692 return make_unibyte_string (buf, XSTRING (string)->size); | 820 return make_unibyte_string (buf, XSTRING (string)->size); |
821 } | |
822 | |
823 DEFUN ("string-make-multibyte", Fstring_make_multibyte, Sstring_make_multibyte, | |
824 1, 1, 0, | |
825 "Return the multibyte equivalent of STRING.") | |
826 (string) | |
827 Lisp_Object string; | |
828 { | |
829 return string_make_multibyte (string); | |
830 } | |
831 | |
832 DEFUN ("string-make-unibyte", Fstring_make_unibyte, Sstring_make_unibyte, | |
833 1, 1, 0, | |
834 "Return the unibyte equivalent of STRING.") | |
835 (string) | |
836 Lisp_Object string; | |
837 { | |
838 return string_make_unibyte (string); | |
693 } | 839 } |
694 | 840 |
695 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0, | 841 DEFUN ("copy-alist", Fcopy_alist, Scopy_alist, 1, 1, 0, |
696 "Return a copy of ALIST.\n\ | 842 "Return a copy of ALIST.\n\ |
697 This is an alist which represents the same mapping from objects to objects,\n\ | 843 This is an alist which represents the same mapping from objects to objects,\n\ |
2311 Qcursor_in_echo_area = intern ("cursor-in-echo-area"); | 2457 Qcursor_in_echo_area = intern ("cursor-in-echo-area"); |
2312 staticpro (&Qcursor_in_echo_area); | 2458 staticpro (&Qcursor_in_echo_area); |
2313 Qwidget_type = intern ("widget-type"); | 2459 Qwidget_type = intern ("widget-type"); |
2314 staticpro (&Qwidget_type); | 2460 staticpro (&Qwidget_type); |
2315 | 2461 |
2462 staticpro (&string_char_byte_cache_string); | |
2463 string_char_byte_cache_string = Qnil; | |
2464 | |
2316 Fset (Qyes_or_no_p_history, Qnil); | 2465 Fset (Qyes_or_no_p_history, Qnil); |
2317 | 2466 |
2318 DEFVAR_LISP ("features", &Vfeatures, | 2467 DEFVAR_LISP ("features", &Vfeatures, |
2319 "A list of symbols which are the features of the executing emacs.\n\ | 2468 "A list of symbols which are the features of the executing emacs.\n\ |
2320 Used by `featurep' and `require', and altered by `provide'."); | 2469 Used by `featurep' and `require', and altered by `provide'."); |
2334 defsubr (&Sstring_lessp); | 2483 defsubr (&Sstring_lessp); |
2335 defsubr (&Sappend); | 2484 defsubr (&Sappend); |
2336 defsubr (&Sconcat); | 2485 defsubr (&Sconcat); |
2337 defsubr (&Svconcat); | 2486 defsubr (&Svconcat); |
2338 defsubr (&Scopy_sequence); | 2487 defsubr (&Scopy_sequence); |
2488 defsubr (&Sstring_make_multibyte); | |
2489 defsubr (&Sstring_make_unibyte); | |
2339 defsubr (&Scopy_alist); | 2490 defsubr (&Scopy_alist); |
2340 defsubr (&Ssubstring); | 2491 defsubr (&Ssubstring); |
2341 defsubr (&Snthcdr); | 2492 defsubr (&Snthcdr); |
2342 defsubr (&Snth); | 2493 defsubr (&Snth); |
2343 defsubr (&Selt); | 2494 defsubr (&Selt); |