Mercurial > hg > xemacs-beta
comparison src/dired.c @ 398:74fd4e045ea6 r21-2-29
Import from CVS: tag r21-2-29
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:13:30 +0200 |
parents | 6719134a07c2 |
children | 2f8bb876ab1d |
comparison
equal
deleted
inserted
replaced
397:f4aeb21a5bad | 398:74fd4e045ea6 |
---|---|
29 #include "regex.h" | 29 #include "regex.h" |
30 #include "opaque.h" | 30 #include "opaque.h" |
31 #include "sysfile.h" | 31 #include "sysfile.h" |
32 #include "sysdir.h" | 32 #include "sysdir.h" |
33 #include "systime.h" | 33 #include "systime.h" |
34 #include "sysdep.h" | |
34 #include "syspwd.h" | 35 #include "syspwd.h" |
35 | 36 |
36 Lisp_Object Vcompletion_ignored_extensions; | 37 Lisp_Object Vcompletion_ignored_extensions; |
37 Lisp_Object Qdirectory_files; | 38 Lisp_Object Qdirectory_files; |
38 Lisp_Object Qfile_name_completion; | 39 Lisp_Object Qfile_name_completion; |
137 && (NILP (match) | 138 && (NILP (match) |
138 || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0)))) | 139 || (0 <= re_search (bufp, dp->d_name, len, 0, len, 0)))) |
139 { | 140 { |
140 if (!NILP (files_only)) | 141 if (!NILP (files_only)) |
141 { | 142 { |
142 int dir_p; | |
143 struct stat st; | 143 struct stat st; |
144 char *cur_statbuf = statbuf; | 144 int dir_p = 0; |
145 char *cur_statbuf_tail = statbuf_tail; | 145 |
146 | 146 memcpy (statbuf_tail, dp->d_name, len); |
147 /* #### I don't think the code under `if' is necessary | 147 statbuf_tail[len] = 0; |
148 anymore. The crashes in this function were reported | 148 |
149 because MAXNAMLEN was used to remember the *whole* | 149 if (stat (statbuf, &st) == 0 |
150 statbuf, instead of using MAXPATHLEN. This should be | 150 && (st.st_mode & S_IFMT) == S_IFDIR) |
151 tested after 21.0 is released. */ | 151 dir_p = 1; |
152 | |
153 /* We normally use the buffer created by alloca. | |
154 However, if the file name we get too big, we'll use a | |
155 malloced buffer, and free it. It is undefined how | |
156 stat() will react to this, but we avoid a buffer | |
157 overrun. */ | |
158 if (len > MAXNAMLEN) | |
159 { | |
160 cur_statbuf = (char *)xmalloc (directorylen + len + 1); | |
161 memcpy (cur_statbuf, statbuf, directorylen); | |
162 cur_statbuf_tail = cur_statbuf + directorylen; | |
163 } | |
164 memcpy (cur_statbuf_tail, dp->d_name, len); | |
165 cur_statbuf_tail[len] = 0; | |
166 | |
167 if (stat (cur_statbuf, &st) < 0) | |
168 dir_p = 0; | |
169 else | |
170 dir_p = ((st.st_mode & S_IFMT) == S_IFDIR); | |
171 | |
172 if (cur_statbuf != statbuf) | |
173 xfree (cur_statbuf); | |
174 | 152 |
175 if (EQ (files_only, Qt) && dir_p) | 153 if (EQ (files_only, Qt) && dir_p) |
176 continue; | 154 continue; |
177 else if (!EQ (files_only, Qt) && !dir_p) | 155 else if (!EQ (files_only, Qt) && !dir_p) |
178 continue; | 156 continue; |
562 if and only if the completion returned in the car was unique. | 540 if and only if the completion returned in the car was unique. |
563 */ | 541 */ |
564 (user)) | 542 (user)) |
565 { | 543 { |
566 int uniq; | 544 int uniq; |
567 Lisp_Object completed; | 545 Lisp_Object completed = user_name_completion (user, 0, &uniq); |
568 | |
569 completed = user_name_completion (user, 0, &uniq); | |
570 return Fcons (completed, uniq ? Qt : Qnil); | 546 return Fcons (completed, uniq ? Qt : Qnil); |
571 } | 547 } |
572 | 548 |
573 DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /* | 549 DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /* |
574 Return a list of all completions of user name USER. | 550 Return a list of all completions of user name USER. |
577 (user)) | 553 (user)) |
578 { | 554 { |
579 return user_name_completion (user, 1, NULL); | 555 return user_name_completion (user, 1, NULL); |
580 } | 556 } |
581 | 557 |
558 struct user_name | |
559 { | |
560 Bufbyte *ptr; | |
561 size_t len; | |
562 }; | |
563 | |
564 struct user_cache | |
565 { | |
566 struct user_name *user_names; | |
567 int length; | |
568 int size; | |
569 EMACS_TIME last_rebuild_time; | |
570 }; | |
571 static struct user_cache user_cache; | |
572 | |
573 static void | |
574 free_user_cache (struct user_cache *cache) | |
575 { | |
576 int i; | |
577 for (i = 0; i < cache->length; i++) | |
578 xfree (cache->user_names[i].ptr); | |
579 xfree (cache->user_names); | |
580 xzero (*cache); | |
581 } | |
582 | |
582 static Lisp_Object | 583 static Lisp_Object |
583 user_name_completion_unwind (Lisp_Object locative) | 584 user_name_completion_unwind (Lisp_Object cache_incomplete_p) |
584 { | 585 { |
585 Lisp_Object obj1 = XCAR (locative); | |
586 Lisp_Object obj2 = XCDR (locative); | |
587 char **cache; | |
588 int clen, i; | |
589 | |
590 | |
591 if (!NILP (obj1) && !NILP (obj2)) | |
592 { | |
593 /* clean up if interrupted building cache */ | |
594 cache = *(char ***)get_opaque_ptr (obj1); | |
595 clen = *(int *)get_opaque_ptr (obj2); | |
596 free_opaque_ptr (obj1); | |
597 free_opaque_ptr (obj2); | |
598 for (i = 0; i < clen; i++) | |
599 free (cache[i]); | |
600 free (cache); | |
601 } | |
602 | |
603 free_cons (XCONS (locative)); | |
604 endpwent (); | 586 endpwent (); |
587 speed_up_interrupts (); | |
588 | |
589 if (! NILP (XCAR (cache_incomplete_p))) | |
590 free_user_cache (&user_cache); | |
591 | |
592 free_cons (XCONS (cache_incomplete_p)); | |
605 | 593 |
606 return Qnil; | 594 return Qnil; |
607 } | 595 } |
608 | 596 |
609 static char **user_cache; | 597 #define USER_CACHE_TTL (24*60*60) /* Time to live: 1 day, in seconds */ |
610 static int user_cache_len; | |
611 static int user_cache_max; | |
612 static long user_cache_time; | |
613 | |
614 #define USER_CACHE_REBUILD (24*60*60) /* 1 day, in seconds */ | |
615 | 598 |
616 static Lisp_Object | 599 static Lisp_Object |
617 user_name_completion (Lisp_Object user, int all_flag, int *uniq) | 600 user_name_completion (Lisp_Object user, int all_flag, int *uniq) |
618 { | 601 { |
619 /* This function can GC */ | 602 /* This function can GC */ |
620 struct passwd *pw; | |
621 int matchcount = 0; | 603 int matchcount = 0; |
622 Lisp_Object bestmatch = Qnil; | 604 Lisp_Object bestmatch = Qnil; |
623 Charcount bestmatchsize = 0; | 605 Charcount bestmatchsize = 0; |
624 int speccount = specpdl_depth (); | |
625 int i, cmax, clen; | |
626 char **cache; | |
627 Charcount user_name_length; | 606 Charcount user_name_length; |
628 Lisp_Object locative; | |
629 EMACS_TIME t; | 607 EMACS_TIME t; |
608 int i; | |
630 struct gcpro gcpro1, gcpro2; | 609 struct gcpro gcpro1, gcpro2; |
631 | 610 |
632 GCPRO2 (user, bestmatch); | 611 GCPRO2 (user, bestmatch); |
633 | 612 |
634 CHECK_STRING (user); | 613 CHECK_STRING (user); |
636 user_name_length = XSTRING_CHAR_LENGTH (user); | 615 user_name_length = XSTRING_CHAR_LENGTH (user); |
637 | 616 |
638 /* Cache user name lookups because it tends to be quite slow. | 617 /* Cache user name lookups because it tends to be quite slow. |
639 * Rebuild the cache occasionally to catch changes */ | 618 * Rebuild the cache occasionally to catch changes */ |
640 EMACS_GET_TIME (t); | 619 EMACS_GET_TIME (t); |
641 if (user_cache && | 620 if (user_cache.user_names && |
642 EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD) | 621 (EMACS_SECS (t) - EMACS_SECS (user_cache.last_rebuild_time) |
643 { | 622 > USER_CACHE_TTL)) |
644 for (i = 0; i < user_cache_len; i++) | 623 free_user_cache (&user_cache); |
645 free (user_cache[i]); | 624 |
646 free (user_cache); | 625 if (!user_cache.user_names) |
647 user_cache = NULL; | 626 { |
648 user_cache_len = 0; | 627 struct passwd *pwd; |
649 user_cache_max = 0; | 628 Lisp_Object cache_incomplete_p = noseeum_cons (Qt, Qnil); |
650 } | 629 int speccount = specpdl_depth (); |
651 | 630 |
652 if (user_cache == NULL || user_cache_max <= 0) | 631 slow_down_interrupts (); |
653 { | |
654 cmax = 200; | |
655 clen = 0; | |
656 cache = (char **) malloc (cmax*sizeof (char *)); | |
657 | |
658 setpwent (); | 632 setpwent (); |
659 locative = noseeum_cons (Qnil, Qnil); | 633 record_unwind_protect (user_name_completion_unwind, cache_incomplete_p); |
660 XCAR (locative) = make_opaque_ptr ((void *) &cache); | 634 while ((pwd = getpwent ())) |
661 XCDR (locative) = make_opaque_ptr ((void *) &clen); | |
662 record_unwind_protect (user_name_completion_unwind, locative); | |
663 /* #### may need to slow down interrupts around call to getpwent | |
664 * below. at least the call to getpwnam in Fuser_full_name | |
665 * is documented as needing it on irix. */ | |
666 while ((pw = getpwent ())) | |
667 { | 635 { |
668 if (clen >= cmax) | |
669 { | |
670 cmax *= 2; | |
671 cache = (char **) realloc (cache, cmax*sizeof (char *)); | |
672 } | |
673 | |
674 QUIT; | 636 QUIT; |
675 | 637 DO_REALLOC (user_cache.user_names, user_cache.size, |
676 cache[clen++] = strdup (pw->pw_name); | 638 user_cache.length + 1, struct user_name); |
639 TO_INTERNAL_FORMAT (C_STRING, pwd->pw_name, | |
640 MALLOC, | |
641 (user_cache.user_names[user_cache.length].ptr, | |
642 user_cache.user_names[user_cache.length].len), | |
643 Qnative); | |
644 user_cache.length++; | |
677 } | 645 } |
678 free_opaque_ptr (XCAR (locative)); | 646 XCAR (cache_incomplete_p) = Qnil; |
679 free_opaque_ptr (XCDR (locative)); | 647 unbind_to (speccount, Qnil); |
680 XCAR (locative) = Qnil; | 648 |
681 XCDR (locative) = Qnil; | 649 EMACS_GET_TIME (user_cache.last_rebuild_time); |
682 | 650 } |
683 unbind_to (speccount, Qnil); /* free locative cons, endpwent() */ | 651 |
684 | 652 for (i = 0; i < user_cache.length; i++) |
685 user_cache_max = cmax; | 653 { |
686 user_cache_len = clen; | 654 Bufbyte *u_name = user_cache.user_names[i].ptr; |
687 user_cache = cache; | 655 Bytecount len = user_cache.user_names[i].len; |
688 user_cache_time = EMACS_SECS (t); | |
689 } | |
690 | |
691 for (i = 0; i < user_cache_len; i++) | |
692 { | |
693 Bufbyte *d_name = (Bufbyte *) user_cache[i]; | |
694 Bytecount len = strlen ((char *) d_name); | |
695 /* scmp() works in chars, not bytes, so we have to compute this: */ | 656 /* scmp() works in chars, not bytes, so we have to compute this: */ |
696 Charcount cclen = bytecount_to_charcount (d_name, len); | 657 Charcount cclen = bytecount_to_charcount (u_name, len); |
697 | 658 |
698 QUIT; | 659 QUIT; |
699 | 660 |
700 if (cclen < user_name_length || | 661 if (cclen < user_name_length |
701 0 <= scmp (d_name, XSTRING_DATA (user), user_name_length)) | 662 || 0 <= scmp_1 (u_name, XSTRING_DATA (user), user_name_length, 0)) |
702 continue; | 663 continue; |
703 | 664 |
704 matchcount++; /* count matching completions */ | 665 matchcount++; /* count matching completions */ |
705 | 666 |
706 if (all_flag || NILP (bestmatch)) | 667 if (all_flag || NILP (bestmatch)) |
707 { | 668 { |
708 Lisp_Object name = Qnil; | 669 Lisp_Object name = Qnil; |
709 struct gcpro ngcpro1; | 670 struct gcpro ngcpro1; |
710 NGCPRO1 (name); | 671 NGCPRO1 (name); |
711 /* This is a possible completion */ | 672 /* This is a possible completion */ |
712 name = make_string (d_name, len); | 673 name = make_string (u_name, len); |
713 if (all_flag) | 674 if (all_flag) |
714 { | 675 { |
715 bestmatch = Fcons (name, bestmatch); | 676 bestmatch = Fcons (name, bestmatch); |
716 } | 677 } |
717 else | 678 else |
723 } | 684 } |
724 else | 685 else |
725 { | 686 { |
726 Charcount compare = min (bestmatchsize, cclen); | 687 Charcount compare = min (bestmatchsize, cclen); |
727 Bufbyte *p1 = XSTRING_DATA (bestmatch); | 688 Bufbyte *p1 = XSTRING_DATA (bestmatch); |
728 Bufbyte *p2 = d_name; | 689 Bufbyte *p2 = u_name; |
729 Charcount matchsize = scmp (p1, p2, compare); | 690 Charcount matchsize = scmp_1 (p1, p2, compare, 0); |
730 | 691 |
731 if (matchsize < 0) | 692 if (matchsize < 0) |
732 matchsize = compare; | 693 matchsize = compare; |
733 if (completion_ignore_case) | |
734 { | |
735 /* If this is an exact match except for case, | |
736 use it as the best match rather than one that is not | |
737 an exact match. This way, we get the case pattern | |
738 of the actual match. */ | |
739 if ((matchsize == cclen | |
740 && matchsize < XSTRING_CHAR_LENGTH (bestmatch)) | |
741 || | |
742 /* If there is no exact match ignoring case, | |
743 prefer a match that does not change the case | |
744 of the input. */ | |
745 (((matchsize == cclen) | |
746 == | |
747 (matchsize == XSTRING_CHAR_LENGTH (bestmatch))) | |
748 /* If there is more than one exact match aside from | |
749 case, and one of them is exact including case, | |
750 prefer that one. */ | |
751 && 0 > scmp_1 (p2, XSTRING_DATA (user), | |
752 user_name_length, 0) | |
753 && 0 <= scmp_1 (p1, XSTRING_DATA (user), | |
754 user_name_length, 0))) | |
755 { | |
756 bestmatch = make_string (d_name, len); | |
757 } | |
758 } | |
759 | 694 |
760 bestmatchsize = matchsize; | 695 bestmatchsize = matchsize; |
761 } | 696 } |
762 } | 697 } |
763 | 698 |
774 } | 709 } |
775 #endif /* ! defined WINDOWSNT */ | 710 #endif /* ! defined WINDOWSNT */ |
776 | 711 |
777 | 712 |
778 Lisp_Object | 713 Lisp_Object |
779 make_directory_hash_table (CONST char *path) | 714 make_directory_hash_table (const char *path) |
780 { | 715 { |
781 DIR *d; | 716 DIR *d; |
782 Lisp_Object hash = | |
783 make_lisp_hash_table (100, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); | |
784 if ((d = opendir (path))) | 717 if ((d = opendir (path))) |
785 { | 718 { |
786 DIRENTRY *dp; | 719 DIRENTRY *dp; |
720 Lisp_Object hash = | |
721 make_lisp_hash_table (20, HASH_TABLE_NON_WEAK, HASH_TABLE_EQUAL); | |
787 | 722 |
788 while ((dp = readdir (d))) | 723 while ((dp = readdir (d))) |
789 { | 724 { |
790 Bytecount len = NAMLEN (dp); | 725 Bytecount len = NAMLEN (dp); |
791 if (DIRENTRY_NONEMPTY (dp)) | 726 if (DIRENTRY_NONEMPTY (dp)) |
792 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */ | 727 /* Cast to Bufbyte* is OK, as readdir() Mule-encapsulates. */ |
793 Fputhash (make_string ((Bufbyte *) dp->d_name, len), Qt, hash); | 728 Fputhash (make_string ((Bufbyte *) dp->d_name, len), Qt, hash); |
794 } | 729 } |
795 closedir (d); | 730 closedir (d); |
796 } | 731 return hash; |
797 return hash; | 732 } |
733 else | |
734 return Qnil; | |
798 } | 735 } |
799 | 736 |
800 Lisp_Object | 737 Lisp_Object |
801 wasteful_word_to_lisp (unsigned int item) | 738 wasteful_word_to_lisp (unsigned int item) |
802 { | 739 { |
953 but does affect the commands that actually do completions. | 890 but does affect the commands that actually do completions. |
954 It is used by the functions `file-name-completion' and | 891 It is used by the functions `file-name-completion' and |
955 `file-name-all-completions'. | 892 `file-name-all-completions'. |
956 */ ); | 893 */ ); |
957 Vcompletion_ignored_extensions = Qnil; | 894 Vcompletion_ignored_extensions = Qnil; |
958 | 895 } |
959 #ifndef WINDOWSNT | |
960 user_cache = NULL; | |
961 user_cache_len = 0; | |
962 user_cache_max = 0; | |
963 #endif | |
964 } |