Mercurial > emacs
comparison src/dired.c @ 94890:907ac6ecef89
(file_name_completion): Tweak the code so as to always do it
in a single pass. Tighten the scope of some variables.
author | Stefan Monnier <monnier@iro.umontreal.ca> |
---|---|
date | Tue, 13 May 2008 05:16:43 +0000 |
parents | 77013c501e34 |
children | 8971ddf55736 |
comparison
equal
deleted
inserted
replaced
94889:e80a3956601b | 94890:907ac6ecef89 |
---|---|
464 Lisp_Object file, dirname; | 464 Lisp_Object file, dirname; |
465 int all_flag, ver_flag; | 465 int all_flag, ver_flag; |
466 Lisp_Object predicate; | 466 Lisp_Object predicate; |
467 { | 467 { |
468 DIR *d; | 468 DIR *d; |
469 int bestmatchsize = 0, skip; | 469 int bestmatchsize = 0; |
470 register int compare, matchsize; | |
471 int matchcount = 0; | 470 int matchcount = 0; |
472 /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. | 471 /* If ALL_FLAG is 1, BESTMATCH is the list of all matches, decoded. |
473 If ALL_FLAG is 0, BESTMATCH is either nil | 472 If ALL_FLAG is 0, BESTMATCH is either nil |
474 or the best match so far, not decoded. */ | 473 or the best match so far, not decoded. */ |
475 Lisp_Object bestmatch, tem, elt, name; | 474 Lisp_Object bestmatch, tem, elt, name; |
476 Lisp_Object encoded_file; | 475 Lisp_Object encoded_file; |
477 Lisp_Object encoded_dir; | 476 Lisp_Object encoded_dir; |
478 struct stat st; | 477 struct stat st; |
479 int directoryp; | 478 int directoryp; |
480 int passcount; | 479 /* If includeall is zero, exclude files in completion-ignored-extensions as |
480 well as "." and "..". Until shown otherwise, assume we can't exclude | |
481 anything. */ | |
482 int includeall = 1; | |
481 int count = SPECPDL_INDEX (); | 483 int count = SPECPDL_INDEX (); |
482 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | 484 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; |
483 | 485 |
484 elt = Qnil; | 486 elt = Qnil; |
485 | 487 |
516 on the encoded file name. */ | 518 on the encoded file name. */ |
517 encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file; | 519 encoded_file = STRING_MULTIBYTE (file) ? ENCODE_FILE (file) : file; |
518 | 520 |
519 encoded_dir = ENCODE_FILE (dirname); | 521 encoded_dir = ENCODE_FILE (dirname); |
520 | 522 |
521 /* With passcount = 0, ignore files that end in an ignored extension. | 523 BLOCK_INPUT; |
522 If nothing found then try again with passcount = 1, don't ignore them. | 524 d = opendir (SDATA (Fdirectory_file_name (encoded_dir))); |
523 If looking for all completions, start with passcount = 1, | 525 UNBLOCK_INPUT; |
524 so always take even the ignored ones. | 526 if (!d) |
525 | 527 report_file_error ("Opening directory", Fcons (dirname, Qnil)); |
526 ** It would not actually be helpful to the user to ignore any possible | 528 |
527 completions when making a list of them.** */ | 529 record_unwind_protect (directory_files_internal_unwind, |
528 | 530 make_save_value (d, 0)); |
529 for (passcount = !!all_flag; NILP (bestmatch) && passcount < 2; passcount++) | 531 |
532 /* Loop reading blocks */ | |
533 /* (att3b compiler bug requires do a null comparison this way) */ | |
534 while (1) | |
530 { | 535 { |
531 int inner_count = SPECPDL_INDEX (); | 536 DIRENTRY *dp; |
532 | 537 int len; |
533 BLOCK_INPUT; | 538 int canexclude = 0; |
534 d = opendir (SDATA (Fdirectory_file_name (encoded_dir))); | |
535 UNBLOCK_INPUT; | |
536 if (!d) | |
537 report_file_error ("Opening directory", Fcons (dirname, Qnil)); | |
538 | |
539 record_unwind_protect (directory_files_internal_unwind, | |
540 make_save_value (d, 0)); | |
541 | |
542 /* Loop reading blocks */ | |
543 /* (att3b compiler bug requires do a null comparison this way) */ | |
544 while (1) | |
545 { | |
546 DIRENTRY *dp; | |
547 int len; | |
548 | 539 |
549 #ifdef VMS | 540 #ifdef VMS |
550 dp = (*readfunc) (d); | 541 dp = (*readfunc) (d); |
551 #else | 542 #else |
552 errno = 0; | 543 errno = 0; |
553 dp = readdir (d); | 544 dp = readdir (d); |
554 if (dp == NULL && (0 | 545 if (dp == NULL && (0 |
555 # ifdef EAGAIN | 546 # ifdef EAGAIN |
556 || errno == EAGAIN | 547 || errno == EAGAIN |
557 # endif | 548 # endif |
558 # ifdef EINTR | 549 # ifdef EINTR |
559 || errno == EINTR | 550 || errno == EINTR |
560 # endif | 551 # endif |
561 )) | 552 )) |
562 { QUIT; continue; } | 553 { QUIT; continue; } |
563 #endif | 554 #endif |
564 | 555 |
565 if (!dp) break; | 556 if (!dp) break; |
566 | 557 |
567 len = NAMLEN (dp); | 558 len = NAMLEN (dp); |
568 | 559 |
569 QUIT; | 560 QUIT; |
570 if (! DIRENTRY_NONEMPTY (dp) | 561 if (! DIRENTRY_NONEMPTY (dp) |
571 || len < SCHARS (encoded_file) | 562 || len < SCHARS (encoded_file) |
572 || 0 <= scmp (dp->d_name, SDATA (encoded_file), | 563 || 0 <= scmp (dp->d_name, SDATA (encoded_file), |
573 SCHARS (encoded_file))) | 564 SCHARS (encoded_file))) |
574 continue; | 565 continue; |
575 | 566 |
576 if (file_name_completion_stat (encoded_dir, dp, &st) < 0) | 567 if (file_name_completion_stat (encoded_dir, dp, &st) < 0) |
577 continue; | 568 continue; |
578 | 569 |
579 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR); | 570 directoryp = ((st.st_mode & S_IFMT) == S_IFDIR); |
580 tem = Qnil; | 571 tem = Qnil; |
581 if (directoryp) | 572 /* If all_flag is set, always include all. |
573 It would not actually be helpful to the user to ignore any possible | |
574 completions when making a list of them. */ | |
575 if (!all_flag) | |
576 { | |
577 int skip; | |
578 if (directoryp) | |
582 { | 579 { |
583 #ifndef TRIVIAL_DIRECTORY_ENTRY | 580 #ifndef TRIVIAL_DIRECTORY_ENTRY |
584 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, "..")) | 581 #define TRIVIAL_DIRECTORY_ENTRY(n) (!strcmp (n, ".") || !strcmp (n, "..")) |
585 #endif | 582 #endif |
586 /* "." and ".." are never interesting as completions, and are | 583 /* "." and ".." are never interesting as completions, and are |
587 actually in the way in a directory with only one file. */ | 584 actually in the way in a directory with only one file. */ |
588 if (!passcount && TRIVIAL_DIRECTORY_ENTRY (dp->d_name)) | 585 if (TRIVIAL_DIRECTORY_ENTRY (dp->d_name)) |
589 continue; | 586 canexclude = 1; |
590 if (!passcount && len > SCHARS (encoded_file)) | 587 else if (len > SCHARS (encoded_file)) |
591 /* Ignore directories if they match an element of | 588 /* Ignore directories if they match an element of |
592 completion-ignored-extensions which ends in a slash. */ | 589 completion-ignored-extensions which ends in a slash. */ |
593 for (tem = Vcompletion_ignored_extensions; | 590 for (tem = Vcompletion_ignored_extensions; |
594 CONSP (tem); tem = XCDR (tem)) | 591 CONSP (tem); tem = XCDR (tem)) |
595 { | 592 { |
616 continue; | 613 continue; |
617 break; | 614 break; |
618 } | 615 } |
619 } | 616 } |
620 else | 617 else |
621 { | 618 { |
622 /* Compare extensions-to-be-ignored against end of this file name */ | 619 /* Compare extensions-to-be-ignored against end of this file name */ |
623 /* if name is not an exact match against specified string */ | 620 /* if name is not an exact match against specified string */ |
624 if (!passcount && len > SCHARS (encoded_file)) | 621 if (len > SCHARS (encoded_file)) |
625 /* and exit this for loop if a match is found */ | 622 /* and exit this for loop if a match is found */ |
626 for (tem = Vcompletion_ignored_extensions; | 623 for (tem = Vcompletion_ignored_extensions; |
627 CONSP (tem); tem = XCDR (tem)) | 624 CONSP (tem); tem = XCDR (tem)) |
628 { | 625 { |
629 elt = XCAR (tem); | 626 elt = XCAR (tem); |
642 } | 639 } |
643 } | 640 } |
644 | 641 |
645 /* If an ignored-extensions match was found, | 642 /* If an ignored-extensions match was found, |
646 don't process this name as a completion. */ | 643 don't process this name as a completion. */ |
647 if (!passcount && CONSP (tem)) | 644 if (CONSP (tem)) |
645 canexclude = 1; | |
646 | |
647 if (!includeall && canexclude) | |
648 /* We're not including all files and this file can be excluded. */ | |
648 continue; | 649 continue; |
649 | 650 |
650 /* FIXME: If we move this `decode' earlier we can eliminate | 651 if (includeall && !canexclude) |
651 the repeated ENCODE_FILE on Vcompletion_ignored_extensions. */ | 652 { /* If we have one non-excludable file, we want to exclude the |
652 name = make_unibyte_string (dp->d_name, len); | 653 excudable files. */ |
653 name = DECODE_FILE (name); | 654 includeall = 0; |
654 | 655 /* Throw away any previous excludable match found. */ |
655 if (!passcount) | 656 bestmatch = Qnil; |
656 { | 657 bestmatchsize = 0; |
657 Lisp_Object regexps; | 658 matchcount = 0; |
658 Lisp_Object zero; | |
659 XSETFASTINT (zero, 0); | |
660 | |
661 /* Ignore this element if it fails to match all the regexps. */ | |
662 for (regexps = Vcompletion_regexp_list; CONSP (regexps); | |
663 regexps = XCDR (regexps)) | |
664 if (fast_string_match (XCAR (regexps), name) < 0) | |
665 break; | |
666 if (CONSP (regexps)) | |
667 continue; | |
668 } | |
669 | |
670 /* This is a possible completion */ | |
671 if (directoryp) | |
672 /* This completion is a directory; make it end with '/'. */ | |
673 name = Ffile_name_as_directory (name); | |
674 | |
675 /* Test the predicate, if any. */ | |
676 if (!NILP (predicate)) | |
677 { | |
678 Lisp_Object val; | |
679 struct gcpro gcpro1; | |
680 | |
681 GCPRO1 (name); | |
682 val = call1 (predicate, name); | |
683 UNGCPRO; | |
684 | |
685 if (NILP (val)) | |
686 continue; | |
687 } | |
688 | |
689 /* Suitably record this match. */ | |
690 | |
691 matchcount++; | |
692 | |
693 if (all_flag) | |
694 bestmatch = Fcons (name, bestmatch); | |
695 else if (NILP (bestmatch)) | |
696 { | |
697 bestmatch = name; | |
698 bestmatchsize = SCHARS (name); | |
699 } | |
700 else | |
701 { | |
702 Lisp_Object zero = make_number (0); | |
703 /* FIXME: This is a copy of the code in Ftry_completion. */ | |
704 compare = min (bestmatchsize, SCHARS (name)); | |
705 tem = Fcompare_strings (bestmatch, zero, | |
706 make_number (compare), | |
707 name, zero, | |
708 make_number (compare), | |
709 completion_ignore_case ? Qt : Qnil); | |
710 if (EQ (tem, Qt)) | |
711 matchsize = compare; | |
712 else if (XINT (tem) < 0) | |
713 matchsize = - XINT (tem) - 1; | |
714 else | |
715 matchsize = XINT (tem) - 1; | |
716 | |
717 if (completion_ignore_case) | |
718 { | |
719 /* If this is an exact match except for case, | |
720 use it as the best match rather than one that is not | |
721 an exact match. This way, we get the case pattern | |
722 of the actual match. */ | |
723 /* This tests that the current file is an exact match | |
724 but BESTMATCH is not (it is too long). */ | |
725 if ((matchsize == SCHARS (name) | |
726 && matchsize + !!directoryp | |
727 < SCHARS (bestmatch)) | |
728 || | |
729 /* If there is no exact match ignoring case, | |
730 prefer a match that does not change the case | |
731 of the input. */ | |
732 /* If there is more than one exact match aside from | |
733 case, and one of them is exact including case, | |
734 prefer that one. */ | |
735 /* This == checks that, of current file and BESTMATCH, | |
736 either both or neither are exact. */ | |
737 (((matchsize == SCHARS (name)) | |
738 == | |
739 (matchsize + !!directoryp == SCHARS (bestmatch))) | |
740 && (tem = Fcompare_strings (name, zero, | |
741 make_number (SCHARS (file)), | |
742 file, zero, | |
743 Qnil, | |
744 Qnil), | |
745 EQ (Qt, tem)) | |
746 && (tem = Fcompare_strings (bestmatch, zero, | |
747 make_number (SCHARS (file)), | |
748 file, zero, | |
749 Qnil, | |
750 Qnil), | |
751 ! EQ (Qt, tem)))) | |
752 bestmatch = name; | |
753 } | |
754 bestmatchsize = matchsize; | |
755 } | 659 } |
756 } | 660 } |
757 /* This closes the directory. */ | 661 /* FIXME: If we move this `decode' earlier we can eliminate |
758 bestmatch = unbind_to (inner_count, bestmatch); | 662 the repeated ENCODE_FILE on Vcompletion_ignored_extensions. */ |
663 name = make_unibyte_string (dp->d_name, len); | |
664 name = DECODE_FILE (name); | |
665 | |
666 { | |
667 Lisp_Object regexps; | |
668 Lisp_Object zero; | |
669 XSETFASTINT (zero, 0); | |
670 | |
671 /* Ignore this element if it fails to match all the regexps. */ | |
672 for (regexps = Vcompletion_regexp_list; CONSP (regexps); | |
673 regexps = XCDR (regexps)) | |
674 if (fast_string_match (XCAR (regexps), name) < 0) | |
675 break; | |
676 if (CONSP (regexps)) | |
677 continue; | |
678 } | |
679 | |
680 /* This is a possible completion */ | |
681 if (directoryp) | |
682 /* This completion is a directory; make it end with '/'. */ | |
683 name = Ffile_name_as_directory (name); | |
684 | |
685 /* Test the predicate, if any. */ | |
686 if (!NILP (predicate)) | |
687 { | |
688 Lisp_Object val; | |
689 struct gcpro gcpro1; | |
690 | |
691 GCPRO1 (name); | |
692 val = call1 (predicate, name); | |
693 UNGCPRO; | |
694 | |
695 if (NILP (val)) | |
696 continue; | |
697 } | |
698 | |
699 /* Suitably record this match. */ | |
700 | |
701 matchcount++; | |
702 | |
703 if (all_flag) | |
704 bestmatch = Fcons (name, bestmatch); | |
705 else if (NILP (bestmatch)) | |
706 { | |
707 bestmatch = name; | |
708 bestmatchsize = SCHARS (name); | |
709 } | |
710 else | |
711 { | |
712 Lisp_Object zero = make_number (0); | |
713 /* FIXME: This is a copy of the code in Ftry_completion. */ | |
714 int compare = min (bestmatchsize, SCHARS (name)); | |
715 Lisp_Object tem | |
716 = Fcompare_strings (bestmatch, zero, | |
717 make_number (compare), | |
718 name, zero, | |
719 make_number (compare), | |
720 completion_ignore_case ? Qt : Qnil); | |
721 int matchsize | |
722 = (EQ (tem, Qt) ? compare | |
723 : XINT (tem) < 0 ? - XINT (tem) - 1 | |
724 : XINT (tem) - 1); | |
725 | |
726 if (completion_ignore_case) | |
727 { | |
728 /* If this is an exact match except for case, | |
729 use it as the best match rather than one that is not | |
730 an exact match. This way, we get the case pattern | |
731 of the actual match. */ | |
732 /* This tests that the current file is an exact match | |
733 but BESTMATCH is not (it is too long). */ | |
734 if ((matchsize == SCHARS (name) | |
735 && matchsize + !!directoryp | |
736 < SCHARS (bestmatch)) | |
737 || | |
738 /* If there is no exact match ignoring case, | |
739 prefer a match that does not change the case | |
740 of the input. */ | |
741 /* If there is more than one exact match aside from | |
742 case, and one of them is exact including case, | |
743 prefer that one. */ | |
744 /* This == checks that, of current file and BESTMATCH, | |
745 either both or neither are exact. */ | |
746 (((matchsize == SCHARS (name)) | |
747 == | |
748 (matchsize + !!directoryp == SCHARS (bestmatch))) | |
749 && (tem = Fcompare_strings (name, zero, | |
750 make_number (SCHARS (file)), | |
751 file, zero, | |
752 Qnil, | |
753 Qnil), | |
754 EQ (Qt, tem)) | |
755 && (tem = Fcompare_strings (bestmatch, zero, | |
756 make_number (SCHARS (file)), | |
757 file, zero, | |
758 Qnil, | |
759 Qnil), | |
760 ! EQ (Qt, tem)))) | |
761 bestmatch = name; | |
762 } | |
763 bestmatchsize = matchsize; | |
764 } | |
759 } | 765 } |
760 | 766 |
761 UNGCPRO; | 767 UNGCPRO; |
768 /* This closes the directory. */ | |
762 bestmatch = unbind_to (count, bestmatch); | 769 bestmatch = unbind_to (count, bestmatch); |
763 | 770 |
764 if (all_flag || NILP (bestmatch)) | 771 if (all_flag || NILP (bestmatch)) |
765 return bestmatch; | 772 return bestmatch; |
766 if (matchcount == 1 && bestmatchsize == SCHARS (file)) | 773 if (matchcount == 1 && bestmatchsize == SCHARS (file)) |