Mercurial > hg > xemacs-beta
comparison src/dired.c @ 373:6240c7796c7a r21-2b2
Import from CVS: tag r21-2b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:04:06 +0200 |
parents | 7df0dd720c89 |
children | d883f39b8495 |
comparison
equal
deleted
inserted
replaced
372:49e1ed2d7ed8 | 373:6240c7796c7a |
---|---|
28 #include "elhash.h" | 28 #include "elhash.h" |
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" | |
34 #include "syspwd.h" | |
33 | 35 |
34 Lisp_Object Vcompletion_ignored_extensions; | 36 Lisp_Object Vcompletion_ignored_extensions; |
35 Lisp_Object Qdirectory_files; | 37 Lisp_Object Qdirectory_files; |
36 Lisp_Object Qfile_name_completion; | 38 Lisp_Object Qfile_name_completion; |
37 Lisp_Object Qfile_name_all_completions; | 39 Lisp_Object Qfile_name_all_completions; |
292 file_name_completion_unwind (Lisp_Object locative) | 294 file_name_completion_unwind (Lisp_Object locative) |
293 { | 295 { |
294 DIR *d; | 296 DIR *d; |
295 Lisp_Object obj = XCAR (locative); | 297 Lisp_Object obj = XCAR (locative); |
296 | 298 |
297 if (NILP (obj)) | 299 if (!NILP (obj)) |
298 return Qnil; | 300 { |
299 d = (DIR *)get_opaque_ptr (obj); | 301 d = (DIR *)get_opaque_ptr (obj); |
300 closedir (d); | 302 closedir (d); |
301 free_opaque_ptr (obj); | 303 free_opaque_ptr (obj); |
304 } | |
302 free_cons (XCONS (locative)); | 305 free_cons (XCONS (locative)); |
303 return Qnil; | 306 return Qnil; |
304 } | 307 } |
305 | 308 |
306 static Lisp_Object | 309 static Lisp_Object |
526 return Qt; | 529 return Qt; |
527 return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize)); | 530 return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize)); |
528 } | 531 } |
529 | 532 |
530 | 533 |
534 static Lisp_Object user_name_completion (Lisp_Object user, | |
535 int all_flag, | |
536 int *uniq); | |
537 | |
538 DEFUN ("user-name-completion", Fuser_name_completion, 1, 1, 0, /* | |
539 Complete user name USER. | |
540 | |
541 Returns the longest string common to all user names that start | |
542 with USER. If there is only one and USER matches it exactly, | |
543 returns t. Returns nil if there is no user name starting with USER. | |
544 */ | |
545 (user)) | |
546 { | |
547 return user_name_completion (user, 0, NULL); | |
548 } | |
549 | |
550 DEFUN ("user-name-completion-1", Fuser_name_completion_1, 1, 1, 0, /* | |
551 Complete user name USER. | |
552 | |
553 This function is identical to `user-name-completion', except that | |
554 the cons of the completion and an indication of whether the | |
555 completion was unique is returned. | |
556 | |
557 The car of the returned value is the longest string common to all | |
558 user names that start with USER. If there is only one and USER | |
559 matches it exactly, the car is t. The car is nil if there is no | |
560 user name starting with USER. The cdr of the result is non-nil | |
561 if and only if the completion returned in the car was unique. | |
562 */ | |
563 (user)) | |
564 { | |
565 int uniq; | |
566 Lisp_Object completed; | |
567 | |
568 completed = user_name_completion (user, 0, &uniq); | |
569 return Fcons (completed, uniq ? Qt : Qnil); | |
570 } | |
571 | |
572 DEFUN ("user-name-all-completions", Fuser_name_all_completions, 1, 1, 0, /* | |
573 Return a list of all completions of user name USER. | |
574 These are all user names which begin with USER. | |
575 */ | |
576 (user)) | |
577 { | |
578 return user_name_completion (user, 1, NULL); | |
579 } | |
580 | |
581 static Lisp_Object | |
582 user_name_completion_unwind (Lisp_Object locative) | |
583 { | |
584 Lisp_Object obj1 = XCAR (locative); | |
585 Lisp_Object obj2 = XCDR (locative); | |
586 char **cache; | |
587 int clen, i; | |
588 | |
589 | |
590 if (!NILP (obj1) && !NILP (obj2)) | |
591 { | |
592 /* clean up if interrupted building cache */ | |
593 cache = *(char ***)get_opaque_ptr (obj1); | |
594 clen = *(int *)get_opaque_ptr (obj2); | |
595 free_opaque_ptr (obj1); | |
596 free_opaque_ptr (obj2); | |
597 for (i = 0; i < clen; i++) | |
598 free (cache[i]); | |
599 free (cache); | |
600 } | |
601 | |
602 free_cons (XCONS (locative)); | |
603 endpwent (); | |
604 | |
605 return Qnil; | |
606 } | |
607 | |
608 static char **user_cache; | |
609 static int user_cache_len; | |
610 static int user_cache_max; | |
611 static long user_cache_time; | |
612 | |
613 #define USER_CACHE_REBUILD (24*60*60) /* 1 day, in seconds */ | |
614 | |
615 static Lisp_Object | |
616 user_name_completion (Lisp_Object user, int all_flag, int *uniq) | |
617 { | |
618 /* This function can GC */ | |
619 struct passwd *pw; | |
620 int matchcount = 0; | |
621 Lisp_Object bestmatch = Qnil; | |
622 Charcount bestmatchsize = 0; | |
623 int speccount = specpdl_depth (); | |
624 int i, cmax, clen; | |
625 char **cache; | |
626 Charcount user_name_length; | |
627 Lisp_Object locative; | |
628 EMACS_TIME t; | |
629 struct gcpro gcpro1, gcpro2; | |
630 | |
631 GCPRO2 (user, bestmatch); | |
632 | |
633 CHECK_STRING (user); | |
634 | |
635 user_name_length = XSTRING_CHAR_LENGTH (user); | |
636 | |
637 /* Cache user name lookups because it tends to be quite slow. | |
638 * Rebuild the cache occasionally to catch changes */ | |
639 EMACS_GET_TIME (t); | |
640 if (user_cache && | |
641 EMACS_SECS (t) - user_cache_time > USER_CACHE_REBUILD) | |
642 { | |
643 for (i = 0; i < user_cache_len; i++) | |
644 free (user_cache[i]); | |
645 free (user_cache); | |
646 user_cache = NULL; | |
647 user_cache_len = 0; | |
648 user_cache_max = 0; | |
649 } | |
650 | |
651 if (user_cache == NULL || user_cache_max <= 0) | |
652 { | |
653 cmax = 200; | |
654 clen = 0; | |
655 cache = (char **) malloc (cmax*sizeof (char *)); | |
656 | |
657 setpwent (); | |
658 locative = noseeum_cons (Qnil, Qnil); | |
659 XCAR (locative) = make_opaque_ptr ((void *) &cache); | |
660 XCDR (locative) = make_opaque_ptr ((void *) &clen); | |
661 record_unwind_protect (user_name_completion_unwind, locative); | |
662 /* #### may need to slow down interrupts around call to getpwent | |
663 * below. at least the call to getpwnam in Fuser_full_name | |
664 * is documented as needing it on irix. */ | |
665 while ((pw = getpwent ())) | |
666 { | |
667 if (clen >= cmax) | |
668 { | |
669 cmax *= 2; | |
670 cache = (char **) realloc (cache, cmax*sizeof (char *)); | |
671 } | |
672 | |
673 QUIT; | |
674 | |
675 cache[clen++] = strdup (pw->pw_name); | |
676 } | |
677 free_opaque_ptr (XCAR (locative)); | |
678 free_opaque_ptr (XCDR (locative)); | |
679 XCAR (locative) = Qnil; | |
680 XCDR (locative) = Qnil; | |
681 | |
682 unbind_to (speccount, Qnil); /* free locative cons, endpwent() */ | |
683 | |
684 user_cache_max = cmax; | |
685 user_cache_len = clen; | |
686 user_cache = cache; | |
687 user_cache_time = EMACS_SECS (t); | |
688 } | |
689 | |
690 for (i = 0; i < user_cache_len; i++) | |
691 { | |
692 Bytecount len; | |
693 /* scmp() works in chars, not bytes, so we have to compute this: */ | |
694 Charcount cclen; | |
695 Bufbyte *d_name; | |
696 | |
697 d_name = (Bufbyte *) user_cache[i]; | |
698 len = strlen (d_name); | |
699 cclen = bytecount_to_charcount (d_name, len); | |
700 | |
701 QUIT; | |
702 | |
703 if (cclen < user_name_length || | |
704 0 <= scmp (d_name, XSTRING_DATA (user), user_name_length)) | |
705 continue; | |
706 | |
707 matchcount++; /* count matching completions */ | |
708 | |
709 if (all_flag || NILP (bestmatch)) | |
710 { | |
711 Lisp_Object name = Qnil; | |
712 struct gcpro ngcpro1; | |
713 NGCPRO1 (name); | |
714 /* This is a possible completion */ | |
715 name = make_string (d_name, len); | |
716 if (all_flag) | |
717 { | |
718 bestmatch = Fcons (name, bestmatch); | |
719 } | |
720 else | |
721 { | |
722 bestmatch = name; | |
723 bestmatchsize = XSTRING_CHAR_LENGTH (name); | |
724 } | |
725 NUNGCPRO; | |
726 } | |
727 else | |
728 { | |
729 Charcount compare = min (bestmatchsize, cclen); | |
730 Bufbyte *p1 = XSTRING_DATA (bestmatch); | |
731 Bufbyte *p2 = d_name; | |
732 Charcount matchsize = scmp (p1, p2, compare); | |
733 | |
734 if (matchsize < 0) | |
735 matchsize = compare; | |
736 if (completion_ignore_case) | |
737 { | |
738 /* If this is an exact match except for case, | |
739 use it as the best match rather than one that is not | |
740 an exact match. This way, we get the case pattern | |
741 of the actual match. */ | |
742 if ((matchsize == cclen | |
743 && matchsize < XSTRING_CHAR_LENGTH (bestmatch)) | |
744 || | |
745 /* If there is no exact match ignoring case, | |
746 prefer a match that does not change the case | |
747 of the input. */ | |
748 (((matchsize == cclen) | |
749 == | |
750 (matchsize == XSTRING_CHAR_LENGTH (bestmatch))) | |
751 /* If there is more than one exact match aside from | |
752 case, and one of them is exact including case, | |
753 prefer that one. */ | |
754 && 0 > scmp_1 (p2, XSTRING_DATA (user), | |
755 user_name_length, 0) | |
756 && 0 <= scmp_1 (p1, XSTRING_DATA (user), | |
757 user_name_length, 0))) | |
758 { | |
759 bestmatch = make_string (d_name, len); | |
760 } | |
761 } | |
762 | |
763 bestmatchsize = matchsize; | |
764 } | |
765 } | |
766 | |
767 UNGCPRO; | |
768 | |
769 if (uniq) | |
770 *uniq = (matchcount == 1); | |
771 | |
772 if (all_flag || NILP (bestmatch)) | |
773 return bestmatch; | |
774 if (matchcount == 1 && bestmatchsize == user_name_length) | |
775 return Qt; | |
776 return Fsubstring (bestmatch, Qzero, make_int (bestmatchsize)); | |
777 } | |
778 | |
779 | |
531 Lisp_Object | 780 Lisp_Object |
532 make_directory_hash_table (CONST char *path) | 781 make_directory_hash_table (CONST char *path) |
533 { | 782 { |
534 DIR *d; | 783 DIR *d; |
535 Lisp_Object hash = make_lisp_hashtable (100, HASHTABLE_NONWEAK, | 784 Lisp_Object hash = make_lisp_hashtable (100, HASHTABLE_NONWEAK, |
687 defsymbol (&Qfile_attributes, "file-attributes"); | 936 defsymbol (&Qfile_attributes, "file-attributes"); |
688 | 937 |
689 DEFSUBR (Fdirectory_files); | 938 DEFSUBR (Fdirectory_files); |
690 DEFSUBR (Ffile_name_completion); | 939 DEFSUBR (Ffile_name_completion); |
691 DEFSUBR (Ffile_name_all_completions); | 940 DEFSUBR (Ffile_name_all_completions); |
941 DEFSUBR (Fuser_name_completion); | |
942 DEFSUBR (Fuser_name_completion_1); | |
943 DEFSUBR (Fuser_name_all_completions); | |
692 DEFSUBR (Ffile_attributes); | 944 DEFSUBR (Ffile_attributes); |
693 } | 945 } |
694 | 946 |
695 void | 947 void |
696 vars_of_dired (void) | 948 vars_of_dired (void) |
701 but does affect the commands that actually do completions. | 953 but does affect the commands that actually do completions. |
702 It is used by the functions `file-name-completion' and | 954 It is used by the functions `file-name-completion' and |
703 `file-name-all-completions'. | 955 `file-name-all-completions'. |
704 */ ); | 956 */ ); |
705 Vcompletion_ignored_extensions = Qnil; | 957 Vcompletion_ignored_extensions = Qnil; |
706 } | 958 |
959 user_cache = NULL; | |
960 user_cache_len = 0; | |
961 user_cache_max = 0; | |
962 } |