/[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

Contents of /trunk/script/sman

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show annotations)
Tue May 9 11:29:45 2000 UTC (23 years, 11 months ago) by cvs2svn
Original Path: cvs-head/script/sman
File size: 12113 byte(s)
This commit was generated by cvs2svn to compensate for changes in r10,
which included commits to RCS files with non-trunk default branches.

1 #!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
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 %hits = $query->execute(top => $OPT{max}, picky => 1);
121 # 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 # we don't do this since Andreas Koenig does not think of it as feature
157 # $term->SetHistory(grep length($_)>4, $term->GetHistory)
158 }
159 warn "Thank you for using sman\n";
160
161 $tb->close;
162 $db->close;
163
164 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