home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / tsw / TSW_3.4.0.exe / Apache2 / perl / perlindex < prev    next >
Encoding:
Text File  |  2004-03-20  |  15.1 KB  |  905 lines

  1. #!perl
  2.     eval 'exec perl -S $0 "$@"'
  3.     if 0;
  4. #                              -*- Mode: Perl -*- 
  5. # $Basename: perlindex.PL $
  6. # $Revision: 1.2 $
  7. # Author          : Ulrich Pfeifer
  8. # Created On      : Mon Jan 22 13:00:41 1996
  9. # Last Modified By: Ulrich Pfeifer
  10. # Last Modified On: Wed Jun 18 19:43:36 2003
  11. # Language        : Perl
  12. # Update Count    : 302
  13. # Status          : Unknown, Use with caution!
  14. # (C) Copyright 1997, Ulrich Pfeifer, all rights reserved.
  15. # %SEEN is used to store the absolute pathes to files which have been
  16. #       indexed. Probably this could be replaced by %FN.
  17. # %FN   $FN{'last'}    greatest documentid
  18. #       $FN{$did}      a pair of $mtf and $filename where $mtf is the
  19. #                      number of occurances of the most frequent word in
  20. #                      the document with number $did.
  21. # %IDF  $IDF{'*all*'}  number of documents (essentially the same as 
  22. #                      $FN{'last'})
  23. #       $IDF{$word}    number of documents containing $word
  24. # %IF   $IF{$word}     list of pairs ($docid,$tf) where $docid is
  25. #                      the number of a document containing $word $tf
  26. use Fcntl;
  27. use less 'time';
  28. use Getopt::Long;
  29. use File::Basename;
  30. use Text::English;
  31.  
  32. # NDBM_File as LAST resort
  33. package AnyDBM_File;
  34.  
  35. @ISA = qw(DB_File GDBM_File SDBM_File ODBM_File NDBM_File) unless @ISA;
  36.  
  37. for $mod (@ISA) {
  38.     last if eval "require $mod"
  39. }
  40.  
  41. package main;
  42.  
  43. $p          = 'w'; # compressed int patch available
  44. $nroff      = '';
  45. $man1direxp = 'D:\Perl\man\man1';
  46. $man3direxp = 'D:\Perl\man\man3';
  47. @perllib    = 'D:\Perl\lib';
  48. push @perllib,'D:\Perl\site\lib';
  49. $prefix     = 'D:\Perl';
  50. $pager      = 'more /e';
  51. use Term::ReadKey;
  52.  
  53. $stemmer = \&Text::English::stem;
  54. # directory for the index 
  55. $IDIR = $man1direxp;
  56. $IDIR =~ s:/[^/]*$::;
  57.  
  58. $opt_index   = '';                # make perl -w happy
  59. $opt_menu    = 1;
  60. $opt_maxhits = 15;
  61. $opt_cbreak  = 1;
  62. &GetOptions(
  63.             'index',
  64.             'cbreak!',
  65.             'maxhits=i',
  66.             'menu!',
  67.             'verbose',
  68.             'dict:i',
  69.             'idir=s',
  70.             ) || die "Usage: $0 [-index] [words ...]\n";
  71.  
  72. if (defined $opt_idir) {
  73.     $IDIR = $opt_idir;          # avoid to many changes below.
  74. }
  75.  
  76. if (defined $opt_dict) {
  77.     $opt_dict ||= 100;
  78. }
  79.  
  80. if ($opt_index) {
  81.     &initstop;
  82.  
  83.     tie (%IF,   AnyDBM_File, "$IDIR/index_if",   O_CREAT|O_RDWR, 0644)
  84.         or die "Could not tie $IDIR/index_if: $!\n";
  85.     tie (%IDF,  AnyDBM_File, "$IDIR/index_idf",  O_CREAT|O_RDWR, 0644)
  86.         or die "Could not tie $IDIR/index_idf: $!\n";
  87.     tie (%SEEN, AnyDBM_File, "$IDIR/index_seen", O_CREAT|O_RDWR, 0644)
  88.         or die "Could not tie $IDIR/index_seen: $!\n";
  89.     tie (%FN,   AnyDBM_File, "$IDIR/index_fn",   O_CREAT|O_RDWR, 0644)
  90.         or die "Could not tie $IDIR/index_fn: $!\n";
  91.  
  92.     require "find.pl";
  93.  
  94.     unless (@ARGV) {            # breaks compatibility :-(
  95.         for $dir (@perllib) {
  96.             print "Scanning $dir ... \n";
  97.             &find($dir);
  98.         }
  99.     }
  100.     for $name (@ARGV) {
  101.         my $fns = $name;
  102.         $fns =~ s:$prefix/::;
  103.         next if $SEEN{$fns};
  104.         next unless -f $name;
  105.         if ($name !~ /(~|,v)$/) {
  106.             $did = $FN{'last'}++;
  107.             $SEEN{$fns} = &index($name, $fns, $did); 
  108.         }
  109.     }
  110.     untie %IF;
  111.     untie %IDF;
  112.     untie %FN;
  113.     untie %SEEN;
  114. } elsif ($opt_dict) {
  115.     tie (%IDF,  AnyDBM_File, "$IDIR/index_idf",  O_RDONLY, 0644)
  116.         or die "Could not tie $IDIR/index_idf: $!\n".
  117.             "Did you run '$0 -index'?\n";
  118.     while (($key,$val) = each %IDF) {
  119.         printf "%-20s %d\n", $key, $val if $val >= $opt_dict;
  120.     }
  121.     untie %IDF;
  122. } else {
  123.     tie (%IF,   AnyDBM_File, "$IDIR/index_if",   O_RDONLY, 0644)
  124.         or die "Could not tie $IDIR/index_if: $!\n".
  125.             "Did you run '$0 -index'?\n";
  126.     tie (%IDF,  AnyDBM_File, "$IDIR/index_idf",   O_RDONLY, 0644)
  127.         or die "Could not tie $IDIR/index_idf: $!\n";
  128.     tie (%FN,   AnyDBM_File, "$IDIR/index_fn",   O_RDONLY, 0644)
  129.         or die "Could not tie $IDIR/index_fn: $!\n";
  130.     &search(@ARGV);
  131.     untie %IF;
  132.     untie %IDF;
  133.     untie %FN;
  134.     untie %SEEN;
  135. }
  136.  
  137. sub wanted {
  138.     my $fns = $name;
  139.  
  140.     if ($name eq $man3direxp) {
  141.         $prune = 1;
  142.     }
  143.     $fns =~ s:$prefix/::;
  144.     return if $SEEN{$fns};
  145.     return unless -f $_;
  146.     if ($name =~ /man|bin|\.(pod|pm)$/) {
  147.         if (!/(~|,v)$/) {
  148.             $did = $FN{'last'}++;
  149.             $SEEN{$fns} = &index($name, $fns, $did); 
  150.         }
  151.     }
  152. }
  153.  
  154. sub index {
  155.     my $fn  = shift;
  156.     my $fns = shift;
  157.     my $did = shift;
  158.     my %tf;
  159.     my $maxtf = 0;
  160.     my $pod = ($fns =~ /\.pod|man/);
  161.  
  162.     open(IN, "<$fn") || warn "Could not open $fn: $!\n", return (0);
  163.     while ($line = <IN>) {
  164.         if ($line =~ /^=head/) {
  165.             $pod = 1;
  166.         } elsif ($line =~ /^=cut/){
  167.             $pod = 0;
  168.         } else {
  169.             next unless $pod;
  170.         }
  171.         for $word (&normalize($line)) {
  172.             next if $stop{$word};
  173.             $tf{$word}++;
  174.         }
  175.     }
  176.     for $tf (values %tf) {
  177.         $maxtf = $tf if $tf > $maxtf;
  178.     }
  179.     for $word (keys %tf) {
  180.         $IDF{$word}++;
  181.         $IF{$word} = '' unless defined $IF{$word}; # perl -w
  182.         $IF{$word} .= pack($p.$p, $did, $tf{$word});
  183.     }
  184.     close(IN);
  185.     $FN{$did} = pack($p, $maxtf).$fns; 
  186.     print STDERR "$fns\n";
  187.     1;
  188. }
  189.  
  190. sub normalize {
  191.     my $line = join ' ', @_;
  192.     my @result;
  193.  
  194.     $line =~ tr/A-Z/a-z/;
  195.     $line =~ tr/a-z0-9/ /cs;
  196.     for $word (split ' ', $line ) {
  197.         $word =~ s/^\d+//;
  198.         next unless length($word) > 2;
  199.         if ($stemmer) {
  200.             push @result, &$stemmer($word);
  201.         } else {
  202.             push @result, $word;
  203.         }
  204.     }
  205.     @result;
  206. }
  207.  
  208. sub search {
  209.     my %score;
  210.     my $maxhits = $opt_maxhits;
  211.     my (@unknown, @stop);
  212.  
  213.     &initstop if $opt_verbose;
  214.     for $word (normalize(@_)) {
  215.         unless ($IF{$word}) {
  216.             if ($stop{$word}) {
  217.                 push @stop, $word;
  218.             } else {
  219.                 push @unknown, $word;
  220.             }
  221.             next;
  222.         }
  223.         my %post = unpack($p.'*',$IF{$word});
  224.         my $idf = log($FN{'last'}/$IDF{$word});
  225.         for $did (keys %post) {
  226.             my ($maxtf) = unpack($p, $FN{$did});
  227.             $score{$did} = 0 unless defined $score{$did}; # perl -w 
  228.             $score{$did} += $post{$did} / $maxtf * $idf;
  229.         }
  230.     }
  231.     if ($opt_verbose) {
  232.         print "Unkown:  @unknown\n" if @unknown;
  233.         print "Ingnore: @stop\n" if @stop;
  234.     }
  235.     if ($opt_menu) {
  236.         my @menu;
  237.         my $answer = '';
  238.         my $no = 0;
  239.         my @s = ('1' .. '9', 'a' .. 'z');
  240.         my %s;
  241.         
  242.         for $did (sort {$score{$b} <=> $score{$a}} keys %score) {
  243.             my ($mtf, $path) = unpack($p.'a*', $FN{$did});
  244.             my $s = $s[$no];
  245.             push @menu, sprintf "%s %6.3f %s\n", $s, $score{$did}, $path;
  246.             $s{$s} = ++$no;
  247.             last unless --$maxhits;
  248.         }
  249.         &cbreak('on') if $opt_cbreak;
  250.         while (1) {
  251.             print @menu;
  252.             print "\nEnter Number or 'q'> ";
  253.             if ($opt_cbreak) {
  254.                 read(TTYIN,$answer,1);
  255.                 print "\n";
  256.             } else {
  257.                 $answer = <STDIN>;
  258.             }
  259.             last if $answer =~ /^q/i;
  260.             $answer = ($s{substr($answer,0,1)})-1;
  261.             if ($answer >= 0 and $answer <= $#menu) {
  262.                 my $selection = $menu[$answer];
  263.                 if ($selection =~ m:/man:) {
  264.                     my ($page, $sect) = 
  265.                         ($selection =~ m:([^/]*)\.(.{1,3})$:);
  266.                     print STDERR "Running man $sect $page\n";
  267.                     system 'man', $sect, $page;
  268.                 } else {
  269.                     my ($path) = ($selection =~ m:(\S+)$:);
  270.                     $path = $prefix.'/'.$path;
  271.                     print STDERR "Running pod2man $path\n";
  272.                     system "pod2man --official $path | $nroff -man | $pager";
  273.                 }
  274.             } else {
  275.                 my $path = $prefix."/bin/perlindex";
  276.                 system "pod2man --official $path | $nroff -man | $pager";
  277.             }
  278.         }
  279.         &cbreak('off') if $opt_cbreak;
  280.     } else {
  281.         for $did (sort {$score{$b} <=> $score{$a}} keys %score) {
  282.             printf("%6.3f %s\n", $score{$did}, 
  283.                    (unpack($p.'a*', $FN{$did}))[1]);
  284.             last unless --$maxhits;
  285.         }
  286.     }
  287. }
  288.  
  289. sub cbreak {
  290.     my $mode = shift;
  291.     if ($mode eq 'on') {
  292.         open(TTYIN, "</dev/tty") || die "can't read /dev/tty: $!";
  293.         open(TTYOUT, ">/dev/tty") || die "can't write /dev/tty: $!";
  294.         select(TTYOUT);
  295.         $| = 1;
  296.         select(STDOUT);
  297.         $SIG{'QUIT'} = $SIG{'INT'} = 'cbreak';
  298.     ReadMode 3; # Set cbreak mode
  299.     } else {
  300.     ReadMode 0; # Restore non-cbreak mode
  301.     }
  302. }
  303.  
  304.  
  305. $stopinited = 0;                # perl -w
  306. sub initstop {
  307.     return if $stopinited++;
  308.     while (<DATA>) {
  309.         next if /^\#/;
  310.         for (normalize($_)) {
  311.           $stop{$_}++;
  312.         }
  313.     }
  314. }
  315.  
  316. =head1 NAME
  317.  
  318. perlindex - index and query perl manual pages
  319.  
  320. =head1 SYNOPSIS
  321.  
  322.     perlindex -index
  323.  
  324.     perlindex tell me where the flowers are
  325.  
  326. =head1 DESCRIPTION
  327.  
  328. "C<perlindex -index>" generates an AnyDBM_File index which can be
  329. searched with free text queries "C<perlindex> I<a verbose query>".
  330.  
  331. Each word of the query is searched in the index and a score is
  332. generated for each document containing it. Scores for all words are
  333. added and the documents with the highest score are printed.  All words
  334. are stemed with Porters algorithm (see L<Text::English>) before
  335. indexing and searching happens.
  336.  
  337. The score is computed as:
  338.  
  339.     $score{$document} += $tf{$word,$document}/$maxtf{$document}
  340.                          * log ($N/$n{$word});
  341.  
  342. where
  343.  
  344. =over 10
  345.  
  346. =item C<$N>
  347.  
  348. is the number of documents in the index,
  349.  
  350. =item C<$n{$word}>
  351.  
  352. is the number of documents containing the I<word>,
  353.  
  354. =item C<$tf{$word,$document}>
  355.  
  356. is the number of occurances of I<word> in the I<document>, and
  357.  
  358. =item C<$maxtf{$document}>
  359.  
  360. is the maximum freqency of any word in I<document>.
  361.  
  362. =back
  363.  
  364. =head1 OPTIONS
  365.  
  366. All options may be abreviated.
  367.  
  368. =over 10
  369.  
  370. =item B<-maxhits> maxhits
  371.  
  372. Maximum numer of hits to display. Default is 15.
  373.  
  374. =item B<-menu>
  375.  
  376. =item B<-nomenu>
  377.  
  378. Use the matches as menu for calling C<man>. Default is B<-menu>.q
  379.  
  380. =item B<-cbreak>
  381.  
  382. =item B<-nocbreak>
  383.  
  384. Switch to cbreak in menu mode or dont. B<-cbreak> is the default.
  385.  
  386. =item B<-verbose>
  387.  
  388. Generates additional information which query words have been not found
  389. in the database and which words of the query are stopwords.
  390.  
  391. =back
  392.  
  393. =head1 EXAMPLE
  394.  
  395.     perlindex foo bar
  396.  
  397.     1  3.735 lib/pod/perlbot.pod
  398.     2  2.640 lib/pod/perlsec.pod
  399.     3  2.153 lib/pod/perldata.pod
  400.     4  1.920 lib/Symbol.pm
  401.     5  1.802 lib/pod/perlsub.pod
  402.     6  1.586 lib/Getopt/Long.pm
  403.     7  1.190 lib/File/Path.pm
  404.     8  1.042 lib/pod/perlop.pod
  405.     9  0.857 lib/pod/perlre.pod
  406.     a  0.830 lib/Shell.pm
  407.     b  0.691 lib/strict.pm
  408.     c  0.691 lib/Carp.pm
  409.     d  0.680 lib/pod/perlpod.pod
  410.     e  0.680 lib/File/Find.pm
  411.     f  0.626 lib/pod/perlsyn.pod
  412.     Enter Number or 'q'>
  413.  
  414. Hitting the keys C<1> to C<f> will display the corresponding manual
  415. page. Hitting C<q> quits. All other keys display this manual page.
  416.  
  417. =head1 FILES
  418.  
  419. The index will be generated in your man directory. Strictly speaking in 
  420. C<$Config{man1direxp}/..>
  421.  
  422.     The following files will be generated:
  423.  
  424.     index_fn           # docid -> (max frequency, filename)
  425.     index_idf          # term  -> number of documents containing term
  426.     index_if           # term  -> (docid, frequency)*
  427.     index_seen         # fn    -> indexed?
  428.     
  429.  
  430. =head1 AUTHOR
  431.  
  432. Ulrich Pfeifer E<lt>F<pfeifer@ls6.informatik.uni-dortmund.de>E<gt>
  433.  
  434. =cut
  435.  
  436. __END__
  437. # freeWAIS-sf stopwords
  438. a
  439. about
  440. above
  441. according
  442. across
  443. actually
  444. adj
  445. after
  446. afterwards
  447. again
  448. against
  449. all
  450. almost
  451. alone
  452. along
  453. already
  454. also
  455. although
  456. always
  457. among
  458. amongst
  459. an
  460. and
  461. another
  462. any
  463. anyhow
  464. anyone
  465. anything
  466. anywhere
  467. are
  468. aren't
  469. around
  470. as
  471. at
  472. b
  473. be
  474. became
  475. because
  476. become
  477. becomes
  478. becoming
  479. been
  480. before
  481. beforehand
  482. begin
  483. beginning
  484. behind
  485. being
  486. below
  487. beside
  488. besides
  489. between
  490. beyond
  491. billion
  492. both
  493. but
  494. by
  495. c
  496. can
  497. can't
  498. cannot
  499. caption
  500. co
  501. co.
  502. could
  503. couldn't
  504. d
  505. did
  506. didn't
  507. do
  508. does
  509. doesn't
  510. don't
  511. down
  512. during
  513. e
  514. each
  515. eg
  516. eight
  517. eighty
  518. either
  519. else
  520. elsewhere
  521. end
  522. ending
  523. enough
  524. etc
  525. even
  526. ever
  527. every
  528. everyone
  529. everything
  530. everywhere
  531. except
  532. f
  533. few
  534. fifty
  535. first
  536. five
  537. vfor
  538. former
  539. formerly
  540. forty
  541. found "
  542. four
  543. from
  544. further
  545. g
  546. h
  547. had
  548. has
  549. hasn't
  550. have
  551. haven't
  552. he
  553. he'd
  554. he'll
  555. he's
  556. hence
  557. her
  558. here
  559. here's
  560. hereafter
  561. hereby
  562. herein
  563. hereupon
  564. hers
  565. herself
  566. him
  567. himself
  568. his
  569. how
  570. however
  571. hundred
  572. i
  573. i'd
  574. i'll
  575. i'm
  576. i've
  577. ie
  578. if
  579. in
  580. inc.
  581. indeed
  582. instead
  583. into
  584. is
  585. isn't
  586. it
  587. it's
  588. its
  589. itself
  590. j
  591. k
  592. l
  593. last
  594. later
  595. latter
  596. latterly
  597. least
  598. less
  599. let
  600. let's
  601. like
  602. likely
  603. ltd
  604. m
  605. made
  606. make
  607. makes
  608. many
  609. maybe
  610. me
  611. meantime
  612. meanwhile
  613. might
  614. million
  615. miss
  616. more
  617. moreover
  618. most
  619. mostly
  620. mr
  621. mrs
  622. much
  623. must
  624. my
  625. myself
  626. n
  627. namely
  628. neither
  629. never
  630. nevertheless
  631. next
  632. nine
  633. ninety
  634. no
  635. nobody
  636. none
  637. nonetheless
  638. noone
  639. nor
  640. not
  641. nothing
  642. now
  643. nowhere
  644. o
  645. of
  646. off
  647. often
  648. on
  649. once
  650. one
  651. one's
  652. only
  653. onto
  654. or
  655. other
  656. others
  657. otherwise
  658. our
  659. ours
  660. ourselves
  661. out
  662. over
  663. overall
  664. own
  665. p
  666. per
  667. perhaps
  668. q
  669. r
  670. rather
  671. recent
  672. recently
  673. s
  674. same
  675. seem
  676. seemed
  677. seeming
  678. seems
  679. seven
  680. seventy
  681. several
  682. she
  683. she'd
  684. she'll
  685. she's
  686. should
  687. shouldn't
  688. since
  689. six
  690. sixty
  691. so
  692. some
  693. somehow
  694. someone
  695. something
  696. sometime
  697. sometimes
  698. somewhere
  699. still
  700. stop
  701. such
  702. t
  703. taking
  704. ten
  705. than
  706. that
  707. that'll
  708. that's
  709. that've
  710. the
  711. their
  712. them
  713. themselves
  714. then
  715. thence
  716. there
  717. there'd
  718. there'll
  719. there're
  720. there's
  721. there've
  722. thereafter
  723. thereby
  724. therefore
  725. therein
  726. thereupon
  727. these
  728. they
  729. they'd
  730. they'll
  731. they're
  732. they've
  733. thirty
  734. this
  735. those
  736. though
  737. thousand
  738. three
  739. through
  740. throughout
  741. thru
  742. thus
  743. to
  744. together
  745. too
  746. toward
  747. towards
  748. trillion
  749. twenty
  750. two
  751. u
  752. under
  753. unless
  754. unlike
  755. unlikely
  756. until
  757. up
  758. upon
  759. us
  760. used
  761. using
  762. v
  763. very
  764. via
  765. w
  766. was
  767. wasn't
  768. we
  769. we'd
  770. we'll
  771. we're
  772. we've
  773. well
  774. were
  775. weren't
  776. what
  777. what'll
  778. what's
  779. what've
  780. whatever
  781. when
  782. whence
  783. whenever
  784. where
  785. where's
  786. whereafter
  787. whereas
  788. whereby
  789. wherein
  790. whereupon
  791. wherever
  792. whether
  793. which
  794. while
  795. whither
  796. who
  797. who'd
  798. who'll
  799. who's
  800. whoever
  801. whole
  802. whom
  803. whomever
  804. whose
  805. why
  806. will
  807. with
  808. within
  809. without
  810. won't
  811. would
  812. wouldn't
  813. x
  814. y
  815. yes
  816. yet
  817. you
  818. you'd
  819. you'll
  820. you're
  821. you've
  822. your
  823. yours
  824. yourself
  825. yourselves
  826. z
  827. # occuring in more than 100 files
  828. acc
  829. accent
  830. accents
  831. and
  832. are
  833. bell
  834. can
  835. character
  836. corrections
  837. crt
  838. daisy
  839. dash
  840. date
  841. defined
  842. definitions
  843. description
  844. devices
  845. diablo
  846. dummy
  847. factors
  848. following
  849. font
  850. for
  851. from
  852. fudge
  853. give
  854. have
  855. header
  856. holds
  857. log
  858. logo
  859. low
  860. lpr
  861. mark
  862. name
  863. nroff
  864. out
  865. output
  866. perl
  867. pitch
  868. put
  869. rcsfile
  870. reference
  871. resolution
  872. revision
  873. see
  874. set
  875. simple
  876. smi
  877. some
  878. string
  879. synopsis
  880. system
  881. that
  882. the
  883. this
  884. translation
  885. troff
  886. typewriter
  887. ucb
  888. unbreakable
  889. use
  890. used
  891. user
  892. vroff
  893. wheel
  894. will
  895. with
  896. you
  897.  
  898.