/[wait]/trunk/script/sman
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/script/sman

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (hide annotations)
Tue May 9 11:29:45 2000 UTC (23 years, 11 months ago) by ulpfr
Original Path: branches/CPAN/script/sman
File size: 12113 byte(s)
Import of WAIT-1.800

1 ulpfr 19 #!perl -w
2     # -*- Mode: Perl -*-
3     # $Basename: sman $
4     # $Revision: 1.14 $
5     # Author : Ulrich Pfeifer
6     # Created On : Fri Aug 30 15:52:25 1996
7     # Last Modified By: Ulrich Pfeifer
8     # Last Modified On: Mon May 8 11:03:46 2000
9     # Language : CPerl
10     #
11     # (C) Copyright 1996-2000, Ulrich Pfeifer
12     #
13 ulpfr 10
14     use strict;
15    
16     use Term::ReadLine;
17     use Getopt::Long;
18     use Fcntl;
19     use Config;
20    
21     require WAIT::Config;
22     require WAIT::Database;
23     require WAIT::Query::Base;
24     require WAIT::Query::Wais;
25    
26    
27     $SIG{PIPE} = 'IGNORE';
28     my %OPT = (database => 'DB',
29     dir => $WAIT::Config->{WAIT_home} || '/tmp',
30     table => 'man',
31     pager => $WAIT::Config->{'pager'} || 'more',
32     filter => 0,
33     max => 15,
34     );
35    
36     GetOptions(\%OPT,
37     'database=s',
38     'dir=s',
39     'table=s',
40     'filter=i',
41     'max=i',
42     'pager:s') || die "Usage: ...\n";
43    
44     my $db = WAIT::Database->open(name => $OPT{database},
45     mode => O_RDONLY,
46     directory => $OPT{dir})
47     or die "Could not open database $OPT{database}: $@";
48    
49     my $tb = $db->table(name => $OPT{table})
50     or die "Could not open table $OPT{table}: $@";
51    
52     # not used: my $layout = $tb->layout; # a WAIT::Parse::Nroff object
53    
54     my $term = new Term::ReadLine 'Simple Query Interface';
55    
56     require WAIT::Format::Term;
57     my $format;
58     if ($Config::Config{'archname'} eq 'i586-linux') {
59     # for color xterm
60     $format = new WAIT::Format::Term query_s => "", query_e => "";
61     } else {
62     $format = new WAIT::Format::Term;
63     }
64    
65     my $pager = ($OPT{pager}) ? \&pager : \&less;
66     my $OUT = $term->OUT;
67    
68     my $st = 1;
69     print $OUT "Enter 'h' for help.\n";
70    
71     # sman is basically offering three services: find the hits and show
72     # them (a query), show metadata for a hit (a view), show a hot (display)
73    
74     my($query, @did);
75    
76     while (defined ($_ = &myreadline("$st> "))) {
77     chomp; $st++;
78    
79     my(%hits, $query_text);
80     if (/^$/) {
81     next;
82     } elsif (/^m (\d+)$/) {
83     $OPT{max} = $1;
84     } elsif (/^f\s*(\d+)?$/) {
85     $OPT{filter} = $1;
86     next;
87     } elsif (/^t$/i) {
88     if ($pager eq \&less) {
89     $pager = \&pager;
90     } else {
91     $pager = \&less;
92     }
93     next;
94     } elsif (/^(\d+)$/) {
95     if (defined $did[$1]) {
96     display($did[$1]); # <----------- display (full doc)
97     next;
98     }
99     } elsif (/^d\s*(\d+)/) {
100     if (defined $did[$1]) {
101     view($did[$1]); # <----------- view (metadata from WAIT)
102     next;
103     }
104     } elsif (/^q$/i) {
105     last;
106     } elsif (/^l$/i) {
107     # fall through
108     } elsif (/^[h?]$/i) {
109     help();
110     next;
111     } elsif (/^hh$/i) {
112     extended_help();
113     next;
114     } else { # <----------- A query (Display a list)
115     $query_text = $_;
116     eval {$query = WAIT::Query::Wais::query($tb, $_)};
117     if ($@ ne '') {
118     print $OUT "$_ => $query\n\$\@='$@'\n";
119     } elsif (ref($query)) {
120 ulpfr 19 %hits = $query->execute(top => $OPT{max}, picky => 1);
121 ulpfr 10 # the hash %hits has as keys document numbers and as values
122     # quality figures. The doc numbers are not what we have as docid
123     # to find the item in the access class, they are WAIT's private
124     # numbers.
125     } else {
126     next;
127     }
128     }
129    
130     next unless %hits;
131     my $no = 1; # numbering the hits for the result table that is
132     # presented to the user
133    
134     @did = (); # store the internal numbers (keys of %hits). The user
135     # will use $no in sman's interface to select a hit.
136    
137     # the following loop uses the values of %hits to sort the results
138     # according to the quality and cut after a number of rows. After
139     # that %hits isn't needed anymore.
140     print "Query: $query_text\n";
141     for my $did (sort {$hits{$b} <=> $hits{$a}} keys %hits) {
142    
143     my %tattr = $tb->fetch($did);
144     # the hash %tattr contains several attributes of the item we are
145     # referring to, namely the attributes that we named in the "attr"
146     # argument of the create_table statement in smakewhatis
147    
148     printf $OUT "%2d %6.3f %s\n", $no, $hits{$did},
149     substr($tattr{headline} ||'',0,68);
150     $did[$no] = $did;
151     last if $no++ >= $OPT{max};
152    
153     }
154    
155     } continue {
156 ulpfr 19 # we don't do this since Andreas Koenig does not think of it as feature
157 ulpfr 10 # $term->SetHistory(grep length($_)>4, $term->GetHistory)
158     }
159 ulpfr 19 warn "Thank you for using sman\n";
160 ulpfr 10
161 ulpfr 19 $tb->close;
162     $db->close;
163    
164 ulpfr 10 sub myreadline {
165     if (@ARGV) {
166     return shift @ARGV;
167     } else {
168     $term->readline(@_);
169     }
170     }
171     sub help {
172     my $idb = "\n\t'". join(q[', '], $tb->fields()) . "'";
173     print $OUT qq[Available commands:
174    
175     <num> Show the document <num>
176     d <num> Show the db entry of document <num>
177     f <num> Display only <num> lines context
178     h,? Display this help message
179     hh Display query examples
180     m <num> Set maxhits to <num>
181     t Toggle display mode (term/less)
182     q Exit from $0
183     l redisplay last ranking
184     Other input is tried as wais query.
185     The following fields are known: $idb
186     ] ;
187     }
188    
189     sub extended_help {
190     print q{
191     Here are some query examples:
192    
193     information retrieval free text query
194     information or retrieval same as above
195     des=information retrieval `information' must be in the description
196     des=(information retrieval) one of them in description
197     des=(information or retrieval) same as above
198     des=(information and retrieval) both of them in description
199     des=(information not retrieval) `information' in description and
200     `retrieval' not in description
201     des=(information system*) wild-card search
202     au=ilia author names may be misspelled
203    
204     You can build arbitary boolean combination of the above examples.
205     Field names may be abbreviated.
206     }
207     }
208    
209     sub view {
210     my $did = shift;
211     my %tattr = $tb->fetch($did);
212     for (keys %tattr) {
213     print $OUT "$_ $tattr{$_}\n";
214     }
215     }
216    
217     sub display {
218     my $did = shift;
219    
220     return unless defined $query and defined $did;
221    
222     print $OUT "Wais display document $did\n";
223     my %tattr = $tb->fetch($did);
224     my $tdid = $tattr{docid};
225     # WHAT DOES HE DO HERE? ULI???
226     # Re: some indexing scripts did use pathnames relative to the table directory
227     # especially the cpanwait script does this. uli
228     # if ($tdid !~ m(^/)) {
229     # $tdid = $tb->dir . '/' . $tdid;
230     # }
231    
232     # The main task of all that follows from here is highlighting. WAIT
233     # is designed to make it possible to show the user why a certain
234     # document was chosen by the indexer.
235    
236     my $buf = $tb->fetch_extern($tdid);
237     # This $buf can be an object that can have enough information to do
238     # highlighting without WAIT's help. If you prefer to implement your
239     # own highlighting, you can do so now with e.g. print
240     # $buf->highlight(query => $query)
241    
242     # All you need to know to implement highlighting is how a
243     # WAIT::Query::Base object looks like (left as an exercise for the
244     # reader).
245    
246     # The impatient reader may want to implement something without
247     # highlighting, in which case he does not need any info about the
248     # query object and can rightaway run e.g.
249     # print $buf->as_string
250    
251     # Thus the impatient reader does not necessarily need the following
252     # heavy wizardry. Just to give you an idea what's going on: every
253     # word in the text must be compared to every word in the query if it
254     # is worth highlighting, and which part of the word is worth
255     # highlighting. This must be done differently for every field in the
256     # table and for every index defined for that field. Try to run a
257     # query with 100 words and you'll be amazed to see it really works.
258     # Or maybe it doesn't. You should be aware that the hilighting code
259     # is to be regarded as alpha. It is certainly the least tested part
260     # of WAIT so far.
261    
262     if ($buf) {
263     my @txt = $query->hilight($buf);
264     # In this operation the following things melt into one piece:
265     # $query: The query entered by the user (Class isa WAIT::Query::Base)
266     # $tb: The table we queried (Class WAIT::Table)
267     # $buf: The document to display (User defined class or string)
268     # The steps taken are:
269     # 1.) $query calls "hilight" on $tb and passes
270     # filtered and raw search terms ($query->{Plain} and $query->{Raw}).
271     # 2.) $tb asks the layout object to tag the object which results
272     # in an array with alternating elements of tags (anon HASHes) and
273     # strings.
274     # 3.) $tb adds some markup on its own: {qt=>1} or some such
275    
276     # The result of that process can optionally be sent through a
277     # filter, just to impress your friends with yet more heavy
278     # wizardry
279     if ($OPT{filter}) {
280     @txt = &filter(@txt);
281     }
282    
283     # And then a formatter (in our case a terminal formatter) turns
284     # all the markup into escape sequences and strings that can in
285     # turn be sent through a pager for instance
286     &$pager($format->as_string(\@txt));
287     }
288    
289     # Hey, that's it. The user out there is deeply impressed now. You
290     # can lean back again:-) He got a document that has some words
291     # hilighted and will probably read and enjoy it. Maybe he'll send
292     # you an email.
293     }
294    
295     sub filter {
296     my @result;
297     my @context;
298     my $lines = 0;
299     my $clines = 0;
300     my $elipsis = 0;
301    
302     print STDERR "Filter ...";
303     while (@_) {
304     my %tag = %{shift @_};
305     my $txt = shift @_;
306    
307     for (split /(\n)/, $txt) {
308     if ($_ eq "\n") {
309     if (exists $tag{_qt}) {
310     #die "Weird!";
311     push @result, {_i=>1}, "[WEIRD]";
312     } elsif ($lines) {
313     push @result, {}, $_;
314     $lines--;
315     } else {
316     push @context, {}, $_;
317     $clines++;
318     }
319     } else {
320     if (exists $tag{_qt}) {
321     push @result, {_i=>1}, "\n[ $elipsis linesĀ ]\n" if $elipsis;
322     push @result, @context, {%tag}, $_;
323     delete $tag{_qt};
324     @context = (); $clines = 0; $elipsis=0;
325     $lines = $OPT{filter}+1;
326     } elsif ($lines) {
327     push @result, \%tag, $_;
328     } else {
329     push @context, \%tag, $_;
330     }
331     }
332     if ($clines>$OPT{filter}) {
333     my (%tag, $txt);
334     while ($clines>$OPT{filter}) {
335     %tag = %{shift @context};
336     $txt = shift @context;
337     if ($txt =~ /\n/) {
338     $clines--;
339     $elipsis++;
340     }
341     }
342     }
343     }
344     }
345     print STDERR " done\n";
346     @result;
347     }
348    
349     sub less {
350     my $flags;
351     if ($WAIT::Config->{pager} =~ /less/) {
352     $flags = '-r';
353     } elsif ($WAIT::Config->{pager} =~ /more/) {
354     $flags = '-c';
355     }
356     open(PAGER, "|$WAIT::Config->{pager} $flags") or die;
357     print PAGER @_;
358     close PAGER;
359     }
360    
361     sub pager {
362     my @lines = split /\n/, $_[0];
363     my $line = 0;
364     for (@lines) {
365     print "$_\n"; $line++;
366     if ($line % 24 == 0) {
367     my $key = $term->readline("[return]");
368     return if $key =~ /^q/i;
369     }
370     }
371     }
372    
373    
374     __END__
375     ## ###################################################################
376     ## pod
377     ## ###################################################################
378    
379     =head1 NAME
380    
381     sman - Search and disply manuals interactive
382    
383     =head1 SYNOPSIS
384    
385     B<sman>
386     [B<-database> I<database name>]
387     [B<-dir> I<database directory>]
388     [B<-table> I<name>]
389     [B<-less>]
390     [B<-filter> I<num>]
391     [B<-max> I<num>]
392    
393     =head1 DESCRIPTION
394    
395     B<Sman> is an interactive search interface to your systems manual pages.
396    
397     =head2 OPTIONS
398    
399     =over 10
400    
401     =item B<-database> I<database name>
402    
403     Change the default database name to I<database name>.
404    
405     =item B<-dir> I<database directory>
406    
407     Change the default database directory to I<database directory>.
408    
409     =item B<-table> I<name>
410    
411     Use I<name> instead of C<man> as table name.
412    
413     =item B<-pager> I<name>
414    
415     Use I<name> instead of the default pager. If no I<name> is supplied a
416     buildin pager is used.
417    
418     =item B<-filter> I<num>
419    
420     Display only I<num> lines above and below an occurance of a search
421     term in the manual.
422    
423     =item B<-max> I<num>
424    
425     Display only I<num> hits. Default is to 10.
426    
427     =head1 SEE ALSO
428    
429     L<smakewhatis>.
430    
431     =head1 AUTHOR
432    
433     Ulrich Pfeifer E<lt>F<pfeifer@ls6.informatik.uni-dortmund.de>E<gt>

Properties

Name Value
cvs2svn:cvs-rev 1.1.1.2
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26